Operations 29 min read

Mastering Micrometer: From Counters to Custom Metrics in Spring Boot

This article provides a comprehensive guide to Micrometer, covering its core metric types, MeterRegistry usage, tagging conventions, and practical code examples, and shows how to integrate it with Spring Boot, Prometheus, and Grafana for end‑to‑end application monitoring.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Mastering Micrometer: From Counters to Custom Metrics in Spring Boot

Micrometer Overview

Spring Actuator uses Micrometer to collect JVM metrics. Micrometer provides a set of Meter types (Counter, FunctionCounter, Timer, FunctionTimer, LongTaskTimer, Gauge, TimeGauge, DistributionSummary) that can be exported to Prometheus and visualized with Grafana.

MeterRegistry

MeterRegistry

is the factory and cache for Meter instances. Common implementations are:

SimpleMeterRegistry – stores data only in memory.

CompositeMeterRegistry – aggregates multiple registries.

Global registry – a static CompositeMeterRegistry accessed via Metrics.

Creating a simple registry:

MeterRegistry registry = new SimpleMeterRegistry();
Counter counter = registry.counter("counter");
counter.increment();

Using the global registry:

Metrics.addRegistry(new SimpleMeterRegistry());
Counter counter = Metrics.counter("counter", "tag-1", "tag-2");
counter.increment();

Tag Naming and Conventions

Meter names use dot notation (e.g., http.server.requests) and are converted to the naming rules of the target system via NamingConvention. Examples:

Prometheus – http_server_requests_duration_seconds Graphite – http.server.requests Tags must be non‑null, appear as key‑value pairs, and are essential for multidimensional analysis. Global tags can be added to all meters:

registry.config().commonTags("stack", "prod", "region", "us-east-1");

Meter Types

Counter

A monotonically increasing count. Typical use is to record total events such as order creation, payments, or HTTP request volume.

Metrics.counter("order.create", "channel", order.getChannel(), "createTime", formatter.format(order.getCreateTime())).increment();

FunctionCounter

Wraps a ToDoubleFunction so the counter value is derived from an external object.

AtomicInteger n = new AtomicInteger(0);
FunctionCounter.builder("functionCounter", n, AtomicInteger::get)
    .baseUnit("function")
    .register(registry);

Timer

Measures the duration of short‑lived events. The functional API is convenient for recording method execution time.

Timer timer = Metrics.timer("method.cost.time", "method.name", method.getName());
 timer.record(() -> createOrder(order));

A builder can be used for custom description and tags:

Timer timer = Timer.builder("my.timer")
    .description("execution time of my method")
    .tags("region", "test")
    .register(registry);

FunctionTimer

Specialized timer that obtains count and total time from functions.

FunctionTimer.builder("functionTimer", holder, holder::getCount, holder::getTotalTime, TimeUnit.NANOSECONDS)
    .register(new SimpleMeterRegistry());

LongTaskTimer

Tracks long‑running tasks until they finish.

LongTaskTimer longTaskTimer = meterRegistry.more().longTaskTimer("longTaskTimer");
longTaskTimer.record(() -> { /* task logic */ });

Gauge

Provides a snapshot of a value that can go up and down, such as collection size or memory usage.

Gauge gauge = Gauge.builder("listGauge", list, List::size).register(registry);

TimeGauge

Gauge with a time‑unit base, useful for exposing durations.

AtomicInteger count = new AtomicInteger();
TimeGauge timeGauge = TimeGauge.builder("timeGauge", count, TimeUnit.SECONDS, AtomicInteger::get).register(registry);

DistributionSummary

Records the distribution of non‑time values, such as payload sizes.

DistributionSummary summary = DistributionSummary.builder("response.size")
    .description("size of response payload")
    .baseUnit("bytes")
    .register(registry);

Integration with Spring Boot, Prometheus, and Grafana

Add the following Maven dependencies (or the equivalent Gradle coordinates):

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
  <version>1.1.0</version>
</dependency>

Expose the Prometheus endpoint via application.yml (or application.properties):

server:
  port: 9091
management:
  server:
    port: 10091
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    prometheus:
      enabled: true

Configure Prometheus (version 2.5 used in the article) to scrape the Spring Boot metrics endpoint:

scrape_configs:
  - job_name: 'spring-boot-app'
    metrics_path: /management/prometheus
    static_configs:
      - targets: ['localhost:10091']

Start Prometheus and verify that metrics such as order_create_total and method_cost_time_seconds_sum appear.

In Grafana, add a Prometheus data source pointing to the Prometheus server (default port 9090) and create dashboards using PromQL queries, e.g.:

sum(rate(order_create_total[1m]))
rate(method_cost_time_seconds_sum[5m])

The complete monitoring stack is:

Spring Boot application with Micrometer and Actuator

Prometheus server scraping /management/prometheus Grafana visualizing the collected metrics

All code snippets above are fully functional and can be copied into a Spring Boot project to observe the described metrics.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavamonitoringMetricsPrometheusSpring BootGrafanaMicrometer
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.