package org.stagemonitor.core.metrics.annotations; import com.codahale.metrics.Timer; import com.codahale.metrics.annotation.Timed; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.matcher.ElementMatcher; import org.stagemonitor.core.Stagemonitor; import org.stagemonitor.core.instrument.StagemonitorByteBuddyTransformer; import org.stagemonitor.core.metrics.metrics2.MetricName; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Collections; import java.util.List; import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; import static org.stagemonitor.core.metrics.metrics2.MetricName.name; /** * Implementation for the {@link Timed} annotation */ public class TimedTransformer extends StagemonitorByteBuddyTransformer { private final static MetricName.MetricNameTemplate metricNameTemplate = name("timer").templateFor("signature"); @Override protected ElementMatcher.Junction<MethodDescription> getExtraMethodElementMatcher() { return isAnnotatedWith(Timed.class); } @Override protected List<StagemonitorDynamicValue<?>> getDynamicValues() { return Collections.<StagemonitorDynamicValue<?>>singletonList(new TimedSignatureDynamicValue()); } @Advice.OnMethodEnter public static Timer.Context startTimer(@TimedSignature String signature) { return Stagemonitor.getMetric2Registry().timer(getTimerName(signature)).time(); } public static MetricName getTimerName(String signature) { return metricNameTemplate.build(signature); } @Advice.OnMethodExit(onThrowable = Throwable.class) public static void stopTimer(@Advice.Enter Timer.Context timer) { timer.stop(); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface TimedSignature { } public static class TimedSignatureDynamicValue extends MetricAnnotationSignatureDynamicValue<TimedSignature> { @Override protected NamingParameters getNamingParameters(MethodDescription instrumentedMethod) { if (instrumentedMethod.getDeclaredAnnotations().isAnnotationPresent(Timed.class)) { final Timed timed = instrumentedMethod.getDeclaredAnnotations().ofType(Timed.class).loadSilent(); return new NamingParameters(timed.name(), timed.absolute()); } else { return new NamingParameters("", false); } } @Override public Class<TimedSignature> getAnnotationClass() { return TimedSignature.class; } } }