Skip to content

Commit f1bef4a

Browse files
authored
Merge pull request #2 from DataDog/ban/fix-java-11-for-pr-3211
Enable compilation with Java 11 for Jetty 11 instrumentation
2 parents ae636a3 + c25ff24 commit f1bef4a

File tree

8 files changed

+147
-105
lines changed

8 files changed

+147
-105
lines changed

dd-java-agent/instrumentation/jetty-11/jetty-11.gradle

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
ext {
2+
minJavaVersionForTests = JavaVersion.VERSION_11
3+
}
4+
15
muzzle {
26
pass {
37
group = "org.eclipse.jetty"
@@ -17,13 +21,30 @@ testSets {
1721
}
1822
}
1923

24+
sourceSets {
25+
"main_java11" {
26+
java.srcDirs "${project.projectDir}/src/main/java11"
27+
}
28+
}
29+
30+
compileMain_java11Java.doFirst {
31+
if (!System.env.JAVA_11_HOME) {
32+
throw new GradleException('JAVA_11_HOME must be set to build Java 11 code')
33+
}
34+
options.fork = true
35+
options.forkOptions.javaHome = file(System.env.JAVA_11_HOME)
36+
sourceCompatibility = JavaVersion.VERSION_11
37+
targetCompatibility = JavaVersion.VERSION_11
38+
}
39+
2040
dependencies {
21-
compileOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '11.0.0'
41+
main_java11CompileOnly group: 'org.eclipse.jetty', name: 'jetty-server', version: '11.0.0'
2242

2343
// Don't want to conflict with jetty from the test server.
2444
testImplementation(project(':dd-java-agent:testing')) {
2545
exclude group: 'org.eclipse.jetty', module: 'jetty-server'
2646
}
47+
testImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '11.0.0'
2748

2849
latestDepTestImplementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '11.+'
2950
}

dd-java-agent/instrumentation/jetty-11/src/main/java/datadog/trace/instrumentation/jetty11/JettyServerInstrumentation.java

+5-70
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,21 @@
22

33
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
44
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.namedOneOf;
5-
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan;
6-
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate;
7-
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan;
8-
import static datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE;
95
import static datadog.trace.bootstrap.instrumentation.java.concurrent.ExcludeFilter.ExcludeType.RUNNABLE;
10-
import static datadog.trace.instrumentation.jetty11.JettyDecorator.DECORATE;
11-
import static datadog.trace.instrumentation.jetty11.JettyDecorator.SERVLET_REQUEST;
12-
import static datadog.trace.instrumentation.jetty11.RequestExtractAdapter.GETTER;
136
import static net.bytebuddy.matcher.ElementMatchers.declaresMethod;
147
import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;
158

169
import com.google.auto.service.AutoService;
1710
import datadog.trace.agent.tooling.ExcludeFilterProvider;
1811
import datadog.trace.agent.tooling.Instrumenter;
19-
import datadog.trace.api.CorrelationIdentifier;
20-
import datadog.trace.api.GlobalTracer;
21-
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
22-
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
2312
import datadog.trace.bootstrap.instrumentation.java.concurrent.ExcludeFilter;
2413
import java.util.Arrays;
2514
import java.util.Collection;
2615
import java.util.Collections;
2716
import java.util.Map;
28-
import net.bytebuddy.asm.Advice;
2917
import net.bytebuddy.description.method.MethodDescription;
3018
import net.bytebuddy.description.type.TypeDescription;
3119
import net.bytebuddy.matcher.ElementMatcher;
32-
import org.eclipse.jetty.server.HttpChannel;
33-
import org.eclipse.jetty.server.Request;
3420

3521
@AutoService(Instrumenter.class)
3622
public final class JettyServerInstrumentation extends Instrumenter.Tracing
@@ -51,6 +37,9 @@ public String[] helperClassNames() {
5137
packageName + ".JettyDecorator",
5238
packageName + ".RequestExtractAdapter",
5339
packageName + ".RequestURIDataAdapter",
40+
packageName + ".JettyServerAdvice",
41+
packageName + ".JettyServerAdvice$HandleAdvice",
42+
packageName + ".JettyServerAdvice$ResetAdvice",
5443
};
5544
}
5645

