Skip to main content

Spring Monitoring

Introduction

Deploying your Spring application to production is just the beginning of its lifecycle. Once deployed, you need to ensure it runs smoothly, performs well, and remains healthy over time. This is where Spring Monitoring comes into play.

Monitoring is the practice of observing and tracking the performance, health, and behavior of your application in real-time. Effective monitoring allows you to:

  • Detect and troubleshoot issues before they impact users
  • Understand application performance and resource utilization
  • Make data-driven decisions for scaling and optimization
  • Ensure service level agreements (SLAs) are being met
  • Gain insights into user behavior and application usage patterns

In this tutorial, we'll explore various tools and techniques for monitoring Spring applications, with a focus on Spring Boot's built-in capabilities and integration with external monitoring systems.

Spring Boot Actuator: Your First Monitoring Tool

Spring Boot Actuator is a sub-project of Spring Boot that adds several production-ready features to your application. It's the foundation of Spring monitoring and provides endpoints for health checks, metrics, logging configuration, and more.

Setting Up Spring Boot Actuator

To start using Actuator, add the following dependency to your pom.xml file:

xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

For Gradle users, add this to your build.gradle:

groovy
implementation 'org.springframework.boot:spring-boot-starter-actuator'

Once added, Spring Boot automatically configures several endpoints that you can use to monitor your application.

Exploring Actuator Endpoints

By default, Spring Boot Actuator exposes the /actuator/health endpoint, which provides basic information about the application's health status. To see what's available, start your application and navigate to:

http://localhost:8080/actuator

You should see output similar to:

json
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"health": {
"href": "http://localhost:8080/actuator/health",
"templated": false
},
"health-path": {
"href": "http://localhost:8080/actuator/health/{*path}",
"templated": true
}
}
}

Enabling More Endpoints

Most Actuator endpoints are disabled by default for security reasons. To enable additional endpoints, add the following to your application.properties or application.yml file:

properties
# Enable all endpoints
management.endpoints.web.exposure.include=*

# Or enable specific endpoints
management.endpoints.web.exposure.include=health,info,metrics,loggers

Using YAML:

yaml
management:
endpoints:
web:
exposure:
include: "health,info,metrics,loggers"

Let's look at some of the most useful endpoints:

Health Endpoint

The /actuator/health endpoint shows the health status of your application:

json
{
"status": "UP"
}

You can configure it to show more details:

properties
management.endpoint.health.show-details=always

With this configuration, you'll get detailed health information:

json
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "H2",
"validationQuery": "isValid()"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 499963174912,
"free": 213333573632
}
}
}
}

Metrics Endpoint

The /actuator/metrics endpoint provides access to application metrics:

json
{
"names": [
"jvm.memory.max",
"jvm.memory.used",
"http.server.requests",
"process.uptime",
// many more...
]
}

To view a specific metric, append its name to the URL:

http://localhost:8080/actuator/metrics/jvm.memory.used

Output:

json
{
"name": "jvm.memory.used",
"description": "The amount of used memory",
"baseUnit": "bytes",
"measurements": [
{
"statistic": "VALUE",
"value": 116719608
}
],
"availableTags": [
{
"tag": "area",
"values": ["heap", "nonheap"]
},
{
"tag": "id",
"values": ["Compressed Class Space", "PS Old Gen", "PS Survivor Space", "PS Eden Space", "Metaspace", "Code Cache"]
}
]
}

Creating Custom Metrics

Spring Boot uses Micrometer, a vendor-neutral application metrics facade, which allows you to send metrics to various monitoring systems like Prometheus, Datadog, or New Relic.

Let's create a custom metric to count visits to a specific endpoint:

java
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {

private final Counter helloCounter;

public HelloController(MeterRegistry registry) {
this.helloCounter = Counter.builder("api.hello.requests")
.description("Number of hello requests")
.register(registry);
}

@GetMapping("/hello")
@ResponseBody
public String hello() {
helloCounter.increment();
return "Hello, World!";
}
}

After accessing the /hello endpoint a few times, you can check your custom metric at:

http://localhost:8080/actuator/metrics/api.hello.requests

Health Check for External Systems

Spring Boot provides a mechanism to check the health of external systems like databases, message brokers, or third-party services. Let's create a custom health indicator for a fictional external API:

java
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class ExternalApiHealthIndicator implements HealthIndicator {

@Override
public Health health() {
boolean apiAvailable = checkApiAvailability(); // Your implementation to check API

if (apiAvailable) {
return Health.up()
.withDetail("message", "External API is working properly")
.build();
} else {
return Health.down()
.withDetail("message", "External API is not available")
.build();
}
}

private boolean checkApiAvailability() {
// Implement the actual check logic
// For example, make an HTTP request to the API and check the response
return true; // Dummy implementation
}
}

This health indicator will now be included in the overall health check and accessible at /actuator/health.

Logging and Log Management

Logs provide critical insights into application behavior. Spring Boot uses the Commons Logging API for internal logging and defaults to Logback for runtime logging.

Configuring Log Levels

You can configure log levels in application.properties:

properties
# Set root logger to INFO
logging.level.root=INFO

# Set specific package to DEBUG
logging.level.org.springframework.web=DEBUG

