Add additional tags for aws requests
MODIFY
dd-java-agent/instrumentation/aws-sdk/aws-sdk.gradle
dd-java-agent/instrumentation/aws-sdk/aws-sdk.gradle
@@ -28,9 +28,6 @@ if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
dependencies {
compileOnly group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.119'
- compile('io.opentracing.contrib:opentracing-aws-sdk:0.0.3') {
- transitive = false
- }
compile project(':dd-trace-ot')
compile project(':dd-java-agent:tooling')

MODIFY
dd-java-agent/instrumentation/aws-sdk/src/main/java/datadog/trace/instrumentation/aws/AWSClientInstrumentation.java
dd-java-agent/instrumentation/aws-sdk/src/main/java/datadog/trace/instrumentation/aws/AWSClientInstrumentation.java
@@ -11,7 +11,6 @@ import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.DDAdvice;
import datadog.trace.agent.tooling.HelperInjector;
import datadog.trace.agent.tooling.Instrumenter;
-import io.opentracing.contrib.aws.TracingRequestHandler;
import io.opentracing.util.GlobalTracer;
import java.util.List;
import net.bytebuddy.agent.builder.AgentBuilder;
@@ -40,8 +39,8 @@ public final class AWSClientInstrumentation extends Instrumenter.Configurable {
"com.amazonaws.handlers.HandlerContextKey"))
.transform(
new HelperInjector(
- "io.opentracing.contrib.aws.TracingRequestHandler",
- "io.opentracing.contrib.aws.SpanDecorator"))
+ "datadog.trace.instrumentation.aws.TracingRequestHandler",
+ "datadog.trace.instrumentation.aws.SpanDecorator"))
.transform(DDAdvice.create().advice(isConstructor(), AWSClientAdvice.class.getName()))
.asDecorator();
}

