Files
gh-giuseppe-trisciuoglio-de…/skills/spring-boot-actuator/references/metrics.md
2025-11-29 18:28:34 +08:00

15 KiB

Metrics with Spring Boot Actuator

Spring Boot Actuator provides dependency management and auto-configuration for Micrometer, an application metrics facade that supports numerous monitoring systems, including:

  • AppOptics
  • Atlas
  • Datadog
  • Dynatrace
  • Elastic
  • Ganglia
  • Graphite
  • Humio
  • InfluxDB
  • JMX
  • KairosDB
  • New Relic
  • OpenTelemetry Protocol (OTLP)
  • Prometheus
  • Simple (in-memory)
  • Google Cloud Monitoring (Stackdriver)
  • StatsD
  • Wavefront

Tip

To learn more about Micrometer's capabilities, see its reference documentation, in particular the concepts section.

Getting Started

Spring Boot auto-configures a composite MeterRegistry and adds a registry to the composite for each of the supported implementations that it finds on the classpath. Having a dependency on micrometer-registry-{system} in your runtime classpath is enough for Spring Boot to configure the registry.

Most registries share common features. For instance, you can disable a particular registry even if the Micrometer registry implementation is on the classpath. The following example disables Datadog:

management:
  datadog:
    metrics:
      export:
        enabled: false

You can also disable all registries unless stated otherwise by the registry-specific property, as the following example shows:

management:
  defaults:
    metrics:
      export:
        enabled: false

Spring Boot also adds any auto-configured registries to the global static composite registry on the Metrics class, unless you explicitly tell it not to:

management:
  metrics:
    use-global-registry: false

You can register any number of MeterRegistryCustomizer beans to further configure the registry, such as applying common tags, before any meters are registered with the registry:

@Component
public class MyMeterRegistryConfiguration {

    @Bean
    public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return registry -> registry.config().commonTags("region", "us-east-1");
    }
}

You can apply customizations to particular registry implementations by being more specific about the generic type:

@Component
public class MyMeterRegistryConfiguration {

    @Bean
    public MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {
        return registry -> registry.config().namingConvention(this::toGraphiteConvention);
    }

    private String toGraphiteConvention(String name, Meter.Type type, String baseUnit) {
        return name.toLowerCase().replace(".", "_");
    }
}

Spring Boot also configures built-in instrumentation that you can control through configuration or dedicated annotation markers.

Supported Metrics

Spring Boot provides automatic meter registration for a wide variety of technologies. In most situations, the defaults provide sensible metrics that can be published to any of the supported monitoring systems.

JVM Metrics

JVM metrics are published under the jvm. meter name. The following JVM metrics are provided:

  • Memory and buffer pools
  • Statistics related to garbage collection
  • Thread utilization
  • Number of classes loaded/unloaded

System Metrics

System metrics are published under the system., process., and disk. meter names. The following system metrics are provided:

  • CPU metrics
  • File descriptor metrics
  • Uptime metrics
  • Disk space metrics

Application Startup Metrics

Application startup metrics are published under the application.started.time meter name. The following startup metrics are provided:

  • Application startup time
  • Application ready time

HTTP Request Metrics

HTTP request metrics are automatically recorded for all HTTP requests. Metrics are published under the http.server.requests meter name.

Tags added to HTTP server request metrics:

  • method: The request's HTTP method (e.g., GET or POST)
  • uri: The request's URI template prior to variable substitution (e.g., /api/person/{id})
  • status: The response's HTTP status code (e.g., 200 or 500)
  • outcome: The request's outcome based on the status code (SUCCESS, REDIRECTION, CLIENT_ERROR, SERVER_ERROR, or UNKNOWN)

To customize the tags, provide a @Bean that implements WebMvcTagsContributor:

@Component
public class MyWebMvcTagsContributor implements WebMvcTagsContributor {

    @Override
    public Iterable<Tag> getTags(HttpServletRequest request, 
                                 HttpServletResponse response, 
                                 Object handler, 
                                 Throwable exception) {
        return Tags.of("custom.tag", "custom-value");
    }

    @Override
    public Iterable<Tag> getLongRequestTags(HttpServletRequest request, 
                                           Object handler) {
        return Tags.of("custom.tag", "custom-value");
    }
}

