CubeAPM
CubeAPM CubeAPM

Spring Boot Actuator: Metrics, Health Checks and Production Setup

Spring Boot Actuator: Metrics, Health Checks and Production Setup

Table of Contents

Spring Boot Actuator turns a basic Spring Boot application into a production ready service by exposing operational endpoints for health checks, metrics, auditing, and environment inspection without any custom code. Without Actuator, teams rely on logs and external monitoring to detect failures. With Actuator, the application itself exposes structured data about memory usage, thread counts, HTTP request rates, and database connection health through REST endpoints that any monitoring tool can consume.

According to the Spring 2024 Developer Survey by VMware, 71% of Java developers use Spring Boot for production applications, and Actuator is enabled in the majority of those deployments to meet SLA monitoring requirements. This guide covers how to enable Actuator, configure health and metrics endpoints, expose them securely, integrate with Prometheus and CubeAPM, and prepare your Spring Boot application for production observability.

Prerequisites

Before following this guide, ensure you have:

  • Java 17 or later installed and configured
  • Spring Boot 3.0 or later (examples use Spring Boot 3.3)
  • Maven 3.6+ or Gradle 7+ for dependency management
  • Basic familiarity with Spring Boot application structure and application.properties configuration
  • A running Spring Boot application to instrument (the guide uses a sample REST API)
  • Access to deploy and test the application locally or in a staging environment

Step 1: Add Spring Boot Actuator Dependency

Spring Boot Actuator is distributed as a standalone dependency. Adding it to your project enables all Actuator functionality with sensible defaults.

For Maven projects, add this to your pom.xml:

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

For Gradle projects, add this to your build.gradle:

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

After adding the dependency, rebuild your project and restart the application. Spring Boot automatically configures Actuator endpoints at /actuator by default.

Verify Actuator is enabled by visiting http://localhost:8080/actuator in your browser. You should see a JSON response listing available endpoints. By default, only /actuator/health and /actuator/info are exposed over HTTP for security reasons.

Step 2: Configure Health Check Endpoints

The /actuator/health endpoint provides a summary of application health by checking components like database connections, disk space, and custom health indicators. By default, it returns a simple status.

To expose detailed health information including component level checks, add this to application.properties:

management.endpoint.health.show-details=always
management.endpoint.health.show-components=always

Restart the application and visit http://localhost:8080/actuator/health. The response now includes details for each health indicator:

{
  "status": "UP",
  "components": {
    "db": {
      "status": "UP",
      "details": {
        "database": "PostgreSQL",
        "validationQuery": "isValid()"
      }
    },
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 250790436864,
        "free": 125395218432,
        "threshold": 10485760
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

Spring Boot includes built in health indicators for common components like databases, message queues, and Elasticsearch. Each indicator runs a lightweight check and reports UP or DOWN. If any component reports DOWN, the overall health status becomes DOWN, allowing load balancers and orchestration tools to route traffic away from unhealthy instances.

To create a custom health indicator, implement the HealthIndicator interface:

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

@Component
public class ExternalApiHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        boolean apiReachable = checkExternalApi();
        if (apiReachable) {
            return Health.up()
                .withDetail("api", "External API is reachable")
                .build();
        } else {
            return Health.down()
                .withDetail("api", "External API is unreachable")
                .build();
        }
    }

    private boolean checkExternalApi() {
        // Add your API check logic here
        return true;
    }
}

This custom indicator appears in the health endpoint response under components.externalApi and participates in the overall health calculation.

Step 3: Enable and Expose Metrics Endpoints

Spring Boot Actuator collects runtime metrics using Micrometer, a vendor neutral metrics facade that supports multiple monitoring systems including Prometheus, Datadog, and Graphite.

By default, metrics are collected but not exposed over HTTP. To expose the /actuator/metrics endpoint, add this to application.properties:

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

Restart the application and visit http://localhost:8080/actuator/metrics. The response lists all available metrics:

{
  "names": [
    "jvm.memory.used",
    "jvm.memory.max",
    "jvm.gc.pause",
    "http.server.requests",
    "system.cpu.usage",
    "process.uptime"
  ]
}

To view a specific metric, append its name to the URL. For example, http://localhost:8080/actuator/metrics/jvm.memory.used returns:

{
  "name": "jvm.memory.used",
  "measurements": [
    {
      "statistic": "VALUE",
      "value": 123456789
    }
  ],
  "availableTags": [
    {
      "tag": "area",
      "values": ["heap", "nonheap"]
    },
    {
      "tag": "id",
      "values": ["G1 Old Gen", "G1 Eden Space"]
    }
  ]
}

Spring Boot automatically instruments common metrics including JVM memory and garbage collection, CPU usage, thread counts, HTTP request rates and latencies, database connection pool usage, and Logback log events. These metrics cover the majority of production monitoring needs without custom instrumentation.