ADD
dd-java-agent/instrumentation/aws-sdk/src/main/java/datadog/trace/instrumentation/aws/SpanDecorator.java
+/*
+ * Copyright 2017-2018 The OpenTracing Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package datadog.trace.instrumentation.aws;
+
+import com.amazonaws.AmazonWebServiceResponse;
+import com.amazonaws.Request;
+import com.amazonaws.Response;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.opentracing.Span;
+import io.opentracing.tag.Tags;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+class SpanDecorator {
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ static final String COMPONENT_NAME = "java-aws-sdk";
+
+ static void onRequest(final Request request, final Span span) {
+ Tags.COMPONENT.set(span, COMPONENT_NAME);
+ Tags.HTTP_METHOD.set(span, request.getHttpMethod().name());
+ Tags.HTTP_URL.set(span, request.getEndpoint().toString());
+ span.setTag("aws.agent", COMPONENT_NAME);
+ span.setTag("aws.service", request.getServiceName());
+ span.setTag("aws.operation", request.getOriginalRequest().getClass().getSimpleName());
+ span.setTag("aws.endpoint", request.getEndpoint().toString());
+ try {
+ span.setTag("params", MAPPER.writeValueAsString(request.getParameters()));
+ } catch (final JsonProcessingException e) {
+ }
+ }
+
+ static void onResponse(final Response response, final Span span) {
+ Tags.HTTP_STATUS.set(span, response.getHttpResponse().getStatusCode());
+ if (response.getAwsResponse() instanceof AmazonWebServiceResponse) {
+ final AmazonWebServiceResponse awsResp = (AmazonWebServiceResponse) response.getAwsResponse();
+ span.setTag("aws.requestId", awsResp.getRequestId());
+ }
+ }
+
+ static void onError(final Throwable throwable, final Span span) {
+ Tags.ERROR.set(span, Boolean.TRUE);
+ span.log(errorLogs(throwable));
+ }
+
+ private static Map<String, Object> errorLogs(final Throwable throwable) {
+ final Map<String, Object> errorLogs = new HashMap<>(4);
+ errorLogs.put("event", Tags.ERROR.getKey());
+ errorLogs.put("error.kind", throwable.getClass().getName());
+ errorLogs.put("error.object", throwable);
+
+ errorLogs.put("message", throwable.getMessage());
+
+ final StringWriter sw = new StringWriter();
+ throwable.printStackTrace(new PrintWriter(sw));
+ errorLogs.put("stack", sw.toString());
+
+ return errorLogs;
+ }
+}

ADD
dd-java-agent/instrumentation/aws-sdk/src/main/java/datadog/trace/instrumentation/aws/TracingRequestHandler.java
+/*
+ * Copyright 2017-2018 The OpenTracing Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package datadog.trace.instrumentation.aws;
+
+import com.amazonaws.AmazonWebServiceRequest;
+import com.amazonaws.Request;
+import com.amazonaws.Response;
+import com.amazonaws.handlers.HandlerContextKey;
+import com.amazonaws.handlers.RequestHandler2;
+import io.opentracing.Span;
+import io.opentracing.SpanContext;
+import io.opentracing.Tracer;
+import io.opentracing.propagation.Format;
+import io.opentracing.propagation.TextMapInjectAdapter;
+import io.opentracing.tag.Tags;
+
+/** Tracing Request Handler */
+public class TracingRequestHandler extends RequestHandler2 {
+
+ private final HandlerContextKey<Span> contextKey = new HandlerContextKey<>("span");
+ private final SpanContext parentContext; // for Async Client
+ private final Tracer tracer;
+
+ public TracingRequestHandler(final Tracer tracer) {
+ this.parentContext = null;
+ this.tracer = tracer;
+ }
+
+ /**
+ * In case of Async Client: beforeRequest runs in separate thread therefore we need to inject
+ * parent context to build chain
+ *
+ * @param parentContext parent context
+ */
+ public TracingRequestHandler(final SpanContext parentContext, final Tracer tracer) {
+ this.parentContext = parentContext;
+ this.tracer = tracer;
+ }
+
+ @Override
+ public AmazonWebServiceRequest beforeExecution(final AmazonWebServiceRequest request) {
+ return request;
+ }
+
+ @Override
+ public AmazonWebServiceRequest beforeMarshalling(final AmazonWebServiceRequest request) {
+ return request;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void beforeRequest(final Request<?> request) {
+ final Tracer.SpanBuilder spanBuilder =
+ tracer
+ .buildSpan(request.getServiceName())
+ .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT);
+
+ if (parentContext != null) {
+ spanBuilder.asChildOf(parentContext);
+ }
+
+ final Span span = spanBuilder.start();
+ SpanDecorator.onRequest(request, span);
+
+ tracer.inject(
+ span.context(),
+ Format.Builtin.HTTP_HEADERS,
+ new TextMapInjectAdapter(request.getHeaders()));
+
+ request.addHandlerContext(contextKey, span);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void afterResponse(final Request<?> request, final Response<?> response) {
+ final Span span = request.getHandlerContext(contextKey);
+ SpanDecorator.onResponse(response, span);
+ span.finish();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void afterError(final Request<?> request, final Response<?> response, final Exception e) {
+ final Span span = request.getHandlerContext(contextKey);
+ SpanDecorator.onError(e, span);
+ span.finish();
+ }
+}

MODIFY
dd-java-agent/instrumentation/aws-sdk/src/test/groovy/AWSClientTest.groovy
dd-java-agent/instrumentation/aws-sdk/src/test/groovy/AWSClientTest.groovy
@@ -147,14 +147,20 @@ class AWSClientTest extends AgentTestRunner {
span.context().parentId == 0
def tags = span.context().tags
- tags["component"] == "java-aws-sdk"
- tags2[Tags.SPAN_KIND.key] == Tags.SPAN_KIND_CLIENT
- tags2[Tags.HTTP_METHOD.key] == "PUT"
- tags2[Tags.HTTP_URL.key] == "http://localhost:$server.address.port/testbucket/"
- tags2[Tags.HTTP_STATUS.key] == 200
+ tags[Tags.COMPONENT.key] == "java-aws-sdk"
+ tags[Tags.SPAN_KIND.key] == Tags.SPAN_KIND_CLIENT
+ tags[Tags.HTTP_METHOD.key] == "PUT"
+ tags[Tags.HTTP_URL.key] == "http://localhost:$server.address.port"
+ tags[Tags.HTTP_STATUS.key] == 200
+ tags["aws.service"] == "Amazon S3"
+ tags["aws.endpoint"] == "http://localhost:$server.address.port"
+ tags["aws.operation"] == "CreateBucketRequest"
+ tags["aws.agent"] == "java-aws-sdk"
+ tags["params"] == "{}"
+ tags["span.type"] == "web"
tags["thread.name"] != null
tags["thread.id"] != null
- tags.size() == 8
+ tags.size() == 13
receivedHeaders.get().get("x-datadog-trace-id") == "$span.traceId"
receivedHeaders.get().get("x-datadog-parent-id") == "$span.spanId"

Add additional tags for aws requests