Micronaut Micrometer

Provides integration between Micronaut and Micrometer

Version: 1.1.1

1 Introduction

This project integrates Micronaut and Micrometer allowing metrics collection for Micronaut applications.

Release Notes

1.1.0

  • Upgrade to Micrometer 1.1.2

  • Support for JCache Metrics

  • Support for @Timed annotation

  • New /prometheus Management Endpoint Added. See PrometheusEndpoint

  • Support for AWS CloudWatch. Thanks to Nathan Zender.

2 Metrics Endpoint

Using the CLI

If you are creating your project using the Micronaut CLI, supply one of micrometer-atlas, micrometer-graphite, micrometer-prometheus, or micrometer-statsd features to enable metrics and preconfigure the selected registery in your project:

$ mn create-app my-app --features micrometer-atlas

The metrics endpoint returns information about the "metrics" of the application. To execute the metrics endpoint, send a GET request to /metrics. This will return a list of the metric names registered with the MeterRegistry bean.

You can get specific metrics by using /metrics/[name] such as /metrics/jvm.memory.used. This would return something like:

Sample Metric Detail Json
{
  "name": "jvm.memory.used",
  "measurements": [
    {
      "statistic": "VALUE",
      "value": 1.45397552E8
    }
  ],
  "availableTags": [
    {
      "tag": "area",
      "values": [
        "heap",
        "nonheap"
      ]
    },
    {
      "tag": "id",
      "values": [
        "Compressed Class Space",
        "PS Survivor Space",
        "PS Old Gen",
        "Metaspace",
        "PS Eden Space",
        "Code Cache"
      ]
    }
  ]
}

You can further limit the metric by using a tag like /metrics/jvm.memory.used?tag=id:PS%20Old%20Gen.

Sample Metric Detail Json
{
  "name": "jvm.memory.used",
  "measurements": [
    {
      "statistic": "VALUE",
      "value": 1.1434488E7
    }
  ],
  "availableTags": [
    {
      "tag": "area",
      "values": [
        "heap"
      ]
    }
  ]
}

You may even use multiple/nested tags like /metrics/jvm.memory.used?tag=id:PS%20Old%20Gen&tag=area:heap.

Sample Metric Detail Json
{
  "name": "jvm.memory.used",
  "measurements": [
    {
      "statistic": "VALUE",
      "value": 1.1434488E7
    }
  ]
}

Configuration

Currently the metrics endpoint will only be enabled if you include the micrometer-core (or one of the typed registries such as micrometer-registry-statsd or micrometer-registry-graphite) AND the management dependencies. You will also need to have the global metrics flag enabled (true by default).

Property
micronaut:
  metrics:
    enabled: true
Gradle
dependencies {
    ...
    compile "io.micronaut.configuration:micronaut-micrometer-core"
    // micrometer-registry-statsd also pulls in micrometer-core so included above to verbose example
    compile "io.micronaut.configuration:micronaut-micrometer-registry-statsd"
    // Also required to enable endpoint
    compile "io.micronaut:micronaut-management"
    ...
}
Maven
<dependency>
  <groupId>io.micronaut.configuration</groupId>
  <artifactId>micronaut-micrometer-core</artifactId>
  <version>${micronaut.version}</version>
</dependency>
<!-- micrometer-registry-statsd also pulls in micrometer-core so included above to verbose example -->
<dependency>
  <groupId>io.micronaut.configuration</groupId>
  <artifactId>micronaut-micrometer-registry-statsd</artifactId>
  <version>${micronaut.version}</version>
</dependency>
<!-- Also required to enable endpoint -->
<dependency>
  <groupId>io.micronaut</groupId>
  <artifactId>micronaut-management</artifactId>
  <version>${micronaut.version}</version>
</dependency>

To configure the metrics endpoint, supply configuration through endpoints.metrics.

Metrics Endpoint Configuration Example
endpoints:
    metrics:
        enabled: Boolean
        sensitive: Boolean

3 Metrics Concepts

Metric Concepts

Key Micrometer.io concepts include a MeterRegistry to register and use meters. A Meter is something that produces metrics.

A MeterRegistry can have some customizations automatically applied.

