Spring Boot Actuator
Quick Start
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
# application.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: when_authorized
info:
env:
enabled: true
info:
app:
name: @project.name@
version: @project.version@
Endpoints Configuration
management:
endpoints:
web:
exposure:
include: "*" # Dev: all
# include: health,info,metrics,prometheus # Prod
exclude: shutdown,threaddump
base-path: /actuator
endpoint:
health:
enabled: true
show-details: when_authorized
show-components: when_authorized
shutdown:
enabled: false # Dangerous in prod
Available Endpoints
| Endpoint |
Description |
Default |
/health |
Health status |
Enabled |
/info |
App info |
Enabled |
/metrics |
Metrics |
Enabled |
/prometheus |
Prometheus format |
Enabled* |
/env |
Environment properties |
Disabled |
/configprops |
Configuration properties |
Disabled |
/beans |
All beans |
Disabled |
/mappings |
Request mappings |
Disabled |
/loggers |
Logger levels |
Disabled |
/threaddump |
Thread dump |
Disabled |
/shutdown |
Graceful shutdown |
Disabled |
Health Indicators
management:
health:
db:
enabled: true
redis:
enabled: true
diskspace:
enabled: true
threshold: 10MB
Custom Health Indicator
@Component
public class ExternalServiceHealthIndicator implements HealthIndicator {
private final RestClient restClient;
@Override
public Health health() {
try {
long startTime = System.currentTimeMillis();
ResponseEntity<Void> response = restClient.get()
.uri("/health")
.retrieve()
.toBodilessEntity();
long responseTime = System.currentTimeMillis() - startTime;
if (response.getStatusCode().is2xxSuccessful()) {
return Health.up()
.withDetail("service", "external-api")
.withDetail("responseTime", responseTime + "ms")
.build();
}
return Health.down().build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}
Full Reference: See health.md for composite indicators, health groups, and availability management.
Kubernetes Probes
management:
endpoint:
health:
probes:
enabled: true
group:
liveness:
include: livenessState
readiness:
include: readinessState,db,redis
health:
livenessstate:
enabled: true
readinessstate:
enabled: true
# Kubernetes deployment
spec:
containers:
- name: app
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
Full Reference: See health.md for availability state management and K8s probe configuration.
Metrics with Micrometer
management:
metrics:
enable:
all: true
tags:
application: ${spring.application.name}
environment: ${spring.profiles.active:default}
distribution:
percentiles-histogram:
http.server.requests: true
Custom Metrics
@Service
public class OrderService {
private final MeterRegistry meterRegistry;
private final Counter orderCounter;
private final Timer orderProcessingTimer;
public OrderService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.orderCounter = Counter.builder("orders.created")
.description("Total orders created")
.register(meterRegistry);
this.orderProcessingTimer = Timer.builder("orders.processing.time")
.publishPercentiles(0.5, 0.95, 0.99)
.register(meterRegistry);
}
public Order createOrder(OrderRequest request) {
return orderProcessingTimer.record(() -> {
Order order = processOrder(request);
orderCounter.increment();
return order;
});
}
}
Full Reference: See metrics.md for annotations, Prometheus config, and Grafana alerts.
Prometheus Integration
management:
endpoints:
web:
exposure:
include: prometheus
prometheus:
metrics:
export:
enabled: true
# prometheus.yml
scrape_configs:
- job_name: 'spring-boot-app'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
static_configs:
- targets: ['localhost:8080']
Security
@Configuration
@EnableWebSecurity
public class ActuatorSecurityConfig {
@Bean
public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(auth -> auth
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.requestMatchers(EndpointRequest.to("prometheus")).permitAll()
.requestMatchers(EndpointRequest.to("env", "beans")).hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.build();
}
}
# Separate management port
management:
server:
port: 9090
address: 127.0.0.1
Full Reference: See custom-endpoints.md for custom endpoints and testing.
Best Practices
| Do |
Don't |
| Expose only necessary endpoints in prod |
Expose all endpoints |
| Use health groups for K8s probes |
Use single health endpoint |
| Configure metrics with consistent tags |
Use high-cardinality tags |
| Implement custom health indicators |
Rely only on built-in |
| Separate management port in production |
Use same port as app |
When NOT to Use This Skill
- Application profiling - Use
spring-profiles for environment config
- Distributed tracing - Use
micrometer-tracing for trace context
- Log aggregation - Use logging frameworks and ELK/Loki
- APM tools - Actuator complements Datadog, New Relic
Common Pitfalls
| Error |
Cause |
Solution |
| Endpoints not exposed |
Missing config |
Add to management.endpoints.web.exposure.include |
| Health always UP |
Indicators not configured |
Verify dependencies in classpath |
| Metrics missing |
Registry not configured |
Add micrometer-registry-prometheus |
| Security bypass |
Endpoints public |
Configure security for actuator |
| Memory leak |
High cardinality tags |
Avoid userId, requestId as tags |
Anti-Patterns
| Anti-Pattern |
Problem |
Solution |
| Exposing all endpoints in prod |
Security risk |
Limit to health, metrics, prometheus |
| High cardinality metric tags |
Memory explosion |
Use bounded tag values |
| No auth on sensitive endpoints |
Information leak |
Configure Spring Security |
| Ignoring health groups |
Poor K8s integration |
Use liveness/readiness groups |
Quick Troubleshooting
| Problem |
Diagnostic |
Fix |
| Endpoints not exposed |
Check config |
Add to exposure.include |
| Health always DOWN |
Check component |
Fix failing indicator |
| Metrics missing |
Check registry |
Add Micrometer dependency |
| 401 on endpoints |
Security blocking |
Configure actuator security |
| Prometheus not scraping |
Check path |
Verify /actuator/prometheus |
Production Checklist
Reference Files
| File |
Content |
| health.md |
Health Indicators, K8s Probes, Availability |
| metrics.md |
Micrometer, Prometheus, Grafana Alerts |
| custom-endpoints.md |
Custom Endpoints, Security, Testing |
External Documentation