Convert AwsSdk1 to Instrumenter API (#4315)
* Convert AwsSdk1 to Instrumenter API * Apply suggestions from code review Co-authored-by: Mateusz Rzeszutek <mrzeszutek@splunk.com> * Polish * Polish and tests * Polish Co-authored-by: Mateusz Rzeszutek <mrzeszutek@splunk.com>
This commit is contained in:
parent
478f936d54
commit
99f6bcde92
|
@ -40,7 +40,7 @@ public abstract class NetClientAttributesExtractor<REQUEST, RESPONSE>
|
|||
set(attributes, SemanticAttributes.NET_PEER_IP, peerIp);
|
||||
|
||||
Integer peerPort = peerPort(request, response);
|
||||
if (peerPort != null) {
|
||||
if (peerPort != null && peerPort > 0) {
|
||||
set(attributes, SemanticAttributes.NET_PEER_PORT, (long) peerPort);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public abstract class NetServerAttributesExtractor<REQUEST, RESPONSE>
|
|||
set(attributes, SemanticAttributes.NET_PEER_IP, peerIp);
|
||||
|
||||
Integer peerPort = peerPort(request);
|
||||
if (peerPort != null) {
|
||||
if (peerPort != null && peerPort > 0) {
|
||||
set(attributes, SemanticAttributes.NET_PEER_PORT, (long) peerPort);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,4 +114,27 @@ class NetClientAttributesExtractorTest {
|
|||
entry(SemanticAttributes.NET_PEER_PORT, 42L),
|
||||
entry(SemanticAttributes.NET_PEER_IP, "4.3.2.1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotSetNegativePort() {
|
||||
// given
|
||||
Map<String, String> request = new HashMap<>();
|
||||
request.put("peerPort", "-42");
|
||||
|
||||
Map<String, String> response = new HashMap<>();
|
||||
response.put("peerPort", "-1");
|
||||
|
||||
TestNetClientAttributesExtractor extractor = new TestNetClientAttributesExtractor();
|
||||
|
||||
// when
|
||||
AttributesBuilder startAttributes = Attributes.builder();
|
||||
extractor.onStart(startAttributes, request);
|
||||
|
||||
AttributesBuilder endAttributes = Attributes.builder();
|
||||
extractor.onEnd(endAttributes, request, response, null);
|
||||
|
||||
// then
|
||||
assertThat(startAttributes.build()).isEmpty();
|
||||
assertThat(endAttributes.build()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,4 +107,27 @@ class NetServerAttributesExtractorTest {
|
|||
|
||||
assertThat(endAttributes.build()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotSetNegativePort() {
|
||||
// given
|
||||
Map<String, String> request = new HashMap<>();
|
||||
request.put("peerPort", "-42");
|
||||
|
||||
Map<String, String> response = new HashMap<>();
|
||||
response.put("peerPort", "-1");
|
||||
|
||||
TestNetServerAttributesExtractor extractor = new TestNetServerAttributesExtractor();
|
||||
|
||||
// when
|
||||
AttributesBuilder startAttributes = Attributes.builder();
|
||||
extractor.onStart(startAttributes, request);
|
||||
|
||||
AttributesBuilder endAttributes = Attributes.builder();
|
||||
extractor.onEnd(endAttributes, request, response, null);
|
||||
|
||||
// then
|
||||
assertThat(startAttributes.build()).isEmpty();
|
||||
assertThat(endAttributes.build()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
|
||||
final class AwsExperimentalAttributes {
|
||||
static final AttributeKey<String> AWS_AGENT = stringKey("aws.agent");
|
||||
static final AttributeKey<String> AWS_SERVICE = stringKey("aws.service");
|
||||
static final AttributeKey<String> AWS_OPERATION = stringKey("aws.operation");
|
||||
static final AttributeKey<String> AWS_ENDPOINT = stringKey("aws.endpoint");
|
||||
static final AttributeKey<String> AWS_BUCKET_NAME = stringKey("aws.bucket.name");
|
||||
static final AttributeKey<String> AWS_QUEUE_URL = stringKey("aws.queue.url");
|
||||
static final AttributeKey<String> AWS_QUEUE_NAME = stringKey("aws.queue.name");
|
||||
static final AttributeKey<String> AWS_STREAM_NAME = stringKey("aws.stream.name");
|
||||
static final AttributeKey<String> AWS_TABLE_NAME = stringKey("aws.table.name");
|
||||
static final AttributeKey<String> AWS_REQUEST_ID = stringKey("aws.requestId");
|
||||
|
||||
private AwsExperimentalAttributes() {}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
class AwsSdkAttributesExtractor extends HttpClientAttributesExtractor<Request<?>, Response<?>> {
|
||||
@Override
|
||||
protected String url(Request<?> request) {
|
||||
return request.getEndpoint().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable String flavor(Request<?> request, @Nullable Response<?> response) {
|
||||
return SemanticAttributes.HttpFlavorValues.HTTP_1_1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(Request<?> request) {
|
||||
return request.getHttpMethod().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> requestHeader(Request<?> request, String name) {
|
||||
String value = request.getHeaders().get(name.equals("user-agent") ? "User-Agent" : name);
|
||||
return value == null ? emptyList() : singletonList(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Long requestContentLength(
|
||||
Request<?> request, @Nullable Response<?> response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Long requestContentLengthUncompressed(
|
||||
Request<?> request, @Nullable Response<?> response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer statusCode(Request<?> request, Response<?> response) {
|
||||
return response.getHttpResponse().getStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Long responseContentLength(Request<?> request, Response<?> response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Long responseContentLengthUncompressed(
|
||||
Request<?> request, Response<?> response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> responseHeader(Request<?> request, Response<?> response, String name) {
|
||||
String value = response.getHttpResponse().getHeaders().get(name);
|
||||
return value == null ? emptyList() : singletonList(value);
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceResponse;
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapSetter;
|
||||
import io.opentelemetry.extension.aws.AwsXrayPropagator;
|
||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
final class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>, Response<?>> {
|
||||
|
||||
private static final ClassValue<String> OPERATION_NAME =
|
||||
new ClassValue<String>() {
|
||||
@Override
|
||||
protected String computeValue(Class<?> type) {
|
||||
String ret = type.getSimpleName();
|
||||
ret = ret.substring(0, ret.length() - 7); // remove 'Request'
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
static final String COMPONENT_NAME = "java-aws-sdk";
|
||||
|
||||
private final NamesCache namesCache = new NamesCache();
|
||||
|
||||
private final boolean captureExperimentalSpanAttributes;
|
||||
|
||||
AwsSdkClientTracer(OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||
super(openTelemetry, new NetPeerAttributes());
|
||||
this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void inject(Context context, Request<?> request) {
|
||||
AwsXrayPropagator.getInstance().inject(context, request, AwsSdkInjectAdapter.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String spanNameForRequest(Request<?> request) {
|
||||
if (request == null) {
|
||||
return DEFAULT_SPAN_NAME;
|
||||
}
|
||||
String awsServiceName = request.getServiceName();
|
||||
Class<?> awsOperation = request.getOriginalRequest().getClass();
|
||||
return qualifiedOperation(awsServiceName, awsOperation);
|
||||
}
|
||||
|
||||
public Context startSpan(SpanKind kind, Context parentContext, Request<?> request) {
|
||||
Context context = super.startSpan(kind, parentContext, request, request, -1);
|
||||
Span span = Span.fromContext(context);
|
||||
|
||||
String awsServiceName = request.getServiceName();
|
||||
|
||||
if (captureExperimentalSpanAttributes) {
|
||||
span.setAttribute("aws.agent", COMPONENT_NAME);
|
||||
span.setAttribute("aws.service", awsServiceName);
|
||||
span.setAttribute("aws.operation", extractOperationName(request));
|
||||
span.setAttribute("aws.endpoint", request.getEndpoint().toString());
|
||||
|
||||
Object originalRequest = request.getOriginalRequest();
|
||||
String bucketName = RequestAccess.getBucketName(originalRequest);
|
||||
if (bucketName != null) {
|
||||
span.setAttribute("aws.bucket.name", bucketName);
|
||||
}
|
||||
String queueUrl = RequestAccess.getQueueUrl(originalRequest);
|
||||
if (queueUrl != null) {
|
||||
span.setAttribute("aws.queue.url", queueUrl);
|
||||
}
|
||||
String queueName = RequestAccess.getQueueName(originalRequest);
|
||||
if (queueName != null) {
|
||||
span.setAttribute("aws.queue.name", queueName);
|
||||
}
|
||||
String streamName = RequestAccess.getStreamName(originalRequest);
|
||||
if (streamName != null) {
|
||||
span.setAttribute("aws.stream.name", streamName);
|
||||
}
|
||||
String tableName = RequestAccess.getTableName(originalRequest);
|
||||
if (tableName != null) {
|
||||
span.setAttribute("aws.table.name", tableName);
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Span span, Response<?> response) {
|
||||
if (captureExperimentalSpanAttributes
|
||||
&& response != null
|
||||
&& response.getAwsResponse() instanceof AmazonWebServiceResponse) {
|
||||
AmazonWebServiceResponse<?> awsResp = (AmazonWebServiceResponse<?>) response.getAwsResponse();
|
||||
span.setAttribute("aws.requestId", awsResp.getRequestId());
|
||||
}
|
||||
super.onResponse(span, response);
|
||||
}
|
||||
|
||||
private String qualifiedOperation(String service, Class<?> operation) {
|
||||
ConcurrentHashMap<String, String> cache = namesCache.get(operation);
|
||||
return cache.computeIfAbsent(
|
||||
service,
|
||||
s ->
|
||||
s.replace("Amazon", "").trim()
|
||||
+ '.'
|
||||
+ operation.getSimpleName().replace("Request", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(Request<?> request) {
|
||||
return request.getHttpMethod().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URI url(Request<?> request) {
|
||||
return request.getEndpoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer status(Response<?> response) {
|
||||
return response.getHttpResponse().getStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String requestHeader(Request<?> request, String name) {
|
||||
return request.getHeaders().get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String responseHeader(Response<?> response, String name) {
|
||||
return response.getHttpResponse().getHeaders().get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextMapSetter<Request<?>> getSetter() {
|
||||
// We override injection and don't want to have the base class do it accidentally.
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.aws-sdk-1.11";
|
||||
}
|
||||
|
||||
static final class NamesCache extends ClassValue<ConcurrentHashMap<String, String>> {
|
||||
@Override
|
||||
protected ConcurrentHashMap<String, String> computeValue(Class<?> type) {
|
||||
return new ConcurrentHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private static String extractOperationName(Request<?> request) {
|
||||
return OPERATION_NAME.get(request.getOriginalRequest().getClass());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_AGENT;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_BUCKET_NAME;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_ENDPOINT;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_OPERATION;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_QUEUE_NAME;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_QUEUE_URL;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_REQUEST_ID;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_SERVICE;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STREAM_NAME;
|
||||
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_TABLE_NAME;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceResponse;
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import io.opentelemetry.api.common.AttributesBuilder;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
class AwsSdkExperimentalAttributesExtractor extends AttributesExtractor<Request<?>, Response<?>> {
|
||||
private static final String COMPONENT_NAME = "java-aws-sdk";
|
||||
private static final ClassValue<String> OPERATION_NAME =
|
||||
new ClassValue<String>() {
|
||||
@Override
|
||||
protected String computeValue(Class<?> type) {
|
||||
String ret = type.getSimpleName();
|
||||
ret = ret.substring(0, ret.length() - 7); // remove 'Request'
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onStart(AttributesBuilder attributes, Request<?> request) {
|
||||
set(attributes, AWS_AGENT, COMPONENT_NAME);
|
||||
set(attributes, AWS_SERVICE, request.getServiceName());
|
||||
set(attributes, AWS_OPERATION, extractOperationName(request));
|
||||
set(attributes, AWS_ENDPOINT, request.getEndpoint().toString());
|
||||
|
||||
Object originalRequest = request.getOriginalRequest();
|
||||
set(attributes, AWS_BUCKET_NAME, RequestAccess.getBucketName(originalRequest));
|
||||
set(attributes, AWS_QUEUE_URL, RequestAccess.getQueueUrl(originalRequest));
|
||||
set(attributes, AWS_QUEUE_NAME, RequestAccess.getQueueName(originalRequest));
|
||||
set(attributes, AWS_STREAM_NAME, RequestAccess.getStreamName(originalRequest));
|
||||
set(attributes, AWS_TABLE_NAME, RequestAccess.getTableName(originalRequest));
|
||||
}
|
||||
|
||||
private static String extractOperationName(Request<?> request) {
|
||||
return OPERATION_NAME.get(request.getOriginalRequest().getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnd(
|
||||
AttributesBuilder attributes,
|
||||
Request<?> request,
|
||||
@Nullable Response<?> response,
|
||||
@Nullable Throwable error) {
|
||||
if (response != null && response.getAwsResponse() instanceof AmazonWebServiceResponse) {
|
||||
AmazonWebServiceResponse<?> awsResp = (AmazonWebServiceResponse<?>) response.getAwsResponse();
|
||||
set(attributes, AWS_REQUEST_ID, awsResp.getRequestId());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
final class AwsSdkInstrumenterFactory {
|
||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.aws-sdk-1.11";
|
||||
|
||||
private static final AwsSdkAttributesExtractor attributesExtractor =
|
||||
new AwsSdkAttributesExtractor();
|
||||
private static final AwsSdkNetAttributesExtractor netAttributesExtractor =
|
||||
new AwsSdkNetAttributesExtractor();
|
||||
private static final AwsSdkExperimentalAttributesExtractor experimentalAttributesExtractor =
|
||||
new AwsSdkExperimentalAttributesExtractor();
|
||||
private static final AwsSdkSpanKindExtractor spanKindExtractor = new AwsSdkSpanKindExtractor();
|
||||
|
||||
private static final List<AttributesExtractor<Request<?>, Response<?>>>
|
||||
defaultAttributesExtractors = Arrays.asList(attributesExtractor, netAttributesExtractor);
|
||||
private static final List<AttributesExtractor<Request<?>, Response<?>>>
|
||||
extendedAttributesExtractors =
|
||||
Arrays.asList(
|
||||
attributesExtractor, netAttributesExtractor, experimentalAttributesExtractor);
|
||||
private static final AwsSdkSpanNameExtractor spanName = new AwsSdkSpanNameExtractor();
|
||||
|
||||
static Instrumenter<Request<?>, Response<?>> requestInstrumenter(
|
||||
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||
|
||||
return createInstrumenter(
|
||||
openTelemetry,
|
||||
captureExperimentalSpanAttributes,
|
||||
AwsSdkInstrumenterFactory.spanKindExtractor);
|
||||
}
|
||||
|
||||
static Instrumenter<Request<?>, Response<?>> consumerInstrumenter(
|
||||
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||
|
||||
return createInstrumenter(
|
||||
openTelemetry, captureExperimentalSpanAttributes, SpanKindExtractor.alwaysConsumer());
|
||||
}
|
||||
|
||||
private static Instrumenter<Request<?>, Response<?>> createInstrumenter(
|
||||
OpenTelemetry openTelemetry,
|
||||
boolean captureExperimentalSpanAttributes,
|
||||
SpanKindExtractor<Request<?>> kindExtractor) {
|
||||
return Instrumenter.<Request<?>, Response<?>>newBuilder(
|
||||
openTelemetry, INSTRUMENTATION_NAME, spanName)
|
||||
.addAttributesExtractors(
|
||||
captureExperimentalSpanAttributes
|
||||
? extendedAttributesExtractors
|
||||
: defaultAttributesExtractors)
|
||||
.newInstrumenter(kindExtractor);
|
||||
}
|
||||
|
||||
private AwsSdkInstrumenterFactory() {}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
class AwsSdkNetAttributesExtractor extends NetClientAttributesExtractor<Request<?>, Response<?>> {
|
||||
@Override
|
||||
public String transport(Request<?> request, @Nullable Response<?> response) {
|
||||
return SemanticAttributes.NetTransportValues.IP_TCP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String peerName(Request<?> request, @Nullable Response<?> response) {
|
||||
return request.getEndpoint().getHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer peerPort(Request<?> request, @Nullable Response<?> response) {
|
||||
return request.getEndpoint().getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String peerIp(Request<?> request, @Nullable Response<?> response) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceRequest;
|
||||
import com.amazonaws.Request;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
||||
|
||||
class AwsSdkSpanKindExtractor implements SpanKindExtractor<Request<?>> {
|
||||
@Override
|
||||
public SpanKind extract(Request<?> request) {
|
||||
AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
|
||||
return (isSqsProducer(originalRequest) ? SpanKind.PRODUCER : SpanKind.CLIENT);
|
||||
}
|
||||
|
||||
private static boolean isSqsProducer(AmazonWebServiceRequest request) {
|
||||
return request
|
||||
.getClass()
|
||||
.getName()
|
||||
.equals("com.amazonaws.services.sqs.model.SendMessageRequest");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.Request;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
class AwsSdkSpanNameExtractor implements SpanNameExtractor<Request<?>> {
|
||||
private final NamesCache namesCache = new NamesCache();
|
||||
|
||||
@Override
|
||||
public String extract(Request<?> request) {
|
||||
String awsServiceName = request.getServiceName();
|
||||
Class<?> awsOperation = request.getOriginalRequest().getClass();
|
||||
return qualifiedOperation(awsServiceName, awsOperation);
|
||||
}
|
||||
|
||||
private String qualifiedOperation(String service, Class<?> operation) {
|
||||
ConcurrentHashMap<String, String> cache = namesCache.get(operation);
|
||||
return cache.computeIfAbsent(
|
||||
service,
|
||||
s ->
|
||||
s.replace("Amazon", "").trim()
|
||||
+ '.'
|
||||
+ operation.getSimpleName().replace("Request", ""));
|
||||
}
|
||||
|
||||
static final class NamesCache extends ClassValue<ConcurrentHashMap<String, String>> {
|
||||
@Override
|
||||
protected ConcurrentHashMap<String, String> computeValue(Class<?> type) {
|
||||
return new ConcurrentHashMap<>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,9 +6,11 @@
|
|||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import com.amazonaws.handlers.RequestHandler2;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
|
||||
/**
|
||||
* Entrypoint for tracing AWS SDK v1 clients.
|
||||
|
@ -40,10 +42,16 @@ public class AwsSdkTracing {
|
|||
return new AwsSdkTracingBuilder(openTelemetry);
|
||||
}
|
||||
|
||||
private final AwsSdkClientTracer tracer;
|
||||
private final Instrumenter<Request<?>, Response<?>> requestInstrumenter;
|
||||
private final Instrumenter<Request<?>, Response<?>> consumerInstrumenter;
|
||||
|
||||
AwsSdkTracing(OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||
tracer = new AwsSdkClientTracer(openTelemetry, captureExperimentalSpanAttributes);
|
||||
requestInstrumenter =
|
||||
AwsSdkInstrumenterFactory.requestInstrumenter(
|
||||
openTelemetry, captureExperimentalSpanAttributes);
|
||||
consumerInstrumenter =
|
||||
AwsSdkInstrumenterFactory.consumerInstrumenter(
|
||||
openTelemetry, captureExperimentalSpanAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,6 +59,6 @@ public class AwsSdkTracing {
|
|||
* withRequestHandlers}.
|
||||
*/
|
||||
public RequestHandler2 newRequestHandler() {
|
||||
return new TracingRequestHandler(tracer);
|
||||
return new TracingRequestHandler(requestInstrumenter, consumerInstrumenter);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ final class SqsReceiveMessageRequestAccess {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<String> getAttributeNames(AmazonWebServiceRequest request) {
|
||||
if (GET_ATTRIBUTE_NAMES == null) {
|
||||
return Collections.emptyList();
|
||||
|
|
|
@ -10,8 +10,9 @@ import com.amazonaws.Request;
|
|||
import com.amazonaws.Response;
|
||||
import com.amazonaws.handlers.HandlerContextKey;
|
||||
import com.amazonaws.handlers.RequestHandler2;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.extension.aws.AwsXrayPropagator;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
|
@ -21,30 +22,27 @@ final class TracingRequestHandler extends RequestHandler2 {
|
|||
static final HandlerContextKey<Context> CONTEXT =
|
||||
new HandlerContextKey<>(Context.class.getName());
|
||||
|
||||
private final AwsSdkClientTracer tracer;
|
||||
private final Instrumenter<Request<?>, Response<?>> requestInstrumenter;
|
||||
private final Instrumenter<Request<?>, Response<?>> consumerInstrumenter;
|
||||
|
||||
TracingRequestHandler(AwsSdkClientTracer tracer) {
|
||||
this.tracer = tracer;
|
||||
TracingRequestHandler(
|
||||
Instrumenter<Request<?>, Response<?>> requestInstrumenter,
|
||||
Instrumenter<Request<?>, Response<?>> consumerInstrumenter) {
|
||||
this.requestInstrumenter = requestInstrumenter;
|
||||
this.consumerInstrumenter = consumerInstrumenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeRequest(Request<?> request) {
|
||||
AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
|
||||
SpanKind kind = (isSqsProducer(originalRequest) ? SpanKind.PRODUCER : SpanKind.CLIENT);
|
||||
|
||||
Context parentContext = Context.current();
|
||||
if (!tracer.shouldStartSpan(parentContext)) {
|
||||
if (!requestInstrumenter.shouldStart(parentContext, request)) {
|
||||
return;
|
||||
}
|
||||
Context context = tracer.startSpan(kind, parentContext, request);
|
||||
request.addHandlerContext(CONTEXT, context);
|
||||
}
|
||||
Context context = requestInstrumenter.start(parentContext, request);
|
||||
|
||||
private static boolean isSqsProducer(AmazonWebServiceRequest request) {
|
||||
return request
|
||||
.getClass()
|
||||
.getName()
|
||||
.equals("com.amazonaws.services.sqs.model.SendMessageRequest");
|
||||
AwsXrayPropagator.getInstance().inject(context, request, AwsSdkInjectAdapter.INSTANCE);
|
||||
|
||||
request.addHandlerContext(CONTEXT, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,8 +77,8 @@ final class TracingRequestHandler extends RequestHandler2 {
|
|||
private void createConsumerSpan(Object message, Request<?> request, Response<?> response) {
|
||||
Context parentContext =
|
||||
SqsParentContext.ofSystemAttributes(SqsMessageAccess.getAttributes(message));
|
||||
Context context = tracer.startSpan(SpanKind.CONSUMER, parentContext, request);
|
||||
tracer.end(context, response);
|
||||
Context context = consumerInstrumenter.start(parentContext, request);
|
||||
consumerInstrumenter.end(context, request, response, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,10 +93,6 @@ final class TracingRequestHandler extends RequestHandler2 {
|
|||
return;
|
||||
}
|
||||
request.addHandlerContext(CONTEXT, null);
|
||||
if (error == null) {
|
||||
tracer.end(context, response);
|
||||
} else {
|
||||
tracer.endExceptionally(context, response, error);
|
||||
}
|
||||
requestInstrumenter.end(context, request, response, error);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue