Micrometer, a versatile application metrics facade, seamlessly integrates with Spring Boot Actuator to capture and expose vital insights into your application’s performance. While Micrometer offers a plethora of pre-defined metrics, you often need to track application-specific metrics that aren’t covered out of the box. This blog post will explore creating custom metrics for Micrometer tracing, along with the necessary Gradle/Maven setup and examples of various custom metric types.

1. Gradle/Maven Setup

First, ensure your Spring Boot project includes the required Micrometer dependencies.

Gradle

dependencies {
    implementation 'io.micrometer:micrometer-core'
    implementation 'io.micrometer:micrometer-registry-prometheus' // Or your preferred registry
}

Maven

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

2. Application.yml Configuration

While Micrometer typically auto-configures itself, you may want to fine-tune its behavior using application.yml:

management:
  metrics:
    export:
      prometheus:
        enabled: true  # Enable Prometheus endpoint (if using Prometheus)

3. The MeterRegistry

The MeterRegistry is the core component in Micrometer responsible for managing and collecting metrics. In Spring Boot applications, Micrometer automatically creates and configures a MeterRegistry bean for you. You can obtain a reference to this bean using dependency injection:

import io.micrometer.core.instrument.MeterRegistry;

@Service
public class MyService {

    private final MeterRegistry meterRegistry;

    public MyService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    // ... your service methods ...
}

Once you have a reference to the MeterRegistry, you can use it to create and register your custom metrics, as shown in the examples below.

4. Creating Custom Metrics

Micrometer provides a rich set of metric types to instrument various aspects of your application.

4.1. Counter

Counters are ideal for tracking the number of occurrences of an event.

import io.micrometer.core.instrument.Counter;

// ... (inside your service class)

public void performOperation() {
    // ... your operation logic ...
    Counter myCounter = Counter.builder("my.custom.counter")
            .description("Counts the number of times a specific operation is performed")
            .register(meterRegistry); 
    myCounter.increment(); 
}

4.2. Gauge

Gauges represent a single numerical value that can go up or down.

import io.micrometer.core.instrument.Gauge;

// ... (inside your service class)

private int currentQueueSize = 0;

public MyService(MeterRegistry registry) {
    Gauge.builder("my.queue.size", this, MyService::getCurrentQueueSize)
            .description("Tracks the current size of a queue")
            .register(registry);
}

public int getCurrentQueueSize() {
    return currentQueueSize;
}

// ... methods to add/remove items from the queue, updating currentQueueSize

4.3. Timer

Timers measure the duration (and distribution) of an operation.

import io.micrometer.core.instrument.Timer;

// ... (inside your service class)

public void performOperation() {
    Timer myTimer = Timer.builder("my.operation.timer")
            .description("Measures the duration of a specific operation")
            .register(meterRegistry);

    myTimer.record(() -> {
        // ... your operation logic ...
    });
}

4.4. Distribution Summary

Distribution summaries track the distribution of events (e.g., request sizes).

import io.micrometer.core.instrument.DistributionSummary;

// ... (inside your service class)

public void processRequest(int requestSize) {
    // ... your request processing logic ...
    DistributionSummary requestSizeSummary = DistributionSummary.builder("my.request.size")
            .description("Tracks the distribution of request sizes")
            .register(meterRegistry);
    requestSizeSummary.record(requestSize); 
}

4.5. Long Task Timer

Long task timers track the duration of long-running operations.

import io.micrometer.core.instrument.LongTaskTimer;

// ... (inside your service class)

public void performLongTask() {
    LongTaskTimer longTaskTimer = LongTaskTimer.builder("my.long.task")
            .description("Tracks the duration of a long-running task")
            .register(meterRegistry);

    longTaskTimer.record(() -> {
        // ... your long-running task logic ...
    });
}

By creating custom metrics with Micrometer and leveraging the MeterRegistry, you gain granular visibility into your Spring Boot application’s behavior. Utilize these metrics to identify bottlenecks, optimize performance, and make informed decisions about your application’s architecture and resource allocation. Remember, effective monitoring is key to building resilient and high-performing applications.


Discover more from GhostProgrammer - Jeff Miller

Subscribe to get the latest posts sent to your email.

By Jeffery Miller

I am known for being able to quickly decipher difficult problems to assist development teams in producing a solution. I have been called upon to be the Team Lead for multiple large-scale projects. I have a keen interest in learning new technologies, always ready for a new challenge.