java

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!

Keywords: Micronaut, Prometheus, Grafana, microservices, observability, metrics, monitoring, cloud-native, performance, scalability



Similar Posts
Blog Image
Micronaut's Compile-Time Magic: Supercharging Java Apps with Lightning-Fast Dependency Injection

Micronaut's compile-time dependency injection boosts Java app performance with faster startup and lower memory usage. It resolves dependencies during compilation, enabling efficient runtime execution and encouraging modular, testable code design.

Blog Image
Rust's Const Generics: Revolutionizing Array Abstractions with Zero Runtime Overhead

Rust's const generics allow creating types parameterized by constant values, enabling powerful array abstractions without runtime overhead. They facilitate fixed-size array types, type-level numeric computations, and expressive APIs. This feature eliminates runtime checks, enhances safety, and improves performance by enabling compile-time size checks and optimizations for array operations.

Blog Image
Unlocking the Secrets: How Micronaut and Spring Vault Make Your Data Unbreakable

Whispering Secrets in a Crowded Room: Unveiling Micronaut and Spring Vault's Security Magic

Blog Image
Level Up Your Java Skills: Go Modular with JPMS and Micronaut

Crafting Cohesive Modular Applications with JPMS and Micronaut

Blog Image
Secure Microservices Like a Ninja: Dynamic OAuth2 Scopes You’ve Never Seen Before

Dynamic OAuth2 scopes enable real-time access control in microservices. They adapt to user status, time, and resource usage, enhancing security and flexibility. Implementation requires modifying authorization servers and updating resource servers.

Blog Image
6 Powerful Java Memory Management Techniques for High-Performance Apps

Discover 6 powerful Java memory management techniques to boost app performance. Learn object lifecycle control, reference types, memory pools, and JVM tuning. Optimize your code now!