yammer @Timed leaving values at zero
Asked Answered
D

2

7

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.

Dissenter answered 11/2, 2013 at 16:8 Comment(0)
G
5

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
Gracchus answered 20/2, 2013 at 3:10 Comment(2)
The spring.schemas file is included in the metrics-spring.jar but if you're using the maven shade plugin you need to use the AppendingTransformer to tell shade to concatenate (not overwrite) the spring.schemas files (see: maven.apache.org/plugins/maven-shade-plugin/examples/…)Reedbuck
I have the same problem and verified that I have the things you described. I'm using the latest 3.0.3. My console reporter is working but it just prints all zeros. No errors logged or anything. Anything else you may have overlooked to mention? ThanksMasticatory
D
3

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.

Dissenter answered 18/2, 2013 at 18:19 Comment(5)
If you do new Delay(), that object isn't part of the Spring lifecycle, so metrics-spring never has a chance to intercept the method invocations. I'd appreciate it if you didn't say my project is useless when the problem is simply a fundamental misunderstanding of core Spring concepts.Reedbuck
@RyanTenney I'm sorry if I offended you and appreciate, most sincerely, what you developed. I thought I was very specific in giving the context for my judgment. I also was forthcoming in saying I would be glad to be proven wrong, and did change my vote to support the answer that showed a way of making this works. That being said, it still seems relevant to the usefulness of the tool that I found no documentation of the issue I came across and that the only (and great) answer I got here fit in 2 pages of explanation. I did NOT say or mean that the project is useless, far from this.Dissenter
@Dissenter did you manage to make it work? I have a similar scenario in my pet project...Braw
@Braw I haven't touched this project in a long time so I am no longer fresh on it, but my recollection is that I was able to make it work as described by stroisi, answer which I accepted. I hope this helps.Dissenter
@RyanTenney - I have a unit test working fine but not working from within a Spring MVC controller. I tired posting on the google group I found as well. I would appreciate any help. groups.google.com/forum/#!topic/metrics-user/EvmtEaVdNeIMasticatory

© 2022 - 2024 — McMap. All rights reserved.