Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

yammer @Timed leaving values at zero

This is a follow-up to my struggle using yammer timing annotations as described here.

My spring context file has simply:

<metrics:annotation-driven />

I have the following class:

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

...

@Component
public class GetSessionServlet extends HttpServlet {

  private final static Logger log = LoggerFactory.getLogger(GetSessionServlet.class);


  @Override
  public void init(final ServletConfig config) throws ServletException {
    super.init(config);
    SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(
            this, config.getServletContext());
  }

  @Override
  @Timed(name = "get-session", rateUnit = TimeUnit.MILLISECONDS)
  @Metered
  @ExceptionMetered(name = "get-session-failures", rateUnit = TimeUnit.MILLISECONDS)
  public void doGet(final HttpServletRequest req,
          final HttpServletResponse resp) throws ServletException, IOException {
    final String sessionId = req.getParameter("sessionId");
    final String fields = req.getParameter("fields");
    final String format = req.getParameter("format");
    if (StringUtils.isEmpty(sessionId)) {
      resp.getWriter().write("sessionId parameter missing!\n");
      return;
    }
    ...
  }

I run my app locally with mvn clean tomcat7:run and then connect jconsole.

In the MBeans tab, I can see an entry with the package name of my GetSessionServlet class with three subfolders doGet (for the @Metered numbers), get-session, and get-session-failures.

However, no matter how many times I call my servlet, all the values in the sub-folders above remain at zero. What am I missing? Also, any documentation on these metered metrics that goes into more details than the official documentation will be greatly appreciated.

like image 267
Lolo Avatar asked Feb 11 '13 16:02

Lolo


2 Answers

I think I got this working.

The first thing I noticed was that the URI in the schemaLocation attribute of the sample spring context file: http://www.yammer.com/schema/metrics/metrics.xsd returns a 404 error.

I googled the issue to see if anyone had complained about the schema being unreachable and found this thread, github.com/codahale/metrics/issues/322, wherein a user comments that the metrics-spring module has been removed from the core metrics repository and moved to: github.com/ryantenney/metrics-spring.

Following the example on that website, I stripped out the old metrics-spring dependency from my pom and added the following:

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

I then updated the xmlns declaration in my spring-context.xml file:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:metrics="http://www.ryantenney.com/schema/metrics"
       xsi:schemaLocation="
           http://www.ryantenney.com/schema/metrics 
           http://www.ryantenney.com/schema/metrics/metrics.xsd 
           ...other schemas...">

Added the annotation-driven element:

<metrics:annotation-driven proxy-target-class="true" />

I enabled proxy-target-class to get class based autowiring working.

And in the bean I wanted to Time added the @Timed annotation and a @PostConstruct method to enable a ConsoleReporter to dump stats every 10 secs:

@PostConstruct
public void init() {
    ConsoleReporter.enable(10, TimeUnit.SECONDS);    
} 

@Timed
public void doService(...) {
    .... do stuff ....
}

I then started up my webapp .... and got a nasty error from the sax parser parsing the spring context.xml file.

It seems that www.ryantenney.com/schema/metrics/metrics.xsd 404s as well!

The workaround for this was simple, however, I downloaded the xsd from the github repository: https://github.com/ryantenney/metrics-spring/blob/master/src/main/resources/com/ryantenney/metrics/spring/config/metrics-3.0.xsd

and then in the src/main/resources/META-INF directory of my maven project added the following files:

META-INF/
    - spring.schemas
    - xsd/
         - metrics.xsd

where metrics.xsd is the xsd file downloaded from github, and spring.schemas is a text file containing:

http\://www.ryantenney.com/schema/metrics/metrics.xsd=META-INF/xsd/metrics.xsd

The spring.schemas file is read by spring at startup and tells it to pull down the xsd from the local file.

With the above in place I was able to successfully fire up my app and hit the endpoint that used the service method.

Watching the console I did indeed see the following dumped every 10 seconds:

com.sample.service.MyServiceClass:
doService:
    count = 8
    mean rate = 0.27 calls/s
    1-minute rate = 0.23 calls/s
    5-minute rate = 0.21 calls/s
    15-minute rate = 0.20 calls/s
    min = 0.13ms
    max = 19.59ms
    mean = 2.59ms
    stddev = 6.87ms
    median = 0.18ms
like image 143
stroisi Avatar answered Nov 20 '22 03:11

stroisi


I posted a similar question here and got not much further. It was pointed out to me that I was probably getting 0 numbers because "Spring cannot intercept an annotated method when that method is called from within the class itself." Though I had read that comment before, I had not realized that I was in this situation, but looking at the source for HttpServlet, I do see indeed methods like doHead that call doGet.

Though that restriction alone is a setback, I proceeded to invoking from my doGet a method in a different class to see if I could perform timing that way (cumbersome but willing to give that a try):

import org.springframework.stereotype.Component;
import com.yammer.metrics.annotation.Metered;
import com.yammer.metrics.annotation.Timed;

@Component
public class Delay {
  //      @Metered
  @Timed
  public void time() {
    System.out.println("Timing...");
    try {
      Thread.sleep(1000);
    } catch (final InterruptedException e) {
      e.printStackTrace();
    }
  }
}

Yet, calling this method from my servlet getter as follows:

public void doGet(final HttpServletRequest req,
      final HttpServletResponse resp) throws ServletException, IOException {

  final Delay delay = new Delay().time();

still doesn't show me any non-null number for the Delay.time method no matter how many times I do a get.

At this point, I am going to take the provocative stand that because of whatever restrictions come with these annotations and the lack of complete documentation and useful code examples, these annotations are not useful, at least in the context of timing servlets.

I do want to be proven wrong and will gladly change my vote to accept another answer because these annotations looked promising and more practical to use than the Metrics.newTimer and alike methods.

like image 3
Lolo Avatar answered Nov 20 '22 03:11

Lolo