We are still cooking the magic in the way!
Metrics with Micrometer
Metrics with Micrometer
Knowing that your application is alive (a health check) is necessary but not sufficient. To operate a production service confidently you need to answer questions like: how many requests per second is this endpoint handling? What is the 95th-percentile response time? How full is the database connection pool? These answers come from metrics, and in Spring Boot 3 the library that collects and exports them is Micrometer.
What Micrometer Is
Micrometer is a vendor-neutral metrics facade — the same API works whether you export data to Prometheus, Datadog, InfluxDB, CloudWatch, or a dozen other backends. The Spring Boot Actuator dependency pulls Micrometer in automatically; you do not need to add it separately.
The central object is the MeterRegistry. Spring Boot auto-configures one and adds it to the application context. Inject it wherever you need to record measurements.
The /metrics Endpoint
When spring-boot-starter-actuator is on the classpath, the /actuator/metrics endpoint is available (HTTP GET). It lists every meter name that Micrometer has registered:
Drill into a specific meter by appending its name:
Filter by tag using a query parameter: /actuator/metrics/jvm.memory.used?tag=area:heap
Built-In Meters
Spring Boot registers a rich set of meters automatically — you get all of the following with zero configuration:
- JVM metrics (
jvm.*) — memory areas, GC pause counts and durations, thread states, class loading. - HTTP server metrics (
http.server.requests) — request count, total time, max time, tagged by URI, method, and HTTP status. - Process metrics (
process.*) — CPU usage, uptime, file descriptors. - System metrics (
system.*) — CPU count, load average, disk space. - HikariCP metrics (
hikaricp.*) — pool size, active connections, idle connections, pending acquisitions, timeouts. - Logback metrics (
logback.events) — event counts by level (INFO, WARN, ERROR).
Recording Custom Metrics
The four primary meter types cover almost every measurement need:
Counter— a monotonically increasing value. Use for events: orders placed, emails sent, errors caught.Gauge— a current snapshot that can go up or down. Use for sizes: queue depth, cache size, active sessions.Timer— records durations and counts. Use for operations with latency: HTTP calls, database queries.DistributionSummary— records a distribution of values without a time unit. Use for sizes: request payload bytes, batch sizes.
Counter Example
Timer Example
Gauge Example
increment() / record() many times. Creating a new meter object per method call is wasteful and causes duplicate-registration warnings.
Tags: The Key to Useful Dashboards
Raw counts are rarely useful on their own. Tags turn a single meter into a multi-dimensional dataset. When you tag orders.placed with channel=web and channel=mobile separately, your monitoring tool can aggregate or split the series as needed.
Keep tags low-cardinality — a finite, small set of values. Never use user IDs, order IDs, or any unbounded value as a tag. Each unique tag combination creates a new time-series in your monitoring backend; high-cardinality tags explode storage and query costs.
tag("userId", userId.toString()) creates millions of unique series. Use low-cardinality categorical values only: status codes, region names, feature flags.
Exporting to Prometheus
The /actuator/metrics endpoint is convenient for ad-hoc inspection, but production monitoring systems scrape metrics in bulk. Prometheus is the most common choice. Add the registry dependency:
Spring Boot auto-configures the Prometheus registry and exposes the /actuator/prometheus endpoint in Prometheus text format. Add one line to your scrape config and every meter you registered — built-in and custom — flows into Prometheus automatically.
Common Pitfalls
- Forgetting to call
.register(registry)— the meter silently does nothing and never appears in/actuator/metrics. - Recording time manually with
System.currentTimeMillis()instead of using aTimer— you lose percentiles, histogram buckets, and the Micrometer clock abstraction (which can be replaced in tests). - Using
@Timedon a non-Spring-managed bean — the AOP proxy that drives the annotation is only created for Spring beans.
Summary
Micrometer gives Spring Boot 3 applications a rich, vendor-neutral metrics layer. You get JVM, HTTP, pool, and system meters for free; add domain-specific Counter, Timer, Gauge, and DistributionSummary meters through the injected MeterRegistry. Keep tags low-cardinality, publish percentiles on latency-sensitive timers, and export to Prometheus (or any other registry) with a single dependency. The next lesson covers securing and customizing the Actuator endpoints so that only the right consumers can access this data.