1. Overview
In this article, we’re going to introduce Spring Boot Actuators and talk about some simple ways to work with them in production.
2. What Is An Actuator?
Actuators enable production-ready features to a Spring Boot application – without having to actually implement these things yourself.
They’re mainly used to expose different types of information about the running application – health, metrics, info, dump, env etc. And while these are no replacement for a production-grade monitoring solution – they’re a very good starting point.
2.1. How to Enable an Actuator
To start using the existing actuators in Boot – we’ll just need to add the spring-boot-actuator dependency to the pom:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>1.2.3.RELEASE</version> </dependency>
3. Endpoints
Endpoints allow you to monitor the application and, in some cases – interact with it as well. Boot comes with many built-in endpoints and, like with pretty much anything in Spring – you can also roll your own.
Most endpoints are sensitive – meaning they’re not fully public – while a handful are not: /health and /info.
Here’s some of the most common endpoints Boot provides out of the box:
- /health – Shows application health information (a simple ‘status’ when accessed over an unauthenticated connection or full message details when authenticated). It is sensitive by default.
- /info – Displays arbitrary application info. Not sensitive by default.
- /metrics – Shows ‘metrics’ information for the current application. It is also sensitive by default.
- /trace – Displays trace information (by default the last few HTTP requests).
You can find the full list of existing endpoints over on the official docs.
4. Customizing Existing Endpoints
Each endpoint can be customized with properties using the following format: endpoints.[endpoint name].[property to customize]
Three properties are available:
- id – by which this endpoint will be accessed over HTTP
- enabled – if true then it can be accessed otherwise not
- sensitive – if true then need authorization to show crucial information over HTTP
For example, add the following properties will customize the /beans endpoint:
endpoints.beans.id=springbeans endpoints.beans.sensitive=false endpoints.beans.enabled=true
4.1. /health Endpoint
The /health endpoint is used to check the health / status of the running application. It’s usually used by basic monitoring software to alert you if the production goes down.
By default only health information is shown to unauthorized access over HTTP:
{ "status" : "UP" }
This health information is collected from all the beans implementing HealthIndicator interface configured in your application context.
Some information returned by HealthIndicator is sensitive in nature – but you can configure endpoints.health.sensitive=false to expose the other information like diskspace, datasource etc.
4.2. A Custom HealthIndicator
You can also roll your own custom health indicator – which can collect any type of custom health data specific to the application and provide it to the /health endpoint:
@Component public class HealthCheck implements HealthIndicator { @Override public Health health() { int errorCode = check(); // perform some specific health check if (errorCode != 0) { return Health.down().withDetail("Error Code", errorCode).build(); } return Health.up().build(); } public int check() { // Your logic to check health return 0; } }
Here’s how the output would look like:
{ "status" : "DOWN", "myHealthCheck" : { "status" : "DOWN", "Error Code" : 1, "Description" : "You custom MyHealthCheck endpoint is down" }, "diskSpace" : { "status" : "UP", "free" : 209047318528, "threshold" : 10485760 } }
4.3. /info Endpoint
You can also customize the data shown by /info endpoint – for example:
info.app.name=Spring Sample Application info.app.description=This is my first spring boot application info.app.version=1.0.0
And the sample output:
{ "app" : { "version" : "1.0.0", "description" : "This is my first spring boot application", "name" : "Spring Sample Application" } }
4.4. /metrics Endpoint
The metrics endpoint is one of the more important endpoints as it gathers and publishes information about OS, JVM and Application level metrics; out of the box, we get things like memory, heap, processors, threads, classes loaded, classes unloaded, thread pools along with some HTTP metrics as well.
Here’s what the output of this endpoint looks like out of the box:
{ "mem" : 193024, "mem.free" : 87693, "processors" : 4, "instance.uptime" : 305027, "uptime" : 307077, "systemload.average" : 0.11, "heap.committed" : 193024, "heap.init" : 124928, "heap.used" : 105330, "heap" : 1764352, "threads.peak" : 22, "threads.daemon" : 19, "threads" : 22, "classes" : 5819, "classes.loaded" : 5819, "classes.unloaded" : 0, "gc.ps_scavenge.count" : 7, "gc.ps_scavenge.time" : 54, "gc.ps_marksweep.count" : 1, "gc.ps_marksweep.time" : 44, "httpsessions.max" : -1, "httpsessions.active" : 0, "counter.status.200.root" : 1, "gauge.response.root" : 37.0 }
4.5. Custom Metric Data
There is actually support here for ‘gauge’ – single value data, and ‘counter’ – incrementing/decrementing data types of metrics. Let’s make use of some of this support to implement our own custom data into the /metrics endpoint.
For example – we’ll customize the login flow to record a successful and failed login attempt:
public interface LoginService { public boolean login(String userName, char[] password); }
And the actual implementation, where we increase the relevant counters:
@Service public class LoginServiceImpl implements LoginService { private CounterService counterService; @Autowired public LoginServiceImpl(CounterService counterService) { this.counterService = counterService; } public boolean login(String userName, char[] password) { boolean success; if (userName.equals("admin") && "secret".toCharArray().equals(password)) { counterService.increment("counter.login.success"); success = true; } else { counterService.increment("counter.login.failure"); success = false; } return success; } }
Here’s what the output might look like:
{ ... "counter.login.success" : 105, "counter.login.failure" : 12, ... }
5. Create A New Endpoint
Besides using the existing endpoints provided by Spring Boot – you can also create an entirely new endpoint.
First – you’ll need to have the new endpoint implementation implement the Endpoint<T> interface:
@Component public class CustomEndpoint implements Endpoint<List<String>> { public String getId() { return "customEndpoint"; } public boolean isEnabled() { return true; } public boolean isSensitive() { return true; } public List<String> invoke() { // Custom logic to build the output List<String> messages = new ArrayList<String>(); messages.add("This is message 1"); messages.add("This is message 2"); return messages; } }
Output:
[ "This is message 1", "This is message 2" ]
6. A New Endpoint To List All Endpoints
Another interesting custom endpoint is one that exposes all available endpoints. To implement this one, you’ll need to extend the AbstractEndpoint<T> class:
@Component public class ListEndpoints extends AbstractEndpoint<List<Endpoint>> { private List<Endpoint> endpoints; @Autowired public ListEndpoints(List<Endpoint> endpoints) { super("listEndpoints"); this.endpoints = endpoints; } public List<Endpoint> invoke() { return this.endpoints; } }
Here’s how the output will look like:
[ { "id" : "customEndpoint", "enabled" : true, "sensitive" : true }, { "id" : "mappings", "sensitive" : true, "enabled" : true }, { "id" : "env", "sensitive" : true, "enabled" : true }, { "id" : "myhealth", "sensitive" : true, "enabled" : true, "timeToLive" : 1000 }, { "id" : "beans", "sensitive" : true, "enabled" : true }, { "id" : "info", "sensitive" : false, "enabled" : true }, { "id" : "metrics", "sensitive" : true, "enabled" : true }, { "id" : "trace", "sensitive" : true, "enabled" : true }, { "id" : "dump", "sensitive" : true, "enabled" : true }, { "id" : "autoconfig", "sensitive" : true, "enabled" : true }, { "id" : "shutdown", "sensitive" : true, "enabled" : true }, { "id" : "configprops", "sensitive" : true, "enabled" : true } ]
7. Further Customization
For security purposes, you might choose to expose the actuator endpoints over a non-standard port – the management.port property can easily be used to configure that.
You can also change the management.address property to restrict where the endpoints can be accessed from over the network:
management.port=8081 management.address=127.0.0.1 management.security.enabled=false
All the built-in endpoints except /info are sensitive by default. If the application is using Spring Security – you can secure these endpoints by defining the default security properties – user name, password and role – in application.properties file:
security.user.name=admin security.user.password=secret management.security.role=SUPERUSER
8. Conclusion
In this tutorial we had a first look at the interesting Actuator functionality provided by Spring Boot. We went over the existing endpoints available in the framework, augmented some of them with new, custom data and finally rolled our own to expose some entirely new kind of data.