Spring Boot Actuator

Last update: 2023-06-02 05:27:47 +0800 +0800

Spring Boot Actuator adds production-oriented monitoring and management features to a Spring Boot application. It exposes information such as health, metrics, configuration, log levels, and thread state through HTTP endpoints or JMX.

Actuator is part of the application itself. It is not a separate monitoring server and does not retain historical data. An endpoint reports the application’s current state; an external system such as Prometheus periodically collects that state and stores it over time.

Adding Actuator #

For Maven:

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

For Gradle:

groovy
implementation("org.springframework.boot:spring-boot-starter-actuator")

After the application starts, the root discovery endpoint is normally:

text
GET /actuator

The health endpoint is:

text
GET /actuator/health

The exact endpoints that exist depend on the application’s dependencies and configuration. For example, a database health contributor is useful only when the application has a configured data source.

What Actuator Provides #

Common Actuator endpoints include:

EndpointPurpose
healthReports overall and component health
infoReports application information
metricsLists and inspects Micrometer meters
prometheusExposes metrics in Prometheus scrape format
loggersInspects and changes logging levels
envInspects properties from the Spring environment
configpropsShows properties bound to configuration classes
beansLists beans in the application context
conditionsExplains positive and negative auto-configuration matches
mappingsLists web request mappings
cachesInspects and evicts application caches
scheduledtasksLists scheduled tasks
quartzInspects Quartz jobs and triggers
startupReports application startup steps when startup recording is enabled
threaddumpProduces a JVM thread dump
heapdumpDownloads a JVM heap dump
httpexchangesShows recent HTTP request-response exchanges when a repository is configured
auditeventsShows security audit events when an audit repository is configured
shutdownGracefully shuts down the application when explicitly enabled

Not every endpoint should be exposed in production. Several reveal configuration, application structure, runtime behavior, or large diagnostic artifacts.

Enabled Is Different from Exposed #

Actuator treats two decisions separately:

  1. Enabled: Whether an endpoint is created in the application context.
  2. Exposed: Whether that endpoint is available through HTTP or JMX.

An endpoint must be both enabled and exposed before a remote client can use it.

Enable or disable one endpoint:

yaml
management:
  endpoint:
    shutdown:
      enabled: true

Control HTTP exposure:

yaml
management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus

Control JMX exposure independently:

yaml
management:
  endpoints:
    jmx:
      exposure:
        include: health,info

An exclusion takes precedence over an inclusion:

yaml
management:
  endpoints:
    web:
      exposure:
        include: "*"
        exclude: env,beans,heapdump,shutdown

Exposing everything and maintaining a denylist is risky because a framework upgrade can add a new endpoint. A small explicit allowlist is safer.

Health Information #

/actuator/health combines results from registered health contributors. Spring Boot can auto-configure contributors for facilities such as:

  • Databases and connection pools
  • Disk space
  • Redis
  • Message brokers
  • Search services
  • Mail servers
  • Custom application dependencies

A healthy response may be as small as:

json
{"status":"UP"}

By default, component details are not shown. Their visibility is controlled by:

yaml
management:
  endpoint:
    health:
      show-details: when-authorized
      show-components: when-authorized

The supported policies are never, when-authorized, and always. Avoid publishing component details anonymously because names, addresses, database state, and exception information can disclose useful operational details.

Custom Health Indicators #

A custom health indicator expresses whether an application-specific dependency can perform the operation the service requires:

java
import org.springframework.boot.health.contributor.Health;
import org.springframework.boot.health.contributor.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class PaymentProviderHealthIndicator implements HealthIndicator {

    private final PaymentClient paymentClient;

    public PaymentProviderHealthIndicator(PaymentClient paymentClient) {
        this.paymentClient = paymentClient;
    }

    @Override
    public Health health() {
        if (paymentClient.isAvailable()) {
            return Health.up().build();
        }
        return Health.down()
            .withDetail("provider", "primary")
            .build();
    }
}

The bean name, without the HealthIndicator suffix, becomes the component ID. The preceding contributor appears as paymentProvider.

Health checks run in response to endpoint requests, so they must be bounded and fast. A check should use a short timeout and avoid expensive scans, large allocations, or modifying remote state.

Health Status and HTTP Responses #

The built-in status values include:

text
UP
DOWN
OUT_OF_SERVICE
UNKNOWN

DOWN and OUT_OF_SERVICE normally produce HTTP 503; healthy and unmapped statuses produce 200. A StatusAggregator combines component statuses into the overall result.

