Spring Boot Actuator: Monitoring

Spring Boot Actuator: Monitoring and Management Made Easy

Introduction

Ever deployed a Spring Boot application and wondered how it's performing in production? Or needed to check the health status of your microservices without digging through logs? That's where Spring Boot Actuator comes in — one of those features that once you start using, you'll wonder how you ever managed without it.

When I first discovered Actuator several years ago, it completely changed how I approach application monitoring and management. Instead of building custom endpoints or relying on complex external tools, Spring Boot Actuator provided out-of-the-box solutions for the most common operational needs.

In this post, I'll walk you through Spring Boot Actuator from the ground up. We'll explore what it is, why you should care, and how to implement it in your applications with practical examples. By the end, you'll have all the knowledge you need to start monitoring your Spring Boot applications like a pro!

Usages

Spring Boot Actuator adds several production-ready features to your application with minimal setup. Here are some of the key use cases that make it invaluable in real-world environments:

Health Monitoring

With Actuator's health endpoint, you can check if your application and its dependencies (databases, message queues, etc.) are operating correctly. This is crucial for:

  • Load balancers deciding whether to route traffic to your instance
  • Kubernetes readiness/liveness probes
  • DevOps teams monitoring application status

Metrics Collection

Actuator provides detailed metrics about your application's performance:

  • JVM memory usage and garbage collection statistics
  • HTTP request timing and response codes
  • Database connection pool usage
  • Custom business metrics you define

Environment Inspection

Need to verify what configuration properties your application is actually using in production? Actuator exposes:

  • Active profiles
  • Property sources and values
  • Environment variables

Logging Control

Actuator allows you to dynamically change log levels at runtime — incredibly useful when troubleshooting production issues without restarting your application.

Thread Dump & Heap Dump

When performance issues strike, you can capture thread dumps and heap dumps for detailed analysis.

Real-world Use Case: Microservice Monitoring

Imagine you're running a microservice architecture with dozens of services. With Actuator:

  1. Your ops team can build a dashboard showing health status across all services
  2. Alert systems can notify you when a service dependency fails
  3. You can identify which microservices are experiencing high latency
  4. During an incident, you can increase log verbosity without service disruption

Code Example

Let's implement Spring Boot Actuator in a sample microservice application to see it in action!

1. Add Actuator to Your Project

First, add the Actuator dependency to your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Or with Gradle:

implementation 'org.springframework.boot:spring-boot-starter-actuator'

2. Basic Configuration

Add these properties to your application.properties (or application.yml):

# Enable all actuator endpoints
management.endpoints.web.exposure.include=*

# Base path for actuator endpoints
management.endpoints.web.base-path=/actuator

# Show details in health endpoint
management.endpoint.health.show-details=always

# Enable shutdown endpoint (disabled by default)
management.endpoint.shutdown.enabled=true

Note: In production, you might want to be more selective about which endpoints you expose.

3. Create a Custom Health Indicator

Let's create a custom health indicator that checks connectivity to an external API our application depends on:

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class ExternalApiHealthIndicator implements HealthIndicator {

    private final RestTemplate restTemplate;
    private final String apiUrl = "https://api.example.com/health";
    
    public ExternalApiHealthIndicator(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
    
    @Override
    public Health health() {
        try {
            // Attempt to call the external API
            restTemplate.getForObject(apiUrl, String.class);
            return Health.up()
                    .withDetail("message", "External API is responding")
                    .build();
        } catch (Exception e) {
            return Health.down()
                    .withDetail("message", "External API is not available")
                    .withDetail("error", e.getMessage())
                    .build();
        }
    }
}

4. Add Custom Metrics

Let's add custom metrics to track business-specific operations:

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final Counter orderCounter;
    private final Counter failedOrderCounter;
    private final Timer orderProcessingTimer;
    
    public OrderService(MeterRegistry registry) {
        this.orderCounter = Counter.builder("app.orders.created")
                .description("Total number of orders created")
                .register(registry);
                
        this.failedOrderCounter = Counter.builder("app.orders.failed")
                .description("Number of failed order creations")
                .register(registry);
                
        this.orderProcessingTimer = Timer.builder("app.orders.processing.time")
                .description("Time taken to process orders")
                .register(registry);
    }
    
    public void createOrder(Order order) {
        Timer.Sample sample = Timer.start();
        
        try {
            // Business logic to process the order
            processOrder(order);
            
            // Increment the order counter
            orderCounter.increment();
        } catch (Exception e) {
            // Increment the failed order counter
            failedOrderCounter.increment();
            throw e;
        } finally {
            // Record the time taken
            sample.stop(orderProcessingTimer);
        }
    }
    
    private void processOrder(Order order) {
        // Order processing logic
    }
}

5. Create Info Contributor

Let's add custom information to the /info endpoint:

import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
public class ApplicationInfoContributor implements InfoContributor {

    @Override
    public void contribute(Info.Builder builder) {
        Map<String, Object> details = new HashMap<>();
        details.put("version", "1.2.3");
        details.put("releaseDate", "2025-04-20");
        details.put("environment", getEnvironmentName());
        
        builder.withDetail("application", details);
    }
    
    private String getEnvironmentName() {
        // Logic to determine environment
        return "production";
    }
}

6. Configure Logging Endpoint