@@ -74,11 +63,11 @@ public boolean matches(MethodDescription target) {
7463
.matches(target.getDeclaringType().asErasure());
7564
}
7665
}))),
77-
JettyServerInstrumentation.class.getName() + "$HandleAdvice");
66+
packageName + ".JettyServerAdvice$HandleAdvice");
7867
transformation.applyAdvice(
7968
// name changed to recycle in 9.3.0
8069
namedOneOf("reset", "recycle").and(takesNoArguments()),
81-
JettyServerInstrumentation.class.getName() + "$ResetAdvice");
70+
packageName + ".JettyServerAdvice$ResetAdvice");
8271
}
8372

8473
@Override
@@ -92,58 +81,4 @@ public boolean matches(MethodDescription target) {
9281
"org.eclipse.jetty.util.thread.TimerScheduler",
9382
"org.eclipse.jetty.util.thread.TimerScheduler$SimpleTask"));
9483
}
95-
96-
public static class HandleAdvice {
97-
98-
@Advice.OnMethodEnter(suppress = Throwable.class)
99-
public static AgentScope onEnter(@Advice.This final HttpChannel channel) {
100-
Request req = channel.getRequest();
101-
102-
Object existingSpan = req.getAttribute(DD_SPAN_ATTRIBUTE);
103-
if (existingSpan instanceof AgentSpan) {
104-
// Request already gone through initial processing, so just activate the span.
105-
return activateSpan((AgentSpan) existingSpan);
106-
}
107-
108-
final AgentSpan.Context.Extracted extractedContext = propagate().extract(req, GETTER);
109-
110-
final AgentSpan span = startSpan(SERVLET_REQUEST, extractedContext).setMeasured(true);
111-
DECORATE.afterStart(span);
112-
DECORATE.onRequest(span, req, req, extractedContext);
113-
114-
final AgentScope scope = activateSpan(span);
115-
scope.setAsyncPropagation(true);
116-
req.setAttribute(DD_SPAN_ATTRIBUTE, span);
117-
req.setAttribute(CorrelationIdentifier.getTraceIdKey(), GlobalTracer.get().getTraceId());
118-
req.setAttribute(CorrelationIdentifier.getSpanIdKey(), GlobalTracer.get().getSpanId());
119-
return scope;
120-
}
121-
122-
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
123-
public static void closeScope(@Advice.Enter final AgentScope scope) {
124-
scope.close();
125-
}
126-
}
127-
128-
/**
129-
* Jetty ensures that connections are reset immediately after the response is sent. This provides
130-
* a reliable point to finish the server span at the last possible moment.
131-
*/
132-
public static class ResetAdvice {
133-
@Advice.OnMethodEnter(suppress = Throwable.class)
134-
public static void stopSpan(@Advice.This final HttpChannel channel) {
135-
Request req = channel.getRequest();
136-
Object spanObj = req.getAttribute(DD_SPAN_ATTRIBUTE);
137-
if (spanObj instanceof AgentSpan) {
138-
final AgentSpan span = (AgentSpan) spanObj;
139-
DECORATE.onResponse(span, channel);
140-
DECORATE.beforeFinish(span);
141-
span.finish();
142-
}
143-
}
144-
145-
private void muzzleCheck(HttpChannel connection) {
146-
connection.run();
147-
}
148-
}
14984
}
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
11
package datadog.trace.instrumentation.jetty11;
22

33
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
4-
import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.SERVLET_CONTEXT;
5-
import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.SERVLET_PATH;
6-
import static datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator.DD_DISPATCH_SPAN_ATTRIBUTE;
7-
import static datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE;
8-
import static datadog.trace.instrumentation.jetty11.JettyDecorator.DD_CONTEXT_PATH_ATTRIBUTE;
9-
import static datadog.trace.instrumentation.jetty11.JettyDecorator.DD_SERVLET_PATH_ATTRIBUTE;
104
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
115

