skip to content

Micrometer Metrics & Export

Micrometer as the metrics facade: registries per backend, counters and gauges, timers and summaries, tags and filters, annotations, exporters, and the meters Boot registers for you. Interviewers ask about metric design, and cardinality is where most answers fail.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

What meters does Spring Boot auto-configure out of the box, and what is a MeterBinder?

level: juniorimportance: must knowfreq 62%

answer

  1. actuator + micrometer => free meters
  2. MeterBinder.bindTo(registry)
  3. jvm.memory / jvm.gc / jvm.threads / system.cpu / process
  4. http.server.requests Timer
  5. hikaricp + logback.events

basics

~20 s

With Actuator + Micrometer on the classpath, Boot auto-registers meters for JVM memory/GC/threads, CPU, process, HTTP requests, datasource, and logback events. A MeterBinder is a small class that binds one such set of metrics to the MeterRegistry.

solid answer

~30 s

Adding spring-boot-starter-actuator (which pulls in micrometer-core) makes Boot auto-configure a broad set of meters without any code. Core groups: jvm.memory.used/max/committed, jvm.gc.*, jvm.threads.*, system.cpu.usage and process.cpu.usage, process.uptime/start.time, http.server.requests (a Timer per endpoint), and — when present — http.client.requests, hikaricp.*/jdbc datasource pool metrics, and logback.events (log lines by level). Each group is produced by a MeterBinder — an interface with bindTo(MeterRegistry) — such as JvmMemoryMetrics, JvmGcMetrics, ProcessorMetrics, LogbackMetrics. Boot registers every MeterBinder bean it finds against the registry. You expose them at /actuator/metrics and /actuator/prometheus. So a MeterBinder is the plug-in unit that knows how to register a related family of gauges/counters/timers.

code

java · 19 lines
java
// The MeterBinder contract (Micrometer)
public interface MeterBinder {
    void bindTo(MeterRegistry registry);
}

// A built-in binder Boot registers for you:
// io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics
// io.micrometer.core.instrument.binder.system.ProcessorMetrics
// io.micrometer.core.instrument.binder.logging.LogbackMetrics

// Any MeterBinder @Bean is auto-bound to the primary MeterRegistry:
@Configuration
class MetricsConfig {
    @Bean
    MeterBinder queueSize(WorkQueue queue) {
        return registry -> Gauge.builder("app.queue.size", queue, WorkQueue::size)
                                .register(registry);
    }
}

go deeper

for a junior

Know that actuator gives free JVM/HTTP/process metrics and that MeterBinder registers a family of meters.

for a middle

Name the concrete binder classes and the meter names/types each produces.

for a senior

Explain conditional registration and how a MeterBinder bean is auto-bound to the registry.

for a principal

Frame built-ins as covering RED/USE signals and decide what custom instrumentation is still needed on top.

