Contrast the Prometheus registry (pull) with the OTLP registry (push) in Spring Boot. How does each get metrics out of the app?
answer
- Pull = Prometheus scrapes /actuator/prometheus
- Push = OTLP POSTs to collector :4318
- OtlpMeterRegistry extends StepMeterRegistry, step=1m
- temporality: CUMULATIVE vs DELTA (OTLP only)
- both can run via CompositeMeterRegistry
basics
~10 sPrometheusMeterRegistry 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.
solid answer
~40 sBoth are Micrometer registry implementations, but they invert the transport direction. `PrometheusMeterRegistry` is pull-based: it holds current meter values and renders them on demand at `/actuator/prometheus`; the external Prometheus server scrapes that HTTP endpoint on its own schedule, so the app opens no outbound connection and stores no target. `OtlpMeterRegistry` (from `micrometer-registry-otlp`) is push-based and extends `StepMeterRegistry`: on a fixed step interval (default 1 minute) it aggregates and POSTs metrics over OTLP — HTTP/protobuf to `http://localhost:4318/v1/metrics` by default — to an OpenTelemetry Collector or compatible backend. Push suits short-lived/serverless workloads and networks where the collector can't reach the app; pull suits stable, discoverable targets and gives the monitoring system control of timing and up/down detection. You can even run both registries at once via the composite registry.
code
java · 14 lines// application.properties
// --- Pull (Prometheus): no target, just expose the endpoint ---
// management.endpoints.web.exposure.include=prometheus
// --- Push (OTLP): tell the app where to send, and how often ---
// management.otlp.metrics.export.url=http://otel-collector:4318/v1/metrics
// management.otlp.metrics.export.step=30s
// management.otlp.metrics.export.aggregation-temporality=cumulative
// management.otlp.metrics.export.headers.Authorization=Bearer ${OTLP_TOKEN}
// Running BOTH is fine: keep micrometer-registry-prometheus AND
// micrometer-registry-otlp on the classpath; Micrometer composes them,
// records each measurement once, and each registry exports its own way.go deeper
State the core direction: Prometheus pulls/scrapes, OTLP pushes to a collector.
Explain StepMeterRegistry/step interval, default OTLP url:4318, and that both can coexist.
Weigh reachability, discovery, up-detection, and temporality trade-offs per environment.
Design the org-wide pipeline: OTel collector as routing/auth choke point vs. Prometheus federation, and failure/loss semantics of each.
Micrometer supports multiple registries simultaneously through a `CompositeMeterRegistry`; each registry decides *how* meters leave the process. The two here differ fundamentally in transport direction. **Prometheus — PULL (scrape):** - Dependency: `io.micrometer:micrometer-registry-prometheus`. - The registry keeps live values in memory and serializes them only when asked, at `/actuator/prometheus`. - The **Prometheus server** is configured with a scrape target (static or via service discovery) and issues periodic HTTP GETs. Scrape interval, retries, and timeouts are owned by Prometheus, not the app. - Benefits: no app-side target config; the collector controls cadence; a failed scrape is itself a signal (the `up` metric), giving cheap liveness detection; easy to point multiple Prometheus instances at the same target. - Costs: the app must be *reachable* and *discoverable* by Prometheus; short-lived jobs may die before being scraped (mitigated by a Pushgateway, which is an edge case). **OTLP — PUSH:** - Dependency: `io.micrometer:micrometer-registry-otlp`. - `OtlpMeterRegistry` extends `StepMeterRegistry`: it rolls up measurements over a **step** window and publishes at the end of each step. Default step is 1 minute (`management.otlp.metrics.export.step`). - It sends over **OTLP** — the OpenTelemetry Protocol — HTTP/protobuf by default to `management.otlp.metrics.export.url` (default `http://localhost:4318/v1/metrics`), typically an **OpenTelemetry Collector** that fans out to backends. Headers (`...export.headers`) carry auth; resource attributes describe the service. - Benefits: works when the app can't be reached inbound (behind NAT, serverless, ephemeral), centralizes routing/auth in the collector, and rides the vendor-neutral OTel ecosystem. - Costs: the app must know and reach the endpoint; if the collector is down, buffered data can be lost; you pick an **aggregation temporality** (see below) that must match the backend. **Aggregation temporality nuance:** OTLP lets you choose CUMULATIVE (default, values accumulate since start — Prometheus-friendly) or DELTA (each push reports the change since the last) via `management.otlp.metrics.export.aggregation-temporality`. Prometheus scraping is inherently cumulative; there's no such choice on the pull side. **Naming differs too:** Prometheus rewrites `dot.case` meter names to `snake_case` and adds unit/`_total` suffixes; OTLP preserves the dotted name to align with OpenTelemetry semantic conventions. So the same meter appears as `http_server_requests_seconds_count` in Prometheus but `http.server.requests` in OTLP. **When to use which:** - Stable, long-lived services in an environment with service discovery → pull/Prometheus. - Ephemeral, serverless, or firewalled-from-the-monitor workloads, or when you want one OTel pipeline for metrics+traces+logs → push/OTLP. - Mixed estates: run both registries; Micrometer records once and both export. **Gotchas:** with push, a too-long step delays visibility and a crash within a step loses that window; with pull, unreachable/undiscovered targets simply vanish from monitoring. Don't assume push is 'more real-time' — it's still batched by the step interval.
- Is push (OTLP) more real-time than pull (Prometheus)?Not necessarily. OtlpMeterRegistry batches over a step window (default 1 minute) before pushing, and Prometheus scrapes on its own interval (often 15s). Latency depends on step vs scrape interval, not on the direction.
- How can one app feed both a Prometheus scrape and an OTLP backend?Keep both micrometer-registry-prometheus and micrometer-registry-otlp on the classpath. Micrometer wraps them in a CompositeMeterRegistry; each meter is recorded once and every registry exports it in its own transport/format.
saying these in an interview costs you the question
- Claiming the app configures a Prometheus URL to push to.
- Saying OTLP streams every measurement instantly (it batches per step interval).
- Thinking you must choose one — both registries can run together.