Skip to content

Commit 6267929

Browse files
committed
Split AWS Lambda instrumentation for streaming and regular handlers.
1 parent 9eaf5a0 commit 6267929

File tree

2 files changed

+131
-7
lines changed

2 files changed

+131
-7
lines changed

dd-java-agent/instrumentation/aws-lambda-handler/src/main/java/datadog/trace/instrumentation/aws/v1/lambda/LambdaHandlerInstrumentation.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,7 @@ public void methodAdvice(MethodTransformer transformer) {
7171
.and(named("handleRequest"))
7272
.and(takesArgument(1, named("com.amazonaws.services.lambda.runtime.Context"))),
7373
getClass().getName() + "$ExtensionCommunicationAdvice");
74-
// three args (streaming)
75-
transformer.applyAdvice(
76-
isMethod()
77-
.and(named("handleRequest"))
78-
.and(takesArgument(2, named("com.amazonaws.services.lambda.runtime.Context"))),
79-
getClass().getName() + "$ExtensionCommunicationAdvice");
8074
// full spec here : https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html
81-
8275
}
8376

8477
public static class ExtensionCommunicationAdvice {
@@ -88,7 +81,10 @@ static AgentScope enter(
8881
@Advice.Argument(0) final Object event,
8982
@Origin("#m") final String methodName) {
9083

84+
System.out.println("Not-Streaming ExtensionCommunicationAdvice.enter()");
85+
9186
if (CallDepthThreadLocalMap.incrementCallDepth(RequestHandler.class) > 0) {
87+
System.out.println("returning");
9288
return null;
9389
}
9490

@@ -110,7 +106,10 @@ static void exit(
110106
@Advice.Return(typing = DYNAMIC) final Object result,
111107
@Advice.Thrown final Throwable throwable) {
112108

109+
System.out.println("Not-Streaming ExtensionCommunicationAdvice.exit()");
110+
113111
if (scope == null) {
112+
System.out.println("returning");
114113
return;
115114
}
116115

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package datadog.trace.instrumentation.aws.v1.lambda;
2+
3+
import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.implementsInterface;
4+
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
5+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan;
6+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan;
7+
import static datadog.trace.instrumentation.aws.v1.lambda.LambdaHandlerDecorator.INVOCATION_SPAN_NAME;
8+
import static net.bytebuddy.asm.Advice.Enter;
9+
import static net.bytebuddy.asm.Advice.OnMethodEnter;
10+
import static net.bytebuddy.asm.Advice.OnMethodExit;
11+
import static net.bytebuddy.asm.Advice.Origin;
12+
import static net.bytebuddy.asm.Advice.This;
13+
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
14+
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
15+
16+
import com.amazonaws.services.lambda.runtime.RequestHandler;
17+
import com.google.auto.service.AutoService;
18+
import datadog.trace.agent.tooling.Instrumenter;
19+
import datadog.trace.agent.tooling.InstrumenterModule;
20+
import datadog.trace.bootstrap.CallDepthThreadLocalMap;
21+
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
22+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
23+
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
24+
import net.bytebuddy.asm.Advice;
25+
import net.bytebuddy.description.type.TypeDescription;
26+
import net.bytebuddy.matcher.ElementMatcher;
27+
28+
@AutoService(InstrumenterModule.class)
29+
public class LambdaStreamHandlerInstrumentation extends InstrumenterModule.Tracing
30+
implements Instrumenter.ForTypeHierarchy {
31+
32+
// these must remain as String literals so they can be easily be shared (copied) with the nested
33+
// advice classes
34+
private static final String HANDLER_ENV_NAME = "_HANDLER";
35+
36+
public LambdaStreamHandlerInstrumentation() {
37+
super("aws-lambda");
38+
}
39+
40+
@Override
41+
public String hierarchyMarkerType() {
42+
return "com.amazonaws.services.lambda.runtime.RequestStreamHandler";
43+
}
44+
45+
@Override
46+
public ElementMatcher<TypeDescription> hierarchyMatcher() {
47+
return implementsInterface(
48+
named(hierarchyMarkerType())
49+
.or(named("com.amazonaws.services.lambda.runtime.RequestHandler")));
50+
}
51+
52+
@Override
53+
public String[] helperClassNames() {
54+
return new String[] {
55+
packageName + ".LambdaHandlerDecorator",
56+
};
57+
}
58+
59+
@Override
60+
protected boolean defaultEnabled() {
61+
final String handler = System.getenv(HANDLER_ENV_NAME);
62+
return null != handler;
63+
}
64+
65+
@Override
66+
public void methodAdvice(MethodTransformer transformer) {
67+
// three args (streaming)
68+
transformer.applyAdvice(
69+
isMethod()
70+
.and(named("handleRequest"))
71+
.and(takesArgument(2, named("com.amazonaws.services.lambda.runtime.Context"))),
72+
getClass().getName() + "$ExtensionCommunicationAdvice");
73+
// full spec here : https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html
74+
}
75+
76+
public static class ExtensionCommunicationAdvice {
77+
@OnMethodEnter
78+
static AgentScope enter(
79+
@This final Object that,
80+
@Advice.Argument(0) final Object event,
81+
@Origin("#m") final String methodName) {
82+
83+
System.out.println("Streaming ExtensionCommunicationAdvice.enter()");
84+
85+
if (CallDepthThreadLocalMap.incrementCallDepth(RequestHandler.class) > 0) {
86+
System.out.println("returning");
87+
return null;
88+
}
89+
90+
AgentSpan.Context lambdaContext = AgentTracer.get().notifyExtensionStart(event);
91+
final AgentSpan span;
92+
if (null == lambdaContext) {
93+
span = startSpan(INVOCATION_SPAN_NAME);
94+
} else {
95+
span = startSpan(INVOCATION_SPAN_NAME, lambdaContext);
96+
}
97+
final AgentScope scope = activateSpan(span);
98+
return scope;
99+
}
100+
101+
@OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
102+
static void exit(
103+
@Origin String method,
104+
@Enter final AgentScope scope,
105+
@Advice.Thrown final Throwable throwable) {
106+
107+
System.out.println("Streaming ExtensionCommunicationAdvice.exit()");
108+
109+
if (scope == null) {
110+
System.out.println("returning");
111+
return;
112+
}
113+
114+
CallDepthThreadLocalMap.reset(RequestHandler.class);
115+
116+
try {
117+
final AgentSpan span = scope.span();
118+
span.finish();
119+
AgentTracer.get().notifyExtensionEnd(span, null, null != throwable);
120+
} finally {
121+
scope.close();
122+
}
123+
}
124+
}
125+
}

0 commit comments

Comments
 (0)