Skip to content

Commit

Permalink
Enhance AWS DynamoDB instrumentation (#1191)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakub Wach authored Sep 18, 2020
1 parent bc8224f commit e8b5488
Show file tree
Hide file tree
Showing 25 changed files with 372 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public final class DbSystem {
public static final String COUCHBASE = "couchbase";
public static final String DB2 = "db2";
public static final String DERBY = "derby";
public static final String DYNAMODB = "dynamodb";
public static final String GEODE = "geode";
public static final String H2 = "h2";
public static final String HSQLDB = "hsqldb";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ protected Span onRequest(Span span, REQUEST request) {
assert span != null;
if (request != null) {
span.setAttribute(SemanticAttributes.HTTP_METHOD.key(), method(request));
span.setAttribute(SemanticAttributes.NET_TRANSPORT.key(), "IP.TCP");

String userAgent = requestHeader(request, USER_AGENT);
if (userAgent != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class HttpClientTracerTest extends BaseTracerTest {

then:
if (req) {
1 * span.setAttribute(SemanticAttributes.NET_TRANSPORT.key(), "IP.TCP")
1 * span.setAttribute(SemanticAttributes.HTTP_METHOD.key(), req.method)
1 * span.setAttribute(SemanticAttributes.HTTP_URL.key(), "$req.url")
1 * span.setAttribute(SemanticAttributes.NET_PEER_NAME.key(), req.url.host)
Expand Down Expand Up @@ -70,6 +71,7 @@ class HttpClientTracerTest extends BaseTracerTest {

then:
if (req) {
1 * span.setAttribute(SemanticAttributes.NET_TRANSPORT.key(), "IP.TCP")
1 * span.setAttribute(SemanticAttributes.HTTP_METHOD.key(), req.method)
1 * span.setAttribute(SemanticAttributes.HTTP_URL.key(), "$req.url")
1 * span.setAttribute(SemanticAttributes.NET_PEER_NAME.key(), req.url.host)
Expand All @@ -90,6 +92,7 @@ class HttpClientTracerTest extends BaseTracerTest {
}

then:
1 * span.setAttribute(SemanticAttributes.NET_TRANSPORT.key(), "IP.TCP")
if (expectedUrl) {
1 * span.setAttribute(SemanticAttributes.HTTP_URL.key(), expectedUrl)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ abstract class AbstractArmeriaTest extends InstrumentationSpecification {
errored code != 200
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.NET_PEER_IP.key()}" "127.0.0.1"
// TODO(anuraaga): peer name shouldn't be set to IP
"${SemanticAttributes.NET_PEER_NAME.key()}" "127.0.0.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class AWS1ClientTest extends AgentTestRunner {
errored false
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.HTTP_URL.key()}" "$server.address/"
"${SemanticAttributes.HTTP_METHOD.key()}" "$method"
"${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200
Expand Down Expand Up @@ -227,6 +228,7 @@ class AWS1ClientTest extends AgentTestRunner {
errorEvent SdkClientException, ~/Unable to execute HTTP request/
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.HTTP_URL.key()}" "http://localhost:${UNUSABLE_PORT}/"
"${SemanticAttributes.HTTP_METHOD.key()}" "$method"
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
Expand Down Expand Up @@ -273,6 +275,7 @@ class AWS1ClientTest extends AgentTestRunner {
errorEvent RuntimeException, "bad handler"
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.HTTP_URL.key()}" "https://s3.amazonaws.com/"
"${SemanticAttributes.HTTP_METHOD.key()}" "HEAD"
"${SemanticAttributes.NET_PEER_NAME.key()}" "s3.amazonaws.com"
Expand Down Expand Up @@ -320,6 +323,7 @@ class AWS1ClientTest extends AgentTestRunner {
}
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.HTTP_URL.key()}" "$server.address/"
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
"${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class AWS0ClientTest extends AgentTestRunner {
errored false
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.HTTP_URL.key()}" "$server.address/"
"${SemanticAttributes.HTTP_METHOD.key()}" "$method"
"${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200
Expand Down Expand Up @@ -172,6 +173,7 @@ class AWS0ClientTest extends AgentTestRunner {
errorEvent AmazonClientException, ~/Unable to execute HTTP request/
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.HTTP_URL.key()}" "http://localhost:${UNUSABLE_PORT}/"
"${SemanticAttributes.HTTP_METHOD.key()}" "$method"
"${SemanticAttributes.NET_PEER_PORT.key()}" 61
Expand Down Expand Up @@ -218,6 +220,7 @@ class AWS0ClientTest extends AgentTestRunner {
errorEvent RuntimeException, "bad handler"
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.HTTP_URL.key()}" "https://s3.amazonaws.com/"
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
"${SemanticAttributes.NET_PEER_NAME.key()}" "s3.amazonaws.com"
Expand Down Expand Up @@ -262,6 +265,7 @@ class AWS0ClientTest extends AgentTestRunner {
errorEvent AmazonClientException, ~/Unable to execute HTTP request/
parent()
attributes {
"${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP"
"${SemanticAttributes.HTTP_URL.key()}" "$server.address/"
"${SemanticAttributes.HTTP_METHOD.key()}" "GET"
"${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ public String[] helperClassNames() {
packageName + ".TracingExecutionInterceptor",
packageName + ".TracingExecutionInterceptor$ScopeHolder",
"io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk",
"io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkClientTracer",
"io.opentelemetry.instrumentation.awssdk.v2_2.TracingExecutionInterceptor",
"io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkHttpClientTracer",
"io.opentelemetry.instrumentation.awssdk.v2_2.RequestType",
"io.opentelemetry.instrumentation.awssdk.v2_2.SdkRequestDecorator",
"io.opentelemetry.instrumentation.awssdk.v2_2.DbRequestDecorator",
"io.opentelemetry.instrumentation.awssdk.v2_2.TracingExecutionInterceptor"
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
public class AwsSdk {

private static final Tracer tracer =
OpenTelemetry.getTracer(AwsSdkClientTracer.TRACER.getInstrumentationName());
OpenTelemetry.getTracer(AwsSdkHttpClientTracer.TRACER.getInstrumentationName());

/** Returns the {@link Tracer} used to instrument the AWS SDK. */
public static Tracer tracer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.opentelemetry.instrumentation.awssdk.v2_2;

import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
import io.opentelemetry.trace.DefaultSpan;
import io.opentelemetry.trace.Span;
Expand All @@ -29,9 +30,10 @@
import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.SdkHttpResponse;

final class AwsSdkClientTracer
final class AwsSdkHttpClientTracer
extends HttpClientTracer<SdkHttpRequest, SdkHttpRequest, SdkHttpResponse> {
static final AwsSdkClientTracer TRACER = new AwsSdkClientTracer();

static final AwsSdkHttpClientTracer TRACER = new AwsSdkHttpClientTracer();

// Certain headers in the request like User-Agent are only available after execution.
Span afterExecution(Span span, SdkHttpRequest request) {
Expand Down Expand Up @@ -78,26 +80,22 @@ protected String getInstrumentationName() {
return "io.opentelemetry.auto.aws-sdk-2.2";
}

/**
* Returns a new client {@link Span} if there is no client {@link Span} in the current {@link
* io.grpc.Context }, or an invalid {@link Span} otherwise.
*/
public Span getOrCreateSpan(String name, Tracer tracer) {
/** This method is overridden to allow other classes in this package to call it. */
@Override
protected Span onRequest(Span span, SdkHttpRequest sdkHttpRequest) {
return super.onRequest(span, sdkHttpRequest);
}

public Span getOrCreateSpan(String name, Tracer tracer, Kind kind) {
io.grpc.Context context = io.grpc.Context.current();
Span clientSpan = CONTEXT_CLIENT_SPAN_KEY.get(context);
Span clientSpan = BaseTracer.CONTEXT_CLIENT_SPAN_KEY.get(context);

if (clientSpan != null) {
// We don't want to create two client spans for a given client call, suppress inner spans.
return DefaultSpan.getInvalid();
}

Span current = TracingContextUtils.getSpan(context);
return tracer.spanBuilder(name).setSpanKind(Kind.CLIENT).setParent(current).startSpan();
}

/** This method is overridden to allow other classes in this package to call it. */
@Override
protected Span onRequest(Span span, SdkHttpRequest sdkHttpRequest) {
return super.onRequest(span, sdkHttpRequest);
return tracer.spanBuilder(name).setSpanKind(kind).setParent(current).startSpan();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright The OpenTelemetry 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 io.opentelemetry.instrumentation.awssdk.v2_2;

import io.opentelemetry.trace.Span;
import io.opentelemetry.trace.attributes.SemanticAttributes;
import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;

final class DbRequestDecorator implements SdkRequestDecorator {

@Override
public void decorate(Span span, SdkRequest sdkRequest, ExecutionAttributes attributes) {

span.setAttribute(SemanticAttributes.DB_SYSTEM.key(), "dynamodb");
// decorate with TableName as db.name (DynamoDB equivalent - not for batch)
sdkRequest
.getValueForField("TableName", String.class)
.ifPresent(val -> span.setAttribute(SemanticAttributes.DB_NAME.key(), val));

String operation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME);
if (operation != null) {
span.setAttribute(SemanticAttributes.DB_OPERATION.key(), operation);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright The OpenTelemetry 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 io.opentelemetry.instrumentation.awssdk.v2_2;

import org.checkerframework.checker.nullness.qual.Nullable;
import software.amazon.awssdk.core.SdkRequest;

enum RequestType {
S3("S3Request", "Bucket"),
SQS("SqsRequest", "QueueUrl", "QueueName"),
Kinesis("KinesisRequest", "StreamName"),
DynamoDB("DynamoDbRequest", "TableName");

private final String requestClass;
private final String[] fields;

RequestType(String requestClass, String... fields) {
this.requestClass = requestClass;
this.fields = fields;
}

String[] getFields() {
return fields;
}

@Nullable
static RequestType ofSdkRequest(SdkRequest request) {
// exact request class should be 1st level child of request type
String typeName =
(request.getClass().getSuperclass() == null
? request.getClass()
: request.getClass().getSuperclass())
.getSimpleName();
for (RequestType type : values()) {
if (type.requestClass.equals(typeName)) {
return type;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright The OpenTelemetry 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 io.opentelemetry.instrumentation.awssdk.v2_2;

import io.opentelemetry.trace.Span;
import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;

interface SdkRequestDecorator {

void decorate(Span span, SdkRequest sdkRequest, ExecutionAttributes attributes);
}
Loading

0 comments on commit e8b5488

Please sign in to comment.