How to Monitor Spring Boot Apps with Prometheus and Grafana: Step‑by‑Step Guide
This tutorial walks through building a Spring Boot application, integrating Micrometer for metric collection, deploying Prometheus and Grafana via Docker, configuring dynamic service discovery, and creating custom request‑count metrics with AOP, providing a complete end‑to‑end monitoring solution.
Overall Architecture
Spring Boot provides actuator endpoints via actuator.
Prometheus is a monitoring system that scrapes metrics from Spring Boot and stores them as time‑series data.
Grafana is a UI dashboard that can query Prometheus and display the metrics.
Spring Boot 2 includes micrometer, which simplifies integration with monitoring systems such as Prometheus.
The overall flow is:
Spring Boot (with micrometer) generates metrics.
Prometheus scrapes the metrics, stores them, and provides a query API.
Grafana connects to Prometheus as a data source and visualizes the metrics.
Practical Steps
Create a Spring Boot application that produces metrics.
Add micrometer dependency to integrate with Prometheus.
Deploy Prometheus.
Configure Prometheus to scrape the Spring Boot application.
Deploy Grafana.
Add Prometheus as a data source in Grafana.
Import a JVM dashboard (ID 4701) to show JVM metrics.
Define custom metrics (e.g., request count) using Micrometer and AOP.
Use dynamic service discovery to avoid restarting Prometheus when targets change.
1. Create Application and Add Micrometer
Create a minimal Spring Boot project and add micrometer dependencies.
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>springboot2demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>application.properties:
spring.application.name=springboot2demo
management.endpoints.web.exposure.include=*
management.metrics.tags.application=${spring.application.name}Add a Bean to register JVM metrics:
package com.example.springboot2demo;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Springboot2demoApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot2demoApplication.class, args);
}
@Bean
MeterRegistryCustomizer<MeterRegistry> configurer(
@Value("${spring.application.name}") String applicationName) {
return registry -> registry.config().commonTags("application", applicationName);
}
}Start the service and view the actuator endpoints.
2. Deploy Prometheus
Run Prometheus via Docker:
$ docker run --name prometheus -d -p 127.0.0.1:9090:9090 prom/prometheusAccess http://localhost:9090/targets to see the target list and http://localhost:9090/graph for the query console.
3. Connect Prometheus to Spring Boot
Edit the Prometheus configuration ( /etc/prometheus/prometheus.yml) to add a job for the Spring Boot app:
- job_name: 'springboot_app'
scrape_interval: 5s
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['192.168.31.6:8080']
labels:
instance: 'springboot2-A'
service: 'springboot2-A-service'Restart the Prometheus container with the updated configuration file mounted:
$ docker run --name prometheus -d \
-p 9090:9090 \
-v [PATH]/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheusThe Spring Boot metrics now appear in the Prometheus target list.
4. Deploy Grafana
Run Grafana via Docker:
$ docker run -d -p 3000:3000 --name=grafana grafana/grafanaLog in at http://localhost:3000 with default credentials admin/admin.
5. Add Prometheus Data Source
In Grafana, add a new data source of type Prometheus pointing to http://localhost:9090.
6. Show JVM Metrics
Import the official JVM dashboard (ID 4701) to visualize JVM statistics.
7. Custom Metrics
Add AOP‑based request counting:
package com.example.springboot2demo;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Aspect
public class APICounterAop {
@Pointcut("execution(public * com.example.springboot2demo.*.*(..))")
public void pointCut() {}
@Autowired
MeterRegistry registry;
private Counter counter;
@PostConstruct
private void init() {
counter = registry.counter("requests_total", "status", "success");
}
@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) {
System.out.println("do before");
counter.increment(); // request count
}
@AfterReturning(pointcut = "pointCut()", returning = "returnVal")
public void doAfterReturning(Object returnVal) {
System.out.println("do after");
}
}Test controller:
package com.example.springboot2demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}After invoking the endpoint several times, the custom metric appears in Prometheus and can be visualized in Grafana.
8. Dynamic Target Management
Instead of static targets, use Prometheus file‑based service discovery. Create a JSON file with target definitions and reference it via file_sd_configs in prometheus.yml. Mount the directory into the container so Prometheus reloads targets automatically.
[
{
"targets": ["192.168.31.6:8080"],
"labels": {
"instance": "springboot2-A",
"service": "springboot2-A-service"
}
}
] - job_name: 'springboot_app'
scrape_interval: 5s
metrics_path: '/actuator/prometheus'
file_sd_configs:
- files:
- /home/*.json
refresh_interval: 1m $ docker run --name prometheus -d -p 9090:9090 \
-v [PATH]/prometheus.yml:/etc/prometheus/prometheus.yml \
-v [PATH]:/home \
prom/prometheusThis enables automatic target updates without restarting Prometheus.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
