Prometheus is an open-source platform used to collect metrics from applications. You can easily apply it to monitor your Spring Boot project and scrape the Actuator /prometheus endpoint.
We’re going to configure Prometheus server to scrape data available on the /actuator/prometheus
endpoint. Read the Monitoring Spring Boot projects with Actuator if your project doesn’t yet support metrics collection.
Meanwhile, you can clone the example spring-boot-log4j-2-scaffolding project from my GitHub repository and test it locally.
Prometheus is a good choice for reliable monitoring. It provides some statistics about a monitored system even if the subject suffers from a failure. As we can read in the documentation:
Each Prometheus server is standalone, not depending on network storage or other remote services. You can rely on it when other parts of your infrastructure are broken, and you do not need to setup extensive infrastructure to use it.
https://prometheus.io/docs/introduction/overview/#when-does-it-fit
Moreover, troubleshooting doesn’t take much time because the documentation is extensive and the tool is widely adopted in the community. Last but not least, integrating it with Spring Boot Actuator is straightforward.
However, it is not recommended in situations which require 100% accuracy, such as for per-request billing.
In the beginning, we’ll expose Actuator endpoints to all users. Later, we’re going to configure Spring Boot security to keep those data locked behind basic authentication. Consequently, we’ll have to pass the default credentials for our Spring Boot app to the Prometheus server. In the end, we want to make sure that only authorised users will be able to browse application metrics and statistics.
For now, we want to monitor Spring Boot with Prometheus without worrying about security configuration. Therefore, we configure Actuator to allow all requests:
// src/main/java/in/keepgrowing/springbootlog4j2scaffolding/config/security/ActuatorSecurity.java
package in.keepgrowing.springbootlog4j2scaffolding.config.security;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests((requests) ->
requests.anyRequest().permitAll());
}
}
Above all, we need to add the Micrometer Registry Prometheus dependency to our pom.xml
file:
# pom.xml
…
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
…
Because our project uses Actuator, we don’t need to configure Micrometer Prometheus manually – it’ll collect and export data in a format compatible with a Prometheus server. You can find more details in the docs:
Spring Boot auto-configures a composite
https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-metrics-getting-startedMeterRegistry
and adds a registry to the composite for each of the supported implementations that it finds on the classpath. Having a dependency onmicrometer-registry-{system}
in your runtime classpath is enough for Spring Boot to configure the registry.
If you use default Actuator settings, the /actuator/prometheus
endpoint is enabled but not exposed. Therefore, we need to explicitly include this endpoint in the list of exposed paths. Below you can see my example configuration that exposes prometheus
alongside info
and health
endpoints:
# application.properties
…
management.endpoints.web.exposure.include=info,health,prometheus
As a result, you can see the data available for scrapping on http://localhost:8080/actuator/prometheus:
We’re going to configure the Prometheus server using both prometheus.yml
file and command-line flags. Let’s start with the following configuration file:
# prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'spring-boot-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app:8080']
For reference, you can explore the official extended example config file.
If you want to specify parameters that should be applied to all other configuration contexts, enclose them in the global
part. Thanks to that, you’ll also have default values that can be used for other sections. In the example file, I set up:
Next, we’re going to tell Prometheus what are its targets and how to scrape them. With that in mind, we’re going to create a job regarding monitoring our Spring Boot app in the scrape_configs section. The job_name
property should carry an unique value to allow distinguishing between collections of instances that Prometheus is scraping.
Furthermore, we need to specify the HTTP resource path where metrics are available. For our target, the proper Actuator endpoint is exposed under the /actuator/prometheus
path.
Prometheus supports service-discovery mechanisms. However, in our example we’re going to configure the target statically via the static_configs
parameter.
Our Prometheus configuration ensures collecting metrics from the example Spring Boot project that is run in Docker. Because I run both Prometheus server and my Spring Boot project as Docker containers in a shared network, I can simply pass to the monitoring tool the service name defined for my Spring Boot project – app
. Therefore, the Actuator endpoints are available for the scraping under the app:8080/…
path.
In contrary, you may need to scrape metrics from a project that is run externally. Don’t forget to provide the proper host and port to its Actuator endpoint in the targets
option in your prometheus.yml
file.
You can’t use localhost:8080
in targets
when running a Prometheus server in Docker. The workaround would be to use the “host
” network_mode (only for a development environment) to enable reaching to localhost from a Docker container.
You can explore my complete docker-compose.yml file for more details.
We’re going to build the prometheus
service from the latest image:
version: "3.3"
services:
…
prometheus:
image: prom/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
ports:
- "9090:9090"
networks:
- internal
volumes:
- ./prometheus/:/etc/prometheus/
- prometheus:/prometheus
depends_on:
- app
…
networks:
internal:
volumes:
prometheus:
In addition to our prometheus.yml
file, we’re going to add some configuration via the command-line flags. The difference between those two methods is explained in the documentation:
While the command-line flags configure immutable system parameters (such as storage locations, amount of data to keep on disk and in memory, etc.), the configuration file defines everything related to scraping jobs and their instances, as well as which rule files to load.
https://prometheus.io/docs/prometheus/latest/configuration/configuration/#configuration-file
First, with the --config.file
flag, we specify which configuration file to load. Locally, our configuration is located under the ./prometheus/prometheus.yml
path. It is mounted in the volumes section to the /etc/prometheus
directory inside the container. As a result, we can tell Prometheus to look for the config under the /etc/prometheus/prometheus.yml
path.
Furthermore, we configure the local storage. The --storage.tsdb.path
flag determines where Prometheus writes its database. We want to write to our prometheus
volume, instead of the default data/
directory in the container to hold data between service restarts. You can also browse documentation to find more storage configuration options.
I also exposed the default Prometheus port – 9090, so I can reach it from my localhost in the browser.
Run the application and the Prometheus server services:
$ mvn package
$ docker-compose up -d app
$ docker-compose up -d prometheus
To verify that Prometheus is able to connect with your app, visit http://localhost:9090/targets:
Remember that I could configure Prometheus target
by simply providing the name of the container with my Spring Boot project – app
, and port on which it runs – 8080, because both containers share a docker network.
What’s more, the metrics collected from Spring Boot are available in the form of graph. Visit http://localhost:9090/graph and use the insert metric at cursor
dropdown to choose a metric, e.g. http_server_requests_seconds_sum
:
Furthermore, you can see the applied configuration under the http://localhost:9090/config url:
Finally, we’ll strengthen the security of our app by removing the Actuator endpoints from public access:
// src/main/java/in/keepgrowing/springbootlog4j2scaffolding/config/security/ActuatorSecurity.java
package in.keepgrowing.springbootlog4j2scaffolding.config.security;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(EndpointRequest.toAnyEndpoint())
.authenticated()
.and()
.httpBasic();
}
}
Apply those changes to the app
service:
$ mvn package
$ docker-compose up -d --build app
Consequently, we need to provide credentials for the spring-boot-app
job in the Prometheus configuration :
# prometheus/prometheus.yml
…
scrape_configs:
- job_name: 'spring-boot-app'
…
basic_auth:
username: test
password: test
…
Prometheus does not support environment variable substitution in configuration file. Therefore, I manually copied the default credentials defined in the application.properties file. There is also option for providing the file with the password_file
parameter. Rebuild the service with the following command:
$ docker-compose up -d --build prometheus
When you visit http://localhost:9090/config you’ll see the credentials presented like on the screenshot below:
In addition, you can find the code applying Prometheus to a Spring Boot project in the commit 2ea8aa1c9763d6aa564b58baa1358bdda56d2a99.
Photo by Wesley Rocha from Pexels
Spring Security allows us to use role-based control to restrict access to API resources. However,…
A custom annotation in Spring Boot tests is an easy and flexible way to provide…
Delegating user management to Keycloak allows us to better focus on meeting the business needs…
Swagger offers various methods to authorize requests to our Keycloak secured API. I'll show you…
Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can…
Keycloak provides simple integration with Spring applications. As a result, we can easily configure our…