🗓️ 18052026 2200

PROMETHEUS SPRING BOOT PIPELINE

micrometer-registry-prometheus creates an end-to-end pipeline in Spring Boot: your code instruments with metric_types → metrics convert to Prometheus exposition format per to_prometheus_mapping → exposed at /actuator/prometheus → scraped by overview → queried with PromQL in Grafana.

This note connects the existing pieces into the full data flow and covers what Spring Boot auto-instruments.

The Pipeline​

Your Code Micrometer Registry Endpoint Prometheus Grafana
───────── ────────── ──────── ──────── ────────── ───────
Counter.increment() → MeterRegistry → PrometheusMeterRegistry → /actuator/prometheus → scrape → PromQL
Timer.record() stores metrics converts to exposition text format endpoint pull every dashboards
Gauge.builder() in memory format on scrape (GET request) 15-30s & alerts

Setup​

Dependency​

<!-- Maven -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
// Gradle
implementation 'io.micrometer:micrometer-registry-prometheus'

Spring Boot 3.x includes this transitively via spring-boot-starter-actuator.

Configuration​

# application.yml
management:
endpoints:
web:
exposure:
include: health, info, prometheus
metrics:
tags:
application: ${spring.application.name}

Verification​

curl http://localhost:8080/actuator/prometheus

Auto-Instrumented Metrics​

Spring Boot + Micrometer registers these without any code.

JVM (jvm_*)​

Prometheus MetricMeasures
jvm_memory_used_bytes{area="heap"}Heap memory in use
jvm_memory_max_bytes{area="heap"}Max heap
jvm_memory_committed_bytesMemory committed by JVM
jvm_gc_pause_seconds_*GC pause durations (histogram)
jvm_gc_memory_allocated_bytes_totalBytes allocated in young gen
jvm_gc_memory_promoted_bytes_totalBytes promoted to old gen
jvm_threads_live_threadsCurrent live threads
jvm_threads_daemon_threadsDaemon thread count
jvm_threads_peak_threadsPeak thread count
jvm_classes_loaded_classesCurrently loaded classes
jvm_buffer_memory_used_bytesDirect/mapped buffer memory

HTTP Server (http_server_requests_*)​

Prometheus MetricLabels
http_server_requests_seconds_countmethod, uri, status, outcome
http_server_requests_seconds_sumsame
http_server_requests_seconds_bucketsame + le
http_server_requests_seconds_maxsame

Auto-timed by Spring MVC and WebFlux. See promql_cheatsheet for query patterns.

WARNING

The uri label uses the route template (/api/users/{id}), not the actual path (/api/users/123). uri="UNKNOWN" means the request hit no mapped handler. Dynamic path segments as label values cause cardinality explosion.

Connection Pool (hikaricp_*)​

Prometheus MetricMeasures
hikaricp_connections_activeConnections in use
hikaricp_connections_idleIdle connections
hikaricp_connections_maxMax pool size
hikaricp_connections_pendingThreads waiting for connection
hikaricp_connections_acquire_seconds_*Connection acquisition time
hikaricp_connections_creation_seconds_*Connection creation time
hikaricp_connections_usage_seconds_*Connection usage duration

System / Process​

Prometheus MetricMeasures
process_cpu_usageJVM process CPU (0.0–1.0)
system_cpu_usageWhole system CPU (0.0–1.0)
process_uptime_secondsJVM uptime
process_start_time_secondsJVM start timestamp
process_files_open_filesOpen file descriptors
process_files_max_filesMax file descriptors

Cache (cache_* — if Spring Cache enabled)​

Prometheus MetricMeasures
cache_gets_total{result="hit"}Cache hits
cache_gets_total{result="miss"}Cache misses
cache_puts_totalCache puts
cache_evictions_totalCache evictions
cache_sizeCurrent cache size

Common Label Dimensions​

LabelSourceExample
applicationmanagement.metrics.tags.application configmy-service
instanceAdded by Prometheus at scrape time10.0.0.5:8080
uriSpring MVC route pattern/api/users/{id}
methodHTTP methodGET
statusHTTP status code200
outcomeSpring outcome categorySUCCESS
areaJVM memory areaheap, nonheap

Prometheus Scrape Configuration​

# prometheus.yml — static target
scrape_configs:
- job_name: 'spring-boot'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
static_configs:
- targets: ['localhost:8080']

For K8s, annotate pods and use service discovery:

# pod annotations
annotations:
prometheus.io/scrape: "true"
prometheus.io/path: "/actuator/prometheus"
prometheus.io/port: "8080"

Or use grafana_alloy to collect and forward metrics to a remote backend.


Troubleshooting​

ProblemCheck
No metrics at /actuator/prometheusmicrometer-registry-prometheus on classpath? Endpoint exposed in config?
Metric name mismatchDots → underscores, counters get _total, timers get _seconds — see to_prometheus_mapping
Missing labelsCheck tag config in metric_types
High cardinality warningAvoid dynamic path variables as tags; use route templates
Metrics disappear after restartCounters reset — use rate() not raw values
uri="UNKNOWN"Request hit no mapped handler — check @RequestMapping
Pool metrics missingHikariCP not on classpath, or pool name not set

Three Layers of Observability​

┌─────────────────────────────────────────────────────┐
│ Application Metrics (this note) │
│ micrometer-registry-prometheus → /actuator/prometheus │
│ JVM, HTTP, pools, custom business metrics │
├─────────────────────────────────────────────────────┤
│ Container Metrics — [[cadvisor_container_metrics]] │
│ CPU, memory, network, disk per container │
├─────────────────────────────────────────────────────┤
│ Host Metrics — [[node_exporter_host_metrics]] │
│ CPU, memory, disk, network per node │
└─────────────────────────────────────────────────────┘

References​