HTTP client instrumentation cleanup: aws-sdk (#1911)
This commit is contained in:
parent
deda1af9c0
commit
49c2a36811
|
@ -11,7 +11,7 @@ import com.amazonaws.Request;
|
||||||
import com.amazonaws.Response;
|
import com.amazonaws.Response;
|
||||||
import io.opentelemetry.api.trace.Span;
|
import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
@ -31,7 +31,7 @@ public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>,
|
||||||
public AwsSdkClientTracer() {}
|
public AwsSdkClientTracer() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String spanNameForRequest(Request<?> request) {
|
protected String spanNameForRequest(Request<?> request) {
|
||||||
if (request == null) {
|
if (request == null) {
|
||||||
return DEFAULT_SPAN_NAME;
|
return DEFAULT_SPAN_NAME;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Setter<Request<?>> getSetter() {
|
protected TextMapPropagator.Setter<Request<?>> getSetter() {
|
||||||
return AwsSdkInjectAdapter.INSTANCE;
|
return AwsSdkInjectAdapter.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ public class RequestMeta {
|
||||||
// Note: aws1.x sdk doesn't have any truly async clients so we can store scope in request context
|
// Note: aws1.x sdk doesn't have any truly async clients so we can store scope in request context
|
||||||
// safely.
|
// safely.
|
||||||
public static final HandlerContextKey<ContextScopePair> CONTEXT_SCOPE_PAIR_CONTEXT_KEY =
|
public static final HandlerContextKey<ContextScopePair> CONTEXT_SCOPE_PAIR_CONTEXT_KEY =
|
||||||
new HandlerContextKey<>(RequestMeta.class.getName() + ".ContextSpanPair");
|
new HandlerContextKey<>(RequestMeta.class.getName() + ".ContextScopePair");
|
||||||
|
|
||||||
private String bucketName;
|
private String bucketName;
|
||||||
private String queueUrl;
|
private String queueUrl;
|
||||||
|
|
|
@ -30,31 +30,33 @@ public class TracingRequestHandler extends RequestHandler2 {
|
||||||
AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
|
AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
|
||||||
RequestMeta requestMeta = contextStore.get(originalRequest);
|
RequestMeta requestMeta = contextStore.get(originalRequest);
|
||||||
Context parentContext = Context.current();
|
Context parentContext = Context.current();
|
||||||
if (tracer().shouldStartSpan(parentContext)) {
|
if (!tracer().shouldStartSpan(parentContext)) {
|
||||||
Context context = tracer().startSpan(parentContext, request, requestMeta);
|
return;
|
||||||
Scope scope = context.makeCurrent();
|
|
||||||
request.addHandlerContext(
|
|
||||||
CONTEXT_SCOPE_PAIR_CONTEXT_KEY, new ContextScopePair(context, scope));
|
|
||||||
}
|
}
|
||||||
|
Context context = tracer().startSpan(parentContext, request, requestMeta);
|
||||||
|
Scope scope = context.makeCurrent();
|
||||||
|
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, new ContextScopePair(context, scope));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterResponse(Request<?> request, Response<?> response) {
|
public void afterResponse(Request<?> request, Response<?> response) {
|
||||||
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
||||||
if (scope != null) {
|
if (scope == null) {
|
||||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
return;
|
||||||
scope.closeScope();
|
|
||||||
tracer().end(scope.getContext(), response);
|
|
||||||
}
|
}
|
||||||
|
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||||
|
scope.closeScope();
|
||||||
|
tracer().end(scope.getContext(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterError(Request<?> request, Response<?> response, Exception e) {
|
public void afterError(Request<?> request, Response<?> response, Exception e) {
|
||||||
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
||||||
if (scope != null) {
|
if (scope == null) {
|
||||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
return;
|
||||||
scope.closeScope();
|
|
||||||
tracer().endExceptionally(scope.getContext(), response, e);
|
|
||||||
}
|
}
|
||||||
|
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||||
|
scope.closeScope();
|
||||||
|
tracer().endExceptionally(scope.getContext(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ package io.opentelemetry.instrumentation.awssdk.v2_2;
|
||||||
import static io.opentelemetry.instrumentation.awssdk.v2_2.TracingExecutionInterceptor.CONTEXT_ATTRIBUTE;
|
import static io.opentelemetry.instrumentation.awssdk.v2_2.TracingExecutionInterceptor.CONTEXT_ATTRIBUTE;
|
||||||
|
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.api.trace.Span;
|
|
||||||
import io.opentelemetry.api.trace.Span.Kind;
|
|
||||||
import io.opentelemetry.api.trace.Tracer;
|
import io.opentelemetry.api.trace.Tracer;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
|
@ -40,29 +38,17 @@ public class AwsSdk {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link ExecutionInterceptor} that can be used with an {@link
|
* Returns an {@link ExecutionInterceptor} that can be used with an {@link
|
||||||
* software.amazon.awssdk.http.SdkHttpClient} to trace SDK requests. Spans are created with the
|
* software.amazon.awssdk.http.SdkHttpClient} to trace SDK requests.
|
||||||
* kind {@link Kind#CLIENT}. If you also instrument the HTTP calls made by the SDK, e.g., by
|
|
||||||
* adding Apache HTTP client or Netty instrumentation, you may want to use {@link
|
|
||||||
* #newInterceptor(Kind)} with {@link Kind#INTERNAL} instead.
|
|
||||||
*/
|
*/
|
||||||
public static ExecutionInterceptor newInterceptor() {
|
public static ExecutionInterceptor newInterceptor() {
|
||||||
return newInterceptor(Kind.CLIENT);
|
return new TracingExecutionInterceptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link ExecutionInterceptor} that can be used with an {@link
|
* Returns the {@link Context} stored in the {@link ExecutionAttributes}, or {@code null} if there
|
||||||
* software.amazon.awssdk.http.SdkHttpClient} to trace SDK requests. Spans are created with the
|
* is no operation set.
|
||||||
* provided {@link Kind}.
|
|
||||||
*/
|
*/
|
||||||
public static ExecutionInterceptor newInterceptor(Kind kind) {
|
public static Context getContext(ExecutionAttributes attributes) {
|
||||||
return new TracingExecutionInterceptor(kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link Span} stored in the {@link ExecutionAttributes}, or {@code null} if there is
|
|
||||||
* no span set.
|
|
||||||
*/
|
|
||||||
public static Context getContextFromAttributes(ExecutionAttributes attributes) {
|
|
||||||
return attributes.getAttribute(CONTEXT_ATTRIBUTE);
|
return attributes.getAttribute(CONTEXT_ATTRIBUTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,21 +5,22 @@
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
||||||
|
|
||||||
|
import static io.opentelemetry.api.trace.Span.Kind.CLIENT;
|
||||||
|
|
||||||
import io.opentelemetry.api.trace.Span;
|
import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.api.trace.Span.Kind;
|
|
||||||
import io.opentelemetry.api.trace.Tracer;
|
|
||||||
import io.opentelemetry.api.trace.attributes.SemanticAttributes;
|
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
|
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
|
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
|
||||||
import software.amazon.awssdk.http.SdkHttpHeaders;
|
import software.amazon.awssdk.http.SdkHttpHeaders;
|
||||||
import software.amazon.awssdk.http.SdkHttpRequest;
|
import software.amazon.awssdk.http.SdkHttpRequest;
|
||||||
import software.amazon.awssdk.http.SdkHttpResponse;
|
import software.amazon.awssdk.http.SdkHttpResponse;
|
||||||
|
|
||||||
final class AwsSdkHttpClientTracer
|
final class AwsSdkHttpClientTracer
|
||||||
extends HttpClientTracer<SdkHttpRequest, SdkHttpRequest, SdkHttpResponse> {
|
extends HttpClientTracer<SdkHttpRequest, SdkHttpRequest.Builder, SdkHttpResponse> {
|
||||||
|
|
||||||
private static final AwsSdkHttpClientTracer TRACER = new AwsSdkHttpClientTracer();
|
private static final AwsSdkHttpClientTracer TRACER = new AwsSdkHttpClientTracer();
|
||||||
|
|
||||||
|
@ -27,10 +28,15 @@ final class AwsSdkHttpClientTracer
|
||||||
return TRACER;
|
return TRACER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certain headers in the request like User-Agent are only available after execution.
|
public Context startSpan(Context parentContext, ExecutionAttributes attributes) {
|
||||||
Span afterExecution(Span span, SdkHttpRequest request) {
|
String spanName = spanName(attributes);
|
||||||
span.setAttribute(SemanticAttributes.HTTP_USER_AGENT, requestHeader(request, USER_AGENT));
|
Span span =
|
||||||
return span;
|
tracer.spanBuilder(spanName).setSpanKind(CLIENT).setParent(parentContext).startSpan();
|
||||||
|
return withClientSpan(parentContext, span);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inject(Context context, SdkHttpRequest.Builder builder) {
|
||||||
|
AwsXRayPropagator.getInstance().inject(context, builder, getSetter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -59,8 +65,8 @@ final class AwsSdkHttpClientTracer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Setter<SdkHttpRequest> getSetter() {
|
protected TextMapPropagator.Setter<SdkHttpRequest.Builder> getSetter() {
|
||||||
return null;
|
return AwsSdkInjectAdapter.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String header(SdkHttpHeaders headers, String name) {
|
private static String header(SdkHttpHeaders headers, String name) {
|
||||||
|
@ -78,9 +84,9 @@ final class AwsSdkHttpClientTracer
|
||||||
super.onRequest(span, sdkHttpRequest);
|
super.onRequest(span, sdkHttpRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Context startSpan(Context parentContext, String name, Tracer tracer, Kind kind) {
|
private static String spanName(ExecutionAttributes attributes) {
|
||||||
Span clientSpan =
|
String awsServiceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME);
|
||||||
tracer.spanBuilder(name).setSpanKind(kind).setParent(parentContext).startSpan();
|
String awsOperation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME);
|
||||||
return parentContext.with(clientSpan).with(BaseTracer.CONTEXT_CLIENT_SPAN_KEY, clientSpan);
|
return awsServiceName + "." + awsOperation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,13 @@
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
||||||
|
|
||||||
import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk.getContextFromAttributes;
|
import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk.getContext;
|
||||||
import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkHttpClientTracer.tracer;
|
import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkHttpClientTracer.tracer;
|
||||||
import static io.opentelemetry.instrumentation.awssdk.v2_2.RequestType.ofSdkRequest;
|
import static io.opentelemetry.instrumentation.awssdk.v2_2.RequestType.ofSdkRequest;
|
||||||
|
|
||||||
import io.opentelemetry.api.trace.Span;
|
import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.api.trace.Span.Kind;
|
import io.opentelemetry.api.trace.attributes.SemanticAttributes;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator;
|
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -61,12 +60,6 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Kind kind;
|
|
||||||
|
|
||||||
TracingExecutionInterceptor(Kind kind) {
|
|
||||||
this.kind = kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private SdkRequestDecorator decorator(ExecutionAttributes executionAttributes) {
|
private SdkRequestDecorator decorator(ExecutionAttributes executionAttributes) {
|
||||||
RequestType type = getTypeFromAttributes(executionAttributes);
|
RequestType type = getTypeFromAttributes(executionAttributes);
|
||||||
|
@ -80,12 +73,12 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
@Override
|
@Override
|
||||||
public void beforeExecution(
|
public void beforeExecution(
|
||||||
Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
|
Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
|
||||||
io.opentelemetry.context.Context parentContext = io.opentelemetry.context.Context.current();
|
io.opentelemetry.context.Context parentOtelContext = io.opentelemetry.context.Context.current();
|
||||||
if (!tracer().shouldStartSpan(parentContext)) {
|
if (!tracer().shouldStartSpan(parentOtelContext)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
io.opentelemetry.context.Context otelContext =
|
io.opentelemetry.context.Context otelContext =
|
||||||
tracer().startSpan(parentContext, spanName(executionAttributes), AwsSdk.tracer(), kind);
|
tracer().startSpan(parentOtelContext, executionAttributes);
|
||||||
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, otelContext);
|
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, otelContext);
|
||||||
RequestType type = ofSdkRequest(context.request());
|
RequestType type = ofSdkRequest(context.request());
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
|
@ -103,20 +96,20 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
@Override
|
@Override
|
||||||
public SdkHttpRequest modifyHttpRequest(
|
public SdkHttpRequest modifyHttpRequest(
|
||||||
Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
|
Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
|
||||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
|
||||||
if (otelContext == null) {
|
if (otelContext == null) {
|
||||||
return context.httpRequest();
|
return context.httpRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
SdkHttpRequest.Builder builder = context.httpRequest().toBuilder();
|
SdkHttpRequest.Builder builder = context.httpRequest().toBuilder();
|
||||||
AwsXRayPropagator.getInstance().inject(otelContext, builder, AwsSdkInjectAdapter.INSTANCE);
|
tracer().inject(otelContext, builder);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterMarshalling(
|
public void afterMarshalling(
|
||||||
Context.AfterMarshalling context, ExecutionAttributes executionAttributes) {
|
Context.AfterMarshalling context, ExecutionAttributes executionAttributes) {
|
||||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
|
||||||
if (otelContext == null) {
|
if (otelContext == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -160,14 +153,18 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
scope.close();
|
scope.close();
|
||||||
}
|
}
|
||||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
|
||||||
if (otelContext != null) {
|
clearAttributes(executionAttributes);
|
||||||
clearAttributes(executionAttributes);
|
Span span = Span.fromContext(otelContext);
|
||||||
Span span = Span.fromContext(otelContext);
|
onUserAgentHeaderAvailable(span, context.httpRequest());
|
||||||
tracer().afterExecution(span, context.httpRequest());
|
onSdkResponse(span, context.response());
|
||||||
onSdkResponse(span, context.response());
|
tracer().end(otelContext, context.httpResponse());
|
||||||
tracer().end(otelContext, context.httpResponse());
|
}
|
||||||
}
|
|
||||||
|
// Certain headers in the request like User-Agent are only available after execution.
|
||||||
|
private void onUserAgentHeaderAvailable(Span span, SdkHttpRequest request) {
|
||||||
|
span.setAttribute(
|
||||||
|
SemanticAttributes.HTTP_USER_AGENT, tracer().requestHeader(request, "User-Agent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSdkResponse(Span span, SdkResponse response) {
|
private void onSdkResponse(Span span, SdkResponse response) {
|
||||||
|
@ -179,22 +176,13 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
@Override
|
@Override
|
||||||
public void onExecutionFailure(
|
public void onExecutionFailure(
|
||||||
Context.FailedExecution context, ExecutionAttributes executionAttributes) {
|
Context.FailedExecution context, ExecutionAttributes executionAttributes) {
|
||||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
|
||||||
if (otelContext != null) {
|
clearAttributes(executionAttributes);
|
||||||
clearAttributes(executionAttributes);
|
tracer().endExceptionally(otelContext, context.exception());
|
||||||
tracer().endExceptionally(otelContext, context.exception());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearAttributes(ExecutionAttributes executionAttributes) {
|
private void clearAttributes(ExecutionAttributes executionAttributes) {
|
||||||
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, null);
|
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, null);
|
||||||
executionAttributes.putAttribute(REQUEST_TYPE_ATTRIBUTE, null);
|
executionAttributes.putAttribute(REQUEST_TYPE_ATTRIBUTE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String spanName(ExecutionAttributes attributes) {
|
|
||||||
String awsServiceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME);
|
|
||||||
String awsOperation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME);
|
|
||||||
|
|
||||||
return awsServiceName + "." + awsOperation;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue