Google

Oct 22, 2014

Yammer metrics to monitor RESTful web services and report them via its admin web

This is a Yammer metrics tutorial to monitor RESTful web services. This extends RESTEasy web service tutorial basic and the basic stand-alone Yammer tutorial.

Step 1: The pom.xml file needs to have relevant dependencies defined relating to Yammer and Spring Web in addition to the JAX-RS librraies that was covered in the previous tutorial.


  <!-- Yammer Metrics -->
  <dependency>
   <groupId>com.yammer.metrics</groupId>
   <artifactId>metrics-core</artifactId>
   <scope>compile</scope>
   <version>${metrics.version}</version>
  </dependency>
  <dependency>
   <groupId>com.yammer.metrics</groupId>
   <artifactId>metrics-annotation</artifactId>
   <scope>compile</scope>
   <version>${metrics.version}</version>
  </dependency>
  <dependency>
   <groupId>com.yammer.metrics</groupId>
   <artifactId>metrics-spring</artifactId>
   <scope>runtime</scope>
   <version>${metrics.version}</version>
  </dependency>
  <dependency>
   <groupId>com.yammer.metrics</groupId>
   <artifactId>metrics-servlet</artifactId>
   <scope>compile</scope>
   <version>${metrics.version}</version>
  </dependency>
  <dependency>
   <groupId>com.yammer.metrics</groupId>
   <artifactId>metrics-web</artifactId>
   <scope>runtime</scope>
   <version>${metrics.version}</version>
  </dependency>

  <!-- Servelet API -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <scope>provided</scope>
   <version>${javax-servlet.version}</version>
  </dependency>

  <!-- Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <scope>compile</scope>
   <version>${spring.version}</version>
  </dependency>


Step 2: Add metrics annotation to the RESTful web service interface and implementation

package com.mytutorial;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

import com.yammer.metrics.annotation.ExceptionMetered;
import com.yammer.metrics.annotation.Timed;

@Path("/myapp")
public interface SimpleRestWeb {

 @GET
 @Path("/name/{name}")
 @Timed
 @ExceptionMetered
 public String sayHello(@PathParam("name") String name);

}


package com.mytutorial;

import java.util.concurrent.atomic.AtomicLong;

import com.yammer.metrics.annotation.Gauge;
import com.yammer.metrics.annotation.Timed;

public class SimpleRestWebImpl implements SimpleRestWeb {

 @Gauge
 AtomicLong requestCount = new AtomicLong();
 
 
@Override
@Metered
 public String sayHello(String name) {
  String result = "Hello " + name;
  requestCount.incrementAndGet();
  return result;
 }

}


Note: A gauge "requestCount" was added to count the number of requests.

Step 3: The applicationContext.xml file under com/mytutorial with mterics bootstrapping.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:metrics="http://www.yammer.com/schema/metrics"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                        http://www.yammer.com/schema/metrics http://www.yammer.com/schema/metrics/metrics.xsd">
    
    <metrics:metrics-registry id="rest-metrics"/>
    <metrics:health-check-registry id="rest-health"/>
    <metrics:annotation-driven metrics-registry="rest-metrics" health-check-registry="rest-health" proxy-target-class="true" />
    
     <bean id="simpleRestWeb" class="com.mytutorial.SimpleRestWebImpl"  />
    
    
</beans>


Step 4: The web.xml file with the Yammer admin servlet and relevant listeners defined.

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
 <display-name>Archetype Created Web Application</display-name>


 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:/com/mytutorial/applicationContext.xml</param-value>
 </context-param>

 <context-param>
  <param-name>resteasy.use.deployment.sensitive.factory</param-name>
  <param-value>false</param-value>
 </context-param>

 <context-param>
  <param-name>resteasy.servlet.mapping.prefix</param-name>
  <param-value>/rest</param-value>
 </context-param>


 <listener>
  <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
 </listener>
 <listener>
  <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
 </listener>
 <listener>
     <listener-class>com.mytutorial.MetricsContextLoaderListener</listener-class>
    </listener>

 
 <servlet>
  <servlet-name>resteasy-simple</servlet-name>
  <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
 </servlet>
 <servlet>
  <servlet-name>admin-servlet</servlet-name>
  <servlet-class>com.yammer.metrics.reporting.AdminServlet</servlet-class>
  <load-on-startup>2</load-on-startup>
 </servlet>


 <servlet-mapping>
  <servlet-name>resteasy-simple</servlet-name>
  <url-pattern>/rest/*</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
  <servlet-name>admin-servlet</servlet-name>
  <url-pattern>/admin/*</url-pattern>
 </servlet-mapping>
</web-app>


Step 5: The ServletContextListener com.mytutorial.MetricsContextLoaderListener defined in the above web.xml is a custom listener used to make MetricsRegistry available from the spring context to the Yammer admin servlet defined in the above web.xml.

package com.mytutorial;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.yammer.metrics.core.MetricsRegistry;
import com.yammer.metrics.reporting.MetricsServlet;

/**
 * Application Lifecycle Listener for Metrics.
 * 
 *I need to fetch the MetricsRegistry from the Spring Context and put it into the ServletContext,
 * for the yammer admin-servlet to be able to find it.....
 *
 */
