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 io.opentelemetry.api.trace.Span;
|
||||
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 java.net.URI;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -31,7 +31,7 @@ public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>,
|
|||
public AwsSdkClientTracer() {}
|
||||
|
||||
@Override
|
||||
public String spanNameForRequest(Request<?> request) {
|
||||
protected String spanNameForRequest(Request<?> request) {
|
||||
if (request == null) {
|
||||
return DEFAULT_SPAN_NAME;
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>,
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Setter<Request<?>> getSetter() {
|
||||
protected TextMapPropagator.Setter<Request<?>> getSetter() {
|
||||
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
|
||||
// safely.
|
||||
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 queueUrl;
|
||||
|
|
|
@ -30,31 +30,33 @@ public class TracingRequestHandler extends RequestHandler2 {
|
|||
AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
|
||||
RequestMeta requestMeta = contextStore.get(originalRequest);
|
||||
Context parentContext = Context.current();
|
||||
if (tracer().shouldStartSpan(parentContext)) {
|
||||
Context context = tracer().startSpan(parentContext, request, requestMeta);
|
||||
Scope scope = context.makeCurrent();
|
||||
request.addHandlerContext(
|
||||
CONTEXT_SCOPE_PAIR_CONTEXT_KEY, new ContextScopePair(context, scope));
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
return;
|
||||
}
|
||||
Context context = tracer().startSpan(parentContext, request, requestMeta);
|
||||
Scope scope = context.makeCurrent();
|
||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, new ContextScopePair(context, scope));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterResponse(Request<?> request, Response<?> response) {
|
||||
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
||||
if (scope != null) {
|
||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
scope.closeScope();
|
||||
tracer().end(scope.getContext(), response);
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
scope.closeScope();
|
||||
tracer().end(scope.getContext(), response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterError(Request<?> request, Response<?> response, Exception e) {
|
||||
ContextScopePair scope = request.getHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY);
|
||||
if (scope != null) {
|
||||
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, null);
|
||||
scope.closeScope();
|
||||
tracer().endExceptionally(scope.getContext(), response, e);
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
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 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.context.Context;
|
||||
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
|
||||
* software.amazon.awssdk.http.SdkHttpClient} to trace SDK requests. Spans are created with the
|
||||
* 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.
|
||||
* software.amazon.awssdk.http.SdkHttpClient} to trace SDK requests.
|
||||
*/
|
||||
public static ExecutionInterceptor newInterceptor() {
|
||||
return newInterceptor(Kind.CLIENT);
|
||||
return new TracingExecutionInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* provided {@link Kind}.
|
||||
* Returns the {@link Context} stored in the {@link ExecutionAttributes}, or {@code null} if there
|
||||
* is no operation set.
|
||||
*/
|
||||
public static ExecutionInterceptor newInterceptor(Kind kind) {
|
||||
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) {
|
||||
public static Context getContext(ExecutionAttributes attributes) {
|
||||
return attributes.getAttribute(CONTEXT_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,21 +5,22 @@
|
|||
|
||||
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.Kind;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.api.trace.attributes.SemanticAttributes;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
|
||||
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
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.SdkHttpRequest;
|
||||
import software.amazon.awssdk.http.SdkHttpResponse;
|
||||
|
||||
final class AwsSdkHttpClientTracer
|
||||
extends HttpClientTracer<SdkHttpRequest, SdkHttpRequest, SdkHttpResponse> {
|
||||
extends HttpClientTracer<SdkHttpRequest, SdkHttpRequest.Builder, SdkHttpResponse> {
|
||||
|
||||
private static final AwsSdkHttpClientTracer TRACER = new AwsSdkHttpClientTracer();
|
||||
|
||||
|
@ -27,10 +28,15 @@ final class AwsSdkHttpClientTracer
|
|||
return TRACER;
|
||||
}
|
||||
|
||||
// Certain headers in the request like User-Agent are only available after execution.
|
||||
Span afterExecution(Span span, SdkHttpRequest request) {
|
||||
span.setAttribute(SemanticAttributes.HTTP_USER_AGENT, requestHeader(request, USER_AGENT));
|
||||
return span;
|
||||
public Context startSpan(Context parentContext, ExecutionAttributes attributes) {
|
||||
String spanName = spanName(attributes);
|
||||
Span 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
|
||||
|
@ -59,8 +65,8 @@ final class AwsSdkHttpClientTracer
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Setter<SdkHttpRequest> getSetter() {
|
||||
return null;
|
||||
protected TextMapPropagator.Setter<SdkHttpRequest.Builder> getSetter() {
|
||||
return AwsSdkInjectAdapter.INSTANCE;
|
||||
}
|
||||
|
||||
private static String header(SdkHttpHeaders headers, String name) {
|
||||
|
@ -78,9 +84,9 @@ final class AwsSdkHttpClientTracer
|
|||
super.onRequest(span, sdkHttpRequest);
|
||||
}
|
||||
|
||||
public Context startSpan(Context parentContext, String name, Tracer tracer, Kind kind) {
|
||||
Span clientSpan =
|
||||
tracer.spanBuilder(name).setSpanKind(kind).setParent(parentContext).startSpan();
|
||||
return parentContext.with(clientSpan).with(BaseTracer.CONTEXT_CLIENT_SPAN_KEY, clientSpan);
|
||||
private static String spanName(ExecutionAttributes attributes) {
|
||||
String awsServiceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME);
|
||||
String awsOperation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME);
|
||||
return awsServiceName + "." + awsOperation;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
|
||||
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.RequestType.ofSdkRequest;
|
||||
|
||||
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.extension.trace.propagation.AwsXRayPropagator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -61,12 +60,6 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
return result;
|
||||
}
|
||||
|
||||
private final Kind kind;
|
||||
|
||||
TracingExecutionInterceptor(Kind kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SdkRequestDecorator decorator(ExecutionAttributes executionAttributes) {
|
||||
RequestType type = getTypeFromAttributes(executionAttributes);
|
||||
|
@ -80,12 +73,12 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
@Override
|
||||
public void beforeExecution(
|
||||
Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
|
||||
io.opentelemetry.context.Context parentContext = io.opentelemetry.context.Context.current();
|
||||
if (!tracer().shouldStartSpan(parentContext)) {
|
||||
io.opentelemetry.context.Context parentOtelContext = io.opentelemetry.context.Context.current();
|
||||
if (!tracer().shouldStartSpan(parentOtelContext)) {
|
||||
return;
|
||||
}
|
||||
io.opentelemetry.context.Context otelContext =
|
||||
tracer().startSpan(parentContext, spanName(executionAttributes), AwsSdk.tracer(), kind);
|
||||
tracer().startSpan(parentOtelContext, executionAttributes);
|
||||
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, otelContext);
|
||||
RequestType type = ofSdkRequest(context.request());
|
||||
if (type != null) {
|
||||
|
@ -103,20 +96,20 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
@Override
|
||||
public SdkHttpRequest modifyHttpRequest(
|
||||
Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
|
||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
||||
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
|
||||
if (otelContext == null) {
|
||||
return context.httpRequest();
|
||||
}
|
||||
|
||||
SdkHttpRequest.Builder builder = context.httpRequest().toBuilder();
|
||||
AwsXRayPropagator.getInstance().inject(otelContext, builder, AwsSdkInjectAdapter.INSTANCE);
|
||||
tracer().inject(otelContext, builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterMarshalling(
|
||||
Context.AfterMarshalling context, ExecutionAttributes executionAttributes) {
|
||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
||||
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
|
||||
if (otelContext == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -160,14 +153,18 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
if (scope != null) {
|
||||
scope.close();
|
||||
}
|
||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
||||
if (otelContext != null) {
|
||||
clearAttributes(executionAttributes);
|
||||
Span span = Span.fromContext(otelContext);
|
||||
tracer().afterExecution(span, context.httpRequest());
|
||||
onSdkResponse(span, context.response());
|
||||
tracer().end(otelContext, context.httpResponse());
|
||||
}
|
||||
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
|
||||
clearAttributes(executionAttributes);
|
||||
Span span = Span.fromContext(otelContext);
|
||||
onUserAgentHeaderAvailable(span, context.httpRequest());
|
||||
onSdkResponse(span, context.response());
|
||||
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) {
|
||||
|
@ -179,22 +176,13 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
@Override
|
||||
public void onExecutionFailure(
|
||||
Context.FailedExecution context, ExecutionAttributes executionAttributes) {
|
||||
io.opentelemetry.context.Context otelContext = getContextFromAttributes(executionAttributes);
|
||||
if (otelContext != null) {
|
||||
clearAttributes(executionAttributes);
|
||||
tracer().endExceptionally(otelContext, context.exception());
|
||||
}
|
||||
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
|
||||
clearAttributes(executionAttributes);
|
||||
tracer().endExceptionally(otelContext, context.exception());
|
||||
}
|
||||
|
||||
private void clearAttributes(ExecutionAttributes executionAttributes) {
|
||||
executionAttributes.putAttribute(CONTEXT_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