Enable runtime log level changes:

# in application.properties
management.endpoint.loggers.enabled=true

7. Secure Actuator Endpoints

Add Spring Security to protect sensitive endpoints:

import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class ActuatorSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.requestMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeHttpRequests(requests -> requests
                .requestMatchers(EndpointRequest.to("health", "info")).permitAll()
                .anyRequest().hasRole("ACTUATOR_ADMIN"))
            .httpBasic();
        return http.build();
    }
}

Explanation

Let's break down what we've implemented and how it works:

Basic Setup

By adding the spring-boot-starter-actuator dependency, Spring Boot automatically registers various endpoints under the /actuator base path. Our configuration exposes all endpoints for demonstration purposes, but in production, you'd typically limit this to only what you need.

Custom Health Indicator

The ExternalApiHealthIndicator class implements Spring's HealthIndicator interface. When someone accesses the /actuator/health endpoint, Spring aggregates results from all health indicators, including ours. If our external API check fails, the overall health status will show as DOWN.

This gives you an instant view of whether all your application dependencies are functioning correctly.

Custom Metrics

Micrometer (included with Actuator) provides a vendor-neutral metrics facade. In our example:

  • We created counters for successful and failed orders
  • We added a timer to measure order processing latency

These metrics are exposed via the /actuator/metrics endpoint. More importantly, they can be scraped by monitoring systems like Prometheus and visualized in dashboards like Grafana.

Info Contributor

The ApplicationInfoContributor adds custom details to the /actuator/info endpoint. This information is useful for identifying which version of the application is running in a particular environment.

Logging Configuration

With the loggers endpoint enabled, you can view and change log levels at runtime by sending POST requests to /actuator/loggers/{logger-name} with a JSON body specifying the desired level.

Security

Our security configuration permits anonymous access to non-sensitive endpoints like health and info, while requiring authentication with the ACTUATOR_ADMIN role for all other endpoints.

Best Practices

Based on my experience implementing Actuator in production systems, here are some best practices to follow:

1. Be Selective with Endpoint Exposure

Don't expose all endpoints in production. Instead, be explicit about which ones you need:

management.endpoints.web.exposure.include=health,info,metrics,prometheus

2. Secure Endpoints Properly

Always secure sensitive endpoints. Consider:

  • Using a separate management port accessible only from internal networks
  • Implementing strong authentication for management endpoints
  • Limiting access to specific IP ranges
# Use a different port for actuator endpoints
management.server.port=8081

3. Customize Health Indicators

Create custom health indicators for all critical dependencies. This provides a complete picture of your application's health status.

4. Implement Business-Relevant Metrics

Don't just rely on technical metrics. Track business-specific metrics that matter to your domain:

  • Number of active users
  • Transaction volumes
  • Business process success/failure rates
  • Domain-specific performance indicators

5. Use Tags for Metric Dimensions

Tags make your metrics more powerful by allowing multi-dimensional analysis:

Counter.builder("app.orders.created")
    .tag("channel", order.getChannel())
    .tag("product", order.getProductType())
    .register(registry)
    .increment();

6. Integrate with Monitoring Systems

Actuator works well with various monitoring systems. For production use, consider:

  • Prometheus + Grafana for metrics collection and visualization
  • Spring Boot Admin for a ready-made UI dashboard
  • ELK stack for advanced log analysis

7. Add Spring Boot Admin

For a quick visual dashboard of your Actuator data, add Spring Boot Admin to your project:

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>3.2.0</version>
</dependency>

8. Include Version Information

Always expose application version info to aid in troubleshooting:

# In application.properties
info.app.name=${project.name}
info.app.version=${project.version}
info.app.build-timestamp=${maven.build.timestamp}

9. Use Health Groups

Organize health indicators into logical groups (available since Spring Boot 2.3):

management.endpoint.health.group.readiness.include=db,redis,kafka
management.endpoint.health.group.liveness.include=ping,diskSpace

10. Rate Limit Access to Endpoints

For high-traffic environments, consider implementing rate limiting for Actuator endpoints to prevent DoS risks.

Conclusion

Spring Boot Actuator is one of those features that transforms how you operate your applications in production. With minimal configuration, you get deep insights into your application's health, performance, and behavior.

In this post, we've covered:

  • Setting up Actuator in your Spring Boot application
  • Creating custom health indicators for dependency checks
  • Implementing business-specific metrics
  • Adding custom application information
  • Securing sensitive endpoints
  • Best practices for production deployment

While the examples we've covered are a great starting point, Actuator offers even more capabilities worth exploring, like HTTP tracing, audit events, and scheduled task insights.

The effort required to implement Actuator is minimal, yet the operational benefits are substantial. In today's world of microservices and distributed systems, having robust monitoring and management capabilities isn't optional—it's essential. And Spring Boot Actuator makes achieving this remarkably simple.

So, what are you waiting for? If you haven't already, add Actuator to your Spring Boot applications today. Your future self (and your DevOps team) will thank you!

Have you implemented Actuator in your projects? What metrics have you found most valuable? Let me know in the comments below!


Description: Master Spring Boot Actuator with this comprehensive guide covering health checks, metrics, and monitoring. Learn implementation best practices with real code examples to improve your application's observability and management capabilities.

Post a Comment

Previous Post Next Post