Skip to content

Commit e1ce7ce

Browse files
committed
servlet-2.2
1 parent f16388c commit e1ce7ce

File tree

3 files changed

+139
-100
lines changed

3 files changed

+139
-100
lines changed

instrumentation/servlet/servlet-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v2_2/Servlet2Advice.java

Lines changed: 88 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.opentelemetry.javaagent.bootstrap.http.HttpServerResponseCustomizerHolder;
1616
import io.opentelemetry.javaagent.bootstrap.servlet.AppServerBridge;
1717
import io.opentelemetry.javaagent.instrumentation.servlet.ServletRequestContext;
18+
import javax.annotation.Nullable;
1819
import javax.servlet.ServletRequest;
1920
import javax.servlet.ServletResponse;
2021
import javax.servlet.http.HttpServletRequest;
@@ -25,93 +26,110 @@
2526
@SuppressWarnings("unused")
2627
public class Servlet2Advice {
2728

28-
@Advice.OnMethodEnter(suppress = Throwable.class)
29-
public static void onEnter(
30-
@Advice.Argument(0) ServletRequest request,
31-
@Advice.Argument(value = 1, typing = Assigner.Typing.DYNAMIC) ServletResponse response,
32-
@Advice.Local("otelCallDepth") CallDepth callDepth,
33-
@Advice.Local("otelRequest") ServletRequestContext<HttpServletRequest> requestContext,
34-
@Advice.Local("otelContext") Context context,
35-
@Advice.Local("otelScope") Scope scope) {
29+
public static class AdviceScope {
30+
private static final VirtualField<ServletResponse, Integer> RESPONSE_STATUS =
31+
VirtualField.find(ServletResponse.class, Integer.class);
32+
private final CallDepth callDepth;
33+
private final ServletRequestContext<HttpServletRequest> requestContext;
34+
private final Context context;
35+
private final Scope scope;
36+
37+
public AdviceScope(
38+
CallDepth callDepth, HttpServletRequest request, HttpServletResponse response) {
39+
this.callDepth = callDepth;
40+
callDepth.getAndIncrement();
41+
42+
Context serverContext = helper().getServerContext(request);
43+
if (serverContext != null) {
44+
Context updatedContext = helper().updateContext(serverContext, request);
45+
if (updatedContext != serverContext) {
46+
// updateContext updated context, need to re-scope
47+
scope = updatedContext.makeCurrent();
48+
} else {
49+
scope = null;
50+
}
51+
requestContext = null;
52+
context = null;
53+
return;
54+
}
3655

37-
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
38-
return;
56+
Context parentContext = Java8BytecodeBridge.currentContext();
57+
requestContext = new ServletRequestContext<>(request);
58+
59+
if (!helper().shouldStart(parentContext, requestContext)) {
60+
context = null;
61+
scope = null;
62+
return;
63+
}
64+
65+
context = helper().start(parentContext, requestContext);
66+
scope = context.makeCurrent();
67+
// reset response status from previous request
68+
// (some servlet containers reuse response objects to reduce memory allocations)
69+
RESPONSE_STATUS.set(response, null);
70+
71+
HttpServerResponseCustomizerHolder.getCustomizer()
72+
.customize(context, response, Servlet2Accessor.INSTANCE);
3973
}
4074

41-
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
75+
public void exit(
76+
@Nullable Throwable throwable, HttpServletRequest request, HttpServletResponse response) {
4277

43-
callDepth = CallDepth.forClass(AppServerBridge.getCallDepthKey());
44-
callDepth.getAndIncrement();
78+
if (scope != null) {
79+
scope.close();
80+
}
4581

46-
Context serverContext = helper().getServerContext(httpServletRequest);
47-
if (serverContext != null) {
48-
Context updatedContext = helper().updateContext(serverContext, httpServletRequest);
49-
if (updatedContext != serverContext) {
50-
// updateContext updated context, need to re-scope
51-
scope = updatedContext.makeCurrent();
82+
boolean topLevel = callDepth.decrementAndGet() == 0;
83+
if (context == null && topLevel) {
84+
Context currentContext = Java8BytecodeBridge.currentContext();
85+
// Something else is managing the context, we're in the outermost level of Servlet
86+
// instrumentation and we have an uncaught throwable. Let's add it to the current span.
87+
if (throwable != null) {
88+
helper().recordException(currentContext, throwable);
89+
}
90+
// also capture request parameters as servlet attributes
91+
helper().captureServletAttributes(currentContext, request);
5292
}
53-
return;
54-
}
5593

56-
Context parentContext = Java8BytecodeBridge.currentContext();
57-
requestContext = new ServletRequestContext<>(httpServletRequest);
94+
if (scope == null || context == null) {
95+
return;
96+
}
5897

59-
if (!helper().shouldStart(parentContext, requestContext)) {
60-
return;
61-
}
98+
int responseStatusCode = HttpServletResponse.SC_OK;
99+
Integer responseStatus = RESPONSE_STATUS.get(response);
100+
if (responseStatus != null) {
101+
responseStatusCode = responseStatus;
102+
}
62103

63-
context = helper().start(parentContext, requestContext);
64-
scope = context.makeCurrent();
65-
// reset response status from previous request
66-
// (some servlet containers reuse response objects to reduce memory allocations)
67-
VirtualField.find(ServletResponse.class, Integer.class).set(response, null);
104+
helper().end(context, requestContext, response, responseStatusCode, throwable);
105+
}
106+
}
68107

69-
HttpServerResponseCustomizerHolder.getCustomizer()
70-
.customize(context, (HttpServletResponse) response, Servlet2Accessor.INSTANCE);
108+
@Nullable
109+
@Advice.OnMethodEnter(suppress = Throwable.class)
110+
public static AdviceScope onEnter(
111+
@Advice.Argument(0) ServletRequest request,
112+
@Advice.Argument(value = 1, typing = Assigner.Typing.DYNAMIC) ServletResponse response) {
113+
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
114+
return null;
115+
}
116+
return new AdviceScope(
117+
CallDepth.forClass(AppServerBridge.getCallDepthKey()),
118+
(HttpServletRequest) request,
119+
(HttpServletResponse) response);
71120
}
72121

73122
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
74123
public static void stopSpan(
75124
@Advice.Argument(0) ServletRequest request,
76125
@Advice.Argument(1) ServletResponse response,
77-
@Advice.Thrown Throwable throwable,
78-
@Advice.Local("otelCallDepth") CallDepth callDepth,
79-
@Advice.Local("otelRequest") ServletRequestContext<HttpServletRequest> requestContext,
80-
@Advice.Local("otelContext") Context context,
81-
@Advice.Local("otelScope") Scope scope) {
82-
83-
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
126+
@Advice.Thrown @Nullable Throwable throwable,
127+
@Advice.Enter @Nullable AdviceScope adviceScope) {
128+
if (adviceScope == null
129+
|| !(request instanceof HttpServletRequest)
130+
|| !(response instanceof HttpServletResponse)) {
84131
return;
85132
}
86-
87-
if (scope != null) {
88-
scope.close();
89-
}
90-
91-
boolean topLevel = callDepth.decrementAndGet() == 0;
92-
if (context == null && topLevel) {
93-
Context currentContext = Java8BytecodeBridge.currentContext();
94-
// Something else is managing the context, we're in the outermost level of Servlet
95-
// instrumentation and we have an uncaught throwable. Let's add it to the current span.
96-
if (throwable != null) {
97-
helper().recordException(currentContext, throwable);
98-
}
99-
// also capture request parameters as servlet attributes
100-
helper().captureServletAttributes(currentContext, (HttpServletRequest) request);
101-
}
102-
103-
if (scope == null || context == null) {
104-
return;
105-
}
106-
107-
int responseStatusCode = HttpServletResponse.SC_OK;
108-
Integer responseStatus = VirtualField.find(ServletResponse.class, Integer.class).get(response);
109-
if (responseStatus != null) {
110-
responseStatusCode = responseStatus;
111-
}
112-
113-
helper()
114-
.end(
115-
context, requestContext, (HttpServletResponse) response, responseStatusCode, throwable);
133+
adviceScope.exit(throwable, (HttpServletRequest) request, (HttpServletResponse) response);
116134
}
117135
}

instrumentation/servlet/servlet-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v2_2/Servlet2InstrumentationModule.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111
import com.google.auto.service.AutoService;
1212
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
1313
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
14+
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
1415
import io.opentelemetry.javaagent.instrumentation.servlet.common.response.HttpServletResponseInstrumentation;
1516
import io.opentelemetry.javaagent.instrumentation.servlet.common.service.ServletAndFilterInstrumentation;
1617
import java.util.Arrays;
1718
import java.util.List;
1819
import net.bytebuddy.matcher.ElementMatcher;
1920

2021
@AutoService(InstrumentationModule.class)
21-
public class Servlet2InstrumentationModule extends InstrumentationModule {
22+
public class Servlet2InstrumentationModule extends InstrumentationModule
23+
implements ExperimentalInstrumentationModule {
2224
private static final String BASE_PACKAGE = "javax.servlet";
2325

2426
public Servlet2InstrumentationModule() {
@@ -43,4 +45,9 @@ public List<TypeInstrumentation> typeInstrumentations() {
4345
private static String adviceClassName(String suffix) {
4446
return Servlet2InstrumentationModule.class.getPackage().getName() + suffix;
4547
}
48+
49+
@Override
50+
public boolean isIndyReady() {
51+
return true;
52+
}
4653
}

instrumentation/servlet/servlet-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v2_2/Servlet2ResponseSendAdvice.java

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,47 +12,61 @@
1212
import io.opentelemetry.instrumentation.api.incubator.semconv.util.ClassAndMethod;
1313
import io.opentelemetry.javaagent.bootstrap.CallDepth;
1414
import io.opentelemetry.javaagent.instrumentation.servlet.common.response.HttpServletResponseAdviceHelper;
15+
import javax.annotation.Nullable;
1516
import javax.servlet.http.HttpServletResponse;
1617
import net.bytebuddy.asm.Advice;
1718

1819
@SuppressWarnings("unused")
1920
public class Servlet2ResponseSendAdvice {
2021

21-
@Advice.OnMethodEnter(suppress = Throwable.class)
22-
public static void start(
23-
@Advice.Origin("#t") Class<?> declaringClass,
24-
@Advice.Origin("#m") String methodName,
25-
@Advice.Local("otelMethod") ClassAndMethod classAndMethod,
26-
@Advice.Local("otelContext") Context context,
27-
@Advice.Local("otelScope") Scope scope,
28-
@Advice.Local("otelCallDepth") CallDepth callDepth) {
29-
callDepth = CallDepth.forClass(HttpServletResponse.class);
30-
if (callDepth.getAndIncrement() > 0) {
31-
return;
22+
public static class AdviceScope {
23+
private final CallDepth callDepth;
24+
private final ClassAndMethod classAndMethod;
25+
private final Context context;
26+
private final Scope scope;
27+
28+
public AdviceScope(CallDepth callDepth, Class<?> declaringClass, String methodName) {
29+
this.callDepth = callDepth;
30+
if (callDepth.getAndIncrement() > 0) {
31+
this.classAndMethod = null;
32+
this.context = null;
33+
this.scope = null;
34+
return;
35+
}
36+
37+
HttpServletResponseAdviceHelper.StartResult result =
38+
HttpServletResponseAdviceHelper.startSpan(
39+
responseInstrumenter(), declaringClass, methodName);
40+
if (result == null) {
41+
this.classAndMethod = null;
42+
this.context = null;
43+
this.scope = null;
44+
return;
45+
}
46+
this.classAndMethod = result.getClassAndMethod();
47+
this.context = result.getContext();
48+
this.scope = result.getScope();
3249
}
3350

34-
HttpServletResponseAdviceHelper.StartResult result =
35-
HttpServletResponseAdviceHelper.startSpan(
36-
responseInstrumenter(), declaringClass, methodName);
37-
if (result != null) {
38-
classAndMethod = result.getClassAndMethod();
39-
context = result.getContext();
40-
scope = result.getScope();
51+
public void exit(@Nullable Throwable throwable) {
52+
if (callDepth.decrementAndGet() > 0) {
53+
return;
54+
}
55+
HttpServletResponseAdviceHelper.stopSpan(
56+
responseInstrumenter(), throwable, context, scope, classAndMethod);
4157
}
4258
}
4359

60+
@Advice.OnMethodEnter(suppress = Throwable.class)
61+
public static AdviceScope start(
62+
@Advice.Origin("#t") Class<?> declaringClass, @Advice.Origin("#m") String methodName) {
63+
return new AdviceScope(
64+
CallDepth.forClass(HttpServletResponse.class), declaringClass, methodName);
65+
}
66+
4467
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
4568
public static void stopSpan(
46-
@Advice.Thrown Throwable throwable,
47-
@Advice.Local("otelMethod") ClassAndMethod classAndMethod,
48-
@Advice.Local("otelContext") Context context,
49-
@Advice.Local("otelScope") Scope scope,
50-
@Advice.Local("otelCallDepth") CallDepth callDepth) {
51-
if (callDepth.decrementAndGet() > 0) {
52-
return;
53-
}
54-
55-
HttpServletResponseAdviceHelper.stopSpan(
56-
responseInstrumenter(), throwable, context, scope, classAndMethod);
69+
@Advice.Thrown @Nullable Throwable throwable, @Advice.Enter AdviceScope adviceScope) {
70+
adviceScope.exit(throwable);
5771
}
5872
}

0 commit comments

Comments
 (0)