Spring Boot Actuator

Overview

In this article, we'll look into Spring Boot Actuator, which provides built-in production ready endpoints that can be used for monitoring and controlling your application.

Monitoring applications may include something as simple as knowing the Health and Info to some complex data like understanding Traffic and Metrics for our application. For example, how much resources (CPU, RAM, etc.) are being used by the application.

You can choose to interact with actuators either with HTTP endpoints or with JMX beans. In this tutorial, we would be using the HTTP endpoints.

In Spring Boot 1, the actuator could only be used with Spring MVC. But with Spring Boot 2 and the introduction of WebFlux, its support has been extended and can also be used with the Jersey framework without the need of Spring MVC in the classpath.

Spring Boot Actuator

In order to demonstrate the actuator in work, we'll be using a simple Spring REST-based service, running on the default port (8080) with a single endpoint of /hello that returns a String message.

To add actuator, we simply add the dependency to our pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>${VERSION}</version>
</dependency>

All the endpoints fall under a common prefix of /actuator. To check, let's navigate our browser to http://localhost:8080/actuator:

spring_boot_actuator_default_endpoints

Note: In Spring Boot 1, all of the actuator endpoints were in the root base path, i.e /, but in Spring Boot 2, all of them are by default grouped under /actuator.

You can change the base path of the actuator endpoints by adding the following properties in the application.properties:

management.endpoints.web.base-path=/admin
management.server.port=8090

Now, all the actuator endpoints will be under the /admin prefix, which makes sense since only an admin should have access to metrics such as these. For this tutorial, we are going to leave it under the default /actuator.

By default, management endpoints are available on the same port as that of your application, but you may choose to expose these on a different HTTP port by setting the management.server.port to an HTTP port of your choice.

We will not be changing it as the default behavior is preferable especially if you are running on the cloud.

Actuator Endpoints

A full list of available endpoints can be seen in the official documentation. You may have noticed that although there are many endpoints available, the result of http://localhost:8080/actuator shows only /health and /info.

Since actuator endpoints contain sensitive information, we have had to explicitly expose each of them, otherwise, we'll only be able to see rudimentary information that's already apparent.

Navigate our browser to http://localhost:8080/actuator/health:

spring_boot_actuator_health

Now, let us check the /info similarly and you will notice that it returns an empty response.

This is because we have not provided any information about it to Spring. This can be done by adding properties to the info prefix in the application.properties:

info.name= Test Spring Service
info.more.detail= This is a demo for Spring Actuator

spring_boot_actuator_info

You can structure the JSON key according to your needs.

Exposing Endpoints

In order to expose endpoints, Spring provides 2 properties that we can use individually or in combination:

  • management.endpoints.web.exposure.exclude: Used to exclude a list of endpoints that we do not want to expose. The default value for it is empty.
  • management.endpoints.web.exposure.include: Used to include a list of endpoints that we want to expose. The default value for it is info, health. This is why both these endpoints were available by default.

Note: exclude takes precedence over include

So, let's tweak the configuration so that we want to expose all of the endpoints except for info and health:

management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=info,health

Note: If you are using a YAML-based properties file, * has a special meaning and can only be used with quotes:

management:
  endpoints:
    web:
      exposure:
        exclude: "*"

For this tutorial, we will be exposing all of our actuator endpoints. So let's add the following endpoint in our application.properties:

management.endpoints.web.exposure.include= *

Now, let's check the actuator endpoint again by opening http://localhost:8080/actuator:

spring_boot_actuator_all

Enabling Endpoints

Besides exposing endpoints, we can also enable and disable them. While exposing only regulates whether we can see them or not, enabling regulates whether they exist as a bean in the context of Spring.

By default, all the endpoints are enabled except for one, the shutdown endpoint. You can enable/disable each endpoint by setting the management.endpoint.<id>.enabled property:

management.endpoint.shutdown.enabled=true
management.endpoint.beans.enabled=false

You can also disable all endpoints by setting management.endpoints.enabled-by-default to false and then individually enable the properties you want. For this tutorial, we would be going with the default setting.

Note: Disabling the endpoints will remove them as beans from the context completely and it wouldn't matter if you have exposed them.

Caching Support

All the endpoints (that are READ operation and do not take any parameter) have basic caching support as well.

Every endpoint has a property of cache.time-to-live that's automatically generated for you which can be used to specify the cache time:

management.endpoint.beans.cache.time-to-live=10s

Securing Actuator Endpoints

By now, it would have been clear that these endpoints store sensitive information about our application and it would be a good idea to secure them.

To do it we can simply add spring security to our application by adding the spring-boot-starter-security dependency in our pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>${VERSION}</version>
</dependency>

By default, just by importing it, all of the endpoints in our application will be secured.

But let's suppose we want our /health endpoint available to all, but the rest of them to be secure. This warrants a custom filter for letting certain users pass and holding back others.

For that we have to add a @Configuration class that extends the WebSecurityConfigurerAdapter, like with any other Spring Boot application that we want to secure with Spring Security.

Then we need to override the .configure() method where we define the security configuration for our application:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll()
            .requestMatchers(EndpointRequest.toAnyEndpoint()).authenticated()
            .and()
            .httpBasic();
    }
}

The above code is self-explanatory, where we allowed any HealthEndpoint to be publicly available, while others require some basic authentication. Also, note that EndpointRequest.to() is a convenience method that automatically takes care of the final URL of your actuator endpoints because you might have changed the base-path of it in your application.

Let's restart again and check the logs:

spring_boot_actuator_security

Because Spring Security is in the classpath, it automatically creates a username of user and a password that is randomly generated at the start of the application, as shown in the logs.

Let's check the /health endpoint and you will see the output without any authentication box. Now let's try any other endpoint, say /env and you will be asked to authenticate:

spring_boot_actuator_security_authenticate

Enter the username and password and you can see the appropriate response:

spring_boot_actuator_security_authenticate_env

If you want to define your own username and password, you can easily do so via the application.properties:

spring.security.user.name=user
spring.security.user.password=password

Creating Custom Endpoints

This can be achieved by adding the @Endpoint and @Component annotation to your class. After that, you can create methods and annotate them with @ReadOperation, @WriteOperation, or @DeleteOperation accordingly. You can, of course, have multiple methods with different operations.

The idea of having multiple operations is to map to different HTTP request methods:

  • @ReadOperation maps to HTTP GET
  • @WriteOperation maps to HTTP POST
  • @DeleteOperation maps to HTTP DELETE

Let's create a simple custom endpoint:

@Component
@Endpoint(id = "details")
public class DetailsEndpoint {

    @ReadOperation
    public String details() {
        return "My App Details";
    }
}

Restart the application and navigate to your browser to http://localhost:8080/actuator/details:

spring_boot_actuator_custom

Conclusion

Monitoring applications may include something as simple as knowing the Health and Info to some complex data like understanding Traffic and Metrics for our application. For example, how much resources (CPU, RAM, etc.) are being used by the application.

Spring Boot Actuator provides build-in production ready endpoints that can be used for monitoring and controlling your application such as /info, /health, /scheduledTasks, etc.

We can also define our own endpoints to meet certain requirements by simple annotating classes with the @Endpoint annotation.

As always, the code for the examples used in this article can be found on GitHub.