To add custom metrics, inject a MeterRegistry and register counters, gauges, or timers:

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

@Service
public class OrderService {

    private final Counter orderCounter;

    public OrderService(MeterRegistry registry) {
        this.orderCounter = Counter.builder("orders.placed")
            .description("Total number of orders placed")
            .register(registry);
    }

    public void placeOrder() {
        // Business logic here
        orderCounter.increment();
    }
}

This custom metric appears at /actuator/metrics/orders.placed and is exported to any configured monitoring backend.

Step 4: Configure Prometheus Integration

Prometheus is a widely used open source monitoring system that scrapes metrics from HTTP endpoints. Spring Boot Actuator includes a Prometheus registry that formats metrics in the Prometheus exposition format.

Add the Micrometer Prometheus dependency to your project:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Ensure the Prometheus endpoint is exposed in application.properties:

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

Restart the application and visit http://localhost:8080/actuator/prometheus. The response is a text format metric dump that Prometheus can scrape:

# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="G1 Eden Space",} 1.23456789E8
jvm_memory_used_bytes{area="heap",id="G1 Old Gen",} 4.56789012E7

# HELP http_server_requests_seconds Duration of HTTP server request handling
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{method="GET",status="200",uri="/api/orders",} 1234.0
http_server_requests_seconds_sum{method="GET",status="200",uri="/api/orders",} 5.678

Configure Prometheus to scrape this endpoint by adding a job to prometheus.yml:

scrape_configs:
  - job_name: 'spring-boot-app'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']

Prometheus now collects all Spring Boot metrics every 15 seconds by default. You can query these metrics in Prometheus or visualize them in Grafana.

Step 5: Integrate with CubeAPM for Full Stack Observability

CubeAPM provides unified APM, logs, and infrastructure monitoring with native OpenTelemetry support. It can collect Spring Boot Actuator metrics alongside distributed traces and logs for complete application visibility.

To send Actuator metrics to CubeAPM, configure the OpenTelemetry exporter. Add the OpenTelemetry Micrometer bridge dependency:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-otlp</artifactId>
</dependency>

Configure the OTLP exporter in application.properties:

management.otlp.metrics.export.enabled=true
management.otlp.metrics.export.url=http://cubeapm-collector:4318/v1/metrics
management.otlp.metrics.export.step=30s

Replace http://cubeapm-collector:4318/v1/metrics with your actual CubeAPM collector endpoint. The step property controls how frequently metrics are pushed.

CubeAPM automatically correlates Actuator metrics with distributed traces and logs from the same application. When a slow HTTP request triggers an alert, CubeAPM shows JVM memory pressure, garbage collection pauses, and database connection pool saturation in the same view as the distributed trace, eliminating the need to switch between tools to diagnose root cause.

For teams running AWS Lambda monitoring or AWS RDS monitoring alongside Spring Boot services, CubeAPM provides a single platform to monitor serverless functions, managed databases, and containerized applications with unified alerting and dashboards.

Step 6: Secure Actuator Endpoints for Production

Exposing Actuator endpoints without authentication allows anyone with network access to view application internals and potentially trigger shutdown or thread dump endpoints. Spring Security integration secures Actuator endpoints while keeping health checks accessible to load balancers.

Add Spring Security dependency:

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

Configure security rules in a SecurityConfig class:

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.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/actuator/health").permitAll()
                .requestMatchers("/actuator/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .httpBasic();
        return http.build();
    }
}

This configuration allows unauthenticated access to /actuator/health for load balancer health checks while requiring ADMIN role authentication for all other Actuator endpoints. In production, use OAuth2 or SAML instead of HTTP Basic authentication.

For Kubernetes deployments, configure the health endpoint as a readiness probe in your pod spec:

apiVersion: v1
kind: Pod
metadata:
  name: spring-boot-app
spec:
  containers:
  - name: app
    image: spring-boot-app:latest
    ports:
    - containerPort: 8080
    readinessProbe:
      httpGet:
        path: /actuator/health/readiness
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
    livenessProbe:
      httpGet:
        path: /actuator/health/liveness
        port: 8080
      initialDelaySeconds: 60
      periodSeconds: 10

Spring Boot 2.3 and later include separate /actuator/health/readiness and /actuator/health/liveness endpoints that Kubernetes uses to determine when a pod is ready to receive traffic and when it should be restarted.

Step 7: Configure Production Ready Application Properties

Production deployments require tuning Actuator configuration for performance, security, and observability. This section covers the most important properties to set before going live.

Create a production specific application-prod.properties file:

# Server configuration
server.port=8080
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s

