Loading...

Use Dropwizard Metrics with CDI in Java EE

:heavy_exclamation_mark: This post is older than a year. Consider some information might not be accurate anymore. :heavy_exclamation_mark:

Java EE provides with CDI (Contexts and Dependency Injection) a powerful way to write loose coupled code. Dropwizard Metrics is a wonderful library to collect metrics about your application. This post shows how to integrate Dropwizard Metrics with CDI into an Java EE application.

Create qualifier for type Metric

/**
* Qualifier used to disambiguate metrics based on their registered name.
*/
@Retention(RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
@Qualifier
public @interface Metric {
    /**
     * Name of the metric, as registered in {@link com.codahale.metrics.MetricRegistry}.
     * @return the metric name
     */
    String value();
}

The class with the central MetricRegistry, eligible for injection

/**
 * Producer for Dropwizard Metrics registry.
 */
@ApplicationScoped
public class Metrics {
    private Slf4jReporter metricsReporter;
    private final MetricRegistry metricRegistry = new MetricRegistry();
    @Produces
    @Singleton
    public MetricRegistry getRegistry() {
        return metricRegistry;
    }
    @PostConstruct
    public void postConstruct() {
        metricsReporter = Slf4jReporter.forRegistry(metricRegistry)
                .outputTo(LoggerFactory.getLogger("metrics"))
                .convertRatesTo(SECONDS)
                .build();
        metricsReporter.start(30, SECONDS);
    }
    @PreDestroy
    public void preDestroy() {
        metricsReporter.stop();
    }
    /**
     * Executes a {@link Runnable} in the context of the given timer.
     * @param timer the timer
     * @param runnable the action to run
     */
    public static void timed(Timer timer, Runnable runnable) {
        try (Timer.Context ignored = timer.time()) {
            runnable.run();
        }
    }
    /**
     * Executes a {@link Supplier} in the context of the given timer.
     * @param timer the timer
     * @param supplier the action to run
     */
    public static <T> T timed(Timer timer, Supplier<T> supplier) {
        try (Timer.Context ignored = timer.time()) {
            return supplier.get();
        }
    }
}

Create producer that automatically registers the metric to the central registry

/**
 CDI producers for metrics
 */
public class BatchMetrics {
    public static final String DELIVERY_SIZE = "delivery.size";
    @Inject
    private MetricRegistry metricRegistry;
    @Produces
    @Metric(DELIVERY_SIZE)
    Histogram deliverySize() {
        return metricRegistry.histogram(DELIVERY_SIZE);
    }
//..
}