Mastering Spring Boot 3 Actuator — Observability, Health Monitoring & Production Ops (Ultimate Guide)
In a cloud-native world, simply “deploying a Spring Boot app” is not enough. You need to know:
Is it healthy? Is it fast? Is it failing silently? Can it auto-heal?
That’s where Spring Boot 3 Actuator becomes your best friend for observability and production operations.
- Deep dive into Spring Boot 3 Actuator concepts (for production, not just local dev)
- All important endpoints:
/health,/metrics,/prometheus,/loggers, etc. - Custom health checks, business metrics & percentiles with Micrometer
- How to integrate Prometheus + Grafana for dashboards
- How to expose secure Kubernetes liveness/readiness probes
- Logging, tracing and ops best practices for real projects
1. Spring Boot Actuator in Spring Boot 3 — Mental Model
Actuator turns your application into an observable system. Instead of guessing what’s happening in production, you expose:
- Health – Is the app and its dependencies (DB, Redis, APIs) up?
- Metrics – How many requests? How slow? How many errors?
- Info – Build, git, environment info for debugging.
- Threads & logs – What is the JVM doing? What are we logging?
- Probes – Signals for Kubernetes / orchestrators to restart or route traffic.
In Spring Boot 3, Actuator is tightly integrated with:
- Micrometer 1.x (metrics facade)
- Jakarta namespace (since Boot 3 moved from javax → jakarta)
- Modern Java versions (17+), containers and cloud platforms
2. Adding Actuator & Basic Setup
2.1. Maven Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.2. Basic Configuration
By default, only a few endpoints are enabled over HTTP. You explicitly choose what to expose:
# application.properties
# Expose selected endpoints over HTTP
management.endpoints.web.exposure.include=health,info,metrics,loggers,prometheus
# Show detailed health info (for internal environments only!)
management.endpoint.health.show-details=always
# Use a nicer base path (optional)
management.endpoints.web.base-path=/actuator
| Endpoint | URL (default base path) | Purpose |
|---|---|---|
health |
/actuator/health |
Overall application health + components |
metrics |
/actuator/metrics |
All available metrics names |
info |
/actuator/info |
Build/git/app info |
prometheus |
/actuator/prometheus |
Prometheus scrape format (Micrometer) |
loggers |
/actuator/loggers |
View/update logger levels at runtime |
management.endpoints.web.exposure.include=*. Expose only what your monitoring and ops tools really need.
3. Health Checks — Making Your App “Observable” for Ops & Kubernetes
3.1. Built-in Health Indicators
Spring Boot auto-registers health indicators if their libraries are on the classpath, for example:
- Database (DataSource health)
- Redis
- RabbitMQ / Kafka
- Disk space
You can see them by calling:
GET /actuator/health
GET /actuator/health/db
GET /actuator/health/diskSpace
3.2. Creating a Custom HealthIndicator
Example: Check an external payment API your service depends on.
@Component
public class PaymentApiHealthIndicator implements HealthIndicator {
private final RestTemplate restTemplate;
public PaymentApiHealthIndicator(RestTemplateBuilder builder) {
this.restTemplate = builder.setConnectTimeout(Duration.ofMillis(500))
.setReadTimeout(Duration.ofMillis(500))
.build();
}
@Override
public Health health() {
try {
ResponseEntity<String> response =
restTemplate.getForEntity("https://payment-api.internal/health", String.class);
if (response.getStatusCode().is2xxSuccessful()) {
return Health.up()
.withDetail("endpoint", "payment-api")
.withDetail("statusCode", response.getStatusCode().value())
.build();
}
return Health.down()
.withDetail("endpoint", "payment-api")
.withDetail("statusCode", response.getStatusCode().value())
.build();
} catch (Exception ex) {
return Health.down(ex).withDetail("endpoint", "payment-api").build();
}
}
}
3.3. Grouping Health Indicators
Sometimes you want a “readiness” group that only includes critical dependencies.
# application.properties
management.endpoint.health.group.readiness.include=db,paymentApi,redis
management.endpoint.health.group.liveness.include=ping
Now you get:
GET /actuator/health/readiness
GET /actuator/health/liveness
4. Metrics with Micrometer — From JVM Stats to Business KPIs
Spring Boot 3 uses Micrometer under the hood. You get standard metrics out of the box:
jvm.memory.used,jvm.threads.livehttp.server.requests(per endpoint, method, status)system.cpu.usage- DataSource metrics, cache metrics, etc.
4.1. Inspecting Metrics
GET /actuator/metrics # list metric names
GET /actuator/metrics/jvm.memory.used
GET /actuator/metrics/http.server.requests
4.2. Creating a Custom Counter
Example: Count completed orders.
@RestController
@RequestMapping("/orders")
public class OrderController {
private final Counter orderCreatedCounter;
public OrderController(MeterRegistry meterRegistry) {
this.orderCreatedCounter = Counter
.builder("app.orders.created.count")
.description("Number of successfully created orders")
.tag("region", "apac")
.register(meterRegistry);
}
@PostMapping
public ResponseEntity<OrderResponse> createOrder(@RequestBody OrderRequest request) {
// ... business logic
orderCreatedCounter.increment();
return ResponseEntity.ok(new OrderResponse("CREATED"));
}
}
4.3. Timer & Percentiles for Latency
For performance monitoring, Timer with percentiles is powerful:
@Service
public class PaymentService {
private final Timer paymentTimer;
public PaymentService(MeterRegistry registry) {
this.paymentTimer = Timer.builder("app.payment.latency")
.description("Payment processing latency")
.publishPercentiles(0.5, 0.95, 0.99)
.maximumExpectedValue(Duration.ofSeconds(5))
.register(registry);
}
public PaymentResult process(PaymentRequest request) {
return paymentTimer.record(() -> {
// slow external call, DB operations...
simulateWork();
return new PaymentResult("OK");
});
}
private void simulateWork() {
try { Thread.sleep(200 + (long) (Math.random() * 300)); }
catch (InterruptedException ignored) {}
}
}
5. Exposing Metrics to Prometheus & Visualizing with Grafana
5.1. Add Prometheus Registry
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
5.2. Enable the Prometheus Endpoint
# application.properties
management.endpoints.web.exposure.include=health,metrics,prometheus
management.endpoint.prometheus.enabled=true
Now Prometheus can scrape:
GET /actuator/prometheus
5.3. Prometheus Configuration Example
scrape_configs:
- job_name: "spring-boot-app"
metrics_path: "/actuator/prometheus"
scrape_interval: 15s
static_configs:
- targets: ["my-app.prod.internal:8080"]
5.4. Grafana Dashboards
In Grafana, configure Prometheus as a data source and:
- Import a generic Spring Boot / Micrometer dashboard
- Build custom panels for
app.orders.created.countorapp.payment.latency - Create alerts on error rate, latency, or CPU usage
6. Securing Actuator Endpoints for Production
Actuator gives a lot of power — which also means attack surface if not secured.
6.1. Add Spring Security
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
6.2. Example Security Configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
// Allow unauthenticated health & readiness for K8s
.requestMatchers("/actuator/health/**").permitAll()
// Everything else actuator-related requires ROLE_ADMIN
.requestMatchers("/actuator/**").hasRole("ADMIN")
// Your app endpoints
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable()); // For APIs; adjust if using browser sessions
return http.build();
}
}
6.3. Disable Risky Endpoints
# Disable environment endpoint (shows env variables)
management.endpoint.env.enabled=false
# Disable beans endpoint in production if not needed
management.endpoint.beans.enabled=false
7. Kubernetes Probes with Spring Boot 3 Actuator
Kubernetes needs to know:
- Is the app alive? (liveness)
- Is it ready to receive traffic? (readiness)
7.1. Enable Probes in Spring
# application.properties
management.endpoint.health.probes.enabled=true
management.health.livenessState.enabled=true
management.health.readinessState.enabled=true
You now get:
/actuator/health/liveness/actuator/health/readiness
7.2. Example K8s Deployment Snippet
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
8. Logs, Log Levels & Live Troubleshooting with Actuator
8.1. View Logger Configuration
GET /actuator/loggers # list all loggers and levels
GET /actuator/loggers/com.example.service.PaymentService
8.2. Change Log Level at Runtime
POST /actuator/loggers/com.example.service.PaymentService
Content-Type: application/json
{
"configuredLevel": "DEBUG"
}
Great for temporary debugging in production without redeploying.
8.3. Best Practices
- Use
INFO+WARNas defaults;DEBUGonly when needed. - Log correlation IDs or trace IDs in every log line.
- Ship logs to a central platform (ELK, Loki, Cloud Logging).
9. Distributed Tracing & OpenTelemetry (High-Level)
Actuator plays nicely with tracing libraries (OpenTelemetry, Brave, etc.). At a high level:
- Add OpenTelemetry dependencies / agents.
- Configure exporters (Jaeger, Zipkin, OTEL Collector).
- Propagate trace context via HTTP headers between services.
- Use Actuator metrics and logs with trace IDs for full observability.
This lets you answer: “Why is this request slow across 5 microservices?”
10. Production Checklist for Actuator & Observability
- ✅ Actuator enabled, only required endpoints exposed.
- ✅ Spring Security configured with roles / API tokens for
/actuator/**. - ✅ Health groups configured (
liveness,readiness, maybeexternal/critical). - ✅ Micrometer custom metrics added for key business events.
- ✅ Metrics exported to Prometheus / APM; dashboards created in Grafana.
- ✅ Liveness & readiness probes wired into Kubernetes.
- ✅ Logs structured + centralized; trace IDs included.
- ✅ Load test your app and validate metrics/alerts before real traffic.
11. Summary & Next Steps
Spring Boot 3 Actuator gives you a complete observability foundation:
- Health endpoints to keep your app auto-healing and resilient.
- Metrics and Micrometer to track performance and business KPIs.
- Secure ops endpoints for logs, info, and on-the-fly debugging.
- Seamless integration with Prometheus, Grafana, Kubernetes and tracing tools.
If you combine this with proper security, resilience patterns (Resilience4j), caching, and microservices architecture, you get a truly production-ready system.
Next: wire this into your real project, and then layer in API gateway security, Redis caching, and resilience patterns (see related posts below). 🚀