A Practical Guide to Monitoring Spring Boot Microservices with Prometheus & Grafana

Microservices are powerful. They allow us to build scalable, resilient, and independently deployable systems. But this power comes with a cost: complexity. When you have dozens or even hundreds of services interacting, figuring out what’s going on—especially when something goes wrong—can feel like searching for a needle in a haystack of haystacks.

This is where observability comes in. It’s more than just “monitoring”; it’s about gaining deep, actionable insights into your system’s behavior. We can break observability down into three pillars:

  • Logs: Structured, event-based records of what happened. “User X failed to log in at 10:05 PM.”
  • Metrics: Aggregated, numerical data over time. “The average API response time over the last 5 minutes was 200ms.”
  • Traces: The end-to-end journey of a request as it travels through multiple services. “Request ABC started at the API gateway, went to the user-service, then the auth-service, and took 350ms in total.”

In this guide, we’ll focus on the cornerstone of observability: metrics. We’ll build a complete, production-grade monitoring stack for a Spring Boot microservice using an industry-standard toolkit.

The Monitoring Dream Team

We’ll use a combination of powerful tools that work seamlessly together:

  1. Spring Boot Actuator: Provides production-ready features for our app, including a wealth of internal metrics out-of-the-box.
  2. Micrometer: An application metrics facade that acts as a universal translator. Spring Boot uses it to format its metrics so that various monitoring systems can understand them. We’ll configure it to talk “Prometheus”.
  3. Prometheus: The powerhouse of our stack. It’s a time-series database that periodically “scrapes” (pulls) metrics from our application and stores them efficiently.
  4. Grafana: The visualization layer. Grafana connects to Prometheus, queries the stored metrics, and turns them into beautiful, insightful dashboards.

Here’s the data flow we’re building:

Spring Boot App → Actuator → Micrometer → a /prometheus endpoint → Prometheus Scraper → Grafana Dashboard

Let’s get building!


Step 1: Building a Monitorable Spring Boot Application

First, we need a microservice to monitor. Let’s create a simple Spring Boot application using the Spring Initializr.

Use the following settings:

  • Project: Maven
  • Language: Java
  • Spring Boot: 3.2.x or later
  • Dependencies:
    • Spring Web
    • Spring Boot Actuator
    • Prometheus (This adds the micrometer-registry-prometheus dependency)

1.1. Maven Dependencies

If you’re setting up the project manually, ensure your pom.xml has these essential dependencies:

<dependencies>
    <!-- For building REST APIs -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Provides /actuator endpoints -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!-- Micrometer adapter for Prometheus -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Other standard dependencies like spring-boot-starter-test -->
</dependencies>

1.2. Configure Application Properties

Next, we need to tell Spring Boot to expose the Prometheus endpoint. By default, only the /health endpoint is exposed over HTTP. Let’s configure this in src/main/resources/application.yml:

server:
  port: 8080

spring:
  application:
    name: product-service

# Actuator Configuration
management:
  endpoints:
    web:
      exposure:
        # Expose 'prometheus' and 'health' endpoints
        include: prometheus,health,info
  metrics:
    # Add application name tag to all metrics for better filtering in Grafana
    tags:
      application: ${spring.application.name}

Why this configuration?

  • management.endpoints.web.exposure.include: This is the crucial part. We are explicitly telling Actuator to make the /actuator/prometheus endpoint available over the web.
  • management.metrics.tags.application: This is a pro-tip! By adding a common tag to every metric emitted by this application, it becomes incredibly easy to filter for this specific service in Grafana, especially when you’re monitoring many services at once.

1.3. Create a Simple REST Controller

Let’s add a basic REST endpoint to generate some traffic and metrics. Create a new file ProductController.java:

package com.ankurm.productservice;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @GetMapping("/{id}")
    public Map<String, String> getProductById(@PathVariable String id) {
        // Simulate fetching a product
        return Map.of("id", id, "name", "Sample Product");
    }
}

1.4. Verify the Metrics Endpoint

Now, run your Spring Boot application. Once it’s started, navigate to http://localhost:8080/actuator/prometheus in your browser.

You should see a large text output of metrics in a format that Prometheus understands. You’ll find JVM metrics (memory, garbage collection), HTTP server metrics, and more. This confirms your application is ready to be monitored!


Step 2: Setting up Prometheus to Scrape Metrics

With our application exporting metrics, we need Prometheus to collect and store them. We’ll run Prometheus using Docker, as it’s the simplest way to get started.