## The big picture Spring Boot's Actuator, combined with **Micrometer** (a vendor-neutral metrics facade, think 'SLF4J for metrics'), gives you a large catalog of production metrics for free. You add one dependency — `spring-boot-starter-actuator` — and Boot's `MetricsAutoConfiguration` / `*MetricsAutoConfiguration` classes register meters against a `MeterRegistry` bean. ### Key terms - **Meter**: a single metric. Micrometer meter types: `Counter` (monotonic count), `Gauge` (instantaneous value that can go up/down, e.g. memory used), `Timer` (count + total time + max of timed events), `DistributionSummary`, `LongTaskTimer`, `FunctionCounter`/`FunctionTimer`. - **MeterRegistry**: the collection all meters are registered into and the thing a monitoring backend reads from (e.g. `PrometheusMeterRegistry`). - **MeterBinder**: a functional-ish interface `interface MeterBinder { void bindTo(MeterRegistry registry); }`. It packages the logic to create and register a *related family* of meters. Boot auto-detects every `MeterBinder` bean in the context and calls `bindTo` on the primary registry via `MeterRegistryPostProcessor`. ### What Boot auto-registers (the built-ins) Provided by Micrometer's `io.micrometer.core.instrument.binder.*` classes, enabled by Boot auto-config: - **JVM**: `JvmMemoryMetrics` -> `jvm.memory.used/committed/max` (tagged by `area`=heap/nonheap and memory pool `id`); `JvmGcMetrics` -> `jvm.gc.pause` timer, `jvm.gc.memory.allocated/promoted`; `JvmThreadMetrics` -> `jvm.threads.live/daemon/peak/states`; `ClassLoaderMetrics` -> `jvm.classes.loaded`. - **System/Process**: `ProcessorMetrics` -> `system.cpu.usage`, `process.cpu.usage`, `system.cpu.count`, `system.load.average.1m`; `UptimeMetrics` -> `process.uptime`, `process.start.time`; `FileDescriptorMetrics` -> `process.files.open/max`. - **HTTP server**: `http.server.requests` — a `Timer` recorded per request by a Servlet `Filter`/WebFlux `WebFilter` (`ServerHttpObservationFilter` in modern Boot), tagged with `uri`, `method`, `status`, `outcome`, `exception`. - **HTTP client**: `http.client.requests` for `RestTemplate`/`RestClient`/`WebClient` instrumented by Boot. - **DataSource/pool**: `DataSourcePoolMetrics` -> `jdbc.connections.*`; if HikariCP is the pool, `hikaricp.connections.*` (active/idle/pending/timeout/usage/acquire). - **Logging**: `LogbackMetrics` -> `logback.events` counter tagged by `level` (error/warn/info/...). - **Tomcat/Jetty**: `TomcatMetrics` -> `tomcat.*` when the container manager is available. ### How to see them `management.endpoints.web.exposure.include=metrics,prometheus`. Then `GET /actuator/metrics` lists names, `GET /actuator/metrics/jvm.memory.used` drills into one, `GET /actuator/prometheus` gives the scrape format. ### Gotchas - Some binders only register when their dependency/condition is present (HikariCP metrics need HikariCP; `http.client.requests` needs an instrumented client). - Metrics are lazily/eagerly created but a Timer like `http.server.requests` only shows tag values that have actually been observed. ### When to rely on them Almost always — they cover the standard RED/USE signals (request rate/errors/duration + resource saturation) with zero code, which is exactly what you want before adding custom business metrics.

  • Which single dependency turns most of these on, and how do you view them?
    spring-boot-starter-actuator (it brings micrometer-core). View via /actuator/metrics, drill into one with /actuator/metrics/{name}, or scrape /actuator/prometheus after exposing the endpoint.
  • Are all built-in meters always registered?
    No — many are conditional. hikaricp.* needs HikariCP as the pool, http.client.requests needs an instrumented RestTemplate/WebClient, TomcatMetrics needs the Tomcat manager. JVM/process/CPU/logback ones are effectively always on.

saying these in an interview costs you the question

  • Thinking you must write code to get JVM/HTTP metrics
  • Believing http.server.requests is a Gauge or Counter rather than a Timer
  • Assuming MeterBinder is a Spring annotation rather than a Micrometer interface

context

open as a page

What is a Micrometer Counter and when should you use one instead of a Gauge?

level: juniorimportance: must knowfreq 70%

basics

~20 s

A Counter records a value that only ever goes up (a total, like requests served). Use a Counter for cumulative counts you increment; use a Gauge for a value that can go up and down, like current queue size.

open as a page

How do you expose your Spring Boot application's metrics to Prometheus, and what is the /actuator/prometheus endpoint?

level: juniorimportance: must knowfreq 70%

basics

~10 s

Add the micrometer-registry-prometheus dependency and expose the endpoint with management.endpoints.web.exposure.include=prometheus. Spring Boot then serves metrics as plain text at /actuator/prometheus, which the Prometheus server reads (scrapes).

open as a page

What is a Micrometer MeterRegistry, and what role does it play in a Spring Boot application?

level: juniorimportance: must knowfreq 70%

basics

~10 s

MeterRegistry is Micrometer's central object that creates and holds meters (counters, gauges, timers). Spring Boot auto-configures one and injects it, so your code records metrics through it without knowing which monitoring backend receives them.

open as a page

What are dimensional tags on a Micrometer meter, and why do they matter?

level: juniorimportance: must knowfreq 55%

basics

~10 s

Tags are key/value labels (like method=GET, status=200) attached to a meter. They let you slice one metric by dimensions and filter or group in your monitoring system instead of creating many separate metrics.

open as a page

What is a Micrometer Timer, and how do you use it to record the latency of a block of code?

level: juniorimportance: must knowfreq 70%

basics

~20 s

A Timer measures how long operations take and counts how often they run. Register one on the MeterRegistry, then wrap the code with timer.record(() -> ...) or record a Duration, and Micrometer tracks count, total time, and max.

open as a page

You add @Timed to a service method but no metric shows up under /actuator/metrics. Why, and how do you fix it?

level: middleimportance: must knowfreq 48%

basics

~20 s

The @Timed annotation does nothing by itself — a TimedAspect bean has to intercept the method. If Spring AOP or that aspect bean is missing, nothing is recorded. Add spring-boot-starter-aop and make sure TimedAspect (and CountedAspect) are registered.

open as a page

Explain the http.server.requests meter: what tags does it carry and how is it recorded?