public class MetricsContextLoaderListener implements ServletContextListener {

    public MetricsContextLoaderListener() {

    }

 public void contextInitialized(ServletContextEvent event) {
        ServletContext context = event.getServletContext();
        MetricsRegistry metricsRegistry = getMetricsRegistry(context);
        setMetricsRegistry(metricsRegistry, context);
    }

 
    public void contextDestroyed(ServletContextEvent event) {

    }

   
    protected MetricsRegistry getMetricsRegistry(ServletContext context) {
        WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(context); 
        return springContext.getBean(MetricsRegistry.class);
    }
    
   
    protected void setMetricsRegistry(MetricsRegistry registry, ServletContext context) {
        context.setAttribute(MetricsServlet.REGISTRY_ATTRIBUTE, registry);
    }
}


Step 6: Build and deploy the war file.

Hit the url: http://localhost:8080/tutorial/rest/myapp/name/arul to invoke the RESTful web service.
Hit the url: http://localhost:8080/tutorial/admin/metrics?pretty=true to get the metrics as json String.
Hit the url: http://localhost:8080/tutorial/admin to get the Yammer menu.

Step 7: The json output for metrics (e.g. http://localhost:8080/tutorial/admin/metrics?pretty=true) will look like

{
{
  "jvm" : {
    "vm" : {
      "name" : "Java HotSpot(TM) 64-Bit Server VM",
      "version" : "1.6.0_45-b06"
    },
    "memory" : {
      "totalInit" : 2.695299072E9,
      "totalUsed" : 2.8351824E8,
      "totalMax" : 5.953159168E9,
      "totalCommitted" : 2.606497792E9,
      "heapInit" : 2.155872256E9,
      "heapUsed" : 2.29205536E8,
      "heapMax" : 3.780509696E9,
      "heapCommitted" : 2.066087936E9,
      "heap_usage" : 0.06062821006450872,
      "non_heap_usage" : 0.02499863539883529,
      "memory_pool_usages" : {
        "Code Cache" : 0.06720225016276042,
        "PS Eden Space" : 0.16319328855716045,
        "PS Old Gen" : 0.009577277144031412,
        "PS Perm Gen" : 0.023997800623475327,
        "PS Survivor Space" : 0.0
      }
    },
    "daemon_thread_count" : 28,
    "thread_count" : 49,
    "current_time" : 1395644957593,
    "uptime" : 24,
    "fd_usage" : "NaN",
    "thread-states" : {
      "new" : 0.0,
      "timed_waiting" : 0.4897959183673469,
      "terminated" : 0.0,
      "waiting" : 0.16326530612244897,
      "blocked" : 0.0,
      "runnable" : 0.3469387755102041
    },
    "garbage-collectors" : {
      "PS MarkSweep" : {
        "runs" : 2,
        "time" : 134
      },
      "PS Scavenge" : {
        "runs" : 2,
        "time" : 33
      }
    }
  },
  "com.mytutorial.SimpleRestWebImpl" : {
    "requestCount" : {
      "type" : "gauge",
      "value" : 1
    },
    "sayHello" : {
      "type" : "timer",
      "duration" : {
        "unit" : "milliseconds",
        "min" : 2999.710987,
        "max" : 2999.710987,
        "mean" : 2999.710987,
        "std_dev" : 0.0,
        "median" : 2999.710987,
        "p75" : 2999.710987,
        "p95" : 2999.710987,
        "p98" : 2999.710987,
        "p99" : 2999.710987,
        "p999" : 2999.710987
      },
      "rate" : {
        "unit" : "seconds",
        "count" : 1,
        "mean" : 0.06855060368303201,
        "m1" : 0.0,
        "m5" : 0.0,
        "m15" : 0.0
      }
    }
  }
}


Take note of "requestCount", which counts the number of requests.

Labels: , ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home