package org.stagemonitor.tracing.profiler; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.ParameterDescription; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatchers; import org.stagemonitor.core.instrument.StagemonitorByteBuddyTransformer; 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 org.stagemonitor.core.instrument.StagemonitorClassNameMatcher.isInsideMonitoredProject; public class ProfilingTransformer extends StagemonitorByteBuddyTransformer { @Override public ElementMatcher.Junction<TypeDescription> getExtraExcludeTypeMatcher() { return makeSureClassesAreNotProfiledTwice(); } /* * If this is a subclass of ProfilingTransformer, make sure to not instrument classes * which are matched by ProfilingTransformer */ private ElementMatcher.Junction<TypeDescription> makeSureClassesAreNotProfiledTwice() { return isSubclass() ? isInsideMonitoredProject() : ElementMatchers.<TypeDescription>none(); } private boolean isSubclass() { return getClass() != ProfilingTransformer.class; } @Override protected Class<? extends StagemonitorByteBuddyTransformer> getAdviceClass() { return ProfilingTransformer.class; } @Advice.OnMethodEnter public static void enter(@ProfilerSignature String signature) { Profiler.start(signature); } @Advice.OnMethodExit(onThrowable = Throwable.class) public static void exit() { Profiler.stop(); } @Override protected int getOrder() { return Integer.MAX_VALUE; } @Override protected List<StagemonitorDynamicValue<?>> getDynamicValues() { return Collections.<StagemonitorDynamicValue<?>>singletonList(new ProfilerDynamicValue()); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface ProfilerSignature { } public static class ProfilerDynamicValue extends StagemonitorDynamicValue<ProfilerSignature> { @Override public Class<ProfilerSignature> getAnnotationClass() { return ProfilerSignature.class; } @Override protected Object doResolve(TypeDescription instrumentedType, MethodDescription method, ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<ProfilerSignature> annotation, Assigner assigner, boolean initialized) { final String returnType = method.getReturnType().asErasure().getSimpleName(); final String className = method.getDeclaringType().getTypeName(); return String.format("%s %s.%s(%s)", returnType, className, method.getName(), getSignature(method)); } public String getSignature(MethodDescription instrumentedMethod) { StringBuilder stringBuilder = new StringBuilder(); boolean comma = false; for (TypeDescription typeDescription : instrumentedMethod.getParameters().asTypeList().asErasures()) { if (comma) { stringBuilder.append(','); } else { comma = true; } stringBuilder.append(typeDescription.getSimpleName()); } return stringBuilder.toString(); } } }