This tutorial describes how to add custom metrics to metrics endpoint of Spring Boot 2.x.x Actuator.
Abstract
Spring Boot Actuator Library starting version 2.x.x has made it very easy to export a service metrics to various analytical systems as demonstrated in Exporting Spring Boot Actuator Metrics to ElasticSearch.
However, it doesn't export Service information such as service name, service host, service port among other things. This makes it impossible to get service level metrics when multiple services are posting data into single ElasticSearch index. By default, it pesists data into metrics-<year>-<month> such as metrics-2019-01.
In this article, we will see how to add basic service information to exported metrics as well as metrics web endpoint. Please note that same mechanism could be used to add any other custom information that you may want to add.
Pre-requisites
- Microservice running on Maven and Spring Boot 2.1.x or newer. In case you don't have one yet, you can download and try this sample code - spring-boot-metrics-es-integration
- Metrics endpoint has been exposed using property management.endpoints.web.exposure.include=metrics in one of your properties file in case you want to verify metrics endpoint with added information
Adding Service Information to Spring Boot Actuator Metrics
Spring Boot Actuator uses MeterRegistry API of Micrometer (a metrics facade just like SLF4j for logging). Meter represents dimensional metrics such as timers, gauges, counters etc.
Since Spring Boot configures MeterRegistry on application startup, it provides us with a MeterRegistryCustomizer interface that we can expose to perform customizations in Micrometer MeterRegistry.
Additionally, MeterRegistry has concepts of tags along with all the metrics and we will leverage same concept to add service information. However, we will use common(global) tags to automatically add service information to all the metrics.
Hence, in order to add service information, we need to expose a bean of type MeterRegistryCustomizer in our Configuration class. I have created a different Configuration class altogether to encapuslate all metrics related changes. This will increase its reusability and make it easier to maintain.
Here is how my Spring Java based Configuration file looks like -
package com.aksain.boot.metrics.es;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.micrometer.core.instrument.MeterRegistry;
@Configuration
public class ApplicationNameMetricsExtension {
@Value("${spring.application.name}")
private String applicationName;
@Value("${server.port}")
private String serverPort;
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() throws UnknownHostException {
final String hostName = InetAddress.getLocalHost().getHostName();
return registry -> registry.config()
// Add service name, host and port to global tags
.commonTags(
"service.name", applicationName,
"service.host", hostName,
"service.port", serverPort
);
}
}
Please ensure that this class should either be in same package as your Spring Boot Application configuration or should fall into package scan in order to work.
Let's start our service now and make a curl request to one of Actuator metrics endpoints to see if our tags have been added. Please note that Actuator endpoint will only work if you have enabled it by using property management.endpoints.web.exposure.include=metrics. These tags will also be exported to your analytical system (elastic, prometheus etc) if you have enabled integration by adding Micrometer Registry dependency as explained in Exporting Spring Boot Actuator Metrics to ElasticSearch.
curl localhost:8080/actuator/metrics/jvm.memory.max
{"name":"jvm.memory.max","description":"The maximum amount of memory in bytes that can be used for memory management","baseUnit":"bytes","measurements":[{"statisti
c":"VALUE","value":1.862270973E9}],"availableTags":[{"tag":"area","values":["heap","nonheap"]},{"tag":"service.name","values":["spring-boot-metrics-es-integration"
]},{"tag":"service.port","values":["8080"]},{"tag":"id","values":["G1 Old Gen","CodeHeap 'non-profiled nmethods'","G1 Survivor Space","Compressed Class Space","Met
aspace","G1 Eden Space","CodeHeap 'non-nmethods'"]},{"tag":"service.host","values":["DESKTOP-T3LUR3H"]}]}
As we can see, service.name, service.port and service.host tags have been added.
Thank you for reading through the tutorial. In case of any feedback/questions/concerns, you can communicate same to us through your comments and we shall get back to you as soon as possible.