level: middleimportance: must knowfreq 68%

basics

~20 s

http.server.requests is a Timer recorded for every HTTP request, tagged with uri, method, status and outcome so you can see request rate, error rate and latency per endpoint. It is added automatically by an Actuator filter.

open as a page

How do you register a Gauge that tracks a live object or function, and how is its value read?

level: middleimportance: must knowfreq 60%

basics

~20 s

You bind the Gauge to an object plus a function that reads its current value, e.g. Gauge.builder("queue.size", queue, Queue::size).register(registry). Micrometer calls that function each time the registry is scraped, so the reported value is always current.

open as a page

Contrast the Prometheus registry (pull) with the OTLP registry (push) in Spring Boot. How does each get metrics out of the app?

level: middleimportance: must knowfreq 65%

basics

~10 s

PrometheusMeterRegistry exposes metrics at /actuator/prometheus and waits for the Prometheus server to scrape (pull). OtlpMeterRegistry actively pushes metrics on a timer to an OTLP endpoint like an OpenTelemetry Collector. One waits; the other sends.

open as a page

Explain Micrometer's 'registry per monitoring system' model and the role of CompositeMeterRegistry.

level: middleimportance: must knowfreq 60%

basics

~20 s

Each monitoring backend has its own MeterRegistry implementation (one per system). To send the same metrics to several backends at once, Micrometer uses a CompositeMeterRegistry that holds child registries and forwards every meter operation to all of them.

open as a page

How do you add common tags (like application or region) to every meter in a Spring Boot app?

level: middleimportance: must knowfreq 50%

basics

~10 s

Define a MeterRegistryCustomizer<MeterRegistry> bean that calls registry.config().commonTags("application", "my-app"). Those tags are then attached to every meter. In Spring Boot you can also set management.metrics.tags.* properties.

open as a page

Why does @Timed silently record nothing when an annotated method is called from another method in the same bean?

level: seniorimportance: must knowfreq 38%

basics

~10 s

@Timed relies on a Spring AOP proxy that wraps the bean. Self-invocation (this.method()) calls the method directly on the target object, bypassing the proxy, so the TimedAspect never runs and no metric is recorded.

open as a page

What is a high-cardinality tag explosion, why is it dangerous, and how do you prevent one in a Spring Boot / Micrometer app?

level: seniorimportance: must knowfreq 48%

basics

~20 s

Cardinality is the number of distinct tag-value combinations, each of which is a separate time series. Putting unbounded values (user IDs, raw URLs, timestamps) in tags creates millions of series — OOM in the app and heavy load/cost in Prometheus. Prevent it with bounded tags, templated URIs, and MeterFilters that strip or cap tags.

open as a page

What do the @Timed and @Counted annotations do in a Micrometer/Spring Boot application?

level: juniorimportance: should knowfreq 40%

basics

~20 s

@Timed records how long a method takes (a Timer metric); @Counted counts how many times it runs (a Counter). You put them on a method and Micrometer publishes the metric automatically, without writing timing code by hand.

open as a page

Which JVM, process and system meters does Boot expose, and how do you read jvm.memory / jvm.gc / system.cpu?

level: middleimportance: should knowfreq 48%

basics

~10 s

Boot exposes jvm.memory.used/max/committed (tagged by area and pool), jvm.gc.pause and allocation counters, jvm.threads.live/daemon/peak, plus system.cpu.usage and process.cpu.usage, process.uptime and process.start.time. They come from Micrometer JVM/System binders.

open as a page

What is a LongTaskTimer and how does it differ from a regular Timer?

level: middleimportance: should knowfreq 50%

basics

~10 s

A LongTaskTimer measures tasks that are still running. It reports how many are in flight and their current accumulated duration, updated while they run. A regular Timer only records after an operation finishes.

open as a page

When and how do you use Timer.Sample instead of Timer.record(Runnable)?

level: middleimportance: should knowfreq 55%

basics

~10 s

Use Timer.Sample when the start and stop of an operation are in different places (e.g. async callbacks) so you can't wrap them in one lambda. Call Timer.start(registry), carry the Sample, then sample.stop(timer) later.

open as a page

Explain the longTask, percentiles, and histogram attributes of @Timed and when you'd use each.

level: seniorimportance: should knowfreq 32%

basics

~10 s

longTask=true measures long-running, still-in-progress calls with a LongTaskTimer (active count + in-flight duration). percentiles computes client-side percentile values (e.g. p95, p99). histogram=true publishes bucket counts so backends like Prometheus can aggregate percentiles across instances.

open as a page

How do the datasource/HikariCP pool metrics and logback.events meter get registered, and what do they tell you?