126
import com.google.auto.service.AutoService;
137
import datadog.trace.agent.tooling.Instrumenter;
14-
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
15-
import jakarta.servlet.http.HttpServletRequest;
16-
import net.bytebuddy.asm.Advice;
178
import net.bytebuddy.description.type.TypeDescription;
189
import net.bytebuddy.matcher.ElementMatcher;
19-
import org.eclipse.jetty.http.HttpFields;
20-
import org.eclipse.jetty.server.HttpChannel;
21-
import org.eclipse.jetty.server.Request;
22-
import org.eclipse.jetty.server.handler.ContextHandler;
2310

2411
@AutoService(Instrumenter.class)
2512
public final class RequestInstrumentation extends Instrumenter.Tracing {
@@ -39,25 +26,6 @@ public void adviceTransformations(AdviceTransformation transformation) {
3926
named("setContext")
4027
.and(takesArgument(0, named("org.eclipse.jetty.server.handler.ContextHandler$Context")))
4128
.and(takesArgument(1, String.class)),
42-
RequestInstrumentation.class.getName() + "$SetContextPathAdvice");
43-
}
44-
45-
/**
46-
* Because we are processing the initial request before the contextPath is set, we must update it
47-
* when it is actually set.
48-
*/
49-
public static class SetContextPathAdvice {
50-
@Advice.OnMethodEnter(suppress = Throwable.class)
51-
public static void updateContextPath(
52-
@Advice.This final Request req, @Advice.Argument(0) final ContextHandler.Context context, @Advice.Argument(1) final String contextPath) {
53-
if (contextPath != null) {
54-
Object span = req.getAttribute(DD_SPAN_ATTRIBUTE);
55-
// Don't want to update while being dispatched to new servlet
56-
if (span instanceof AgentSpan && req.getAttribute(DD_DISPATCH_SPAN_ATTRIBUTE) == null) {
57-
((AgentSpan) span).setTag(SERVLET_CONTEXT, contextPath);
58-
req.setAttribute(DD_CONTEXT_PATH_ATTRIBUTE, contextPath);
59-
}
60-
}
61-
}
29+
packageName + ".SetContextPathAdvice");
6230
}
6331
}
+14-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package datadog.trace.instrumentation.jetty11;
22

3+
import static datadog.trace.instrumentation.jetty11.RequestExtractAdapter.GETTER;
4+
35
import datadog.trace.api.Config;
46
import datadog.trace.api.DDTags;
7+
import datadog.trace.bootstrap.instrumentation.api.AgentPropagation;
58
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
69
import datadog.trace.bootstrap.instrumentation.api.URIDataAdapter;
710
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
@@ -11,7 +14,7 @@
1114
import org.eclipse.jetty.server.Request;
1215
import org.eclipse.jetty.server.Response;
1316

