Spring Boot Actuator with Prometheus

In this article of Spring Boot, we will integrate Spring Boot actuator with Prometheus. Monitoring the application health is important on the production environment. This help us notice any error or performance issue with the application.

 

Introduction

Spring Boot Actuator provides production-ready features for Spring Boot application. It will help us check and manage our application in the production environment. Monitoring our production environment is critical especially when we have multiple services and each service is critical for the overall system functionality and performance. In this article, we will learn to integrate spring boot actuator with Prometheus. We will have the Prometheus dashboard showing the data generated from the Spring Boot application.

[pullquote align=”normal”] I assume that you know of the Prometheus monitoring system or at least heard about it. [/pullquote]

 

1. Prometheus

Prometheus is an open-source systems monitoring and alerting toolkit originally built at SoundCloud.

  • A multi-dimensional data model with time series data identified by metric name and key/value pairs
  • PromQL, a flexible query language to leverage this dimensionality
  • No reliance on distributed storage; single server nodes are autonomous
  • Time series collection happens via a pull model over HTTP
  • Pushing time series supported via an intermediary gateway
  • Targets discovered via service discovery or static configuration
  • Multiple modes of graphing and dash boarding support.

 

2. Enabling Actuator in Spring Boot

All the actuators production-grade features provided through the spring-boot-actuator starter. To enable these features in our application, we need to add spring-boot-starter-actuator in the pom.xml.

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

This will add the actuator feature to our Spring Boot application. To exposes metrics in a format Prometheus server can scrape, we need to add the micrometer-registry-prometheus dependency in the pom.xml file.

 

3. Add Prometheus Registry

To expose the Prometheus end point for the actuator, let’s add the micrometer-registry-prometheus dependency in the pom.xml file.

<!-- Micrometer Prometheus registry  -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Once we add above entry to the pom.xml file, Spring Boot will perform the following important tasks for our application:

  • Automatically configure a PrometheusMeterRegistry.
  • Add a registry to collect and export the data for the Prometheus server.

Let’s explore the Spring Boot actuator Prometheus end point. Let’s open the http://localhost:8080/actuator to see actuator end points:

prometheus endpoint

Click on the http://localhost:8080/actuator/prometheus to see the data exposed by the prometheus endpoint.It exposed the data in the same format a Prometheus server can scrap. Let’s clock on the end point to see the end point metrics:

# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="PS Survivor Space",} 0.0
jvm_memory_used_bytes{area="heap",id="PS Old Gen",} 1.193076E7
jvm_memory_used_bytes{area="heap",id="PS Eden Space",} 2.9005864E7
jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 3.68316E7
jvm_memory_used_bytes{area="nonheap",id="Code Cache",} 1.0210688E7
jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 4891336.0
# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool
# TYPE jvm_buffer_count_buffers gauge
jvm_buffer_count_buffers{id="direct",} 4.0
jvm_buffer_count_buffers{id="mapped",} 0.0
# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time
# TYPE system_load_average_1m gauge
system_load_average_1m 4.25439453125
# HELP jvm_gc_max_data_size_bytes Max size of old generation memory pool
# TYPE jvm_gc_max_data_size_bytes gauge
jvm_gc_max_data_size_bytes 2.863661056E9
# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process
# TYPE process_cpu_usage gauge
process_cpu_usage 0.0
# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the young generation memory pool after one GC to before the next
# TYPE jvm_gc_memory_allocated_bytes_total counter
jvm_gc_memory_allocated_bytes_total 1.18344592E8
# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management
# TYPE jvm_memory_max_bytes gauge
jvm_memory_max_bytes{area="heap",id="PS Survivor Space",} 1.4680064E7
jvm_memory_max_bytes{area="heap",id="PS Old Gen",} 2.863661056E9
jvm_memory_max_bytes{area="heap",id="PS Eden Space",} 1.4024704E9
jvm_memory_max_bytes{area="nonheap",id="Metaspace",} -1.0
jvm_memory_max_bytes{area="nonheap",id="Code Cache",} 2.5165824E8
jvm_memory_max_bytes{area="nonheap",id="Compressed Class Space",} 1.073741824E9
# HELP tomcat_sessions_active_current_sessions  
# TYPE tomcat_sessions_active_current_sessions gauge
tomcat_sessions_active_current_sessions 0.0
# HELP tomcat_sessions_rejected_sessions_total  
# TYPE tomcat_sessions_rejected_sessions_total counter
tomcat_sessions_rejected_sessions_total 0.0
# HELP jvm_threads_peak_threads The peak live thread count since the Java virtual machine started or peak was reset
# TYPE jvm_threads_peak_threads gauge
jvm_threads_peak_threads 22.0
# HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine
# TYPE jvm_classes_loaded_classes gauge
jvm_classes_loaded_classes 7222.0
# HELP system_cpu_usage The "recent cpu usage" for the whole system
# TYPE system_cpu_usage gauge
system_cpu_usage 0.0
# HELP system_cpu_count The number of processors available to the Java virtual machine
# TYPE system_cpu_count gauge
system_cpu_count 4.0
# HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use
# TYPE jvm_memory_committed_bytes gauge
jvm_memory_committed_bytes{area="heap",id="PS Survivor Space",} 1.4680064E7
jvm_memory_committed_bytes{area="heap",id="PS Old Gen",} 1.45227776E8
jvm_memory_committed_bytes{area="heap",id="PS Eden Space",} 1.60432128E8
jvm_memory_committed_bytes{area="nonheap",id="Metaspace",} 3.9493632E7
jvm_memory_committed_bytes{area="nonheap",id="Code Cache",} 1.1862016E7
jvm_memory_committed_bytes{area="nonheap",id="Compressed Class Space",} 5423104.0
# HELP logback_events_total Number of error level events that made it to the logs
# TYPE logback_events_total counter
logback_events_total{level="warn",} 0.0
logback_events_total{level="debug",} 0.0
logback_events_total{level="error",} 0.0
logback_events_total{level="trace",} 0.0
logback_events_total{level="info",} 7.0
# HELP process_start_time_seconds Start time of the process since unix epoch.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.575221091629E9
# HELP jvm_threads_daemon_threads The current number of live daemon threads
# TYPE jvm_threads_daemon_threads gauge
jvm_threads_daemon_threads 18.0
# HELP tomcat_sessions_created_sessions_total  
# TYPE tomcat_sessions_created_sessions_total counter
tomcat_sessions_created_sessions_total 0.0
# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool
# TYPE jvm_buffer_memory_used_bytes gauge
jvm_buffer_memory_used_bytes{id="direct",} 32768.0
jvm_buffer_memory_used_bytes{id="mapped",} 0.0
# HELP http_server_requests_seconds  
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/actuator/",} 1.0
http_server_requests_seconds_sum{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/actuator/",} 0.148708594
# HELP http_server_requests_seconds_max  
# TYPE http_server_requests_seconds_max gauge
http_server_requests_seconds_max{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/actuator/",} 0.0
# HELP jvm_classes_unloaded_classes_total The total number of classes unloaded since the Java virtual machine has started execution
# TYPE jvm_classes_unloaded_classes_total counter
jvm_classes_unloaded_classes_total 0.0
# HELP process_uptime_seconds The uptime of the Java virtual machine
# TYPE process_uptime_seconds gauge
process_uptime_seconds 841.365
# HELP process_files_open_files The open file descriptor count
# TYPE process_files_open_files gauge
process_files_open_files 92.0

 

4. Setup Prometheus Server

Let download and setup the Prometheus server on our machine. We will use the Prometheus docker image. You can find more details on the official site.To download the docker image, run the following command on your local machine

$ docker pull prom/prometheus

Once the download is complete, you can check the local copy of the image by running the $ docker image ls command. This is how the output might look like in your local machine:

download docker image

[pullquote align=”normal”] I assume that you know the Docker basics. If you are not comfortable with Docker, you can configure and setup the Prometheus server without Docker. [/pullquote]

 

5. Prometheus Server Configuration

Next step is to configure the Prometheus server. We will create a file name prometheus.yml .We will set up all the configuration in this file including 

  1. How frequently a server will scrape the data.
  2. Spring Boot actuator end point for the Prometheus server.

This is how our yml file look like:

global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.

  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    monitor: 'codelab-monitor'

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=` to any time series scraped from this config.
  - job_name: 'prometheus'

    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s

    static_configs:
      - targets: ['localhost:9090']

  # Details to connect Prometheus with Spring Boot actuator end point to scrap the data
  # The job name is added as a label `job=` to any time series scraped from this config.
  - job_name: 'spring-actuator'
   
    # Actuator end point to collect the data. 
    metrics_path: '/actuator/prometheus'

    #How frequently to scape the data from the end point
    scrape_interval: 5s

    #target end point. We are using the Docker, so local host will not work. You can change it with
    #localhost if not using the Docker.
    static_configs:
    - targets: ['HOST_IP:8080']

[pullquote align=”normal”] Save this file, we will use this file while starting the Prometheus server. For more details. Read Configuration file .Don’t forget to replace the HOST_IP with your machine IP[/pullquote]

 

6. Starting Prometheus

Let’s run the Prometheus server. Run the following command to the start the server

docker run -d -p 9090:9090 \
    -v /usr/local/share/javadevjournal/prometheus.yml:/etc/prometheus/prometheus.yml \
    prom/prometheus

 

6.1 Prometheus Dashboard

It’s time to explore the Prometheus dashboard. Let’s open the http://localhost:9090 URL on your browser. We will see something like:

Prometheus dashboard

To ensure, our custom prometheus.yml picked by the server, click on the status-target

Spring Boot Actuator metrics monitoring with Prometheus

 

Let’s try to get some metrics using the dashboard:

CPU Usage

Spring Boot Actuator with Prometheus

System Load

System load Prometheus

For more detail read Querying Prometheus

 

Summary

In this post, we saw how to integrate Spring Boot actuator with Prometheus. Prometheus is a powerful monitoring servers and provides a lot of features. With Spring boot actuator, it’s easy to integrate and monitor the application health using Prometheus. The source code for this post is available on the GitHub