use of com.newrelic.agent.bridge.Transaction in project newrelic-java-agent by newrelic.
the class SpringController_Instrumentation method requestMapping.
@WeaveWithAnnotation(annotationClasses = { "org.springframework.web.bind.annotation.RequestMapping", "org.springframework.web.bind.annotation.PatchMapping", "org.springframework.web.bind.annotation.PutMapping", "org.springframework.web.bind.annotation.GetMapping", "org.springframework.web.bind.annotation.PostMapping", "org.springframework.web.bind.annotation.DeleteMapping" })
@WeaveIntoAllMethods
@Trace
private static void requestMapping() {
Transaction transaction = AgentBridge.getAgent().getTransaction(false);
if (transaction != null) {
RequestMapping rootPathMapping = Weaver.getClassAnnotation(RequestMapping.class);
String rootPath = null;
if (rootPathMapping != null) {
rootPath = SpringControllerUtility.getPathValue(rootPathMapping.value(), rootPathMapping.path());
}
// PUT, DELETE, POST, GET
if (Weaver.getMethodAnnotation(RequestMapping.class) != null) {
RequestMapping methodPathMapping = Weaver.getMethodAnnotation(RequestMapping.class);
String methodPath = SpringControllerUtility.getPathValue(methodPathMapping.value(), methodPathMapping.path());
processAnnotations(transaction, methodPathMapping.method(), rootPath, methodPath, MethodHandles.lookup().lookupClass());
} else if (Weaver.getMethodAnnotation(PutMapping.class) != null) {
PutMapping methodPathMapping = Weaver.getMethodAnnotation(PutMapping.class);
String methodPath = SpringControllerUtility.getPathValue(methodPathMapping.value(), methodPathMapping.path());
processAnnotations(transaction, new RequestMethod[] { RequestMethod.PUT }, rootPath, methodPath, MethodHandles.lookup().lookupClass());
} else if (Weaver.getMethodAnnotation(DeleteMapping.class) != null) {
DeleteMapping methodPathMapping = Weaver.getMethodAnnotation(DeleteMapping.class);
String methodPath = SpringControllerUtility.getPathValue(methodPathMapping.value(), methodPathMapping.path());
processAnnotations(transaction, new RequestMethod[] { RequestMethod.DELETE }, rootPath, methodPath, MethodHandles.lookup().lookupClass());
} else if (Weaver.getMethodAnnotation(PostMapping.class) != null) {
PostMapping methodPathMapping = Weaver.getMethodAnnotation(PostMapping.class);
String methodPath = SpringControllerUtility.getPathValue(methodPathMapping.value(), methodPathMapping.path());
processAnnotations(transaction, new RequestMethod[] { RequestMethod.POST }, rootPath, methodPath, MethodHandles.lookup().lookupClass());
} else if (Weaver.getMethodAnnotation(PatchMapping.class) != null) {
PatchMapping methodPathMapping = Weaver.getMethodAnnotation(PatchMapping.class);
String methodPath = SpringControllerUtility.getPathValue(methodPathMapping.value(), methodPathMapping.path());
processAnnotations(transaction, new RequestMethod[] { RequestMethod.PATCH }, rootPath, methodPath, MethodHandles.lookup().lookupClass());
} else if (Weaver.getMethodAnnotation(GetMapping.class) != null) {
GetMapping methodPathMapping = Weaver.getMethodAnnotation(GetMapping.class);
String methodPath = SpringControllerUtility.getPathValue(methodPathMapping.value(), methodPathMapping.path());
processAnnotations(transaction, new RequestMethod[] { RequestMethod.GET }, rootPath, methodPath, MethodHandles.lookup().lookupClass());
}
}
}
use of com.newrelic.agent.bridge.Transaction in project newrelic-java-agent by newrelic.
the class SpringController_Instrumentation method instrumentation.
@WeaveWithAnnotation(annotationClasses = { "org.springframework.web.bind.annotation.RequestMapping" })
@WeaveIntoAllMethods
@Trace
private static void instrumentation() {
Transaction transaction = AgentBridge.getAgent().getTransaction(false);
if (transaction != null) {
RequestMapping rootPathMapping = Weaver.getClassAnnotation(RequestMapping.class);
RequestMapping methodPathMapping = Weaver.getMethodAnnotation(RequestMapping.class);
String rootPath = SpringControllerUtility.getPathValue(rootPathMapping);
String methodPath = SpringControllerUtility.getPathValue(methodPathMapping);
RequestMethod httpMethod = RequestMethod.GET;
RequestMethod[] methods = methodPathMapping.method();
if (methods.length > 0) {
httpMethod = methods[0];
}
if (rootPath == null && methodPath == null) {
AgentBridge.getAgent().getLogger().log(Level.FINE, "No path was specified for SpringController {0}", MethodHandles.lookup().lookupClass().getName());
} else {
String fullPath = SpringControllerUtility.getPath(rootPath, methodPath, httpMethod);
transaction.setTransactionName(TransactionNamePriority.FRAMEWORK_HIGH, true, "SpringController", fullPath);
}
}
}
use of com.newrelic.agent.bridge.Transaction in project newrelic-java-agent by newrelic.
the class TraceClassVisitor method visitMethod.
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
// skip bridge methods. Tracing will occur on impl method.
if ((access & Opcodes.ACC_BRIDGE) != 0) {
/*
* Some versions of the Agent (mid 3.20.* -> low 3.30.*) had a bug here that caused us to trace bridge
* methods, resulting in double counting of @Trace'd methods. This bug only affected late versions of JDK7
* and all versions of JDK8 due to annotations being automatically copied by the JVM over to bridge methods.
*/
return mv;
}
Method method = new Method(name, desc);
if (traceInfo.getIgnoreTransactionMethods().contains(method)) {
instrumentationContext.markAsModified();
return new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {
@Override
protected void onMethodEnter() {
BridgeUtils.getCurrentTransaction(this);
BytecodeGenProxyBuilder.newBuilder(Transaction.class, this, true).build().ignore();
}
};
} else {
final TraceDetails trace = traceInfo.getTraceAnnotations().get(method);
if (null != trace) {
tracedMethods.add(method);
PointCut pointCut = instrumentationContext.getOldStylePointCut(method);
if (pointCut == null) {
boolean custom = trace.isCustom();
boolean noticeSql = noticeSqlMethods.contains(method);
if (trace.excludeFromTransactionTrace() && trace.isLeaf()) {
mv = new FlyweightTraceMethodVisitor(className, mv, access, name, desc, trace, instrumentationContext.getClassBeingRedefined());
} else {
mv = new TraceMethodVisitor(className, mv, access, name, desc, trace, custom, noticeSql, instrumentationContext.getClassBeingRedefined());
if (!trace.getParameterAttributeNames().isEmpty()) {
for (ParameterAttributeName attr : trace.getParameterAttributeNames()) {
final ParameterAttributeName param = attr;
if (param.getMethodMatcher().matches(access, name, desc, null)) {
try {
final Type type = method.getArgumentTypes()[param.getIndex()];
if (type.getSort() == Type.ARRAY) {
Agent.LOG.log(Level.FINE, "Unable to record an attribute value for {0}.{1} because it is an array", className, method);
} else {
mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {
@Override
protected void onMethodEnter() {
super.getStatic(BridgeUtils.AGENT_BRIDGE_TYPE, BridgeUtils.PUBLIC_API_FIELD_NAME, BridgeUtils.PUBLIC_API_TYPE);
PublicApi api = BytecodeGenProxyBuilder.newBuilder(PublicApi.class, this, false).build();
push(param.getAttributeName());
loadArg(param.getIndex());
// if this is a primitive value we need to box it to an object
if (type.getSort() != Type.OBJECT) {
box(type);
}
Label objectLabel = newLabel();
Label skipLabel = newLabel();
Label popStackLabel = newLabel();
// dup the value for null check
dup();
ifNull(popStackLabel);
// dup the value for instanceOf check
dup();
instanceOf(Type.getType(Number.class));
ifZCmp(EQ, objectLabel);
// if this is a number, cast it to a number and call the
// addCustomParameter api that takes a number
checkCast(Type.getType(Number.class));
api.addCustomParameter("", 0);
goTo(skipLabel);
visitLabel(objectLabel);
// otherwise, it's a non-null object so call toString
invokeVirtual(Type.getType(Object.class), new Method("toString", Type.getType(String.class), new Type[0]));
api.addCustomParameter("", "");
goTo(skipLabel);
// the values originally on the stack won't be consumed by either
// of the api calls above if the attribute was null
visitLabel(popStackLabel);
pop();
pop();
pop();
visitLabel(skipLabel);
}
};
}
} catch (ArrayIndexOutOfBoundsException e) {
Agent.LOG.log(Level.FINEST, e, e.toString());
}
}
}
}
if (trace.rollupMetricName().length > 0) {
final int cacheId = AgentBridge.instrumentation.addToObjectCache(trace.rollupMetricName());
mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {
@Override
protected void onMethodEnter() {
getStatic(BridgeUtils.TRACED_METHOD_TYPE, BridgeUtils.CURRENT_TRANSACTION_FIELD_NAME, BridgeUtils.TRACED_METHOD_TYPE);
super.getStatic(BridgeUtils.AGENT_BRIDGE_TYPE, BridgeUtils.INSTRUMENTATION_FIELD_NAME, BridgeUtils.INSTRUMENTATION_TYPE);
Instrumentation instrumentation = BytecodeGenProxyBuilder.newBuilder(Instrumentation.class, this, true).build();
instrumentation.getCachedObject(cacheId);
super.checkCast(Type.getType(String[].class));
TracedMethod tracedMethod = BytecodeGenProxyBuilder.newBuilder(TracedMethod.class, this, false).build();
tracedMethod.setRollupMetricNames((String[]) null);
}
};
}
if (TransactionName.isSimpleTransactionName(trace.transactionName())) {
mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {
@Override
protected void onMethodEnter() {
TracedMethod tracedMethod = BytecodeGenProxyBuilder.newBuilder(TracedMethod.class, this, true).build();
getStatic(BridgeUtils.TRACED_METHOD_TYPE, BridgeUtils.CURRENT_TRANSACTION_FIELD_NAME, BridgeUtils.TRACED_METHOD_TYPE);
tracedMethod.nameTransaction(trace.transactionName().transactionNamePriority);
}
};
} else if (trace.transactionName() != null) {
mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {
@Override
protected void onMethodEnter() {
BridgeUtils.getCurrentTransaction(this);
Transaction transaction = BytecodeGenProxyBuilder.newBuilder(Transaction.class, this, true).build();
TransactionName transactionName = trace.transactionName();
transaction.setTransactionName(transactionName.transactionNamePriority, transactionName.override, transactionName.category, transactionName.path);
// the method returns a boolean. Discard it.
pop();
}
};
}
if (trace.isWebTransaction()) {
mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {
@Override
protected void onMethodExit(int opcode) {
getStatic(BridgeUtils.TRANSACTION_TYPE, BridgeUtils.CURRENT_TRANSACTION_FIELD_NAME, BridgeUtils.TRANSACTION_TYPE);
BytecodeGenProxyBuilder.newBuilder(Transaction.class, this, true).build().convertToWebTransaction();
}
};
}
if (null != trace.metricPrefix()) {
mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {
@Override
protected void onMethodExit(int opcode) {
// write: AgentBridge.getAgent().getTracedMethod.setMetricPrefix("usersPrefix")
this.invokeStatic(BridgeUtils.AGENT_BRIDGE_TYPE, new Method(BridgeUtils.AGENT_BRIDGE_GET_AGENT_METHOD, BridgeUtils.AGENT_BRIDGE_AGENT_TYPE, new Type[0]));
this.invokeVirtual(BridgeUtils.AGENT_BRIDGE_AGENT_TYPE, new Method(BridgeUtils.GET_TRACED_METHOD_METHOD_NAME, BridgeUtils.TRACED_METHOD_TYPE, new Type[0]));
BytecodeGenProxyBuilder.newBuilder(TracedMethod.class, this, true).build().setCustomMetricPrefix(trace.metricPrefix());
}
};
}
}
instrumentationContext.addTimedMethods(method);
} else {
Agent.LOG.warning(className + '.' + method + " is matched to trace, but it was already instrumented by " + pointCut.toString());
}
}
if (traceInfo.getIgnoreApdexMethods().contains(method)) {
instrumentationContext.markAsModified();
mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {
@Override
protected void onMethodEnter() {
invokeStatic(BridgeUtils.NEW_RELIC_API_TYPE, TraceMethodVisitor.IGNORE_APDEX_METHOD);
}
};
}
}
return mv;
}
use of com.newrelic.agent.bridge.Transaction in project newrelic-java-agent by newrelic.
the class FlyweightTraceMethodVisitor method onEveryExit.
/**
* This code is injected at every exit instruction, whether a return or an ATHROW.
*
* @see Transaction#finishFlyweightTracer(TracedMethod, long, long, String, String, String, String, String[])
*/
private void onEveryExit() {
Label skip = super.newLabel();
super.loadLocal(parentTracerLocal);
super.ifNull(skip);
BridgeUtils.getCurrentTransactionOrNull(this);
super.ifNull(skip);
BridgeUtils.getCurrentTransaction(this);
BytecodeGenProxyBuilder<Transaction> builder = BytecodeGenProxyBuilder.newBuilder(Transaction.class, this, true);
Variables loader = builder.getVariables();
String[] rollupMetricNames;
if (rollupMetricNamesCacheId >= 0) {
rollupMetricNames = loader.load(String[].class, new Runnable() {
@Override
public void run() {
getStatic(BridgeUtils.AGENT_BRIDGE_TYPE, BridgeUtils.INSTRUMENTATION_FIELD_NAME, BridgeUtils.INSTRUMENTATION_TYPE);
BytecodeGenProxyBuilder.newBuilder(Instrumentation.class, FlyweightTraceMethodVisitor.this, true).build().getCachedObject(rollupMetricNamesCacheId);
checkCast(Type.getType(String[].class));
}
});
} else {
rollupMetricNames = null;
}
// -1 and -2 are identifiers that tell the ApiBuilder's proxy to (-1) load a local variable and (-2) call
// System.nanoTime when those values are
// encountered
long startTime = loader.loadLocal(startTimeLocal, Type.LONG_TYPE, -1L);
long loadEndTime = loader.load(-2l, new Runnable() {
@Override
public void run() {
invokeStatic(Type.getType(System.class), new Method("nanoTime", Type.LONG_TYPE, new Type[0]));
}
});
Transaction transactionApi = builder.build();
transactionApi.finishFlyweightTracer(loader.loadLocal(parentTracerLocal, TracedMethod.class), startTime, loadEndTime, className, this.method.getName(), this.methodDesc, loader.loadLocal(metricNameLocal, String.class), rollupMetricNames);
super.visitLabel(skip);
}
use of com.newrelic.agent.bridge.Transaction in project newrelic-java-agent by newrelic.
the class AgentImplTest method testAsyncTracerShouldNotStartTxn.
@Test
public void testAsyncTracerShouldNotStartTxn() {
TransactionActivity txa = TransactionActivity.create(null, 0);
ClassMethodSignature sig = new ClassMethodSignature("class", "method", "methodDesc");
OtherRootTracer tracer = new OtherRootTracer(txa, sig, null, null, TracerFlags.ASYNC, System.nanoTime());
txa.tracerStarted(tracer);
Transaction txn = agentImpl.getTransaction();
Assert.assertTrue(txn instanceof NoOpTransaction);
Assert.assertFalse(txn instanceof com.newrelic.agent.Transaction);
}
Aggregations