use of com.newrelic.agent.instrumentation.tracing.TraceDetails in project newrelic-java-agent by newrelic.
the class FinalClassTransformer method addModifiedMethodAnnotation.
private ClassVisitor addModifiedMethodAnnotation(ClassVisitor cv, final InstrumentationContext context, final ClassLoader loader) {
return new ClassVisitor(WeaveUtils.ASM_API_LEVEL, cv) {
private String className;
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
className = name;
super.visit(version, access, name, signature, superName, interfaces);
}
/**
* @see InstrumentedMethod#instrumentationTypes()
* @see InstrumentedMethod#instrumentationNames()
* @see InstrumentedMethod#dispatcher()
*/
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
Method method = new Method(name, desc);
if (context.isModified(method)) {
if (loader != null) {
TraceDetails traceDetails = context.getTraceInformation().getTraceAnnotations().get(method);
boolean dispatcher = false;
if (traceDetails != null) {
dispatcher = traceDetails.dispatcher();
}
AnnotationVisitor av = mv.visitAnnotation(Type.getDescriptor(InstrumentedMethod.class), true);
av.visit("dispatcher", dispatcher);
List<String> instrumentationNames = new ArrayList<>();
List<InstrumentationType> instrumentationTypes = new ArrayList<>();
Level logLevel = Level.FINER;
if (traceDetails != null) {
if (traceDetails.instrumentationSourceNames() != null) {
instrumentationNames.addAll(traceDetails.instrumentationSourceNames());
}
if (traceDetails.instrumentationTypes() != null) {
for (InstrumentationType type : traceDetails.instrumentationTypes()) {
instrumentationTypes.add(type);
}
}
if (traceDetails.isCustom()) {
logLevel = Level.FINE;
}
}
PointCut pointCut = context.getOldStylePointCut(method);
if (pointCut != null) {
instrumentationNames.add(pointCut.getClass().getName());
instrumentationTypes.add(InstrumentationType.Pointcut);
}
Collection<String> instrumentationPackages = context.getMergeInstrumentationPackages(method);
if (instrumentationPackages != null && !instrumentationPackages.isEmpty()) {
for (String current : instrumentationPackages) {
instrumentationNames.add(current);
instrumentationTypes.add(InstrumentationType.WeaveInstrumentation);
}
}
if (instrumentationNames.size() == 0) {
instrumentationNames.add("Unknown");
Agent.LOG.finest("Unknown instrumentation source for " + className + '.' + method);
}
if (instrumentationTypes.size() == 0) {
instrumentationTypes.add(InstrumentationType.Unknown);
Agent.LOG.finest("Unknown instrumentation type for " + className + '.' + method);
}
AnnotationVisitor visitArrayName = av.visitArray("instrumentationNames");
for (String current : instrumentationNames) {
// the key on this is ignored
visitArrayName.visit("", current);
}
visitArrayName.visitEnd();
AnnotationVisitor visitArrayType = av.visitArray("instrumentationTypes");
for (InstrumentationType type : instrumentationTypes) {
// the key on this is ignored
visitArrayType.visitEnum("", Type.getDescriptor(InstrumentationType.class), type.toString());
}
visitArrayType.visitEnd();
av.visitEnd();
if (Agent.LOG.isLoggable(logLevel)) {
Agent.LOG.log(logLevel, "Instrumented " + Type.getObjectType(className).getClassName() + '.' + method + ", " + instrumentationTypes + ", " + instrumentationNames);
}
}
}
return mv;
}
};
}
use of com.newrelic.agent.instrumentation.tracing.TraceDetails in project newrelic-java-agent by newrelic.
the class TraceByReturnTypeMatchVisitor method newClassMatchVisitor.
@Override
public ClassVisitor newClassMatchVisitor(ClassLoader loader, Class<?> classBeingRedefined, final ClassReader reader, ClassVisitor cv, final InstrumentationContext context) {
return new ClassVisitor(WeaveUtils.ASM_API_LEVEL, cv) {
private boolean isScalaFutureTrace = false;
private List<String> traceReturnTypeDescriptors = new ArrayList<>();
@Override
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
AnnotationVisitor av = super.visitAnnotation(descriptor, visible);
if (TRACE_BY_RETURN_TYPE_DESC.equals(descriptor)) {
isScalaFutureTrace = true;
av = new AnnotationVisitor(WeaveUtils.ASM_API_LEVEL, av) {
@Override
public AnnotationVisitor visitArray(String name) {
AnnotationVisitor av = super.visitArray(name);
if (TRACE_RETURN_TYPES_NAME.equals(name)) {
return new AnnotationVisitor(WeaveUtils.ASM_API_LEVEL, av) {
@Override
public void visit(String name, Object value) {
super.visit(name, value);
traceReturnTypeDescriptors.add(((Type) value).getDescriptor());
}
};
}
return av;
}
};
}
return av;
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (isScalaFutureTrace && isTracedMethod(descriptor)) {
Method method = new Method(name, descriptor);
TraceDetails traceDetails = TraceDetailsBuilder.newBuilder().setMetricName(method.getName()).setInstrumentationType(InstrumentationType.BuiltIn).setInstrumentationSourceName(TraceByReturnType.class.getName()).setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, MetricNames.CUSTOM, method.getName()).build();
context.addTrace(method, traceDetails);
}
return mv;
}
private boolean isTracedMethod(String descriptor) {
boolean matchFound = false;
for (String returnTypeDescriptor : traceReturnTypeDescriptors) {
if (descriptor.endsWith(returnTypeDescriptor)) {
matchFound = true;
break;
}
}
return matchFound;
}
};
}
use of com.newrelic.agent.instrumentation.tracing.TraceDetails in project newrelic-java-agent by newrelic.
the class TraceInformation method putTraceAnnotation.
void putTraceAnnotation(Method method, TraceDetails trace) {
if (traces == null) {
traces = new HashMap<>();
} else {
TraceDetails existing = traces.get(method);
if (existing != null) {
Agent.LOG.log(Level.FINEST, "Merging trace details {0} and {1} for method {2}", existing, trace, method);
trace = TraceDetailsBuilder.merge(existing, trace);
}
}
traces.put(method, trace);
}
use of com.newrelic.agent.instrumentation.tracing.TraceDetails in project newrelic-java-agent by newrelic.
the class FinalClassTransformer method addSupportabilityMetrics.
// Record that we applied "user" instrumentation to a class. Note: generates metric names based on class
// names. But should not cause a metric explosion because auto-generated classes are filtered by the
// ClassFileTransformer and never reach this point. If a metric explosion originates here, the root cause
// is a failure of our proxy-filtering algorithm.
private void addSupportabilityMetrics(ClassReader reader, String className, InstrumentationContext context) {
StatsService statsService = ServiceFactory.getStatsService();
if (statsService != null) {
for (Method m : context.getTimedMethods()) {
TraceDetails traceDetails = context.getTraceInformation().getTraceAnnotations().get(m);
if (traceDetails != null && traceDetails.isCustom()) {
String metricOrigin = MessageFormat.format(MetricNames.SUPPORTABILITY_INSTRUMENT, className.replace('/', '.'), m.getName(), m.getDescriptor());
statsService.doStatsWork(StatsWorks.getRecordMetricWork(metricOrigin, 1), metricOrigin);
}
}
}
}
use of com.newrelic.agent.instrumentation.tracing.TraceDetails in project newrelic-java-agent by newrelic.
the class CustomClassTransformer method addMatchesToTraces.
private void addMatchesToTraces(InstrumentationContext pContext, Match match) {
Collection<ExtensionClassAndMethodMatcher> matches = new ArrayList<>(extensionPointCuts);
matches.retainAll(match.getClassMatches().keySet());
if (!matches.isEmpty()) {
for (ExtensionClassAndMethodMatcher pc : matches) {
for (Method m : match.getMethods()) {
if (pc.getMethodMatcher().matches(MethodMatcher.UNSPECIFIED_ACCESS, m.getName(), m.getDescriptor(), match.getMethodAnnotations(m))) {
Method method = pContext.getBridgeMethods().get(m);
if (method != null) {
// we don't want to instrument bridge methods, we want to instrument the typed
// implementation because the bridge method will always call the typed implementation
// but direct calls to the typed instrumentation won't pass through the bridge method
m = method;
}
TraceDetails td = pc.getTraceDetails();
if (td.ignoreTransaction()) {
if (LOG.isFinerEnabled()) {
LOG.log(Level.FINER, MessageFormat.format("Matched method {0} for ignoring the transaction trace.", m.toString()));
}
pContext.addIgnoreTransactionMethod(m);
} else {
if (LOG.isFinerEnabled()) {
LOG.log(Level.FINER, MessageFormat.format("Matched method {0} for instrumentation.", m.toString()));
}
pContext.addTrace(m, td);
}
}
}
}
}
}
Aggregations