14-
public class JettyDecorator extends HttpServerDecorator<Request, Request, Response> {
17+
public class JettyDecorator extends HttpServerDecorator<Request, Request, Response, Request> {
1518
public static final CharSequence SERVLET_REQUEST = UTF8BytesString.create("servlet.request");
1619
public static final CharSequence JETTY_SERVER = UTF8BytesString.create("jetty-server");
1720
public static final JettyDecorator DECORATE = new JettyDecorator();
@@ -28,6 +31,16 @@ protected CharSequence component() {
2831
return JETTY_SERVER;
2932
}
3033

34+
@Override
35+
protected AgentPropagation.ContextVisitor<Request> getter() {
36+
return GETTER;
37+
}
38+
39+
@Override
40+
public CharSequence spanName() {
41+
return SERVLET_REQUEST;
42+
}
43+
3144
@Override
3245
protected String method(final Request request) {
3346
return request.getMethod();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package datadog.trace.instrumentation.jetty11;
2+
3+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan;
4+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate;
5+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan;
6+
import static datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE;
7+
import static datadog.trace.instrumentation.jetty11.JettyDecorator.DECORATE;
8+
import static datadog.trace.instrumentation.jetty11.JettyDecorator.SERVLET_REQUEST;
9+
import static datadog.trace.instrumentation.jetty11.RequestExtractAdapter.GETTER;
10+
11+
import datadog.trace.api.CorrelationIdentifier;
12+
import datadog.trace.api.GlobalTracer;
13+
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
14+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
15+
import net.bytebuddy.asm.Advice;
16+
import org.eclipse.jetty.server.HttpChannel;
17+
import org.eclipse.jetty.server.Request;
18+
19+
public class JettyServerAdvice {
20+
public static class HandleAdvice {
21+
22+
@Advice.OnMethodEnter(suppress = Throwable.class)
23+
public static AgentScope onEnter(@Advice.This final HttpChannel channel) {
24+
Request req = channel.getRequest();
25+
26+
Object existingSpan = req.getAttribute(DD_SPAN_ATTRIBUTE);
27+
if (existingSpan instanceof AgentSpan) {
28+
// Request already gone through initial processing, so just activate the span.
29+
return activateSpan((AgentSpan) existingSpan);
30+
}
31+
32+
final AgentSpan.Context.Extracted extractedContext = propagate().extract(req, GETTER);
33+
34+
final AgentSpan span = startSpan(SERVLET_REQUEST, extractedContext).setMeasured(true);
35+
DECORATE.afterStart(span);
36+
DECORATE.onRequest(span, req, req, extractedContext);
37+
38+
final AgentScope scope = activateSpan(span);
39+
scope.setAsyncPropagation(true);
40+
req.setAttribute(DD_SPAN_ATTRIBUTE, span);
41+
req.setAttribute(CorrelationIdentifier.getTraceIdKey(), GlobalTracer.get().getTraceId());
42+
req.setAttribute(CorrelationIdentifier.getSpanIdKey(), GlobalTracer.get().getSpanId());
43+
return scope;
44+
}
45+
46+
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
47+
public static void closeScope(@Advice.Enter final AgentScope scope) {
48+
scope.close();
49+
}
50+
}
51+
52+
/**
53+
* Jetty ensures that connections are reset immediately after the response is sent. This provides
54+
* a reliable point to finish the server span at the last possible moment.
55+
*/
56+
public static class ResetAdvice {
57+
@Advice.OnMethodEnter(suppress = Throwable.class)
58+
public static void stopSpan(@Advice.This final HttpChannel channel) {
59+
Request req = channel.getRequest();
60+
Object spanObj = req.getAttribute(DD_SPAN_ATTRIBUTE);
61+
if (spanObj instanceof AgentSpan) {
62+
final AgentSpan span = (AgentSpan) spanObj;
63+
DECORATE.onResponse(span, channel);
64+
DECORATE.beforeFinish(span);
65+
span.finish();
66+
}
67+
}
68+
69+
private void muzzleCheck(HttpChannel connection) {
70+
connection.run();
71+
}
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package datadog.trace.instrumentation.jetty11;
2+
3+
import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.SERVLET_CONTEXT;
4+
import static datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator.DD_DISPATCH_SPAN_ATTRIBUTE;
5+
import static datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE;
6+
import static datadog.trace.instrumentation.jetty11.JettyDecorator.DD_CONTEXT_PATH_ATTRIBUTE;
7+
8+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
9+
import net.bytebuddy.asm.Advice;
10+
import org.eclipse.jetty.server.Request;
11+
import org.eclipse.jetty.server.handler.ContextHandler;
12+
13+
/**
14+
* Because we are processing the initial request before the contextPath is set, we must update it
15+
* when it is actually set.
16+
*/
17+
public class SetContextPathAdvice {
18+
@Advice.OnMethodEnter(suppress = Throwable.class)
19+
public static void updateContextPath(
20+
@Advice.This final Request req,
21+
@Advice.Argument(0) final ContextHandler.Context context,
22+
@Advice.Argument(1) final String contextPath) {
23+
if (contextPath != null) {
24+
Object span = req.getAttribute(DD_SPAN_ATTRIBUTE);
25+
// Don't want to update while being dispatched to new servlet
26+
if (span instanceof AgentSpan && req.getAttribute(DD_DISPATCH_SPAN_ATTRIBUTE) == null) {
27+
((AgentSpan) span).setTag(SERVLET_CONTEXT, contextPath);
28+
req.setAttribute(DD_CONTEXT_PATH_ATTRIBUTE, contextPath);
29+
}
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)