2.1. Create Prometheus Configuration

Prometheus needs a configuration file to know *what* to monitor. Create a file named prometheus.yml on your local machine.

# prometheus.yml
global:
  scrape_interval: 15s # How frequently to scrape targets by default

scrape_configs:
  # A scrape configuration containing exactly one endpoint to scrape:
  # your Spring Boot application.
  - job_name: 'spring-boot-app'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['host.docker.internal:8080']

Key points:

  • scrape_interval: 15s: Prometheus will ask our app for metrics every 15 seconds.
  • job_name: A friendly name for our group of targets.
  • metrics_path: The path on the target where metrics are exposed.
  • targets: ['host.docker.internal:8080']: This is the magic part. When running Prometheus in a Docker container, localhost refers to the container itself. host.docker.internal is a special DNS name that Docker provides for containers to connect to the host machine. This tells Prometheus to reach out from its container to port 8080 on your machine, where the Spring Boot app is running.

2.2. Run Prometheus with Docker

Open your terminal and run the following command. Make sure to replace /path/to/your/prometheus.yml with the actual absolute path to the file you just created.

docker run \
    -d \
    --name prometheus \
    -p 9090:9090 \
    -v /path/to/your/prometheus.yml:/etc/prometheus/prometheus.yml \
    prom/prometheus
  • -d: Run in detached mode.
  • --name prometheus: A friendly name for our container.
  • -p 9090:9090: Map port 9090 on the host to port 9090 in the container.
  • -v ...: Mount our local prometheus.yml into the container where Prometheus expects to find it.

2.3. Verify Prometheus Setup

Navigate to http://localhost:9090. This is the Prometheus web UI. Click on Status → Targets. You should see your spring-boot-app job with a green “UP” state. This means Prometheus is successfully scraping metrics from your application!


Step 3: Visualizing Metrics with Grafana

While the Prometheus UI is great for querying and debugging, Grafana is the tool we use for creating powerful, shareable dashboards.

3.1. Run Grafana with Docker

Let’s spin up a Grafana container. It’s another one-liner:

docker run \
    -d \
    --name grafana \
    -p 3000:3000 \
    grafana/grafana-oss

This will start Grafana and make it available on port 3000.

3.2. Configure Grafana

Now, let’s configure Grafana to use Prometheus as its data source.

  1. Open Grafana in your browser at http://localhost:3000.
  2. Log in with the default credentials: user: adminpassword: admin. You’ll be prompted to change the password.
  3. Add a Data Source:
    • Click the gear icon (Configuration) on the left menu, then “Data Sources”.
    • Click “Add data source” and select “Prometheus”.
    • In the “Prometheus server URL” field, enter http://host.docker.internal:9090. This tells Grafana (running in a container) how to find Prometheus (running in another container, but accessible via the host).
    • Click “Save & test”. You should see a green checkmark saying “Data source is working”.
  4. Import a Dashboard:
    • Creating dashboards from scratch is an art. A great way to start is by importing a pre-built one.
    • Click the plus icon (+) on the left menu, then “Import”.
    • In the “Import via grafana.com” field, enter the ID 4701. This is a popular and comprehensive “JVM (Micrometer)” dashboard.
    • Click “Load”.
    • On the next screen, at the bottom, select your Prometheus data source from the dropdown menu.
    • Click “Import”.

And that’s it! You should now be looking at a beautiful, detailed dashboard showing live metrics from your Spring Boot application, including JVM memory usage, CPU load, garbage collection pauses, HTTP request timings, and much more.

Conclusion & Next Steps

Congratulations! You have successfully built a robust, industry-standard monitoring stack for your Spring Boot microservice. You now have the visibility needed to understand your application’s performance and health in real-time.

This setup is the foundation of a truly observable system. From here, you can explore more advanced topics:

  • Custom Metrics: Instrument your own business logic using Micrometer’s MeterRegistry to track things like “orders placed” or “items in cart”.
  • Alerting: Configure Prometheus’s companion, Alertmanager, to send you notifications (via Slack, PagerDuty, etc.) when metrics cross critical thresholds (e.g., “API error rate > 5%”).
  • Distributed Tracing: Integrate tools like Zipkin or Jaeger to trace requests across multiple microservices and pinpoint bottlenecks in complex workflows.

Monitoring is not an afterthought; it’s a core feature of a reliable system. By building it in from the start, you’re setting yourself and your team up for success.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.