Meter Registry Configurer

  • Any bean that implements MeterRegistryConfigurer gets applied to every applicable MeterRegistry bean on creation

  • The implementation of the MeterRegistryConfigurer supports() method determines if the configurer is applied to a particular registry

    • If you want all registries to get the customization, simply return return true

    • Otherwise, you can evaluate the registry for its class type, its class hierarchy, or other criteria.

    • Remember you only get one shot for autoconfiguration; i.e. when the bean context is started.

    • However, in code, you can apply additional customizations to the registry config

MeterRegistryConfigurer Interface
/*
 * Copyright 2017-2019 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.configuration.metrics.aggregator;

import io.micrometer.core.instrument.MeterRegistry;

/**
 * Class that will configure meter registries.  This is done on bean added event so that
 * composite registry can be skipped and non-composite registries can be added to composite.
 *
 * @author Christian Oestreich
 * @param <T> an instance of a meter registry that will be configured
 * @since 1.0
 */
public interface MeterRegistryConfigurer<T extends MeterRegistry> {

    /**
     * Method to configure a meter registry with binders, filters, etc.
     *
     * @param meterRegistry Meter Registry
     */
    void configure(T meterRegistry);

    /**
     * Method to determine if this configurer supports the meter registry type.
     *
     * @param meterRegistry a meter registry
     * @return boolean whether is supported
     */
    boolean supports(T meterRegistry);
}
Example
/*
 * Copyright 2017-2019 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.docs;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.micronaut.configuration.metrics.aggregator.MeterRegistryConfigurer;

public class SimpleMeterRegistryConfigurer implements MeterRegistryConfigurer {

    @Override
    public void configure(MeterRegistry meterRegistry) {
        meterRegistry.config().commonTags("key", "value");
    }

    @Override
    public boolean supports(MeterRegistry meterRegistry) {
        return meterRegistry instanceof SimpleMeterRegistry;
    }
}

Meter Filter

  • A meter filter can be used to determine if a Meter is to be added to the registry. See Meter Filters

  • Any bean that implements MeterFilter will be applied to all registries when the registry is first created

You can create custom filters similar to the following inside your application. Micrometer’s MeterFilter class provides several convenience methods to help with the creation of these filters.

Example
/*
 * Copyright 2017-2019 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.docs;

import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;

import javax.inject.Singleton;
import java.util.Arrays;

@Factory
public class MeterFilterFactory {

    /**
     * Exclude metrics starting with jvm
     *
     * @return meter filter
     */
    @Bean
    @Singleton
    MeterFilter jvmExclusionFilter() {
        return MeterFilter.denyNameStartsWith("jvm");
    }

    /**
     * Add global tags to all metrics
     *
     * @return meter filter
     */
    @Bean
    @Singleton
    MeterFilter addCommonTagFilter() {
        return MeterFilter.commonTags(Arrays.asList(Tag.of("scope", "demo")));
    }

    /**
     * Rename a tag key for every metric beginning with a given prefix.
     * <p>
     * This will rename the metric name http.server.requests tag value called `method` to `httpmethod`
     * <p>
     * OLD: http.server.requests ['method':'GET", ...]
     * NEW: http.server.requests ['httpmethod':'GET", ...]
     *
     * @return meter filter
     */
    @Bean
    @Singleton
    MeterFilter renameFilter() {
        return MeterFilter.renameTag("http.server.requests", "method", "httpmethod");
    }
}

Meter Binder

Meter Binders get applied to Meter Registry to mix in metrics producers. Micrometer.io defines several of these for cross-cutting metrics related to JVM metrics, caches, classloaders, etc. These all extend a simple interface MeterBinder, but these are not auto wired as beans and manual wiring is required given how micrometer is currently implemented.

Provided Binders

The following metrics currently have binders and are enabled by default. The settings listed below can disable the specific metric binders if you do not with to collect or report the specific metrics.

Jvm Metrics

The JVM metrics bindings will provide several jvm metrics.

Control Property: micronaut.metrics.binders.jvm.enabled

Table 1. Metrics provided

Name

jvm.buffer.count

jvm.buffer.memory.used

jvm.buffer.total.capacity

jvm.classes.loaded

jvm.classes.unloaded

jvm.gc.live.data.size

jvm.gc.max.data.size

jvm.gc.memory.allocated

jvm.gc.memory.promoted

jvm.memory.committed

jvm.memory.max

jvm.memory.used

jvm.threads.daemon

jvm.threads.live

jvm.threads.peak

Web Metrics

There is a default web filter provided for web metrics. All routes, status codes, methods and exceptions will be timed and counted.