# Actuator endpoints
management.endpoints.web.base-path=/actuator
management.endpoints.web.exposure.include=health,info,metrics,prometheus
management.endpoint.health.show-details=when-authorized
management.endpoint.health.probes.enabled=true

# Metrics export
management.metrics.export.prometheus.enabled=true
management.metrics.distribution.percentiles-histogram.http.server.requests=true
management.metrics.tags.application=${spring.application.name}
management.metrics.tags.environment=production

# Info endpoint
info.app.name=${spring.application.name}
[email protected]@
[email protected]@
[email protected]@

# Security
management.endpoints.web.cors.allowed-origins=https://monitoring.company.com
management.endpoints.web.cors.allowed-methods=GET,POST

The server.shutdown=graceful setting ensures Spring Boot waits for active requests to complete before shutting down, preventing connection errors during rolling deployments. The percentiles-histogram setting enables percentile calculation for HTTP request latencies, which is required for accurate SLO tracking.

Metric tags are critical for multi-environment deployments. Adding application and environment tags allows you to filter Prometheus queries by application name and environment, making it possible to compare production and staging metrics or track multiple services in a single Grafana dashboard.

The info endpoint exposes application metadata that appears in Spring Boot Admin dashboards and helps operations teams identify which version is deployed in each environment. Using Maven property placeholders like @project.version@ ensures the version number updates automatically during builds.

Troubleshooting Common Issues

Actuator endpoints return 404

Verify the spring-boot-starter-actuator dependency is included in your build file and the application has been rebuilt. Check that management.endpoints.web.exposure.include includes the endpoint you are trying to access. The default configuration only exposes health and info.

Health endpoint shows DOWN status

Check the detailed health response at /actuator/health to identify which component is reporting DOWN. Common causes include database connection failures, disk space below the threshold (default 10MB), or custom health indicators returning failure status. Review application logs for error messages from the failing component.

Metrics endpoint shows no custom metrics

Ensure your custom metric code is being executed. Add a log statement where the metric is incremented to verify the code path is reached. Check that the MeterRegistry is being injected correctly and not null. Verify the metric name does not conflict with built in metric names.

Prometheus scrape fails with connection refused

Confirm the Spring Boot application is running and the Actuator endpoints are accessible from the Prometheus server. Check firewall rules and security groups if running in a cloud environment. Verify the metrics_path in prometheus.yml matches the actual endpoint path (/actuator/prometheus by default).

High memory usage after enabling Actuator

Actuator metrics collection has minimal overhead, but enabling histogram percentiles for all HTTP requests can increase memory consumption on high traffic applications. Disable percentiles-histogram for non critical endpoints or use Prometheus monitoring to calculate percentiles at query time instead of recording them in application memory.

Disclaimer: Feature availability and configuration options may vary between Spring Boot versions. Always verify current syntax and capabilities in the official Spring Boot Actuator documentation for your specific version before deploying to production.

Frequently Asked Questions

How do I expose Actuator endpoints over HTTP?

Add `management.endpoints.web.exposure.include` to `application.properties` with a comma separated list of endpoints to expose. Use `*` to expose all endpoints, but secure them with Spring Security in production. Only `/actuator/health` and `/actuator/info` are exposed by default.

Can I change the Actuator base path from /actuator?

Set `management.endpoints.web.base-path=/custom-path` in `application.properties` to change the base path. This is useful when `/actuator` conflicts with existing application routes or when you want to obscure monitoring endpoints from casual discovery.

How do I disable specific Actuator endpoints?

Set `management.endpoint.[endpoint-name].enabled=false` in `application.properties`. For example, `management.endpoint.shutdown.enabled=false` disables the shutdown endpoint. This is safer than relying solely on security rules because it prevents the endpoint from being registered at all.

What is the difference between /actuator/health/readiness and /actuator/health/liveness?

Readiness indicates whether the application is ready to accept traffic. Liveness indicates whether the application should be restarted. A failing readiness check removes the pod from the load balancer. A failing liveness check triggers a pod restart. Use readiness for dependency health checks and liveness for internal application health.

How do I add custom information to the /actuator/info endpoint?

Add properties prefixed with `info.` to `application.properties`. These appear in the info endpoint response. You can also create a custom `InfoContributor` bean to add dynamic information at runtime.

Can I use Actuator with Spring Boot 2.x?

Yes, Actuator works with Spring Boot 2.0 and later. Some property names and security configuration syntax differ between Spring Boot 2.x and 3.x. Refer to the Spring Boot documentation for your specific version for accurate configuration examples.

How do I monitor Spring Boot applications running in Docker containers?

Expose Actuator endpoints and configure health checks in your Dockerfile and docker-compose.yml. Use the health endpoint for Docker healthcheck directives. Export metrics to Prometheus or CubeAPM running in separate containers to avoid coupling monitoring infrastructure to application containers.

×
×