Skip to content

Instantly share code, notes, and snippets.

@kimble
Created May 6, 2012 19:01
Show Gist options
  • Save kimble/2623833 to your computer and use it in GitHub Desktop.
Save kimble/2623833 to your computer and use it in GitHub Desktop.
Dropwizard instrumentation of Guice beans annotated with @timed
package com.developerb.dropbot;
import com.developerb.dropbot.instrumentation.MethodInvocationTimingInterceptor;
import com.google.inject.AbstractModule;
import com.yammer.metrics.annotation.Timed;
import static com.google.inject.matcher.Matchers.annotatedWith;
import static com.google.inject.matcher.Matchers.any;
/**
* @author Kim A. Betti
*/
public class DropBotModule extends AbstractModule {
@Override
protected void configure() {
bindInterceptor(any(), annotatedWith(Timed.class), new MethodInvocationTimingInterceptor());
// ...
}
}
package com.developerb.dropbot.instrumentation;
import com.yammer.metrics.Metrics;
import com.yammer.metrics.annotation.Timed;
import com.yammer.metrics.core.MetricName;
import com.yammer.metrics.core.Timer;
import com.yammer.metrics.core.TimerContext;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import static com.yammer.metrics.core.MetricName.chooseGroup;
import static com.yammer.metrics.core.MetricName.chooseName;
import static com.yammer.metrics.core.MetricName.chooseType;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* Based on InstrumentedResourceMethodDispatchProvider
* @author Kim A. Betti
*/
public class MethodInvocationTimingInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> clazz = invocation.getThis().getClass();
Timed annotation = invocation.getMethod().getAnnotation(Timed.class);
MetricName metricName = buildMetric(invocation, clazz, annotation);
Timer timer = buildTimer(annotation, metricName);
return proceedInvocationWithTimer(invocation, timer);
}
private MetricName buildMetric(MethodInvocation invocation, Class<?> clazz, Timed annotation) {
String group = chooseGroup(annotation.group(), clazz);
String type = chooseType(annotation.type(), clazz);
String name = chooseName(annotation.name(), invocation.getMethod());
return new MetricName(group, type, name);
}
private Timer buildTimer(Timed annotation, MetricName metricName) {
return Metrics.newTimer(metricName,
annotation.durationUnit() == null ? MILLISECONDS : annotation.durationUnit(),
annotation.rateUnit() == null ? SECONDS : annotation.rateUnit());
}
private Object proceedInvocationWithTimer(MethodInvocation invocation, Timer timer) throws Throwable {
TimerContext context = timer.time();
try {
return invocation.proceed();
}
finally {
context.stop();
}
}
}
package com.developerb.dropbot.bot.posten;
import com.sun.jersey.api.client.WebResource;
import com.yammer.dropwizard.client.JerseyClient;
import com.yammer.metrics.annotation.Timed;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
import javax.inject.Inject;
import static javax.ws.rs.core.MediaType.APPLICATION_ATOM_XML_TYPE;
/**
* Proof of concept client for Bring's zip code service.
* Reference: http://developer.bring.com/learn/postalcode/apireference.html
* @author Kim A. Betti
*/
public class PostenZipCodeClient implements ZipCodeClient {
private final WebResource api;
@Inject
public PostenZipCodeClient(JerseyClient client) {
api = client.resource("http://fraktguide.bring.no/fraktguide/api/postalCode.json");
}
@Override
@Timed(group="external", type="posten-zip-code-service", name="reverse-lookup")
public String resolve(String zipCode) {
PostenResult response = api.queryParam("country", "no")
.queryParam("pnr", zipCode)
.accept(APPLICATION_ATOM_XML_TYPE)
.get(PostenResult.class);
if (response.isInvalid()) {
throw new InvalidZipCodeException(zipCode, "Norway");
}
else {
return response.place;
}
}
private static class PostenResult {
@NotEmpty
private final String place;
private final boolean valid;
@JsonCreator
public PostenResult(@JsonProperty("result") String place,
@JsonProperty("valid") boolean valid) {
this.valid = valid;
this.place = place;
}
public String getPlace() {
return place;
}
public boolean isInvalid() {
return !valid;
}
}
}
{
"external.posten-zip-code-service" : {
"reverse-lookup" : {
"type" : "timer",
"duration" : {
"unit" : "milliseconds",
"min" : 39.74018,
"max" : 5474.089895,
"mean" : 1634.8598794000002,
"std_dev" : 2355.3624835465334,
"median" : 219.17689,
"p75" : 3913.0017159999998,
"p95" : 5474.089895,
"p98" : 5474.089895,
"p99" : 5474.089895,
"p999" : 5474.089895
},
"rate" : {
"unit" : "seconds",
"count" : 5,
"mean" : 0.0012641292163691517,
"m1" : 0.015991117074135343,
"m5" : 0.0033057369185648107,
"m15" : 0.001164697404800008
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment