Skip to content

Commit 4e90a7d

Browse files
authored
Merge pull request #206 from DataDog/tyler/aws
Prevent headers from being added for AWS client calls
2 parents 140c3ad + 13c774e commit 4e90a7d

7 files changed

Lines changed: 175 additions & 37 deletions

File tree

dd-java-agent-ittests/dd-java-agent-ittests.gradle

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,9 @@ dependencies {
3737
testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '8.2.0.v20160908'
3838
testCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.0.41'
3939
testCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '8.0.41'
40-
// note: aws transitively pulls in apache-httpclient, which we also test against:
41-
// testCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3'
42-
testCompile(group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.119')
40+
testCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3'
4341
testCompile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.6.0'
44-
testCompile(group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.2.0')
45-
testCompile(group: 'org.cassandraunit', name: 'cassandra-unit', version: '3.1.3.2') {
46-
exclude(module: 'netty-handler')
47-
}
42+
4843
testCompile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.8.2'
4944
testCompile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.8.2'
5045

dd-java-agent-ittests/src/test/java/datadog/trace/agent/integration/AWSInstrumentationTest.java

Lines changed: 0 additions & 24 deletions
This file was deleted.

dd-java-agent/instrumentation/apache-httpclient-4.3/src/main/java/datadog/trace/instrumentation/apachehttpclient/DDTracingClientExec.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,15 @@ private CloseableHttpResponse createNetworkSpan(
127127
.startActive(true);
128128

129129
final Span networkSpan = networkScope.span();
130-
tracer.inject(
131-
networkSpan.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersInjectAdapter(request));
130+
131+
final boolean awsClientCall = request.getHeaders("amz-sdk-invocation-id").length > 0;
132+
// AWS calls are often signed, so we can't add headers without breaking the signature.
133+
if (!awsClientCall) {
134+
tracer.inject(
135+
networkSpan.context(),
136+
Format.Builtin.HTTP_HEADERS,
137+
new HttpHeadersInjectAdapter(request));
138+
}
132139

133140
try {
134141
// request tags

dd-java-agent/instrumentation/aws-sdk/aws-sdk.gradle

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ versionScan {
1515

1616
apply from: "${rootDir}/gradle/java.gradle"
1717

18+
if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
19+
sourceSets {
20+
test {
21+
groovy {
22+
// These classes use Ratpack which requires Java 8. (Currently also incompatible with Java 9.)
23+
exclude '**/AWSClientTest.groovy'
24+
}
25+
}
26+
}
27+
}
28+
1829
dependencies {
1930
compileOnly group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.119'
2031
compile('io.opentracing.contrib:opentracing-aws-sdk:0.0.3') {
@@ -27,4 +38,9 @@ dependencies {
2738
compile deps.bytebuddy
2839
compile deps.opentracing
2940
compile deps.autoservice
41+
42+
testCompile project(':dd-java-agent:testing')
43+
// Include httpclient instrumentation for testing because it is a dependency for aws-sdk.
44+
testCompile project(':dd-java-agent:instrumentation:apache-httpclient-4.3')
45+
testCompile group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.119'
3046
}

dd-java-agent/instrumentation/aws-sdk/src/main/java/datadog/trace/instrumentation/aws/AWSClientInstrumentation.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import io.opentracing.contrib.aws.TracingRequestHandler;
1818
import io.opentracing.util.GlobalTracer;
1919
import java.util.ArrayList;
20+
import java.util.Collections;
2021
import java.util.List;
2122
import net.bytebuddy.agent.builder.AgentBuilder;
2223
import net.bytebuddy.asm.Advice;
@@ -48,21 +49,22 @@ public AgentBuilder instrument(final AgentBuilder agentBuilder) {
4849
}
4950

5051
public static class AWSClientAdvice {
51-
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
52+
@Advice.OnMethodEnter(suppress = Throwable.class)
5253
public static void addHandler(@Advice.This final AwsClientBuilder<?, ?> builder) {
5354
List<RequestHandler2> handlers = builder.getRequestHandlers();
5455
boolean hasDDHandler = false;
5556
if (null == handlers) {
56-
handlers = new ArrayList<RequestHandler2>(1);
57+
handlers = Collections.emptyList();
5758
} else {
58-
for (RequestHandler2 handler : handlers) {
59+
for (final RequestHandler2 handler : handlers) {
5960
if (handler instanceof TracingRequestHandler) {
6061
hasDDHandler = true;
6162
break;
6263
}
6364
}
6465
}
6566
if (!hasDDHandler) {
67+
handlers = new ArrayList<>(handlers); // copy since returned list is unmodifiable
6668
handlers.add(new TracingRequestHandler(GlobalTracer.get()));
6769
builder.setRequestHandlers(handlers.toArray(new RequestHandler2[0]));
6870
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import com.amazonaws.AmazonWebServiceClient
2+
import com.amazonaws.auth.AWSStaticCredentialsProvider
3+
import com.amazonaws.auth.AnonymousAWSCredentials
4+
import com.amazonaws.client.builder.AwsClientBuilder
5+
import com.amazonaws.handlers.RequestHandler2
6+
import com.amazonaws.regions.Regions
7+
import com.amazonaws.services.s3.AmazonS3ClientBuilder
8+
import datadog.trace.agent.test.AgentTestRunner
9+
import datadog.trace.api.DDTags
10+
import io.opentracing.tag.Tags
11+
import ratpack.http.Headers
12+
13+
import java.util.concurrent.atomic.AtomicReference
14+
15+
import static ratpack.groovy.test.embed.GroovyEmbeddedApp.ratpack
16+
17+
class AWSClientTest extends AgentTestRunner {
18+
19+
def "request handler is hooked up"() {
20+
setup:
21+
def builder = AmazonS3ClientBuilder.standard()
22+
.withRegion(Regions.US_EAST_1)
23+
if (addHandler) {
24+
builder.withRequestHandlers(new RequestHandler2() {})
25+
}
26+
AmazonWebServiceClient client = builder.build()
27+
28+
expect:
29+
client.requestHandler2s != null
30+
client.requestHandler2s.size() == size
31+
client.requestHandler2s.get(position).getClass().getSimpleName() == "TracingRequestHandler"
32+
33+
where:
34+
addHandler | size | position
35+
true | 2 | 1
36+
false | 1 | 0
37+
}
38+
39+
def "send request with mocked back end"() {
40+
setup:
41+
def receivedHeaders = new AtomicReference<Headers>()
42+
def server = ratpack {
43+
handlers {
44+
all {
45+
receivedHeaders.set(request.headers)
46+
response.status(200).send("pong")
47+
}
48+
}
49+
}
50+
AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration("http://localhost:$server.address.port", "us-west-2");
51+
52+
AmazonWebServiceClient client = AmazonS3ClientBuilder
53+
.standard()
54+
.withPathStyleAccessEnabled(true)
55+
.withEndpointConfiguration(endpoint)
56+
.withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials()))
57+
.build()
58+
59+
def bucket = client.createBucket("testbucket")
60+
61+
expect:
62+
bucket != null
63+
64+
client.requestHandler2s != null
65+
client.requestHandler2s.size() == 1
66+
client.requestHandler2s.get(0).getClass().getSimpleName() == "TracingRequestHandler"
67+
68+
TEST_WRITER.size() == 2
69+
70+
def trace = TEST_WRITER.get(0)
71+
trace.size() == 2
72+
73+
and: // span 0 - from apache-httpclient instrumentation
74+
def span1 = trace[0]
75+
76+
span1.context().operationName == "PUT"
77+
span1.serviceName == "unnamed-java-app"
78+
span1.resourceName == "PUT"
79+
span1.type == null
80+
!span1.context().getErrorFlag()
81+
span1.context().parentId == 0
82+
83+
84+
def tags1 = span1.context().tags
85+
tags1["component"] == "apache-httpclient"
86+
tags1["thread.name"] != null
87+
tags1["thread.id"] != null
88+
tags1.size() == 3
89+
90+
and: // span 1 - from aws instrumentation
91+
def span2 = trace[1]
92+
93+
span2.context().operationName == "PUT"
94+
span2.serviceName == "unnamed-java-app"
95+
span2.resourceName == "PUT"
96+
span2.type == null
97+
!span2.context().getErrorFlag()
98+
span2.context().parentId == span1.spanId
99+
100+
101+
def tags2 = span2.context().tags
102+
tags2[Tags.SPAN_KIND.key] == Tags.SPAN_KIND_CLIENT
103+
tags2[Tags.HTTP_METHOD.key] == "PUT"
104+
tags2[Tags.HTTP_URL.key] == "http://localhost:$server.address.port/testbucket/"
105+
tags2[Tags.PEER_HOSTNAME.key] == "localhost"
106+
tags2[Tags.PEER_PORT.key] == server.address.port
107+
tags2[DDTags.THREAD_NAME] != null
108+
tags2[DDTags.THREAD_ID] != null
109+
tags2.size() == 8
110+
111+
and:
112+
113+
def trace2 = TEST_WRITER.get(1)
114+
trace2.size() == 1
115+
116+
and: // span 0 - from aws instrumentation
117+
def span = trace2[0]
118+
119+
span.context().operationName == "Amazon S3"
120+
span.serviceName == "unnamed-java-app"
121+
span.resourceName == "Amazon S3"
122+
span.type == null
123+
!span.context().getErrorFlag()
124+
span.context().parentId == 0
125+
126+
def tags = span.context().tags
127+
tags["component"] == "java-aws-sdk"
128+
tags2[Tags.SPAN_KIND.key] == Tags.SPAN_KIND_CLIENT
129+
tags2[Tags.HTTP_METHOD.key] == "PUT"
130+
tags2[Tags.HTTP_URL.key] == "http://localhost:$server.address.port/testbucket/"
131+
tags2[Tags.HTTP_STATUS.key] == 200
132+
tags["thread.name"] != null
133+
tags["thread.id"] != null
134+
tags.size() == 7
135+
136+
receivedHeaders.get().get("x-datadog-trace-id") == "$span.traceId"
137+
receivedHeaders.get().get("x-datadog-parent-id") == "$span.spanId"
138+
139+
cleanup:
140+
server.close()
141+
}
142+
}

dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms/util/MessagePropertyTextMap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import javax.jms.Message;
1010

1111
public class MessagePropertyTextMap implements TextMap {
12-
static final String DASH = "_$dash$_";
12+
static final String DASH = "__dash__";
1313

1414
private final Message message;
1515

0 commit comments

Comments
 (0)