Spring Boot Actuator provides production-ready features to help you monitor and manage your application. It exposes various endpoints that give insight into application metrics, health, configuration, and more.
What is Spring Boot Actuator?
Spring Boot Actuator offers built-in endpoints that allow you to monitor and interact with your application. It's essential for:
- Application monitoring - Health checks, metrics, and performance data
- Production readiness - Insights into application state and behavior
- Troubleshooting - Diagnostic information and environment details
- Management - Shutdown, configuration changes, and more
Setup and Configuration
Dependencies
Maven:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- For web endpoints --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- For Micrometer metrics (optional) --> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>
Gradle:
implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'io.micrometer:micrometer-registry-prometheus'
Basic Configuration
# application.yml management: endpoints: web: exposure: include: health,info,metrics,env,beans base-path: /management # Custom base path enabled-by-default: true endpoint: health: show-details: always show-components: always info: enabled: true info: env: enabled: true build: enabled: true
Core Actuator Endpoints
Example 1: Health Endpoint
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import java.util.concurrent.ThreadLocalRandom;
@Component
public class CustomHealthIndicator implements HealthIndicator {
private final DatabaseService databaseService;
private final ExternalService externalService;
public CustomHealthIndicator(DatabaseService databaseService,
ExternalService externalService) {
this.databaseService = databaseService;
this.externalService = externalService;
}
@Override
public Health health() {
// Check database connectivity
boolean dbHealthy = databaseService.isConnected();
// Check external service
boolean externalHealthy = externalService.isAvailable();
// Custom health logic
if (!dbHealthy) {
return Health.down()
.withDetail("database", "Connection failed")
.withDetail("timestamp", System.currentTimeMillis())
.build();
}
if (!externalHealthy) {
return Health.outOfService()
.withDetail("external-service", "Temporarily unavailable")
.withException(new RuntimeException("Service timeout"))
.build();
}
// Simulate some custom metrics
double systemLoad = ThreadLocalRandom.current().nextDouble(0.0, 1.0);
return Health.up()
.withDetail("database", "Connected")
.withDetail("external-service", "Available")
.withDetail("system-load", systemLoad)
.withDetail("active-threads", Thread.activeCount())
.build();
}
}
// Additional health indicators
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
@Override
public Health health() {
try {
// Simulate database check
boolean isHealthy = checkDatabaseConnection();
if (isHealthy) {
return Health.up()
.withDetail("database", "PostgreSQL")
.withDetail("connection-pool", "Active")
.withDetail("active-connections", 15)
.build();
} else {
return Health.down()
.withDetail("database", "PostgreSQL")
.withDetail("error", "Connection timeout")
.build();
}
} catch (Exception e) {
return Health.down(e).build();
}
}
private boolean checkDatabaseConnection() {
// Actual database connectivity check
return Math.random() > 0.2; // 80% success rate for demo
}
}
@Component
public class DiskSpaceHealthIndicator implements HealthIndicator {
@Override
public Health health() {
long freeDiskSpace = new File("/").getFreeSpace();
long totalDiskSpace = new File("/").getTotalSpace();
double freePercentage = (double) freeDiskSpace / totalDiskSpace * 100;
if (freePercentage > 10) {
return Health.up()
.withDetail("total-space", formatBytes(totalDiskSpace))
.withDetail("free-space", formatBytes(freeDiskSpace))
.withDetail("free-percentage", String.format("%.2f%%", freePercentage))
.build();
} else {
return Health.down()
.withDetail("error", "Low disk space")
.withDetail("free-percentage", String.format("%.2f%%", freePercentage))
.build();
}
}
private String formatBytes(long bytes) {
return String.format("%.2f GB", bytes / (1024.0 * 1024.0 * 1024.0));
}
}
Health Endpoint Response:
{
"status": "UP",
"components": {
"custom": {
"status": "UP",
"details": {
"database": "Connected",
"external-service": "Available",
"system-load": 0.45,
"active-threads": 25
}
},
"diskSpace": {
"status": "UP",
"details": {
"total-space": "465.76 GB",
"free-space": "125.34 GB",
"free-percentage": "26.92%"
}
},
"ping": {
"status": "UP"
}
}
}
Custom Endpoints
Example 2: Creating Custom Actuator Endpoints
import org.springframework.boot.actuate.endpoint.annotation.*;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Component
@Endpoint(id = "features")
public class FeaturesEndpoint {
private final Map<String, Feature> features = new ConcurrentHashMap<>();
public FeaturesEndpoint() {
// Initialize with some features
features.put("user-auth", new Feature("user-auth", true, "User authentication system"));
features.put("payment-processing", new Feature("payment-processing", false, "Payment gateway integration"));
features.put("analytics", new Feature("analytics", true, "User analytics dashboard"));
}
@ReadOperation
public Map<String, Object> features() {
Map<String, Object> result = new HashMap<>();
result.put("timestamp", new Date());
result.put("features", features.values());
result.put("enabledCount", features.values().stream()
.filter(Feature::isEnabled)
.count());
return result;
}
@ReadOperation
public Feature feature(@Selector String name) {
return features.get(name);
}
@WriteOperation
public void updateFeature(@Selector String name, boolean enabled) {
Feature feature = features.get(name);
if (feature != null) {
feature.setEnabled(enabled);
feature.setLastModified(new Date());
}
}
@DeleteOperation
public void removeFeature(@Selector String name) {
features.remove(name);
}
public static class Feature {
private String name;
private boolean enabled;
private String description;
private Date lastModified;
public Feature(String name, boolean enabled, String description) {
this.name = name;
this.enabled = enabled;
this.description = description;
this.lastModified = new Date();
}
// Getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) {
this.enabled = enabled;
this.lastModified = new Date();
}
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public Date getLastModified() { return lastModified; }
public void setLastModified(Date lastModified) { this.lastModified = lastModified; }
}
}
Example 3: Web-specific Endpoint
import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.lang.management.*;
import java.util.*;
@RestControllerEndpoint(id = "jvm")
public class JvmInfoEndpoint {
@GetMapping
public Map<String, Object> jvmInfo() {
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean();
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
Map<String, Object> info = new LinkedHashMap<>();
info.put("jvm-name", runtimeMxBean.getVmName());
info.put("jvm-version", runtimeMxBean.getVmVersion());
info.put("start-time", runtimeMxBean.getStartTime());
info.put("uptime", runtimeMxBean.getUptime());
// Memory information
Map<String, Object> memory = new HashMap<>();
memory.put("heap-used", memoryMxBean.getHeapMemoryUsage().getUsed());
memory.put("heap-max", memoryMxBean.getHeapMemoryUsage().getMax());
memory.put("non-heap-used", memoryMxBean.getNonHeapMemoryUsage().getUsed());
info.put("memory", memory);
// Thread information
Map<String, Object> threads = new HashMap<>();
threads.put("thread-count", threadMxBean.getThreadCount());
threads.put("daemon-thread-count", threadMxBean.getDaemonThreadCount());
threads.put("peak-thread-count", threadMxBean.getPeakThreadCount());
info.put("threads", threads);
// System properties
info.put("system-properties", runtimeMxBean.getSystemProperties());
return info;
}
@GetMapping("/memory")
public ResponseEntity<Map<String, Object>> memoryDetails() {
MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean();
Map<String, Object> memoryInfo = new HashMap<>();
memoryInfo.put("heap", formatMemoryUsage(memoryMxBean.getHeapMemoryUsage()));
memoryInfo.put("non-heap", formatMemoryUsage(memoryMxBean.getNonHeapMemoryUsage()));
memoryInfo.put("object-pending-finalization", memoryMxBean.getObjectPendingFinalizationCount());
return ResponseEntity.ok(memoryInfo);
}
@GetMapping("/threads")
public List<Map<String, Object>> threadDump() {
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
long[] threadIds = threadMxBean.getAllThreadIds();
List<Map<String, Object>> threads = new ArrayList<>();
for (long threadId : threadIds) {
ThreadInfo threadInfo = threadMxBean.getThreadInfo(threadId);
if (threadInfo != null) {
Map<String, Object> threadData = new HashMap<>();
threadData.put("id", threadInfo.getThreadId());
threadData.put("name", threadInfo.getThreadName());
threadData.put("state", threadInfo.getThreadState().name());
threadData.put("cpu-time", threadMxBean.getThreadCpuTime(threadId));
threadData.put("user-time", threadMxBean.getThreadUserTime(threadId));
threads.add(threadData);
}
}
return threads;
}
@PostMapping("/gc")
public ResponseEntity<Map<String, Object>> triggerGc() {
long startTime = System.currentTimeMillis();
System.gc();
long endTime = System.currentTimeMillis();
Map<String, Object> result = new HashMap<>();
result.put("message", "Garbage collection triggered");
result.put("duration-ms", endTime - startTime);
result.put("timestamp", new Date());
return ResponseEntity.ok(result);
}
private Map<String, Object> formatMemoryUsage(MemoryUsage usage) {
Map<String, Object> formatted = new HashMap<>();
formatted.put("init", usage.getInit());
formatted.put("used", usage.getUsed());
formatted.put("committed", usage.getCommitted());
formatted.put("max", usage.getMax());
return formatted;
}
}
Metrics and Monitoring
Example 4: Custom Metrics with Micrometer
import io.micrometer.core.instrument.*;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Component
public class ApplicationMetrics {
private final MeterRegistry meterRegistry;
private final Counter apiRequestCounter;
private final Timer apiResponseTimer;
private final Gauge cacheSizeGauge;
private final AtomicLong activeUsers;
private final Map<String, Counter> endpointCounters;
public ApplicationMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.endpointCounters = new ConcurrentHashMap<>();
this.activeUsers = new AtomicLong(0);
// Initialize counters and timers
this.apiRequestCounter = Counter.builder("api.requests.total")
.description("Total number of API requests")
.tag("application", "my-spring-app")
.register(meterRegistry);
this.apiResponseTimer = Timer.builder("api.response.time")
.description("API response time")
.register(meterRegistry);
this.cacheSizeGauge = Gauge.builder("cache.size")
.description("Current cache size")
.register(meterRegistry, new AtomicLong(0));
// Register custom metrics
registerCustomMetrics();
}
public void incrementRequestCount(String endpoint, String method, int status) {
apiRequestCounter.increment();
// Endpoint-specific counter
String counterName = "api.requests." + endpoint.toLowerCase();
Counter endpointCounter = endpointCounters.computeIfAbsent(counterName,
key -> Counter.builder(key)
.description("Requests for " + endpoint)
.tag("method", method)
.tag("status", String.valueOf(status))
.register(meterRegistry));
endpointCounter.increment();
}
public void recordResponseTime(String endpoint, long durationMs) {
apiResponseTimer.record(java.time.Duration.ofMillis(durationMs));
Timer.builder("api.response.time.endpoint")
.tag("endpoint", endpoint)
.register(meterRegistry)
.record(java.time.Duration.ofMillis(durationMs));
}
public void setCacheSize(long size) {
// Update gauge value
meterRegistry.gauge("cache.size", size);
}
public void userLoggedIn() {
activeUsers.incrementAndGet();
meterRegistry.gauge("users.active", activeUsers);
}
public void userLoggedOut() {
activeUsers.decrementAndGet();
}
public void recordBusinessTransaction(String type, double amount, boolean success) {
Counter.builder("business.transactions")
.tag("type", type)
.tag("status", success ? "success" : "failure")
.register(meterRegistry)
.increment();
if (success) {
Counter.builder("business.revenue")
.tag("type", type)
.register(meterRegistry)
.increment(amount);
}
}
private void registerCustomMetrics() {
// JVM metrics (already provided by Micrometer, but here's custom example)
Gauge.builder("jvm.memory.used.percent")
.description("JVM memory used percentage")
.baseUnit("percent")
.register(meterRegistry, this, metrics -> {
Runtime runtime = Runtime.getRuntime();
long used = runtime.totalMemory() - runtime.freeMemory();
long max = runtime.maxMemory();
return (double) used / max * 100;
});
}
}
// Usage in services
@Service
public class UserService {
private final ApplicationMetrics metrics;
private final Map<Long, User> userCache = new ConcurrentHashMap<>();
public UserService(ApplicationMetrics metrics) {
this.metrics = metrics;
}
public User getUserById(Long id) {
long startTime = System.currentTimeMillis();
try {
metrics.incrementRequestCount("getUser", "GET", 200);
User user = userCache.computeIfAbsent(id, this::fetchUserFromDatabase);
metrics.recordResponseTime("getUser", System.currentTimeMillis() - startTime);
metrics.setCacheSize(userCache.size());
return user;
} catch (Exception e) {
metrics.incrementRequestCount("getUser", "GET", 500);
throw e;
}
}
public void userLogin(User user) {
metrics.userLoggedIn();
metrics.recordBusinessTransaction("login", 0.0, true);
}
public void userLogout(User user) {
metrics.userLoggedOut();
}
private User fetchUserFromDatabase(Long id) {
// Database fetch logic
return new User(id, "User " + id);
}
}
Info Endpoint Customization
Example 5: Custom Info Contributions
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
@Component
public class CustomInfoContributor implements InfoContributor {
private final ApplicationProperties properties;
private final UserService userService;
public CustomInfoContributor(ApplicationProperties properties,
UserService userService) {
this.properties = properties;
this.userService = userService;
}
@Override
public void contribute(Info.Builder builder) {
// Application-specific info
Map<String, Object> appInfo = new HashMap<>();
appInfo.put("name", properties.getName());
appInfo.put("version", properties.getVersion());
appInfo.put("environment", properties.getEnvironment());
appInfo.put("startup-time", new java.util.Date());
// System info
Map<String, Object> systemInfo = new HashMap<>();
try {
systemInfo.put("hostname", InetAddress.getLocalHost().getHostName());
systemInfo.put("ip", InetAddress.getLocalHost().getHostAddress());
} catch (Exception e) {
systemInfo.put("hostname", "unknown");
}
systemInfo.put("java-version", System.getProperty("java.version"));
systemInfo.put("os", System.getProperty("os.name"));
// Runtime info
Runtime runtime = Runtime.getRuntime();
Map<String, Object> runtimeInfo = new HashMap<>();
runtimeInfo.put("available-processors", runtime.availableProcessors());
runtimeInfo.put("free-memory", runtime.freeMemory());
runtimeInfo.put("total-memory", runtime.totalMemory());
runtimeInfo.put("max-memory", runtime.maxMemory());
// Business metrics
Map<String, Object> businessInfo = new HashMap<>();
businessInfo.put("active-users", userService.getActiveUserCount());
businessInfo.put("total-users", userService.getTotalUserCount());
businessInfo.put("cache-hit-rate", userService.getCacheHitRate());
builder.withDetail("application", appInfo)
.withDetail("system", systemInfo)
.withDetail("runtime", runtimeInfo)
.withDetail("business", businessInfo)
.withDetail("custom-message", "Application is running smoothly!");
}
}
@Component
public class BuildInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
Map<String, Object> buildInfo = new HashMap<>();
buildInfo.put("artifact", getClass().getPackage().getImplementationTitle());
buildInfo.put("version", getClass().getPackage().getImplementationVersion());
buildInfo.put("build-time", "2024-01-15T10:30:00Z"); // Should come from build properties
buildInfo.put("builder", "Spring Boot Maven Plugin");
builder.withDetail("build", buildInfo);
}
}
// Configuration properties
@ConfigurationProperties(prefix = "app.info")
@Component
public class ApplicationProperties {
private String name;
private String version;
private String environment;
// Getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getEnvironment() { return environment; }
public void setEnvironment(String environment) { this.environment = environment; }
}
application.yml for Info Endpoint:
management:
info:
env:
enabled: true
build:
enabled: true
git:
mode: full
app:
info:
name: "My Spring Application"
version: "2.1.0"
environment: "production"
info:
app:
name: "${app.info.name}"
version: "${app.info.version}"
environment: "${app.info.environment}"
build:
artifact: "@project.artifactId@"
name: "@project.name@"
version: "@project.version@"
time: "@build.time@"
Security and Access Control
Example 6: Securing Actuator Endpoints
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
@Configuration
@EnableWebSecurity
public class ActuatorSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
// Public endpoints
.requestMatchers("/public/**").permitAll()
// Actuator endpoints with different access levels
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.requestMatchers(EndpointRequest.to("metrics", "env")).hasRole("MONITOR")
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN")
// Application endpoints
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/**").hasRole("USER")
.anyRequest().authenticated()
)
.httpBasic(withDefaults())
.csrf(csrf -> csrf
// Disable CSRF for actuator endpoints (typically not needed for monitoring)
.ignoringRequestMatchers(EndpointRequest.toAnyEndpoint())
);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("user")
.password("{noop}password") // {noop} for plain text (use proper encoding in production)
.roles("USER")
.build();
UserDetails monitor = User.withUsername("monitor")
.password("{noop}monitor123")
.roles("USER", "MONITOR")
.build();
UserDetails admin = User.withUsername("admin")
.password("{noop}admin123")
.roles("USER", "MONITOR", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, monitor, admin);
}
}
Example 7: Custom Security for Specific Endpoints
@Component
public class ActuatorAccessManager {
private static final Set<String> SENSITIVE_ENDPOINTS = Set.of(
"env", "configprops", "loggers", "heapdump", "threaddump"
);
public boolean canAccess(String endpoint, String userRole, String clientIp) {
// Allow health and info for everyone
if (endpoint.equals("health") || endpoint.equals("info")) {
return true;
}
// Check if endpoint is sensitive
if (SENSITIVE_ENDPOINTS.contains(endpoint)) {
return "ADMIN".equals(userRole) && isInternalIp(clientIp);
}
// Metrics and beans require MONITOR role
if (endpoint.equals("metrics") || endpoint.equals("beans")) {
return "MONITOR".equals(userRole) || "ADMIN".equals(userRole);
}
return false;
}
private boolean isInternalIp(String ip) {
return ip.startsWith("192.168.") || ip.startsWith("10.") || ip.equals("127.0.0.1");
}
}
Complete Configuration Example
application.yml - Complete Actuator Configuration
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,beans,loggers,features,jvm
exclude: shutdown
base-path: /actuator
discovery:
enabled: true
jmx:
exposure:
include: "*"
enabled-by-default: true
endpoint:
health:
show-details: when_authorized
show-components: always
enabled: true
probes:
enabled: true
info:
enabled: true
metrics:
enabled: true
env:
enabled: true
beans:
enabled: true
loggers:
enabled: true
features:
enabled: true
jvm:
enabled: true
health:
db:
enabled: true
diskspace:
enabled: true
redis:
enabled: true
mail:
enabled: true
info:
env:
enabled: true
build:
enabled: true
git:
mode: full
metrics:
export:
prometheus:
enabled: true
distribution:
percentiles-histogram:
http.server.requests: true
enable:
jvm: true
logback: true
system: true
process: true
server:
port: 8081 # Separate management port
address: 127.0.0.1 # Bind to localhost only
trace:
http:
enabled: true
# Custom application info
app:
info:
name: "My Spring Boot Application"
version: "2.1.0"
environment: "production"
info:
app:
name: "${app.info.name}"
version: "${app.info.version}"
environment: "${app.info.environment}"
build:
artifact: "@project.artifactId@"
name: "@project.name@"
version: "@project.version@"
time: "@build.time@"
Testing Actuator Endpoints
Example 8: Testing with Spring Boot Test
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.context.TestPropertySource;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(properties = {
"management.endpoints.web.exposure.include=*",
"management.endpoint.health.show-details=always"
})
public class ActuatorEndpointsTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testHealthEndpoint() throws Exception {
mockMvc.perform(get("/actuator/health"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value("UP"))
.andExpect(jsonPath("$.components.diskSpace.status").value("UP"));
}
@Test
public void testInfoEndpoint() throws Exception {
mockMvc.perform(get("/actuator/info"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.app.name").exists())
.andExpect(jsonPath("$.build.version").exists());
}
@Test
public void testMetricsEndpoint() throws Exception {
mockMvc.perform(get("/actuator/metrics"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.names").isArray());
}
@Test
public void testCustomFeaturesEndpoint() throws Exception {
mockMvc.perform(get("/actuator/features"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.timestamp").exists())
.andExpect(jsonPath("$.features").isArray())
.andExpect(jsonPath("$.enabledCount").isNumber());
}
@Test
public void testJvmEndpoint() throws Exception {
mockMvc.perform(get("/actuator/jvm"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.jvm-name").exists())
.andExpect(jsonPath("$.memory").exists());
}
}
Best Practices
- Security: Always secure sensitive endpoints in production
- Exposure: Only expose necessary endpoints
- Monitoring: Integrate with monitoring systems (Prometheus, Grafana)
- Health Checks: Implement meaningful health indicators
- Customization: Add business-specific metrics and info
- Documentation: Document your custom endpoints
- Testing: Test all actuator endpoints
Common Endpoints Summary
| Endpoint | Description | Typically Enabled |
|---|---|---|
health | Application health information | Yes |
info | Application information | Yes |
metrics | Application metrics | Yes |
env | Environment properties | In development |
beans | Spring beans | In development |
loggers | Logger configurations | In development |
configprops | Configuration properties | In development |
mappings | URL mappings | In development |
shutdown | Graceful shutdown | No (production) |
Spring Boot Actuator provides comprehensive monitoring and management capabilities that are essential for production applications. By leveraging these endpoints, you can gain deep insights into your application's behavior and health.