Custom status ordering and HTTP mappings can be configured, but custom mappings replace the defaults. Preserve the standard mappings explicitly when adding a new status.

Liveness and Readiness #

Actuator provides health groups for container orchestrators:

text
/actuator/health/liveness
/actuator/health/readiness

The distinction matters:

  • Liveness asks whether the process is irrecoverably broken and should be restarted.
  • Readiness asks whether the process should currently receive traffic.

Do not add every external dependency to liveness. If a shared database fails, restarting every application instance will not repair the database and may make the incident worse.

Readiness may include dependencies required to serve requests, but the choice depends on system behavior. A service that can provide degraded responses without a dependency may remain ready.

Health groups can also be published on the main application port:

yaml
management:
  endpoint:
    health:
      group:
        live:
          additional-path: server:/healthz
        ready:
          additional-path: server:/readyz

This avoids a misleading result where a separate management port responds even though the main server can no longer accept requests.

How Actuator Interfaces with Micrometer #

Actuator uses Micrometer as its metrics and observation foundation. Spring Boot auto-configures a Micrometer MeterRegistry, binds JVM, process, system, HTTP, database-pool, and framework instrumentation to it, and adds each supported registry implementation found on the runtime classpath. The Actuator metrics endpoint lets an operator inspect those meters, while a registry-specific endpoint exports them to a backend. For example, micrometer-registry-prometheus adds a Prometheus registry and enables the prometheus Actuator endpoint. Actuator therefore supplies auto-configuration and transport, Micrometer supplies the instrumentation model, and Prometheus supplies time-series storage and PromQL.

Add the Prometheus registry:

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

Expose its endpoint:

yaml
management:
  endpoints:
    web:
      exposure:
        include: health,prometheus

Prometheus can then scrape:

text
GET /actuator/prometheus

The metrics and prometheus endpoints serve different audiences:

  • /actuator/metrics is a diagnostic API for exploring meter names, measurements, and available tags.
  • /actuator/prometheus returns all publishable measurements in the text format expected by Prometheus.

The metrics endpoint does not provide historical graphs. It reads the current state of the in-process Micrometer registry.

Built-in Metrics #

Depending on the application and its dependencies, Spring Boot can publish metrics for:

  • JVM memory, garbage collection, threads, and loaded classes
  • Process CPU use, uptime, and file descriptors
  • Host CPU and disk space
  • HTTP server requests
  • HTTP client requests
  • Data source connection pools
  • Caches
  • Spring Data repositories
  • Messaging systems
  • Task executors and schedulers
  • Application startup
  • Log events

For example, HTTP server instrumentation records a timer with dimensions such as method, normalized route, response status, outcome, and exception. Prometheus may expose it as a family based on:

text
http_server_requests_seconds

Use normalized routes such as /orders/{id} rather than raw paths such as /orders/4815162342. Raw paths create unbounded metric cardinality.

Common Tags #

Apply stable tags before meters are registered:

java
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MetricsConfiguration {

    @Bean
    MeterRegistryCustomizer<MeterRegistry> commonTags() {
        return registry -> registry.config().commonTags(
            "service", "checkout",
            "region", "eu-west-1"
        );
    }
}

Do not use request IDs, user IDs, email addresses, timestamps, or other unbounded values as metric tags.

Info Contributors #

The info endpoint can publish selected application information. Useful values include the application name, build version, and source revision:

yaml
info:
  app:
    name: checkout
    description: Checkout API

Build plugins can generate build metadata, and source-control plugins can generate Git metadata. Publish only what operators need; branch names, complete property sets, and environment details may reveal more than intended.

Changing Log Levels at Runtime #

The loggers endpoint can inspect effective logging levels:

text
GET /actuator/loggers/com.example.checkout

It can also change a configured level while the process is running:

http
POST /actuator/loggers/com.example.checkout
Content-Type: application/json

{"configuredLevel":"DEBUG"}

To clear the explicit level and return to inherited configuration:

http
POST /actuator/loggers/com.example.checkout
Content-Type: application/json

{"configuredLevel":null}

Runtime changes are operational state, not persistent configuration. They are lost when the application restarts. This endpoint is powerful and should be restricted to trusted operators.

HTTP Exchange Recording #

The httpexchanges endpoint is available when the application provides an HttpExchangeRepository. An in-memory implementation is suitable only for development because it retains a limited number of exchanges in application memory.

HTTP exchange data may contain paths, headers, principal names, timing, and status information. Configure recording conservatively and never treat it as a replacement for a production log or tracing backend.

Auditing #

