Skip to content

Debugging Spring Boot Production Issues and Custom Health Checks

Debugging production issues locally involves reproducing the production environment as closely as possible.

  1. Analyze production logs using centralized logging tools such as ELK Stack, Splunk, or Datadog.
  2. Reproduce the issue locally using:
    • The same request payload
    • The same application version
    • The same configuration
    • A production database snapshot
  3. Enable debug logging.
  4. Attach a debugger (locally or remotely).
  5. Use distributed tracing for microservices.
  6. Add temporary logs or metrics if necessary.
flowchart TD
A[Production Issue] --> B[Analyze Logs]
B --> C[Reproduce Locally]
C --> D[Restore Production Data]
D --> E[Enable Debug Logging]
E --> F[Debug / Trace]
F --> G[Identify Root Cause]
Terminal window
curl -X POST http://localhost:8080/orders -d '{"productId":101,"qty":2}'
logging.level.root=DEBUG
logging.level.org.springframework=DEBUG
Terminal window
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar app.jar
  • ELK Stack
  • Splunk
  • Datadog
  • Zipkin
  • Jaeger
  • Micrometer Tracing (modern replacement for Spring Cloud Sleuth on Spring Boot 3.x)

Beyond the built-in /actuator/health status, a custom HealthIndicator reports the health of application-specific dependencies.

@Component
public class CustomHealth implements HealthIndicator {
@Override
public Health health() {
if (serviceRunning()) {
return Health.up().build();
}
return Health.down().build();
}
}

This appears automatically as an additional entry under /actuator/health — see the production monitoring guide for the full Actuator endpoint list.

  • Debug production issues by reproducing them locally with the same payload, version, config, and a production data snapshot — not by guessing against a different environment.
  • Remote debugging (-agentlib:jdwp) lets you attach a local debugger to a running JVM, useful when local reproduction alone isn’t enough.
  • A custom HealthIndicator extends /actuator/health to reflect the status of application-specific dependencies, not just the built-in checks.