WebFlux Metrics

WebFlux metrics are automatically recorded for all WebFlux requests. Metrics are published under the http.server.requests meter name.

Tags added to WebFlux request metrics:

  • method: The request's HTTP method
  • uri: The request's URI template
  • status: The response's HTTP status code
  • outcome: The request's outcome

Data Source Metrics

Auto-configuration enables the instrumentation of all available DataSource objects with metrics prefixed with hikaricp., tomcat.datasource., or dbcp2..

Connection pool metrics are published under the following meter names:

  • hikaricp.connections (HikariCP)
  • tomcat.datasource.connections (Tomcat)
  • dbcp2.connections (Apache DBCP2)

Cache Metrics

Auto-configuration enables the instrumentation of all available Cache managers on startup with metrics prefixed with cache.. The cache instrumentation is standardized for a basic set of metrics.

Cache metrics include:

  • Size
  • Hit ratio
  • Evictions
  • Puts and misses

Task Execution and Scheduling Metrics

Auto-configuration enables the instrumentation of all available ThreadPoolTaskExecutor and ThreadPoolTaskScheduler beans with metrics prefixed with executor. and scheduler. respectively.

Executor metrics include:

  • Active threads
  • Pool size
  • Queue size
  • Task completion

Custom Metrics

To record your own metrics, inject MeterRegistry into your component:

@Component
public class MyService {
    private final Counter counter;
    private final Timer timer;
    private final Gauge gauge;

    public MyService(MeterRegistry meterRegistry) {
        this.counter = Counter.builder("my.counter")
                .description("A simple counter")
                .register(meterRegistry);
        
        this.timer = Timer.builder("my.timer")
                .description("A simple timer")
                .register(meterRegistry);
        
        this.gauge = Gauge.builder("my.gauge")
                .description("A simple gauge")
                .register(meterRegistry, this, MyService::calculateGaugeValue);
    }

    public void doSomething() {
        counter.increment();
        
        Timer.Sample sample = Timer.start(meterRegistry);
        // ... do work
        sample.stop(timer);
    }
    
    private double calculateGaugeValue(MyService self) {
        return Math.random();
    }
}

Using @Timed Annotation

You can use the @Timed annotation to time method executions:

@Component
public class MyService {

    @Timed(name = "my.method.time", description = "Time taken to execute my method")
    public void timedMethod() {
        // method body
    }
}

For the @Timed annotation to work, you need to enable timing support:

@Configuration
@EnableConfigurationProperties
public class TimedConfiguration {

    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
    }
}

Using @Counted Annotation

You can use the @Counted annotation to count method invocations:

@Component
public class MyService {

    @Counted(name = "my.method.count", description = "Number of times my method is called")
    public void countedMethod() {
        // method body
    }
}

For the @Counted annotation to work, you need to enable counting support:

@Configuration
public class CountedConfiguration {

    @Bean
    public CountedAspect countedAspect(MeterRegistry registry) {
        return new CountedAspect(registry);
    }
}

Meter Filters

You can register any number of MeterFilter beans to control how meters are registered:

@Configuration
public class MetricsConfiguration {

    @Bean
    public MeterFilter renameFilter() {
        return MeterFilter.rename("old.metric.name", "new.metric.name");
    }

    @Bean
    public MeterFilter denyFilter() {
        return MeterFilter.deny(id -> id.getName().contains("unwanted"));
    }

    @Bean
    public MeterFilter tagFilter() {
        return MeterFilter.commonTags("application", "my-app");
    }
}

Metrics Endpoint

The metrics endpoint provides access to all the metrics collected by the application. You can view the names of all available meters by visiting /actuator/metrics.

To view the value of a particular meter, specify its name as a path parameter:

GET /actuator/metrics/jvm.memory.used

The response contains the meter's measurements:

{
  "name": "jvm.memory.used",
  "description": "The amount of used memory",
  "baseUnit": "bytes",
  "measurements": [
    {
      "statistic": "VALUE",
      "value": 8.73E8
    }
  ],
  "availableTags": [
    {
      "tag": "area",
      "values": ["heap", "nonheap"]
    },
    {
      "tag": "id",
      "values": ["Compressed Class Space", "PS Eden Space", "PS Survivor Space"]
    }
  ]
}