# Set your application packages
logging.level.com.yourcompany.yourapp=DEBUG

Log File Configuration

To output logs to a file:

properties
# Output to a file
logging.file.name=application.log

# Or specify a path
logging.file.path=/var/logs

# Configure file rotation
logging.logback.rollingpolicy.max-file-size=10MB
logging.logback.rollingpolicy.max-history=7

Viewing Logs Through Actuator

With Actuator, you can also view and modify log levels at runtime:

GET /actuator/loggers

To view a specific logger:

GET /actuator/loggers/org.springframework

To change a log level at runtime:

POST /actuator/loggers/org.springframework
Content-Type: application/json

{
"configuredLevel": "DEBUG"
}

Integrating with Monitoring Systems

While Actuator provides powerful built-in monitoring capabilities, most production applications benefit from integration with dedicated monitoring systems.

Prometheus Integration

Prometheus is a popular open-source monitoring system. To integrate with it:

  1. Add the Micrometer Prometheus dependency:
xml
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
  1. Ensure the Prometheus endpoint is exposed:
properties
management.endpoints.web.exposure.include=prometheus

Now your metrics will be available in Prometheus format at:

http://localhost:8080/actuator/prometheus

Sample output:

# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="PS Eden Space",} 2.3773024E7
jvm_memory_used_bytes{area="heap",id="PS Old Gen",} 1.4325176E7
jvm_memory_used_bytes{area="heap",id="PS Survivor Space",} 2111488.0
jvm_memory_used_bytes{area="nonheap",id="Code Cache",} 1.4208512E7
jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 3.2150608E7
jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 4287952.0

Spring Boot Admin

Spring Boot Admin is a web application that manages and monitors Spring Boot applications. It provides a user interface for Actuator endpoints.

  1. Set up the Spring Boot Admin Server in a separate application:
xml
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.7.0</version>
</dependency>
  1. Enable it with @EnableAdminServer:
java
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableAdminServer
public class AdminServerApplication {
public static void main(String[] args) {
SpringApplication.run(AdminServerApplication.class, args);
}
}
  1. Configure your application as a client:
xml
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.7.0</version>
</dependency>
  1. Add client configuration:
properties
spring.boot.admin.client.url=http://localhost:8080
management.endpoints.web.exposure.include=*

Real-World Monitoring Strategy

In a production environment, you'll want a comprehensive monitoring strategy. Here's a practical approach:

  1. Application Health:

    • Use Actuator's /health endpoint for basic health checks
    • Implement custom health indicators for critical dependencies
    • Configure health checks in your load balancer or orchestrator (like Kubernetes)
  2. Metrics Collection:

    • Export metrics to a time-series database (Prometheus, InfluxDB)
    • Set up dashboards (Grafana) for visualization
    • Focus on key performance indicators:
      • Response times (p95, p99 latencies)
      • Error rates
      • Throughput
      • Resource utilization (CPU, memory, disk I/O)
      • Business metrics (transactions, active users)
  3. Alerting:

    • Configure alerts based on thresholds for critical metrics
    • Set up on-call rotations and notification channels
    • Implement different severity levels
  4. Logging:

    • Aggregate logs using ELK stack (Elasticsearch, Logstash, Kibana) or similar tools
    • Use structured logging format (JSON)
    • Implement log correlation with request IDs
  5. Distributed Tracing:

    • Add Spring Cloud Sleuth and Zipkin for request tracing
    • Analyze request flows across microservices

Example Configuration for Production Monitoring

Here's a configuration example that balances security and monitoring needs:

yaml
management:
endpoints:
web:
base-path: /management
exposure:
include: ['health', 'info', 'metrics', 'prometheus', 'loggers']
endpoint:
health:
show-details: when_authorized
show-components: when_authorized
probes:
enabled: true
group:
readiness:
include: db, redis, kafka
metrics:
export:
prometheus:
enabled: true
info:
env:
enabled: true
java:
enabled: true
os:
enabled: true

# Secure the endpoints
spring:
security:
user:
name: admin
password: ${ACTUATOR_PASSWORD:changeit}
roles: ACTUATOR_ADMIN

Summary

Monitoring is a critical aspect of deploying Spring applications to production environments. In this tutorial, we've covered:

  • Setting up Spring Boot Actuator for basic monitoring
  • Configuring and using various Actuator endpoints
  • Creating custom metrics and health indicators
  • Managing application logs
  • Integrating with external monitoring systems like Prometheus and Spring Boot Admin
  • Implementing a comprehensive monitoring strategy for production

Effective monitoring ensures that your application remains healthy, performs well, and provides the best experience to your users. It also helps you detect and resolve issues quickly, reducing downtime and improving overall service quality.

Additional Resources

Exercises

  1. Add Spring Boot Actuator to an existing application and explore the default endpoints.
  2. Create a custom metric that tracks the duration of a specific business operation.
  3. Implement a custom health indicator that checks connectivity to an external service.
  4. Set up Prometheus and Grafana locally to collect and visualize metrics from your Spring application.
  5. Configure log rotation for your application and implement a strategy for log archival.
  6. Create a dashboard that displays key performance indicators for your application.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)