Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement statistics using dropwizard metrics and spring-mvc

I am having about 20 APIs and I want to implement statistics like execution time, responses count .. for each API. After doing some research, I came to know that dropwizard metrics is the best approach for implementing such functionalities. I am using Spring MVC framework (non-bootable). Can anybody please suggest me how to integrate Metrics to Spring MVC framework?

If possible please provide any code as a reference.

like image 301
kumar Avatar asked Dec 22 '15 06:12

kumar


2 Answers

You can use Metrics for Spring. Here's a github link, which explains how to integrate it with Spring MVC. The metrics-spring module integrates Dropwizard Metrics library with Spring, and provides XML and Java configuration.

Maven

Current version is 3.1.2, which is compatible with Metrics 3.1.2

<dependency>
    <groupId>com.ryantenney.metrics</groupId>
    <artifactId>metrics-spring</artifactId>
    <version>3.1.2</version>
</dependency>

Basic Usage

As of version 3, metrics-spring may be configured using XML or Java, depending on your personal preference.

XML configuration:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:metrics="http://www.ryantenney.com/schema/metrics"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.ryantenney.com/schema/metrics
           http://www.ryantenney.com/schema/metrics/metrics.xsd">

    <!-- Creates a MetricRegistry bean -->
    <metrics:metric-registry id="metricRegistry" />

    <!-- Creates a HealthCheckRegistry bean (Optional) -->
    <metrics:health-check-registry id="health" />

    <!-- Registers BeanPostProcessors with Spring which proxy beans and capture metrics -->
    <!-- Include this once per context (once in the parent context and in any subcontexts) -->
    <metrics:annotation-driven metric-registry="metricRegistry" />

    <!-- Example reporter definiton. Supported reporters include jmx, slf4j, graphite, and others. -->
    <!-- Reporters should be defined only once, preferably in the parent context -->
    <metrics:reporter type="console" metric-registry="metricRegistry" period="1m" />

    <!-- Register metric beans (Optional) -->
    <!-- The metrics in this example require metrics-jvm -->
    <metrics:register metric-registry="metricRegistry">
        <bean metrics:name="jvm.gc" class="com.codahale.metrics.jvm.GarbageCollectorMetricSet" />
        <bean metrics:name="jvm.memory" class="com.codahale.metrics.jvm.MemoryUsageGaugeSet" />
        <bean metrics:name="jvm.thread-states" class="com.codahale.metrics.jvm.ThreadStatesGaugeSet" />
        <bean metrics:name="jvm.fd.usage" class="com.codahale.metrics.jvm.FileDescriptorRatioGauge" />
    </metrics:register>

    <!-- Beans and other Spring config -->

</beans>

Java Config:

import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Configuration;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter;

@Configuration
@EnableMetrics
public class SpringConfiguringClass extends MetricsConfigurerAdapter {

    @Override
    public void configureReporters(MetricRegistry metricRegistry) {
        // registerReporter allows the MetricsConfigurerAdapter to
        // shut down the reporter when the Spring context is closed
        registerReporter(ConsoleReporter
            .forRegistry(metricRegistry)
            .build())
            .start(1, TimeUnit.MINUTES);
    }

}

Read More on Metrics Spring

like image 118
Lucky Avatar answered Oct 05 '22 22:10

Lucky


As it has been already suggested Metrics Spring offers some interesting integration with Spring. If you want to to access those metrics from a JSON API you still need to add the servlet as documented at http://metrics.dropwizard.io/3.1.0/manual/servlets/.

In order to use these servlets you need to add the dependency:

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-servlets</artifactId>
    <version>${metrics.version}</version>
</dependency>

Then you add the servlet in web.xml:

<servlet>
 <servlet-name>metrics-admin</servlet-name>
 <servlet-class>com.codahale.metrics.servlets.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
 <servlet-name>metrics-admin</servlet-name>
 <url-pattern>/metrics/admin/*</url-pattern>
</servlet-mapping>

You can also use JavaConfig to configure it.

Register the servlet:

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.codahale.metrics.servlets.AdminServlet;

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{RootConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        ServletRegistration.Dynamic metricsServlet = servletContext.addServlet("metrics", new AdminServlet());
        metricsServlet.addMapping("/metrics/admin/*");
    }
}

And provide the attributes needed by the servlet:

import java.util.concurrent.TimeUnit;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.health.HealthCheckRegistry;
import com.codahale.metrics.servlets.HealthCheckServlet;
import com.codahale.metrics.servlets.MetricsServlet;
import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter;

@Configuration
@EnableMetrics
public class MetricsConfiguration extends MetricsConfigurerAdapter {

    @Autowired ServletContext servletContext;
    @Autowired
    private HealthCheckRegistry healthCheckRegistry;
    @Override
    public void configureReporters(MetricRegistry metricRegistry) {
        registerReporter(ConsoleReporter
            .forRegistry(metricRegistry)
            .build())
            .start(1, TimeUnit.MINUTES);
        servletContext.setAttribute(MetricsServlet.METRICS_REGISTRY, metricRegistry);
        servletContext.setAttribute(HealthCheckServlet.HEALTH_CHECK_REGISTRY, healthCheckRegistry);
    }
}
like image 40
Iñaki Ibarrola Atxa Avatar answered Oct 05 '22 23:10

Iñaki Ibarrola Atxa