You can drill down to a particular meter by adding query parameters:

GET /actuator/metrics/jvm.memory.used?tag=area:heap&tag=id:PS%20Eden%20Space

Monitoring System Integration

Prometheus

To export metrics to Prometheus, add the following dependency:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

This exposes a /actuator/prometheus endpoint that presents metrics in the format expected by a Prometheus server.

Configuration example:

management:
  endpoints:
    web:
      exposure:
        include: "prometheus"
  metrics:
    export:
      prometheus:
        enabled: true
        step: 1m
        descriptions: true

Datadog

To export metrics to Datadog, add the following dependency:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-datadog</artifactId>
</dependency>

Configuration:

management:
  metrics:
    export:
      datadog:
        api-key: ${DATADOG_API_KEY}
        application-key: ${DATADOG_APP_KEY}
        uri: https://api.datadoghq.com
        step: 1m

InfluxDB

To export metrics to InfluxDB, add the following dependency:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-influx</artifactId>
</dependency>

Configuration:

management:
  metrics:
    export:
      influx:
        uri: http://localhost:8086
        db: mydb
        username: ${INFLUX_USERNAME}
        password: ${INFLUX_PASSWORD}
        step: 1m

New Relic

To export metrics to New Relic, add the following dependency:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-newrelic</artifactId>
</dependency>

Configuration:

management:
  metrics:
    export:
      newrelic:
        api-key: ${NEW_RELIC_API_KEY}
        account-id: ${NEW_RELIC_ACCOUNT_ID}
        step: 1m

Simple Registry (In-Memory)

The simple registry is automatically configured if no other registry is found on the classpath. It stores metrics in memory and is useful for development and testing:

management:
  metrics:
    export:
      simple:
        enabled: true
        step: 1m

Performance Considerations

Meter Cardinality

Be mindful of meter cardinality when adding tags. High-cardinality tags (like user IDs) can lead to performance issues:

// Bad - high cardinality
Timer.builder("user.request.time")
    .tag("user.id", userId)  // Could be millions of different values
    .register(registry);

// Good - low cardinality
Timer.builder("user.request.time")
    .tag("user.type", userType)  // Limited number of values
    .register(registry);

Sampling

For high-throughput applications, consider using sampling to reduce overhead:

@Bean
public MeterFilter samplingFilter() {
    return MeterFilter.maximumExpectedValue("http.server.requests", 
                                           Duration.ofMillis(500));
}

Meter Registry Configuration

Configure appropriate publishing intervals to balance between timeliness and performance:

management:
  metrics:
    export:
      prometheus:
        step: 30s  # Adjust based on your needs

Security Considerations

Sensitive Data

Be careful not to include sensitive information in metric tags or names:

// Bad - exposes sensitive data
Counter.builder("login.attempts")
    .tag("username", username)  // Could expose usernames
    .register(registry);

// Good - uses hashed or anonymized data
Counter.builder("login.attempts")
    .tag("outcome", successful ? "success" : "failure")
    .register(registry);

Endpoint Security

Secure the metrics endpoint in production:

management:
  endpoints:
    web:
      exposure:
        include: "metrics"
  endpoint:
    metrics:
      access: restricted

Or using Spring Security:

@Configuration
public class ActuatorSecurity {

    @Bean
    public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
        return http
            .requestMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeHttpRequests(requests -> 
                requests.anyRequest().hasRole("ACTUATOR"))
            .httpBasic(withDefaults())
            .build();
    }
}

Best Practices

  1. Use meaningful meter names: Follow naming conventions specific to your monitoring system
  2. Add appropriate tags: Use tags to add dimensions but avoid high cardinality
  3. Monitor meter cardinality: High cardinality can impact performance
  4. Use meter filters: Filter out unwanted metrics or rename meters
  5. Configure appropriate publishing intervals: Balance between timeliness and performance
  6. Secure sensitive endpoints: Protect metrics endpoints in production
  7. Test metrics in development: Verify metrics are collected correctly before deploying
  8. Document custom metrics: Maintain documentation for custom metrics and their purposes