Control Property: micronaut.metrics.binders.web.enabled

Filter Path

If enabled, be default the path /** will be intercepted. If you wish to change which paths are run through the filter set the following property.

Control Property: micronaut.metrics.http.path

Table 2. Metrics provided

Name

http.server.requests

http.client.requests

System Metrics

There are multiple metrics that can be separately toggled.

Uptime Metrics

The uptime metrics bindings will provide system uptime metrics.

Control Property: micronaut.metrics.binders.uptime.enabled

Table 3. Metrics provided

Name

process.uptime

process.start.time

Processor Metrics

The processor metrics bindings will provide system processor metrics.

Control Property: micronaut.metrics.binders.processor.enabled

Table 4. Metrics provided

Name

system.load.average.1m

system.cpu.usage

system.cpu.count

process.cpu.usage

File Descriptor Metrics

The file descriptor metrics bindings will provide system file descriptor metrics.

Control Property: micronaut.metrics.binders.files.enabled

Table 5. Metrics provided

Name

process.files.open

process.files.max

Logback Metrics

The logging metrics bindings will provide logging metrics if using Logback.

Control Property: micronaut.metrics.binders.logback.enabled

Table 6. Metrics provided

Name

logback.events

Hibernate Metrics

You can enable metrics for Hibernate by setting the hibernate.generate_statistics property to true in configuration. For example for the default entity manager:

Enabling Hibernate Metrics

jpa:
    default:
        properties:
            hibernate:
                generate_statistics: true

Micrometer will automatically expose Hibernate statistics. See the source code for HibernateMetrics for the available metrics.

DataSource Metrics

The data source metrics bindings will provide data source pool metrics.

Control Property: micronaut.metrics.binders.jdbc.enabled

There is a different set of pool metric names for HikariCP and other pool providers.

If you are using io.micronaut.configuration:micronaut-jdbc-hikari you will get additional pool metrics as HikariCP has built in support for meter registries.

Table 7. HikariCP Metrics Provided

Name

hikaricp.connections.idle

hikaricp.connections.pending

hikaricp.connections

hikaricp.connections.active

hikaricp.connections.creation

hikaricp.connections.max

hikaricp.connections.min

hikaricp.connections.usage

hikaricp.connections.timeout

hikaricp.connections.acquire

If you are using io.micronaut.configuration:micronaut-jdbc-tomcat or io.micronaut.configuration:micronaut-jdbc-dbcp you will get the following metrics

Table 8. Generic Pool Metrics provided

Name

jdbc.connections.usage

jdbc.connections.active

jdbc.connections.max

jdbc.connections.min

Adding Custom Metrics

To add metrics to your application you can inject a MeterRegistry bean to your class and use the provided methods to access counters, timers, etc.

See the Micrometer.io docs at https://micrometer.io/docs for more information.

Custom Metrics Example
/*
 * Copyright 2017-2019 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.docs;

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

import javax.validation.constraints.NotBlank;

@Controller("/")
public class IndexController {

    private MeterRegistry meterRegistry;

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

    @Get("/hello/{name}")
    public Single hello(@NotBlank String name) {
        meterRegistry
                .counter("web.access", "controller", "index", "action", "hello")
                .increment();
        return Single.just("Hello " + name);
    }

}

Metrics Registries & Reporters

By default there a metrics endpoint wired up and metrics are provided to it for viewing or retrieving via http. If you want to register a specific type of reporter you will need to include a typed registry configuration. The following are the currently supported libraries for reporting metrics.

Statsd Registry

You can include the statsd reporter via io.micronaut.configuration:micronaut-micrometer-registry-statsd:${micronaut.version}

compile 'io.micronaut.configuration:micronaut-micrometer-registry-statsd'
<dependency>
    <groupId>io.micronaut.configuration</groupId>
    <artifactId>micronaut-micrometer-registry-statsd</artifactId>
</dependency>

You can configure this reporter using micronaut.metrics.export.statsd. The most commonly changed configuration properties are listed below, but see StatdsConfig for more options

Name

Description

enabled

Whether to enable the reporter. Could disable to local dev for example. Default: true

flavor

The type of metric to use (datadog, etsy or telegraf). Default: datadog

step

How frequently to report metrics. Default: PT1M (1 min). See java.time.Duration#parse(CharSequence)

host

The host to communicate to statsd on. Default: localhost

port

The port to communicate to statsd on. Default: 8125

Example Statsd Config
micronaut:
  metrics:
    enabled: true
    export:
      statsd:
        enabled: true
        flavor: datadog
        step: PT1M
        host: localhost
        port: 8125

Graphite Registry

You can include the graphite reporter via io.micronaut.configuration:micronaut-micrometer-registry-graphite:${micronaut.version}

compile 'io.micronaut.configuration:micronaut-micrometer-registry-graphite'
<dependency>
    <groupId>io.micronaut.configuration</groupId>
    <artifactId>micronaut-micrometer-registry-graphite</artifactId>
</dependency>

You can configure this reporter using micronaut.metrics.export.graphite. The most commonly changed configuration properties are listed below, but see GraphiteConfig for more options

Name

Description

enabled

Whether to enable the reporter. Could disable to local dev for example. Default: true

step

How frequently to report metrics. Default: PT1M (1 min). See java.time.Duration#parse(CharSequence)

host

The host to communicate with graphite. Default: localhost

port

The port to communicate with graphite. Default: 2004

Example Graphite Config
micronaut:
  metrics:
    enabled: true
    export:
      graphite:
        enabled: true
        step: PT1M
        host: localhost
        port: 2004

Atlas Registry

You can include the atlas reporter via io.micronaut.configuration:micronaut-micrometer-registry-atlas:${micronaut.version}

compile 'io.micronaut.configuration:micronaut-micrometer-registry-atlas'
<dependency>
    <groupId>io.micronaut.configuration</groupId>
    <artifactId>micronaut-micrometer-registry-atlas</artifactId>
</dependency>

You can configure this reporter using micronaut.metrics.export.atlas. The most commonly changed configuration properties are listed below, but see AtlasConfig for more options

Name

Description

enabled

Whether to enable the reporter. Could disable to local dev for example. Default: true

step

How frequently to report metrics. Default: PT1M (1 min). See java.time.Duration#parse(CharSequence)

uri

The uri for the atlas backend. Default: http://localhost:7101/api/v1/publish

Example Atlas Config
micronaut:
  metrics:
    enabled: true
    export:
      atlas:
        enabled: true
        uri: http://localhost:7101/api/v1/publish
        step: PT1M

Prometheus Registry

You can include the prometheus reporter via io.micronaut.configuration:micronaut-micrometer-registry-prometheus:${micronaut.version}

compile 'io.micronaut.configuration:micronaut-micrometer-registry-prometheus'
<dependency>
    <groupId>io.micronaut.configuration</groupId>
    <artifactId>micronaut-micrometer-registry-prometheus</artifactId>
</dependency>

You can configure this reporter using micronaut.metrics.export.prometheus. The most commonly changed configuration properties are listed below, but see PrometheusConfig for more options

Name

Description

enabled

Whether to enable the reporter. Could disable to local dev for example. Default: true

step

How frequently to report metrics. Default: PT1M (1 min). See java.time.Duration#parse(CharSequence)

descriptions

Boolean if meter descriptions should be sent to Prometheus. Turn this off to minimize the amount of data sent on each scrape. Default: true

Example Prometheus Config
micronaut:
  metrics:
    enabled: true
    export:
      prometheus:
        enabled: true
        step: PT1M
        descriptions: true

CloudWatch Registry

You can include the cloudwatch reporter via io.micronaut.configuration:micronaut-micrometer-registry-cloudwatch:${micronaut.version}

compile 'io.micronaut.configuration:micronaut-micrometer-registry-cloudwatch'
<dependency>
    <groupId>io.micronaut.configuration</groupId>
    <artifactId>micronaut-micrometer-registry-cloudwatch</artifactId>
</dependency>

You can configure this reporter using micronaut.metrics.export.cloudwatch. The most commonly changed configuration properties are listed below, but see CloudWatchConfig for more options

Name

Description

enabled

Boolean whether to enable the reporter. Could disable to local dev for example. Default: true

namespace

String Namespace that will show up in cloudwatch for these metrics. Default: micronaut.

batchSize

Number Number of metrics to send in a batch to Cloudwatch. Default: 20 Matches max limit found on Cloudwatch API Reference.

Example Cloudwatch Config
micronaut:
  metrics:
    enabled: true
    export:
      cloudwatch:
        enabled: true
        namespace: myAwesomeAppMetrics
        batchSize: 10