level: seniorimportance: should knowfreq 40%

basics

~20 s

When a DataSource bean exists Boot registers jdbc.connections.* pool metrics; if the pool is HikariCP it also exposes hikaricp.connections.active/idle/pending/max plus timing metrics. logback.events counts log lines per level via LogbackMetrics, so you can alert on error-log rate.

open as a page

What are the pitfalls of gauging a collection's size, especially around references and re-registration?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Micrometer keeps only a weak reference to the collection, so if you don't hold a strong reference it gets collected and the Gauge shows NaN. Also, if you replace the collection with a new instance, the Gauge still points at the old one, and re-registering a same-named Gauge is ignored.

open as a page

How does Micrometer translate a meter name and tags for Prometheus versus OTLP? Walk through what happens to a timer named http.server.requests.

level: seniorimportance: should knowfreq 45%

basics

~10 s

Micrometer uses dot-separated names internally. The Prometheus registry rewrites them to snake_case and adds unit/_total suffixes (http_server_requests_seconds...), turning tags into labels. The OTLP registry keeps the dotted name (http.server.requests) per OpenTelemetry conventions.

open as a page

You need your Spring Boot service to push metrics via OTLP to an OpenTelemetry Collector. How do you configure OtlpMeterRegistry, and what key properties matter?

level: seniorimportance: should knowfreq 40%

basics

~10 s

Add micrometer-registry-otlp; Spring Boot auto-configures OtlpMeterRegistry. Set management.otlp.metrics.export.url to the collector (default http://localhost:4318/v1/metrics), tune step (interval), add auth via export.headers, and pick the aggregation-temporality. It pushes on each step.

open as a page

How do MeterRegistryCustomizer and MeterFilter interact with a CompositeMeterRegistry — where do common tags and filters actually apply?

level: seniorimportance: should knowfreq 35%

basics

~20 s

In Spring Boot you customize registries with MeterRegistryCustomizer beans (e.g. add common tags) and shape/filter meters with MeterFilter. Boot applies customizers to each registry including the composite; a filter on the composite affects all children fan-out.

open as a page

What is Metrics.globalRegistry, when would you use it, and what are the pitfalls versus injecting a MeterRegistry?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Metrics.globalRegistry is a static, application-wide CompositeMeterRegistry. It lets code without dependency injection record metrics. The pitfall in Spring: unless you wire the Boot registry into it, metrics recorded there aren't exported by Boot's own registry.

open as a page

What can a Micrometer MeterFilter do, and how do you register one in Spring Boot? Cover deny/accept, rename, and tag mapping.

level: seniorimportance: should knowfreq 42%

basics

~20 s

A MeterFilter runs at meter registration and can accept, deny, or transform meters. It has three hooks: accept() to include/exclude, map() to rename meters or add/rename/drop tags, and configure() to tune distribution stats. You register it via registry.config().meterFilter(...) or as a bean.

open as a page

What is a DistributionSummary and when would you use it instead of a Timer?

level: seniorimportance: should knowfreq 45%

basics

~10 s

A DistributionSummary tracks the distribution of non-time measurements, like request payload sizes or items per batch. It records count, total, and max like a Timer but for arbitrary magnitudes instead of durations, via summary.record(value).

open as a page

The uri tag on http.client.requests is causing a metrics cardinality explosion. How do the built-in meters get their tags, and how do you control/limit cardinality across the registry?

level: principalimportance: should knowfreq 34%

basics

~20 s

Built-in meters get tags from Observation conventions (server/client). To limit cardinality, ensure client calls use URI templates (not interpolated URLs), and add a MeterFilter to deny high-cardinality tags, cap max tag values, rename, or drop whole meters registry-wide.

open as a page

When would you back a metric with an AtomicInteger/DoubleAdder and gauge it, versus using a Counter or a plain bound Gauge? How do you reason about it at design scale?

level: principalimportance: should knowfreq 25%

basics

~20 s

Use a Counter for cumulative, only-up event totals. Use a bound Gauge when you already have a live object to read a current value from. Back a metric with an AtomicInteger/LongAdder + Gauge when the current value goes up and down but no natural object exposes it, so you maintain the number yourself.

open as a page

You must ship metrics to Prometheus (local scrape) and a hosted APM simultaneously, with per-backend cost/cardinality controls and clean shutdown. How do you design this with Micrometer registries?

level: principalimportance: should knowfreq 25%

basics

~20 s

Add both registry starters so Boot fans out via one CompositeMeterRegistry. Instrument once against the injected MeterRegistry. Apply per-child MeterFilters for cost/cardinality, tune each backend's step, and ensure push registries close on shutdown to flush.

open as a page

showing 1–30 of 35