Boost Your Micronaut Apps: Mastering Monitoring with Prometheus and Grafana

Micronaut, Prometheus, and Grafana form a powerful monitoring solution for cloud applications. Custom metrics, visualizations, and alerting provide valuable insights into application performance and user behavior.

Boost Your Micronaut Apps: Mastering Monitoring with Prometheus and Grafana

Micronaut has become a go-to framework for building microservices and serverless applications. It’s lightning-fast startup time and low memory footprint make it perfect for cloud environments. But how do we monitor these applications effectively? Enter Prometheus and Grafana - the dynamic duo of observability.

Let’s dive into how we can leverage these tools with Micronaut to create a robust monitoring solution. First things first, we need to add the necessary dependencies to our Micronaut project. In your build.gradle file, include these lines:

implementation("io.micronaut.micrometer:micronaut-micrometer-core")
implementation("io.micronaut.micrometer:micronaut-micrometer-registry-prometheus")

Now, we need to configure Micronaut to expose a Prometheus endpoint. In your application.yml file, add:

micronaut:
  metrics:
    enabled: true
    export:
      prometheus:
        enabled: true
        step: PT1M
        descriptions: true

This tells Micronaut to enable metrics and expose them in Prometheus format. The ‘step’ property sets how often metrics are collected, and ‘descriptions’ adds human-readable descriptions to the metrics.

With these configurations in place, Micronaut will automatically expose a /prometheus endpoint that Prometheus can scrape. But we’re not done yet! Let’s create some custom metrics to really showcase the power of this setup.

Imagine we’re building a simple online bookstore. We might want to track how many times each book is viewed. Here’s how we could implement that:

import io.micrometer.core.instrument.MeterRegistry;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/books")
public class BookController {

    private final MeterRegistry meterRegistry;

    public BookController(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @Get("/{id}")
    public Book getBook(Long id) {
        // Increment the view count for this book
        meterRegistry.counter("book.views", "id", id.toString()).increment();
        
        // Fetch and return the book (implementation omitted)
        return fetchBook(id);
    }
}

In this example, we’re using Micrometer (which Micronaut integrates with) to create a counter. Every time a book is viewed, we increment the counter for that specific book ID.

Now that we have our application emitting metrics, let’s set up Prometheus to collect them. We’ll use Docker to keep things simple. Create a file named prometheus.yml:

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'micronaut'
    metrics_path: '/prometheus'
    static_configs:
      - targets: ['host.docker.internal:8080']

This configuration tells Prometheus to scrape our Micronaut application every 15 seconds. The ‘host.docker.internal’ is a special DNS name in Docker that resolves to the host machine’s IP.

Now, let’s fire up Prometheus with Docker:

docker run -p 9090:9090 -v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus

Great! Prometheus is now collecting metrics from our Micronaut application. But raw numbers aren’t very exciting, are they? This is where Grafana comes in to make our metrics visually appealing and easier to understand.

Let’s set up Grafana:

docker run -d -p 3000:3000 grafana/grafana

Once Grafana is running, we can access it at http://localhost:3000. The default login is admin/admin. The first thing we need to do is add Prometheus as a data source. Go to Configuration > Data Sources > Add data source > Prometheus. Set the URL to http://host.docker.internal:9090 and save.

Now comes the fun part - creating dashboards! Let’s create a simple dashboard to visualize our book views. Create a new dashboard and add a graph panel. In the panel settings, use this PromQL query:

sum(increase(book_views_total[1h])) by (id)

This query shows the increase in views for each book over the last hour. Play around with different visualizations and time ranges to find what works best for your needs.

But wait, there’s more! Micronaut provides a wealth of built-in metrics that we can visualize. For example, we can track HTTP request durations with this query:

histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le))

This shows the 95th percentile of HTTP request durations over the last 5 minutes. It’s a great way to keep an eye on your application’s performance.

Now, you might be thinking, “This is cool and all, but what about when I deploy to the cloud?” Great question! Most cloud providers have their own managed Prometheus and Grafana services that you can use. For example, on AWS you could use Amazon Managed Service for Prometheus and Amazon Managed Grafana.

The beauty of this setup is that it’s cloud-agnostic. Whether you’re running on AWS, Google Cloud, or your own bare metal servers, the principles remain the same. You just need to ensure that your Prometheus instance can reach your Micronaut applications, and that Grafana can reach Prometheus.

One thing to keep in mind when running in the cloud is that you’ll want to secure your /prometheus endpoint. You don’t want just anyone to be able to scrape your metrics! Micronaut makes this easy with its security features. Here’s a quick example of how you could secure the endpoint with basic auth:

@Requires(property = "micronaut.security.enabled", value = "true")
@Controller("/prometheus")
public class SecurePrometheusController {

    @Secured("ADMIN")
    @Get(produces = MediaType.TEXT_PLAIN)
    public String getMetrics() {
        // Return Prometheus metrics
    }
}

This ensures that only users with the ADMIN role can access the Prometheus metrics.

As your application grows, you’ll find more and more uses for metrics. Maybe you want to track how many users are logged in at any given time, or how many items are in users’ shopping carts. With Micronaut, Prometheus, and Grafana, the sky’s the limit!

One of my favorite things about this setup is how it encourages a data-driven approach to development. Instead of guessing about how your application is performing or how users are interacting with it, you have cold, hard data at your fingertips.

I remember one project where we used this exact stack to diagnose a mysterious performance issue. We were seeing sporadic slowdowns, but couldn’t reproduce them consistently. By setting up detailed metrics and visualizing them in Grafana, we were able to correlate the slowdowns with specific database queries. It turned out that a particular query was causing table scans under certain conditions. Without our metrics, we might have been hunting for that bug for weeks!

As you get more comfortable with this setup, you’ll find yourself adding metrics to everything. CPU usage, memory usage, cache hit rates, database connection pool stats - all of these can provide valuable insights into your application’s behavior.

And don’t forget about alerting! Grafana has powerful alerting capabilities that can notify you when things go wrong. Set up alerts for things like high error rates, slow response times, or low disk space, and you’ll be the first to know when your application needs attention.

In conclusion, the combination of Micronaut, Prometheus, and Grafana provides a powerful toolset for monitoring your applications in the cloud. It gives you visibility into your application’s behavior, helps you diagnose issues quickly, and allows you to make data-driven decisions about performance optimizations and feature development. So go forth and instrument your code - your future self will thank you!