Actuator’s auditing support can publish security events such as authentication success, authentication failure, and access denial. An AuditEventRepository stores and retrieves the events exposed by auditevents.

An in-memory repository is useful for development but is not durable. Production audit requirements normally call for a purpose-built persistent and access-controlled destination.

Audit records can contain sensitive security information. Protect them independently from ordinary application metrics.

Management Server Configuration #

The Actuator HTTP endpoints use the application server by default. Their base path can be changed:

yaml
management:
  endpoints:
    web:
      base-path: /manage

They can also run on a separate port:

yaml
management:
  server:
    port: 9091

A separate management address can limit which network interfaces accept management traffic:

yaml
management:
  server:
    port: 9091
    address: 127.0.0.1

A separate port provides network isolation but creates another server to operate. It can also report healthy while the main application connector is broken. Use main-port health paths when the orchestrator must verify the actual traffic-serving interface.

Securing Actuator #

Actuator endpoints are administrative APIs. Network placement is not a substitute for authentication and authorization.

When Spring Security is present and the application has not supplied its own security filter chain, Spring Boot secures Actuator endpoints other than health. Once the application defines a SecurityFilterChain, Spring Boot backs off and the application owns the complete access policy.

A typical policy permits probes, restricts Prometheus to the monitoring network or role, and reserves other endpoints for administrators:

java
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration(proxyBeanMethods = false)
public class ActuatorSecurityConfiguration {

    @Bean
    SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
        http.securityMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeHttpRequests(requests -> requests
                .requestMatchers(EndpointRequest.to(HealthEndpoint.class))
                    .permitAll()
                .anyRequest()
                    .hasRole("OPS"))
            .httpBasic(Customizer.withDefaults());
        return http.build();
    }
}

The application’s normal routes need their own filter chain when a dedicated Actuator chain uses securityMatcher.

Additional safeguards include:

  1. Expose only required endpoints.
  2. Restrict management traffic with firewalls, security groups, or Kubernetes network policies.
  3. Require TLS and authentication across untrusted networks.
  4. Avoid exposing environment, configuration, heap dump, and shutdown endpoints publicly.
  5. Keep sensitive-value sanitization enabled.
  6. Audit write operations such as log-level changes and shutdown.

Creating Custom Endpoints #

Actuator can expose custom management operations through technology-neutral endpoint annotations:

java
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;

@Component
@Endpoint(id = "featureflags")
public class FeatureFlagsEndpoint {

    private final FeatureFlags featureFlags;

    public FeatureFlagsEndpoint(FeatureFlags featureFlags) {
        this.featureFlags = featureFlags;
    }

    @ReadOperation
    public Map<String, Boolean> flags() {
        return featureFlags.snapshot();
    }
}

Actuator maps endpoint operations to HTTP and JMX:

  • @ReadOperation reads state.
  • @WriteOperation changes state.
  • @DeleteOperation deletes state.

Custom endpoints should expose management state, not become an alternative business API. Keep responses bounded, stable, and free of secrets. Write and delete operations need stricter authorization than read-only diagnostics.

Actuator Compared with a Monitoring Stack #

ComponentResponsibility
Spring Boot ActuatorExposes application management endpoints
MicrometerInstruments metrics and observations
PrometheusScrapes, stores, queries, and evaluates metric rules
GrafanaVisualizes metrics, logs, and traces
AlertmanagerGroups and routes Prometheus alerts
Loki or ElasticsearchStores and queries logs
Tempo, Jaeger, or another tracing backendStores and queries traces

Actuator is the application’s observability surface, not the entire observability platform. Its health endpoint serves current status, while Micrometer and external backends provide measurements that remain useful after the application restarts.

Production Guidelines #

  1. Begin with only health and the required metrics-export endpoint exposed.
  2. Keep health checks fast, bounded, and side-effect free.
  3. Separate liveness from readiness.
  4. Do not make liveness depend on shared external infrastructure.
  5. Protect diagnostic and write-capable endpoints with strong authorization.
  6. Keep endpoint details and sensitive values hidden from anonymous clients.
  7. Use Micrometer tags with bounded cardinality.
  8. Export metrics to a durable backend rather than polling metrics manually.
  9. Treat heap dumps, environment data, and configuration reports as sensitive.
  10. Test management access rules separately from the application’s user-facing security rules.

Actuator makes a Spring Boot process manageable by exposing carefully designed views of its current state. Its value comes from combining those endpoints with Micrometer instrumentation and external systems that retain, query, visualize, and alert on telemetry over time.

Comments

Read or comment on GitHub (sign-in required to comment)