Skip to content

Commit a13e4a0

Browse files
authored
Merge pull request #910 from DataDog/labbati/jersey-1.19
Extend support for Jersey client to 1.9+
2 parents 4501dbe + 5624cef commit a13e4a0

File tree

19 files changed

+273
-11
lines changed

19 files changed

+273
-11
lines changed

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,12 @@ public static ResettableClassFileTransformer installBytebuddyAgent(
107107
// Working around until a long-term fix for modules can be
108108
// put in place.
109109
.and(not(named("java.util.logging.LogManager$Cleaner")))))))
110-
.or(nameStartsWith("com.sun.").and(not(nameStartsWith("com.sun.messaging."))))
110+
.or(
111+
nameStartsWith("com.sun.")
112+
.and(
113+
not(
114+
nameStartsWith("com.sun.messaging.")
115+
.or(nameStartsWith("com.sun.jersey.api.client")))))
111116
.or(
112117
nameStartsWith("sun.")
113118
.and(
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
muzzle {
2+
pass {
3+
group = "com.sun.jersey"
4+
module = "jersey-client"
5+
versions = "[1.9,)"
6+
// We can't assert inverse because 1.1.5.2 was a weird release that also works.
7+
}
8+
fail {
9+
group = "com.sun.jersey"
10+
module = "jersey-client"
11+
versions = "[1.2,1.9)"
12+
}
13+
}
14+
15+
apply from: "${rootDir}/gradle/java.gradle"
16+
17+
apply plugin: 'org.unbroken-dome.test-sets'
18+
19+
testSets {
20+
latestDepTest {
21+
dirName = 'test'
22+
}
23+
}
24+
25+
dependencies {
26+
compileOnly group: 'com.sun.jersey', name: 'jersey-client', version: '1.9'
27+
28+
compile deps.bytebuddy
29+
compile deps.opentracing
30+
annotationProcessor deps.autoservice
31+
implementation deps.autoservice
32+
33+
compile project(':dd-java-agent:agent-tooling')
34+
35+
testCompile project(':dd-java-agent:testing')
36+
37+
testCompile group: 'com.sun.jersey', name: 'jersey-client', version: '1.9'
38+
39+
latestDepTestCompile group: 'com.sun.jersey', name: 'jersey-client', version: '+'
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package datadog.trace.instrumentation.jaxrs.v1;
2+
3+
import io.opentracing.propagation.TextMap;
4+
import java.util.Iterator;
5+
import java.util.Map;
6+
import javax.ws.rs.core.MultivaluedMap;
7+
8+
public final class InjectAdapter implements TextMap {
9+
private final MultivaluedMap<String, Object> map;
10+
11+
public InjectAdapter(final MultivaluedMap<String, Object> map) {
12+
this.map = map;
13+
}
14+
15+
@Override
16+
public Iterator<Map.Entry<String, String>> iterator() {
17+
throw new UnsupportedOperationException(
18+
"InjectAdapter should only be used with Tracer.inject()");
19+
}
20+
21+
@Override
22+
public void put(final String key, final String value) {
23+
// Don't allow duplicates.
24+
map.putSingle(key, value);
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package datadog.trace.instrumentation.jaxrs.v1;
2+
3+
import com.sun.jersey.api.client.ClientRequest;
4+
import com.sun.jersey.api.client.ClientResponse;
5+
import datadog.trace.agent.decorator.HttpClientDecorator;
6+
import java.net.URI;
7+
8+
public class JaxRsClientV1Decorator extends HttpClientDecorator<ClientRequest, ClientResponse> {
9+
public static final JaxRsClientV1Decorator DECORATE = new JaxRsClientV1Decorator();
10+
11+
@Override
12+
protected String[] instrumentationNames() {
13+
return new String[] {"jax-rs", "jaxrs", "jax-rs-client"};
14+
}
15+
16+
@Override
17+
protected String component() {
18+
return "jax-rs.client";
19+
}
20+
21+
@Override
22+
protected String method(final ClientRequest httpRequest) {
23+
return httpRequest.getMethod();
24+
}
25+
26+
@Override
27+
protected URI url(final ClientRequest httpRequest) {
28+
return httpRequest.getURI();
29+
}
30+
31+
@Override
32+
protected String hostname(final ClientRequest httpRequest) {
33+
return httpRequest.getURI().getHost();
34+
}
35+
36+
@Override
37+
protected Integer port(final ClientRequest httpRequest) {
38+
return httpRequest.getURI().getPort();
39+
}
40+
41+
@Override
42+
protected Integer status(ClientResponse clientResponse) {
43+
return clientResponse.getStatus();
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package datadog.trace.instrumentation.jaxrs.v1;
2+
3+
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
4+
import static datadog.trace.instrumentation.jaxrs.v1.JaxRsClientV1Decorator.DECORATE;
5+
import static java.util.Collections.singletonMap;
6+
import static net.bytebuddy.matcher.ElementMatchers.named;
7+
import static net.bytebuddy.matcher.ElementMatchers.returns;
8+
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
9+
10+
import com.google.auto.service.AutoService;
11+
import com.sun.jersey.api.client.ClientHandler;
12+
import com.sun.jersey.api.client.ClientRequest;
13+
import com.sun.jersey.api.client.ClientResponse;
14+
import datadog.trace.agent.tooling.Instrumenter;
15+
import datadog.trace.api.DDTags;
16+
import io.opentracing.Scope;
17+
import io.opentracing.Span;
18+
import io.opentracing.Tracer;
19+
import io.opentracing.propagation.Format;
20+
import io.opentracing.util.GlobalTracer;
21+
import java.util.Map;
22+
import net.bytebuddy.asm.Advice;
23+
import net.bytebuddy.description.method.MethodDescription;
24+
import net.bytebuddy.description.type.TypeDescription;
25+
import net.bytebuddy.matcher.ElementMatcher;
26+
27+
@AutoService(Instrumenter.class)
28+
public final class JaxRsClientV1Instrumentation extends Instrumenter.Default {
29+
30+
public JaxRsClientV1Instrumentation() {
31+
super("jax-rs", "jaxrs", "jax-rs-client");
32+
}
33+
34+
@Override
35+
public ElementMatcher<TypeDescription> typeMatcher() {
36+
return safeHasSuperType(named("com.sun.jersey.api.client.ClientHandler"));
37+
}
38+
39+
@Override
40+
public String[] helperClassNames() {
41+
return new String[] {
42+
"datadog.trace.agent.decorator.BaseDecorator",
43+
"datadog.trace.agent.decorator.ClientDecorator",
44+
"datadog.trace.agent.decorator.HttpClientDecorator",
45+
packageName + ".JaxRsClientV1Decorator",
46+
packageName + ".InjectAdapter",
47+
};
48+
}
49+
50+
@Override
51+
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
52+
return singletonMap(
53+
named("handle")
54+
.and(
55+
takesArgument(
56+
0, safeHasSuperType(named("com.sun.jersey.api.client.ClientRequest"))))
57+
.and(returns(safeHasSuperType(named("com.sun.jersey.api.client.ClientResponse")))),
58+
HandleAdvice.class.getName());
59+
}
60+
61+
public static class HandleAdvice {
62+
63+
@Advice.OnMethodEnter
64+
public static Scope onEnter(
65+
@Advice.Argument(value = 0) final ClientRequest request,
66+
@Advice.This final ClientHandler thisObj) {
67+
68+
// WARNING: this might be a chain...so we only have to trace the first in the chain.
69+
final boolean isRootClientHandler = null == request.getProperties().get("dd.span");
70+
if (isRootClientHandler) {
71+
final Tracer tracer = GlobalTracer.get();
72+
final Span span =
73+
tracer
74+
.buildSpan("jax-rs.client.call")
75+
.withTag(DDTags.RESOURCE_NAME, request.getMethod() + " jax-rs.client.call")
76+
.start();
77+
DECORATE.afterStart(span);
78+
DECORATE.onRequest(span, request);
79+
request.getProperties().put("dd.span", span);
80+
81+
tracer.inject(
82+
span.context(), Format.Builtin.HTTP_HEADERS, new InjectAdapter(request.getHeaders()));
83+
return tracer.scopeManager().activate(span, true);
84+
}
85+
return null;
86+
}
87+
88+
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
89+
public static void onExit(
90+
@Advice.Enter final Scope scope,
91+
@Advice.Return final ClientResponse response,
92+
@Advice.Thrown final Throwable throwable) {
93+
if (null != scope) {
94+
final Span span = scope.span();
95+
DECORATE.onResponse(span, response);
96+
DECORATE.onError(span, throwable);
97+
DECORATE.beforeFinish(span);
98+
scope.close();
99+
}
100+
}
101+
}
102+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import com.sun.jersey.api.client.Client
2+
import com.sun.jersey.api.client.ClientResponse
3+
import com.sun.jersey.api.client.filter.CsrfProtectionFilter
4+
import com.sun.jersey.api.client.filter.GZIPContentEncodingFilter
5+
import com.sun.jersey.api.client.filter.LoggingFilter
6+
import datadog.trace.agent.test.base.HttpClientTest
7+
import datadog.trace.instrumentation.jaxrs.v1.JaxRsClientV1Decorator
8+
import spock.lang.Shared
9+
10+
class JaxRsClientV1Test extends HttpClientTest<JaxRsClientV1Decorator> {
11+
12+
@Shared
13+
Client client = Client.create()
14+
15+
def setupSpec() {
16+
// Add filters to ensure spans aren't duplicated.
17+
client.addFilter(new LoggingFilter())
18+
client.addFilter(new GZIPContentEncodingFilter())
19+
client.addFilter(new CsrfProtectionFilter())
20+
}
21+
22+
@Override
23+
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
24+
def resource = client.resource(uri).requestBuilder
25+
headers.each { resource.header(it.key, it.value) }
26+
def body = BODY_METHODS.contains(method) ? "" : null
27+
ClientResponse response = resource.method(method, ClientResponse, body)
28+
callback?.call()
29+
30+
return response.status
31+
}
32+
33+
@Override
34+
JaxRsClientV1Decorator decorator() {
35+
return JaxRsClientV1Decorator.DECORATE
36+
}
37+
38+
@Override
39+
String expectedOperationName() {
40+
return "jax-rs.client.call"
41+
}
42+
43+
boolean testRedirects() {
44+
false
45+
}
46+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ dependencies {
1818

1919
compile project(':dd-java-agent:agent-tooling')
2020

21-
compileOnly project(':dd-java-agent:instrumentation:jax-rs-client')
21+
compileOnly project(':dd-java-agent:instrumentation:jax-rs-client-2.0')
2222
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ dependencies {
1818

1919
compile project(':dd-java-agent:agent-tooling')
2020

21-
compileOnly project(':dd-java-agent:instrumentation:jax-rs-client')
21+
compileOnly project(':dd-java-agent:instrumentation:jax-rs-client-2.0')
2222
}

dd-java-agent/instrumentation/jax-rs-client/jax-rs-client.gradle renamed to dd-java-agent/instrumentation/jax-rs-client-2.0/jax-rs-client-2.0.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ dependencies {
3737
testCompile project(':dd-java-agent:testing')
3838
testCompile project(':dd-java-agent:instrumentation:java-concurrent')
3939

40-
testCompile project(':dd-java-agent:instrumentation:jax-rs-client:connection-error-handling-jersey')
41-
testCompile project(':dd-java-agent:instrumentation:jax-rs-client:connection-error-handling-resteasy')
40+
testCompile project(':dd-java-agent:instrumentation:jax-rs-client-2.0:connection-error-handling-jersey')
41+
testCompile project(':dd-java-agent:instrumentation:jax-rs-client-2.0:connection-error-handling-resteasy')
4242

4343
testCompile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0.1'
4444

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ public void filter(final ClientRequestContext requestContext) {
3131
DECORATE.afterStart(span);
3232
DECORATE.onRequest(span, requestContext);
3333

34-
log.debug("{} - client span started", span);
35-
3634
GlobalTracer.get()
3735
.inject(
3836
span.context(),
@@ -52,7 +50,6 @@ public void filter(
5250
DECORATE.onResponse(span, responseContext);
5351
DECORATE.beforeFinish(span);
5452
span.finish();
55-
log.debug("{} - client spanObj finished", spanObj);
5653
}
5754
}
5855
}

settings.gradle

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ include ':dd-java-agent:instrumentation:hibernate:core-4.3'
4949
include ':dd-java-agent:instrumentation:http-url-connection'
5050
include ':dd-java-agent:instrumentation:hystrix-1.4'
5151
include ':dd-java-agent:instrumentation:jax-rs-annotations'
52-
include ':dd-java-agent:instrumentation:jax-rs-client'
53-
include ':dd-java-agent:instrumentation:jax-rs-client:connection-error-handling-jersey'
54-
include ':dd-java-agent:instrumentation:jax-rs-client:connection-error-handling-resteasy'
52+
include ':dd-java-agent:instrumentation:jax-rs-client-1.9'
53+
include ':dd-java-agent:instrumentation:jax-rs-client-2.0'
54+
include ':dd-java-agent:instrumentation:jax-rs-client-2.0:connection-error-handling-jersey'
55+
include ':dd-java-agent:instrumentation:jax-rs-client-2.0:connection-error-handling-resteasy'
5556
include ':dd-java-agent:instrumentation:java-concurrent'
5657
include ':dd-java-agent:instrumentation:java-concurrent:kotlin-testing'
5758
include ':dd-java-agent:instrumentation:java-concurrent:scala-testing'

0 commit comments

Comments
 (0)