To expose custom metrics in Spring Boot, you can use Micrometer, which is the metrics collection facade integrated into Spring Boot Actuator. Spring Boot Actuator provides production-ready endpoints like /actuator/metrics, and you can extend it with custom metrics to track application-specific behavior.
Step-by-Step Guide to Expose Custom Metrics
1. Add Required Dependencies
If you’re using Spring Boot Starter Actuator (most common case):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
If you want to export metrics to Prometheus, Datadog, etc., add the corresponding registry (e.g., Prometheus):
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
2. Enable Metrics Endpoint in application.properties
management.endpoints.web.exposure.include=metrics,prometheus
This exposes:
/actuator/metrics– for all metrics/actuator/metrics/<metric-name>– for individual metrics/actuator/prometheus– for Prometheus scraping (if you added the Prometheus registry)
3. Inject MeterRegistry to Register Custom Metrics
You can use MeterRegistry to create custom counters, timers, gauges, etc.
Custom Counter Example:
@Component
public class CustomMetricsService {
private final Counter userCreatedCounter;
public CustomMetricsService(MeterRegistry registry) {
this.userCreatedCounter = Counter.builder("app.user.created.count")
.description("Number of users created")
.register(registry);
}
public void userCreated() {
// business logic to create a user
userCreatedCounter.increment(); // increment the custom metric
}
}
Now you can see this metric at:
/actuator/metrics/app.user.created.count
4. Expose Custom Timers (Duration Tracking)
@Component
public class CustomTimerService {
private final Timer requestTimer;
public CustomTimerService(MeterRegistry registry) {
this.requestTimer = Timer.builder("app.request.duration")
.description("Request processing time")
.register(registry);
}
public void process() {
requestTimer.record(() -> {
// code whose duration you want to measure
try {
Thread.sleep(200); // simulate delay
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
}
Check metrics via:
/actuator/metrics/app.request.duration
5. Expose Gauges (Real-time Value Tracking)
For values that fluctuate, like queue size or memory usage.
@Component
public class QueueMonitor {
private final Queue<String> queue = new ConcurrentLinkedQueue<>();
public QueueMonitor(MeterRegistry registry) {
Gauge.builder("app.queue.size", queue, Queue::size)
.description("Size of in-memory queue")
.register(registry);
}
public void addToQueue(String item) {
queue.add(item);
}
public String removeFromQueue() {
return queue.poll();
}
}
Access via:
/actuator/metrics/app.queue.size
Types of Custom Metrics
| Type | Description | Method |
|---|---|---|
| Counter | Increments when an event happens | Counter.builder(...).increment() |
| Gauge | Reports a changing value (e.g., queue size) | Gauge.builder(...).register() |
| Timer | Records duration of operations | Timer.record(Runnable) |
| Histogram | Shows distribution of values (via Timer) | Handled automatically in Timer |
