Spring Boot Actuator & Monitoring Interview Questions
Spring Boot Actuator's key endpoints, securing them in production, and the custom health indicators and Prometheus wiring interviewers actually probe for.
Q11. What is Spring Boot Actuator, and what do the key endpoints actually expose?
Actuator adds the production-readiness features an operations team needs to run a Spring Boot service with confidence — without them, you're flying blind on anything that isn't an application log.
1. Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2. The endpoints that actually come up in practice
| Endpoint | What it's for |
|---|---|
/actuator/health | Application health status — the one your load balancer or Kubernetes liveness probe hits |
/actuator/metrics | JVM metrics, HTTP request metrics, custom Micrometer counters |
/actuator/info | Build/version metadata, useful for confirming what's actually deployed |
/actuator/env | Resolved environment properties — invaluable, and dangerous if exposed publicly |
/actuator/loggers | View and change log levels at runtime, without a redeploy |
The question that actually separates candidates here: never expose /actuator/env or /actuator/loggers on the public internet. /env can leak database credentials and API keys resolved from environment variables, and /loggers lets an attacker turn debug logging on to exfiltrate request bodies. In production, Actuator endpoints should sit behind a separate management port, bound to an internal network only, with just /health exposed externally for probes.
Q23. How do you create custom Actuator endpoints?
1. Custom Endpoint
@Component
@Endpoint(id = "custom")
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> customEndpoint() {
Map<String, Object> info = new HashMap<>();
info.put("status", "active");
info.put("version", "1.0");
return info;
}
@WriteOperation
public void updateSetting(@Selector String name, String value) {
// Update configuration
}
@DeleteOperation
public void resetSettings() {
// Reset to defaults
}
}
2. Web-Specific Endpoint
@Component
@WebEndpoint(id = "status")
public class StatusEndpoint {
@ReadOperation
public ResponseEntity<String> status() {
return ResponseEntity.ok("System is running");
}
}
3. Custom Health Indicator
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
@Autowired
private DataSource dataSource;
@Override
public Health health() {
try (Connection conn = dataSource.getConnection()) {
if (conn.isValid(1000)) {
return Health.up()
.withDetail("database", "Available")
.withDetail("validationQuery", "SELECT 1")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
return Health.down().build();
}
}
4. Access Endpoint
GET /actuator/custom
GET /actuator/status
GET /actuator/health
The implementation is straightforward, but a custom endpoint is part of the management surface and should expose only operational data that is safe to disclose. The production question is who can reach it and what happens when the health check itself is slow or unavailable.
Q24. Explain Actuator Metrics and Integration with Prometheus
1. Enable Prometheus
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
2. Configuration
management.endpoints.web.exposure.include=health,info,metrics,prometheus
management.metrics.export.prometheus.enabled=true
3. Custom Metrics
@Service
public class OrderService {
private final Counter orderCounter;
private final Timer orderTimer;
private final Gauge activeOrders;
public OrderService(MeterRegistry registry) {
this.orderCounter = Counter.builder("orders.created")
.description("Total orders created")
.tag("type", "online")
.register(registry);
this.orderTimer = Timer.builder("order.processing.time")
.description("Order processing time")
.register(registry);
this.activeOrders = Gauge.builder("orders.active",
this::getActiveOrderCount)
.register(registry);
}
public void createOrder(Order order) {
orderTimer.record(() -> {
// Process order
orderRepository.save(order);
orderCounter.increment();
});
}
}
4. Prometheus Scrape Config
scrape_configs:
- job_name: 'spring-boot-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']
5. Common Metrics
jvm.memory.used- JVM memory usagehttp.server.requests- HTTP request metricsjdbc.connections.active- DB connectionsprocess.cpu.usage- CPU usage
Metrics become useful only when they support a decision: pair application counters and timers with dashboards and alerts that identify saturation, errors, and latency rather than collecting every possible measurement without an action attached.
Q25. How do you secure Actuator endpoints in production?
1. Use Different Port
management.server.port=9090
management.server.address=127.0.0.1 # Only localhost
2. Change Base Path
management.endpoints.web.base-path=/admin/actuator
3. Security Configuration
@Configuration
public class ActuatorSecurity {
@Bean
public SecurityFilterChain actuatorSecurity(HttpSecurity http) {
http
.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests()
.requestMatchers(EndpointRequest.to("health", "info"))
.permitAll()
.anyRequest()
.hasRole("ACTUATOR_ADMIN")
.and()
.httpBasic();
return http.build();
}
}
4. Expose Only Needed Endpoints
management.endpoints.web.exposure.include=health,info,metrics
management.endpoints.web.exposure.exclude=env,beans
5. Role-Based Access
management.endpoint.health.show-details=when-authorized
management.endpoint.health.roles=ADMIN
The security boundary should be tested from outside the application network, not inferred from configuration alone; an endpoint that is harmless on localhost can expose credentials or control operations once a proxy or container network changes.