Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#859 fix inherited timed annotation #861

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.codahale.metrics.annotation.ExceptionMetered;
import com.codahale.metrics.annotation.Metered;
import com.codahale.metrics.annotation.Timed;
import org.glassfish.jersey.server.model.Invocable;
import org.glassfish.jersey.server.model.ModelProcessor;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.ResourceMethod;
Expand All @@ -32,14 +33,13 @@
* request events indicating that the method is about to be invoked, or just got done
* being invoked.
*/

@Provider
public class InstrumentedResourceMethodApplicationListener implements ApplicationEventListener, ModelProcessor {

private final MetricRegistry metrics;
private ConcurrentMap<Method, Timer> timers = new ConcurrentHashMap<>();
private ConcurrentMap<Method, Meter> meters = new ConcurrentHashMap<>();
private ConcurrentMap<Method, ExceptionMeterMetric> exceptionMeters = new ConcurrentHashMap<>();
private final ConcurrentMap<String, Timer> timers = new ConcurrentHashMap<>();
private final ConcurrentMap<String, Meter> meters = new ConcurrentHashMap<>();
private final ConcurrentMap<String, ExceptionMeterMetric> exceptionMeters = new ConcurrentHashMap<>();

/**
* Construct an application event listener using the given metrics registry.
Expand All @@ -64,29 +64,35 @@ private static class ExceptionMeterMetric {
public final Class<? extends Throwable> cause;

public ExceptionMeterMetric(final MetricRegistry registry,
final ResourceMethod method,
final Class<?> handlerClass,
final Method definitionMethod,
final ExceptionMetered exceptionMetered) {
final String name = chooseName(exceptionMetered.name(),
exceptionMetered.absolute(), method, ExceptionMetered.DEFAULT_NAME_SUFFIX);
exceptionMetered.absolute(), handlerClass, definitionMethod, ExceptionMetered.DEFAULT_NAME_SUFFIX);
this.meter = registry.meter(name);
this.cause = exceptionMetered.cause();
}
}

private static class TimerRequestEventListener implements RequestEventListener {
private final ConcurrentMap<Method, Timer> timers;
private final ConcurrentMap<String, Timer> timers;
private Timer.Context context = null;

public TimerRequestEventListener(final ConcurrentMap<Method, Timer> timers) {
public TimerRequestEventListener(final ConcurrentMap<String, Timer> timers) {
this.timers = timers;
}

@Override
public void onEvent(RequestEvent event) {
if (event.getType() == RequestEvent.Type.RESOURCE_METHOD_START) {
final Timer timer = this.timers.get(event.getUriInfo()
.getMatchedResourceMethod().getInvocable().getDefinitionMethod());
if (timer != null) {
final ResourceMethod method = event.getUriInfo().getMatchedResourceMethod();
final Invocable methodInvocable = method.getInvocable();
final Method definitionMethod = methodInvocable.getDefinitionMethod();
final Timed annotation = definitionMethod.getAnnotation(Timed.class);

if (annotation != null) {
final Class<?> handlerClass = methodInvocable.getHandler().getHandlerClass();
final Timer timer = this.timers.get(chooseName(annotation.name(), annotation.absolute(), handlerClass, definitionMethod));
this.context = timer.time();
}
} else if (event.getType() == RequestEvent.Type.RESOURCE_METHOD_FINISHED) {
Expand All @@ -98,43 +104,55 @@ public void onEvent(RequestEvent event) {
}

private static class MeterRequestEventListener implements RequestEventListener {
private final ConcurrentMap<Method, Meter> meters;
private final ConcurrentMap<String, Meter> meters;

public MeterRequestEventListener(final ConcurrentMap<Method, Meter> meters) {
public MeterRequestEventListener(final ConcurrentMap<String, Meter> meters) {
this.meters = meters;
}

@Override
public void onEvent(RequestEvent event) {
if (event.getType() == RequestEvent.Type.RESOURCE_METHOD_START) {
final Meter meter = this.meters.get(event.getUriInfo()
.getMatchedResourceMethod().getInvocable().getDefinitionMethod());
if (meter != null) {
final ResourceMethod method = event.getUriInfo().getMatchedResourceMethod();
final Invocable methodInvocable = method.getInvocable();
final Method definitionMethod = methodInvocable.getDefinitionMethod();
final Metered annotation = definitionMethod.getAnnotation(Metered.class);

if (annotation != null) {
final Class<?> handlerClass = methodInvocable.getHandler().getHandlerClass();
final Meter meter = this.meters.get(chooseName(annotation.name(), annotation.absolute(), handlerClass, definitionMethod));
meter.mark();
}
}
}
}

private static class ExceptionMeterRequestEventListener implements RequestEventListener {
private final ConcurrentMap<Method, ExceptionMeterMetric> exceptionMeters;
private final ConcurrentMap<String, ExceptionMeterMetric> exceptionMeters;

public ExceptionMeterRequestEventListener(final ConcurrentMap<Method, ExceptionMeterMetric> exceptionMeters) {
public ExceptionMeterRequestEventListener(final ConcurrentMap<String, ExceptionMeterMetric> exceptionMeters) {
this.exceptionMeters = exceptionMeters;
}

@Override
public void onEvent(RequestEvent event) {
if (event.getType() == RequestEvent.Type.ON_EXCEPTION) {
final ResourceMethod method = event.getUriInfo().getMatchedResourceMethod();
final ExceptionMeterMetric metric = (method != null) ?
this.exceptionMeters.get(method.getInvocable().getDefinitionMethod()) : null;

if (metric != null) {
if (metric.cause.isAssignableFrom(event.getException().getClass()) ||
(event.getException().getCause() != null &&
metric.cause.isAssignableFrom(event.getException().getCause().getClass()))) {
metric.meter.mark();

if (method != null) {
final Invocable methodInvocable = method.getInvocable();
final Method definitionMethod = methodInvocable.getDefinitionMethod();
final ExceptionMetered annotation = definitionMethod.getAnnotation(ExceptionMetered.class);

if (annotation != null) {
final Class<?> handlerClass = methodInvocable.getHandler().getHandlerClass();
final ExceptionMeterMetric metric = this.exceptionMeters.get(chooseName(annotation.name(), annotation.absolute(), handlerClass, definitionMethod));

if (metric.cause.isAssignableFrom(event.getException().getClass()) ||
(event.getException().getCause() != null &&
metric.cause.isAssignableFrom(event.getException().getCause().getClass()))) {
metric.meter.mark();
}
}
}
}
Expand Down Expand Up @@ -204,56 +222,50 @@ public RequestEventListener onRequest(final RequestEvent event) {
}

private void registerTimedAnnotations(final ResourceMethod method) {
final Method definitionMethod = method.getInvocable().getDefinitionMethod();
final Invocable methodInvocable = method.getInvocable();
final Method definitionMethod = methodInvocable.getDefinitionMethod();
final Timed annotation = definitionMethod.getAnnotation(Timed.class);

if (annotation != null) {
timers.putIfAbsent(definitionMethod, timerMetric(this.metrics, method, annotation));
if (annotation != null) {
final Class<?> handlerClass = methodInvocable.getHandler().getHandlerClass();
String methodName = chooseName(annotation.name(), annotation.absolute(), handlerClass, definitionMethod);
timers.putIfAbsent(methodName, this.metrics.timer(methodName));
}
}

private void registerMeteredAnnotations(final ResourceMethod method) {
final Method definitionMethod = method.getInvocable().getDefinitionMethod();
final Invocable methodInvocable = method.getInvocable();
final Method definitionMethod = methodInvocable.getDefinitionMethod();
final Metered annotation = definitionMethod.getAnnotation(Metered.class);

if (annotation != null) {
meters.putIfAbsent(definitionMethod, meterMetric(metrics, method, annotation));
if (annotation != null) {
final Class<?> handlerClass = methodInvocable.getHandler().getHandlerClass();
String methodName = chooseName(annotation.name(), annotation.absolute(), handlerClass, definitionMethod);
meters.putIfAbsent(methodName, this.metrics.meter(methodName));
}
}

private void registerExceptionMeteredAnnotations(final ResourceMethod method) {
final Method definitionMethod = method.getInvocable().getDefinitionMethod();
final Invocable methodInvocable = method.getInvocable();
final Method definitionMethod = methodInvocable.getDefinitionMethod();
final ExceptionMetered annotation = definitionMethod.getAnnotation(ExceptionMetered.class);

if (annotation != null) {
exceptionMeters.putIfAbsent(definitionMethod, new ExceptionMeterMetric(metrics, method, annotation));
if (annotation != null) {
final Class<?> handlerClass = methodInvocable.getHandler().getHandlerClass();
String methodName = chooseName(annotation.name(), annotation.absolute(), handlerClass, definitionMethod);
exceptionMeters.putIfAbsent(methodName, new ExceptionMeterMetric(metrics, handlerClass, definitionMethod, annotation));
}
}

private static Timer timerMetric(final MetricRegistry registry,
final ResourceMethod method,
final Timed timed) {
final String name = chooseName(timed.name(), timed.absolute(), method);
return registry.timer(name);
}

private static Meter meterMetric(final MetricRegistry registry,
final ResourceMethod method,
final Metered metered) {
final String name = chooseName(metered.name(), metered.absolute(), method);
return registry.meter(name);
}

protected static String chooseName(final String explicitName, final boolean absolute, final ResourceMethod method, final String... suffixes) {
protected static String chooseName(final String explicitName, final boolean absolute, final Class<?> handlerClass,
final Method definitionMethod, final String... suffixes) {
if (explicitName != null && !explicitName.isEmpty()) {
if (absolute) {
return explicitName;
}
return name(method.getInvocable().getDefinitionMethod().getDeclaringClass(), explicitName);
return name(handlerClass, explicitName);
}

return name(name(method.getInvocable().getDefinitionMethod().getDeclaringClass(),
method.getInvocable().getDefinitionMethod().getName()),
suffixes);
return name(name(handlerClass, definitionMethod.getName()), suffixes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.codahale.metrics.jersey2.resources.InstrumentedChildResource;
import com.codahale.metrics.jersey2.resources.InstrumentedResource;
import com.codahale.metrics.jersey2.resources.InstrumentedSecondChildResource;
import com.codahale.metrics.jersey2.resources.InstrumentedSubResource;
import org.glassfish.jersey.client.ClientResponse;
import org.glassfish.jersey.server.ResourceConfig;
Expand Down Expand Up @@ -41,6 +43,8 @@ protected Application configure() {
ResourceConfig config = new ResourceConfig();
config = config.register(new MetricsFeature(this.registry));
config = config.register(InstrumentedResource.class);
config = config.register(InstrumentedChildResource.class);
config = config.register(InstrumentedSecondChildResource.class);

return config;
}
Expand All @@ -57,6 +61,42 @@ public void timedMethodsAreTimed() {
assertThat(timer.getCount()).isEqualTo(1);
}

@Test
public void absoluteTimedMethodsAreTimed() {
assertThat(target("timed/absolute")
.request()
.get(String.class))
.isEqualTo("yay");

final Timer timer = registry.timer("absoluteTimed");

assertThat(timer.getCount()).isEqualTo(1);
}

@Test
public void namedTimedMethodsAreTimed() {
assertThat(target("timed/named")
.request()
.get(String.class))
.isEqualTo("yay");

final Timer timer = registry.timer(name(InstrumentedResource.class, "namedTimed"));

assertThat(timer.getCount()).isEqualTo(1);
}

@Test
public void childTimedMethodsAreTimed() {
assertThat(target("/child/timed")
.request()
.get(String.class))
.isEqualTo("yay");

final Timer timer = registry.timer(name(InstrumentedChildResource.class, "timed"));

assertThat(timer.getCount()).isEqualTo(1);
}

@Test
public void meteredMethodsAreMetered() {
assertThat(target("metered")
Expand All @@ -68,6 +108,28 @@ public void meteredMethodsAreMetered() {
assertThat(meter.getCount()).isEqualTo(1);
}

@Test
public void absoluteMeteredMethodsAreMetered() {
assertThat(target("metered/absolute")
.request()
.get(String.class))
.isEqualTo("woo");

final Meter meter = registry.meter("absoluteMetered");
assertThat(meter.getCount()).isEqualTo(1);
}

@Test
public void namedMeteredMethodsAreMetered() {
assertThat(target("metered/named")
.request()
.get(String.class))
.isEqualTo("woo");

final Meter meter = registry.meter(name(InstrumentedResource.class, "namedMetered"));
assertThat(meter.getCount()).isEqualTo(1);
}

@Test
public void exceptionMeteredMethodsAreExceptionMetered() {
final Meter meter = registry.meter(name(InstrumentedResource.class,
Expand Down Expand Up @@ -95,6 +157,57 @@ public void exceptionMeteredMethodsAreExceptionMetered() {
assertThat(meter.getCount()).isEqualTo(1);
}

@Test
public void absoluteExceptionMeteredMethodsAreExceptionMetered() {
final Meter meter = registry.meter("absoluteExceptionMetered");

assertThat(target("exception-metered/absolute")
.request()
.get(String.class))
.isEqualTo("fuh");

assertThat(meter.getCount()).isZero();

try {
target("exception-metered/absolute")
.queryParam("splode", true)
.request()
.get(String.class);

failBecauseExceptionWasNotThrown(ProcessingException.class);
} catch (ProcessingException e) {
assertThat(e.getCause()).isInstanceOf(IOException.class);
}

assertThat(meter.getCount()).isEqualTo(1);
}

@Test
public void namedExceptionMeteredMethodsAreExceptionMetered() {
final Meter meter = registry.meter(name(InstrumentedResource.class,
"namedExceptionMeteredOtherName"));

assertThat(target("exception-metered/named")
.request()
.get(String.class))
.isEqualTo("fuh");

assertThat(meter.getCount()).isZero();

try {
target("exception-metered/named")
.queryParam("splode", true)
.request()
.get(String.class);

failBecauseExceptionWasNotThrown(ProcessingException.class);
} catch (ProcessingException e) {
assertThat(e.getCause()).isInstanceOf(IOException.class);
}

assertThat(meter.getCount()).isEqualTo(1);
}

@Test
public void testResourceNotFound() {
final Response response = target().path("not-found").request().get();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.codahale.metrics.jersey2.resources;

import javax.ws.rs.Path;

@Path("/child")
public class InstrumentedChildResource extends InstrumentedParentResource {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.codahale.metrics.jersey2.resources;

import com.codahale.metrics.annotation.Timed;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

@Produces(MediaType.TEXT_PLAIN)
public class InstrumentedParentResource {
@GET
@Timed
@Path("/timed")
public String timed() {
return "yay";
}
}
Loading