Add messaging conventions to sqs spans (#9712)
This commit is contained in:
parent
e9f07d3195
commit
6719ba358e
|
@ -192,7 +192,7 @@ class S3TracingTest extends AgentInstrumentationSpecification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
name "SQS.ReceiveMessage"
|
name "s3ToSqsTestQueue receive"
|
||||||
kind CONSUMER
|
kind CONSUMER
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -210,6 +210,9 @@ class S3TracingTest extends AgentInstrumentationSpecification {
|
||||||
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
||||||
"net.peer.port" { it == null || Number }
|
"net.peer.port" { it == null || Number }
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "s3ToSqsTestQueue"
|
||||||
|
"$SemanticAttributes.MESSAGING_OPERATION" "receive"
|
||||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
}
|
}
|
||||||
|
@ -556,7 +559,7 @@ class S3TracingTest extends AgentInstrumentationSpecification {
|
||||||
}
|
}
|
||||||
trace(9, 1) {
|
trace(9, 1) {
|
||||||
span(0) {
|
span(0) {
|
||||||
name "SQS.ReceiveMessage"
|
name "s3ToSnsToSqsTestQueue receive"
|
||||||
kind CONSUMER
|
kind CONSUMER
|
||||||
hasNoParent()
|
hasNoParent()
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -574,6 +577,9 @@ class S3TracingTest extends AgentInstrumentationSpecification {
|
||||||
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
||||||
"net.peer.port" { it == null || Number }
|
"net.peer.port" { it == null || Number }
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "s3ToSnsToSqsTestQueue"
|
||||||
|
"$SemanticAttributes.MESSAGING_OPERATION" "receive"
|
||||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,7 +176,7 @@ class SnsTracingTest extends AgentInstrumentationSpecification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
name "SQS.ReceiveMessage"
|
name "snsToSqsTestQueue receive"
|
||||||
kind CONSUMER
|
kind CONSUMER
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -194,6 +194,9 @@ class SnsTracingTest extends AgentInstrumentationSpecification {
|
||||||
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
||||||
"net.peer.port" { it == null || Number }
|
"net.peer.port" { it == null || Number }
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "snsToSqsTestQueue"
|
||||||
|
"$SemanticAttributes.MESSAGING_OPERATION" "receive"
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,20 @@
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
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.Request;
|
||||||
import com.amazonaws.Response;
|
import com.amazonaws.Response;
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessageOperation;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingAttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcClientAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcClientAttributesExtractor;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -25,7 +32,6 @@ final class AwsSdkInstrumenterFactory {
|
||||||
RpcClientAttributesExtractor.create(AwsSdkRpcAttributesGetter.INSTANCE);
|
RpcClientAttributesExtractor.create(AwsSdkRpcAttributesGetter.INSTANCE);
|
||||||
private static final AwsSdkExperimentalAttributesExtractor experimentalAttributesExtractor =
|
private static final AwsSdkExperimentalAttributesExtractor experimentalAttributesExtractor =
|
||||||
new AwsSdkExperimentalAttributesExtractor();
|
new AwsSdkExperimentalAttributesExtractor();
|
||||||
private static final AwsSdkSpanKindExtractor spanKindExtractor = new AwsSdkSpanKindExtractor();
|
|
||||||
|
|
||||||
private static final List<AttributesExtractor<Request<?>, Response<?>>>
|
private static final List<AttributesExtractor<Request<?>, Response<?>>>
|
||||||
defaultAttributesExtractors = Arrays.asList(httpAttributesExtractor, rpcAttributesExtractor);
|
defaultAttributesExtractors = Arrays.asList(httpAttributesExtractor, rpcAttributesExtractor);
|
||||||
|
@ -41,27 +47,55 @@ final class AwsSdkInstrumenterFactory {
|
||||||
return createInstrumenter(
|
return createInstrumenter(
|
||||||
openTelemetry,
|
openTelemetry,
|
||||||
captureExperimentalSpanAttributes,
|
captureExperimentalSpanAttributes,
|
||||||
AwsSdkInstrumenterFactory.spanKindExtractor);
|
spanName,
|
||||||
|
SpanKindExtractor.alwaysClient(),
|
||||||
|
emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Instrumenter<Request<?>, Response<?>> consumerInstrumenter(
|
static Instrumenter<Request<?>, Response<?>> consumerInstrumenter(
|
||||||
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||||
|
return sqsInstrumenter(
|
||||||
|
openTelemetry, MessageOperation.RECEIVE, captureExperimentalSpanAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Instrumenter<Request<?>, Response<?>> producerInstrumenter(
|
||||||
|
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||||
|
return sqsInstrumenter(
|
||||||
|
openTelemetry, MessageOperation.PUBLISH, captureExperimentalSpanAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Instrumenter<Request<?>, Response<?>> sqsInstrumenter(
|
||||||
|
OpenTelemetry openTelemetry,
|
||||||
|
MessageOperation operation,
|
||||||
|
boolean captureExperimentalSpanAttributes) {
|
||||||
|
SqsAttributesGetter getter = SqsAttributesGetter.INSTANCE;
|
||||||
|
AttributesExtractor<Request<?>, Response<?>> messagingAttributeExtractor =
|
||||||
|
MessagingAttributesExtractor.builder(getter, operation).build();
|
||||||
|
|
||||||
return createInstrumenter(
|
return createInstrumenter(
|
||||||
openTelemetry, captureExperimentalSpanAttributes, SpanKindExtractor.alwaysConsumer());
|
openTelemetry,
|
||||||
|
captureExperimentalSpanAttributes,
|
||||||
|
MessagingSpanNameExtractor.create(getter, operation),
|
||||||
|
operation == MessageOperation.PUBLISH
|
||||||
|
? SpanKindExtractor.alwaysProducer()
|
||||||
|
: SpanKindExtractor.alwaysConsumer(),
|
||||||
|
singletonList(messagingAttributeExtractor));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Instrumenter<Request<?>, Response<?>> createInstrumenter(
|
private static Instrumenter<Request<?>, Response<?>> createInstrumenter(
|
||||||
OpenTelemetry openTelemetry,
|
OpenTelemetry openTelemetry,
|
||||||
boolean captureExperimentalSpanAttributes,
|
boolean captureExperimentalSpanAttributes,
|
||||||
SpanKindExtractor<Request<?>> kindExtractor) {
|
SpanNameExtractor<Request<?>> spanNameExtractor,
|
||||||
|
SpanKindExtractor<Request<?>> spanKindExtractor,
|
||||||
|
List<AttributesExtractor<Request<?>, Response<?>>> additionalAttributeExtractors) {
|
||||||
return Instrumenter.<Request<?>, Response<?>>builder(
|
return Instrumenter.<Request<?>, Response<?>>builder(
|
||||||
openTelemetry, INSTRUMENTATION_NAME, spanName)
|
openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
|
||||||
.addAttributesExtractors(
|
.addAttributesExtractors(
|
||||||
captureExperimentalSpanAttributes
|
captureExperimentalSpanAttributes
|
||||||
? extendedAttributesExtractors
|
? extendedAttributesExtractors
|
||||||
: defaultAttributesExtractors)
|
: defaultAttributesExtractors)
|
||||||
.buildInstrumenter(kindExtractor);
|
.addAttributesExtractors(additionalAttributeExtractors)
|
||||||
|
.buildInstrumenter(spanKindExtractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AwsSdkInstrumenterFactory() {}
|
private AwsSdkInstrumenterFactory() {}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -46,6 +46,7 @@ public class AwsSdkTelemetry {
|
||||||
|
|
||||||
private final Instrumenter<Request<?>, Response<?>> requestInstrumenter;
|
private final Instrumenter<Request<?>, Response<?>> requestInstrumenter;
|
||||||
private final Instrumenter<Request<?>, Response<?>> consumerInstrumenter;
|
private final Instrumenter<Request<?>, Response<?>> consumerInstrumenter;
|
||||||
|
private final Instrumenter<Request<?>, Response<?>> producerInstrumenter;
|
||||||
|
|
||||||
AwsSdkTelemetry(OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
AwsSdkTelemetry(OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||||
requestInstrumenter =
|
requestInstrumenter =
|
||||||
|
@ -54,6 +55,9 @@ public class AwsSdkTelemetry {
|
||||||
consumerInstrumenter =
|
consumerInstrumenter =
|
||||||
AwsSdkInstrumenterFactory.consumerInstrumenter(
|
AwsSdkInstrumenterFactory.consumerInstrumenter(
|
||||||
openTelemetry, captureExperimentalSpanAttributes);
|
openTelemetry, captureExperimentalSpanAttributes);
|
||||||
|
producerInstrumenter =
|
||||||
|
AwsSdkInstrumenterFactory.producerInstrumenter(
|
||||||
|
openTelemetry, captureExperimentalSpanAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +65,7 @@ public class AwsSdkTelemetry {
|
||||||
* withRequestHandlers}.
|
* withRequestHandlers}.
|
||||||
*/
|
*/
|
||||||
public RequestHandler2 newRequestHandler() {
|
public RequestHandler2 newRequestHandler() {
|
||||||
return new TracingRequestHandler(requestInstrumenter, consumerInstrumenter);
|
return new TracingRequestHandler(
|
||||||
|
requestInstrumenter, consumerInstrumenter, producerInstrumenter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import com.amazonaws.Request;
|
||||||
import com.amazonaws.Response;
|
import com.amazonaws.Response;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
import io.opentelemetry.javaagent.tooling.muzzle.NoMuzzle;
|
import io.opentelemetry.javaagent.tooling.muzzle.NoMuzzle;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
final class SqsAccess {
|
final class SqsAccess {
|
||||||
private SqsAccess() {}
|
private SqsAccess() {}
|
||||||
|
@ -28,4 +30,9 @@ final class SqsAccess {
|
||||||
static boolean beforeMarshalling(AmazonWebServiceRequest request) {
|
static boolean beforeMarshalling(AmazonWebServiceRequest request) {
|
||||||
return enabled && SqsImpl.beforeMarshalling(request);
|
return enabled && SqsImpl.beforeMarshalling(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NoMuzzle
|
||||||
|
static Map<String, String> getMessageAttributes(Request<?> request) {
|
||||||
|
return enabled ? SqsImpl.getMessageAttributes(request) : Collections.emptyMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.messaging.MessagingAttributesGetter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
enum SqsAttributesGetter implements MessagingAttributesGetter<Request<?>, Response<?>> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSystem(Request<?> request) {
|
||||||
|
return "AmazonSQS";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDestination(Request<?> request) {
|
||||||
|
Object originalRequest = request.getOriginalRequest();
|
||||||
|
String queueUrl = RequestAccess.getQueueUrl(originalRequest);
|
||||||
|
int i = queueUrl.lastIndexOf('/');
|
||||||
|
return i > 0 ? queueUrl.substring(i + 1) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTemporaryDestination(Request<?> request) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String getConversationId(Request<?> request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Long getMessagePayloadSize(Request<?> request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Long getMessagePayloadCompressedSize(Request<?> request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String getMessageId(Request<?> request, @Nullable Response<?> response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getMessageHeader(Request<?> request, String name) {
|
||||||
|
String value = SqsAccess.getMessageAttributes(request).get(name);
|
||||||
|
return value != null ? Collections.singletonList(value) : Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,10 +10,15 @@ import com.amazonaws.Request;
|
||||||
import com.amazonaws.Response;
|
import com.amazonaws.Response;
|
||||||
import com.amazonaws.services.sqs.AmazonSQS;
|
import com.amazonaws.services.sqs.AmazonSQS;
|
||||||
import com.amazonaws.services.sqs.model.Message;
|
import com.amazonaws.services.sqs.model.Message;
|
||||||
|
import com.amazonaws.services.sqs.model.MessageAttributeValue;
|
||||||
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
|
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
|
||||||
import com.amazonaws.services.sqs.model.ReceiveMessageResult;
|
import com.amazonaws.services.sqs.model.ReceiveMessageResult;
|
||||||
|
import com.amazonaws.services.sqs.model.SendMessageRequest;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
final class SqsImpl {
|
final class SqsImpl {
|
||||||
static {
|
static {
|
||||||
|
@ -67,4 +72,19 @@ final class SqsImpl {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Map<String, String> getMessageAttributes(Request<?> request) {
|
||||||
|
if (request instanceof SendMessageRequest) {
|
||||||
|
Map<String, MessageAttributeValue> map =
|
||||||
|
((SendMessageRequest) request).getMessageAttributes();
|
||||||
|
if (!map.isEmpty()) {
|
||||||
|
Map<String, String> result = new HashMap<>();
|
||||||
|
for (Map.Entry<String, MessageAttributeValue> entry : map.entrySet()) {
|
||||||
|
result.put(entry.getKey(), entry.getValue().getStringValue());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,15 @@ final class TracingRequestHandler extends RequestHandler2 {
|
||||||
|
|
||||||
private final Instrumenter<Request<?>, Response<?>> requestInstrumenter;
|
private final Instrumenter<Request<?>, Response<?>> requestInstrumenter;
|
||||||
private final Instrumenter<Request<?>, Response<?>> consumerInstrumenter;
|
private final Instrumenter<Request<?>, Response<?>> consumerInstrumenter;
|
||||||
|
private final Instrumenter<Request<?>, Response<?>> producerInstrumenter;
|
||||||
|
|
||||||
TracingRequestHandler(
|
TracingRequestHandler(
|
||||||
Instrumenter<Request<?>, Response<?>> requestInstrumenter,
|
Instrumenter<Request<?>, Response<?>> requestInstrumenter,
|
||||||
Instrumenter<Request<?>, Response<?>> consumerInstrumenter) {
|
Instrumenter<Request<?>, Response<?>> consumerInstrumenter,
|
||||||
|
Instrumenter<Request<?>, Response<?>> producerInstrumenter) {
|
||||||
this.requestInstrumenter = requestInstrumenter;
|
this.requestInstrumenter = requestInstrumenter;
|
||||||
this.consumerInstrumenter = consumerInstrumenter;
|
this.consumerInstrumenter = consumerInstrumenter;
|
||||||
|
this.producerInstrumenter = producerInstrumenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,8 +53,10 @@ final class TracingRequestHandler extends RequestHandler2 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instrumenter<Request<?>, Response<?>> instrumenter = getInstrumenter(request);
|
||||||
|
|
||||||
Context parentContext = Context.current();
|
Context parentContext = Context.current();
|
||||||
if (!requestInstrumenter.shouldStart(parentContext, request)) {
|
if (!instrumenter.shouldStart(parentContext, request)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,14 +67,14 @@ final class TracingRequestHandler extends RequestHandler2 {
|
||||||
if (Context.root() == parentContext
|
if (Context.root() == parentContext
|
||||||
&& "com.amazonaws.services.sqs.model.ReceiveMessageRequest"
|
&& "com.amazonaws.services.sqs.model.ReceiveMessageRequest"
|
||||||
.equals(request.getOriginalRequest().getClass().getName())) {
|
.equals(request.getOriginalRequest().getClass().getName())) {
|
||||||
Context context = InstrumenterUtil.suppressSpan(requestInstrumenter, parentContext, request);
|
Context context = InstrumenterUtil.suppressSpan(instrumenter, parentContext, request);
|
||||||
context = context.with(REQUEST_START_KEY, Instant.now());
|
context = context.with(REQUEST_START_KEY, Instant.now());
|
||||||
context = context.with(PARENT_CONTEXT_KEY, parentContext);
|
context = context.with(PARENT_CONTEXT_KEY, parentContext);
|
||||||
request.addHandlerContext(CONTEXT, context);
|
request.addHandlerContext(CONTEXT, context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context context = requestInstrumenter.start(parentContext, request);
|
Context context = instrumenter.start(parentContext, request);
|
||||||
|
|
||||||
AwsXrayPropagator.getInstance().inject(context, request, HeaderSetter.INSTANCE);
|
AwsXrayPropagator.getInstance().inject(context, request, HeaderSetter.INSTANCE);
|
||||||
|
|
||||||
|
@ -104,24 +109,28 @@ final class TracingRequestHandler extends RequestHandler2 {
|
||||||
}
|
}
|
||||||
request.addHandlerContext(CONTEXT, null);
|
request.addHandlerContext(CONTEXT, null);
|
||||||
|
|
||||||
|
Instrumenter<Request<?>, Response<?>> instrumenter = getInstrumenter(request);
|
||||||
|
|
||||||
// see beforeRequest, requestStart is only set when we skip creating request span for sqs
|
// see beforeRequest, requestStart is only set when we skip creating request span for sqs
|
||||||
// AmazonSQSClient.receiveMessage calls
|
// AmazonSQSClient.receiveMessage calls
|
||||||
Instant requestStart = context.get(REQUEST_START_KEY);
|
Instant requestStart = context.get(REQUEST_START_KEY);
|
||||||
if (requestStart != null) {
|
if (requestStart != null) {
|
||||||
|
Context parentContext = context.get(PARENT_CONTEXT_KEY);
|
||||||
// create request span if there was an error
|
// create request span if there was an error
|
||||||
if (error != null) {
|
if (error != null && requestInstrumenter.shouldStart(parentContext, request)) {
|
||||||
InstrumenterUtil.startAndEnd(
|
InstrumenterUtil.startAndEnd(
|
||||||
requestInstrumenter,
|
instrumenter, parentContext, request, response, error, requestStart, Instant.now());
|
||||||
context.get(PARENT_CONTEXT_KEY),
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
error,
|
|
||||||
requestStart,
|
|
||||||
Instant.now());
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestInstrumenter.end(context, request, response, error);
|
instrumenter.end(context, request, response, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Instrumenter<Request<?>, Response<?>> getInstrumenter(Request<?> request) {
|
||||||
|
boolean isSqsProducer =
|
||||||
|
"com.amazonaws.services.sqs.model.SendMessageRequest"
|
||||||
|
.equals(request.getOriginalRequest().getClass().getName());
|
||||||
|
return isSqsProducer ? producerInstrumenter : requestInstrumenter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ abstract class AbstractSqsTracingTest extends InstrumentationSpecification {
|
||||||
}
|
}
|
||||||
trace(1, 2) {
|
trace(1, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
name "SQS.SendMessage"
|
name "testSdkSqs publish"
|
||||||
kind PRODUCER
|
kind PRODUCER
|
||||||
hasNoParent()
|
hasNoParent()
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -102,13 +102,15 @@ abstract class AbstractSqsTracingTest extends InstrumentationSpecification {
|
||||||
"http.url" "http://localhost:$sqsPort"
|
"http.url" "http://localhost:$sqsPort"
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
name "SQS.ReceiveMessage"
|
name "testSdkSqs receive"
|
||||||
kind CONSUMER
|
kind CONSUMER
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -124,6 +126,9 @@ abstract class AbstractSqsTracingTest extends InstrumentationSpecification {
|
||||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
|
"$SemanticAttributes.MESSAGING_OPERATION" "receive"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
||||||
|
@ -172,7 +177,7 @@ abstract class AbstractSqsTracingTest extends InstrumentationSpecification {
|
||||||
}
|
}
|
||||||
trace(1, 2) {
|
trace(1, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
name "SQS.SendMessage"
|
name "testSdkSqs publish"
|
||||||
kind PRODUCER
|
kind PRODUCER
|
||||||
hasNoParent()
|
hasNoParent()
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -187,13 +192,15 @@ abstract class AbstractSqsTracingTest extends InstrumentationSpecification {
|
||||||
"http.url" "http://localhost:$sqsPort"
|
"http.url" "http://localhost:$sqsPort"
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
name "SQS.ReceiveMessage"
|
name "testSdkSqs receive"
|
||||||
kind CONSUMER
|
kind CONSUMER
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -209,6 +216,9 @@ abstract class AbstractSqsTracingTest extends InstrumentationSpecification {
|
||||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
|
"$SemanticAttributes.MESSAGING_OPERATION" "receive"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
"$SemanticAttributes.NET_PROTOCOL_NAME" "http"
|
||||||
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
"$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
||||||
|
|
|
@ -11,10 +11,9 @@ import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
import software.amazon.awssdk.http.SdkHttpResponse;
|
|
||||||
|
|
||||||
class AwsSdkExperimentalAttributesExtractor
|
class AwsSdkExperimentalAttributesExtractor
|
||||||
implements AttributesExtractor<ExecutionAttributes, SdkHttpResponse> {
|
implements AttributesExtractor<ExecutionAttributes, Response> {
|
||||||
|
|
||||||
private static final String COMPONENT_NAME = "java-aws-sdk";
|
private static final String COMPONENT_NAME = "java-aws-sdk";
|
||||||
private static final AttributeKey<String> AWS_AGENT = AttributeKey.stringKey("aws.agent");
|
private static final AttributeKey<String> AWS_AGENT = AttributeKey.stringKey("aws.agent");
|
||||||
|
@ -32,6 +31,6 @@ class AwsSdkExperimentalAttributesExtractor
|
||||||
AttributesBuilder attributes,
|
AttributesBuilder attributes,
|
||||||
Context context,
|
Context context,
|
||||||
ExecutionAttributes executionAttributes,
|
ExecutionAttributes executionAttributes,
|
||||||
@Nullable SdkHttpResponse sdkHttpResponse,
|
@Nullable Response response,
|
||||||
@Nullable Throwable error) {}
|
@Nullable Throwable error) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,9 @@ import java.util.List;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
import software.amazon.awssdk.http.SdkHttpRequest;
|
import software.amazon.awssdk.http.SdkHttpRequest;
|
||||||
import software.amazon.awssdk.http.SdkHttpResponse;
|
|
||||||
|
|
||||||
class AwsSdkHttpAttributesGetter
|
class AwsSdkHttpAttributesGetter
|
||||||
implements HttpClientAttributesGetter<ExecutionAttributes, SdkHttpResponse> {
|
implements HttpClientAttributesGetter<ExecutionAttributes, Response> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUrlFull(ExecutionAttributes request) {
|
public String getUrlFull(ExecutionAttributes request) {
|
||||||
|
@ -41,14 +40,14 @@ class AwsSdkHttpAttributesGetter
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer getHttpResponseStatusCode(
|
public Integer getHttpResponseStatusCode(
|
||||||
ExecutionAttributes request, SdkHttpResponse response, @Nullable Throwable error) {
|
ExecutionAttributes request, Response response, @Nullable Throwable error) {
|
||||||
return response.statusCode();
|
return response.getSdkHttpResponse().statusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getHttpResponseHeader(
|
public List<String> getHttpResponseHeader(
|
||||||
ExecutionAttributes request, SdkHttpResponse response, String name) {
|
ExecutionAttributes request, Response response, String name) {
|
||||||
List<String> value = response.headers().get(name);
|
List<String> value = response.getSdkHttpResponse().headers().get(name);
|
||||||
return value == null ? emptyList() : value;
|
return value == null ? emptyList() : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ import io.opentelemetry.instrumentation.api.internal.SpanKey;
|
||||||
import io.opentelemetry.instrumentation.api.internal.SpanKeyProvider;
|
import io.opentelemetry.instrumentation.api.internal.SpanKeyProvider;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
import software.amazon.awssdk.http.SdkHttpResponse;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An attribute extractor that reports implementing HTTP client semantic conventions. Adding this
|
* An attribute extractor that reports implementing HTTP client semantic conventions. Adding this
|
||||||
|
@ -21,7 +20,7 @@ import software.amazon.awssdk.http.SdkHttpResponse;
|
||||||
* HttpClientAttributesExtractor} would.
|
* HttpClientAttributesExtractor} would.
|
||||||
*/
|
*/
|
||||||
class AwsSdkHttpClientSuppressionAttributesExtractor
|
class AwsSdkHttpClientSuppressionAttributesExtractor
|
||||||
implements AttributesExtractor<ExecutionAttributes, SdkHttpResponse>, SpanKeyProvider {
|
implements AttributesExtractor<ExecutionAttributes, Response>, SpanKeyProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart(
|
public void onStart(
|
||||||
|
@ -34,7 +33,7 @@ class AwsSdkHttpClientSuppressionAttributesExtractor
|
||||||
AttributesBuilder attributes,
|
AttributesBuilder attributes,
|
||||||
Context context,
|
Context context,
|
||||||
ExecutionAttributes executionAttributes,
|
ExecutionAttributes executionAttributes,
|
||||||
@Nullable SdkHttpResponse sdkHttpResponse,
|
@Nullable Response response,
|
||||||
@Nullable Throwable error) {}
|
@Nullable Throwable error) {}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
@ -9,53 +9,55 @@ import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessageOperation;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingAttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingSpanNameExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcClientAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcClientAttributesExtractor;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
|
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
|
||||||
import software.amazon.awssdk.http.SdkHttpResponse;
|
|
||||||
|
|
||||||
final class AwsSdkInstrumenterFactory {
|
final class AwsSdkInstrumenterFactory {
|
||||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.aws-sdk-2.2";
|
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.aws-sdk-2.2";
|
||||||
|
|
||||||
static final AttributesExtractor<ExecutionAttributes, SdkHttpResponse> rpcAttributesExtractor =
|
private static final AttributesExtractor<ExecutionAttributes, Response> rpcAttributesExtractor =
|
||||||
RpcClientAttributesExtractor.create(AwsSdkRpcAttributesGetter.INSTANCE);
|
RpcClientAttributesExtractor.create(AwsSdkRpcAttributesGetter.INSTANCE);
|
||||||
private static final AwsSdkExperimentalAttributesExtractor experimentalAttributesExtractor =
|
private static final AwsSdkExperimentalAttributesExtractor experimentalAttributesExtractor =
|
||||||
new AwsSdkExperimentalAttributesExtractor();
|
new AwsSdkExperimentalAttributesExtractor();
|
||||||
|
|
||||||
static final AwsSdkHttpAttributesGetter httpAttributesGetter = new AwsSdkHttpAttributesGetter();
|
static final AwsSdkHttpAttributesGetter httpAttributesGetter = new AwsSdkHttpAttributesGetter();
|
||||||
static final AttributesExtractor<ExecutionAttributes, SdkHttpResponse> httpAttributesExtractor =
|
static final AttributesExtractor<ExecutionAttributes, Response> httpAttributesExtractor =
|
||||||
HttpClientAttributesExtractor.create(httpAttributesGetter);
|
HttpClientAttributesExtractor.create(httpAttributesGetter);
|
||||||
|
|
||||||
private static final AttributesExtractor<ExecutionAttributes, SdkHttpResponse>
|
private static final AttributesExtractor<ExecutionAttributes, Response>
|
||||||
httpClientSuppressionAttributesExtractor =
|
httpClientSuppressionAttributesExtractor =
|
||||||
new AwsSdkHttpClientSuppressionAttributesExtractor();
|
new AwsSdkHttpClientSuppressionAttributesExtractor();
|
||||||
|
|
||||||
private static final AwsSdkSpanKindExtractor spanKindExtractor = new AwsSdkSpanKindExtractor();
|
private static final List<AttributesExtractor<ExecutionAttributes, Response>>
|
||||||
|
|
||||||
private static final List<AttributesExtractor<ExecutionAttributes, SdkHttpResponse>>
|
|
||||||
defaultAttributesExtractors =
|
defaultAttributesExtractors =
|
||||||
Arrays.asList(rpcAttributesExtractor, httpClientSuppressionAttributesExtractor);
|
Arrays.asList(rpcAttributesExtractor, httpClientSuppressionAttributesExtractor);
|
||||||
|
|
||||||
private static final List<AttributesExtractor<ExecutionAttributes, SdkHttpResponse>>
|
private static final List<AttributesExtractor<ExecutionAttributes, Response>>
|
||||||
extendedAttributesExtractors =
|
extendedAttributesExtractors =
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
rpcAttributesExtractor,
|
rpcAttributesExtractor,
|
||||||
experimentalAttributesExtractor,
|
experimentalAttributesExtractor,
|
||||||
httpClientSuppressionAttributesExtractor);
|
httpClientSuppressionAttributesExtractor);
|
||||||
|
|
||||||
private static final List<AttributesExtractor<ExecutionAttributes, SdkHttpResponse>>
|
private static final List<AttributesExtractor<ExecutionAttributes, Response>>
|
||||||
defaultConsumerAttributesExtractors =
|
defaultConsumerAttributesExtractors =
|
||||||
Arrays.asList(rpcAttributesExtractor, httpAttributesExtractor);
|
Arrays.asList(rpcAttributesExtractor, httpAttributesExtractor);
|
||||||
|
|
||||||
private static final List<AttributesExtractor<ExecutionAttributes, SdkHttpResponse>>
|
private static final List<AttributesExtractor<ExecutionAttributes, Response>>
|
||||||
extendedConsumerAttributesExtractors =
|
extendedConsumerAttributesExtractors =
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
rpcAttributesExtractor, httpAttributesExtractor, experimentalAttributesExtractor);
|
rpcAttributesExtractor, httpAttributesExtractor, experimentalAttributesExtractor);
|
||||||
|
|
||||||
static Instrumenter<ExecutionAttributes, SdkHttpResponse> requestInstrumenter(
|
static Instrumenter<ExecutionAttributes, Response> requestInstrumenter(
|
||||||
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||||
|
|
||||||
return createInstrumenter(
|
return createInstrumenter(
|
||||||
|
@ -63,27 +65,60 @@ final class AwsSdkInstrumenterFactory {
|
||||||
captureExperimentalSpanAttributes
|
captureExperimentalSpanAttributes
|
||||||
? extendedAttributesExtractors
|
? extendedAttributesExtractors
|
||||||
: defaultAttributesExtractors,
|
: defaultAttributesExtractors,
|
||||||
AwsSdkInstrumenterFactory.spanKindExtractor);
|
AwsSdkInstrumenterFactory::spanName,
|
||||||
|
SpanKindExtractor.alwaysClient());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Instrumenter<ExecutionAttributes, SdkHttpResponse> consumerInstrumenter(
|
static Instrumenter<ExecutionAttributes, Response> consumerInstrumenter(
|
||||||
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||||
|
return sqsInstrumenter(
|
||||||
|
openTelemetry,
|
||||||
|
MessageOperation.RECEIVE,
|
||||||
|
captureExperimentalSpanAttributes
|
||||||
|
? extendedConsumerAttributesExtractors
|
||||||
|
: defaultConsumerAttributesExtractors);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Instrumenter<ExecutionAttributes, Response> producerInstrumenter(
|
||||||
|
OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
|
||||||
|
return sqsInstrumenter(
|
||||||
|
openTelemetry,
|
||||||
|
MessageOperation.PUBLISH,
|
||||||
|
captureExperimentalSpanAttributes
|
||||||
|
? extendedAttributesExtractors
|
||||||
|
: defaultAttributesExtractors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Instrumenter<ExecutionAttributes, Response> sqsInstrumenter(
|
||||||
|
OpenTelemetry openTelemetry,
|
||||||
|
MessageOperation operation,
|
||||||
|
List<AttributesExtractor<ExecutionAttributes, Response>> extractors) {
|
||||||
|
SqsAttributesGetter getter = SqsAttributesGetter.INSTANCE;
|
||||||
|
AttributesExtractor<ExecutionAttributes, Response> messagingAttributeExtractor =
|
||||||
|
MessagingAttributesExtractor.builder(getter, operation).build();
|
||||||
|
List<AttributesExtractor<ExecutionAttributes, Response>> newExtractors =
|
||||||
|
new ArrayList<>(extractors);
|
||||||
|
newExtractors.add(messagingAttributeExtractor);
|
||||||
|
|
||||||
return createInstrumenter(
|
return createInstrumenter(
|
||||||
openTelemetry,
|
openTelemetry,
|
||||||
captureExperimentalSpanAttributes
|
newExtractors,
|
||||||
? extendedConsumerAttributesExtractors
|
MessagingSpanNameExtractor.create(getter, operation),
|
||||||
: defaultConsumerAttributesExtractors,
|
operation == MessageOperation.PUBLISH
|
||||||
SpanKindExtractor.alwaysConsumer());
|
? SpanKindExtractor.alwaysProducer()
|
||||||
|
: SpanKindExtractor.alwaysConsumer());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Instrumenter<ExecutionAttributes, SdkHttpResponse> createInstrumenter(
|
private static Instrumenter<ExecutionAttributes, Response> createInstrumenter(
|
||||||
OpenTelemetry openTelemetry,
|
OpenTelemetry openTelemetry,
|
||||||
List<AttributesExtractor<ExecutionAttributes, SdkHttpResponse>> extractors,
|
List<AttributesExtractor<ExecutionAttributes, Response>> extractors,
|
||||||
|
SpanNameExtractor<ExecutionAttributes> spanNameExtractor,
|
||||||
SpanKindExtractor<ExecutionAttributes> spanKindExtractor) {
|
SpanKindExtractor<ExecutionAttributes> spanKindExtractor) {
|
||||||
|
|
||||||
return Instrumenter.<ExecutionAttributes, SdkHttpResponse>builder(
|
return Instrumenter.<ExecutionAttributes, Response>builder(
|
||||||
openTelemetry, INSTRUMENTATION_NAME, AwsSdkInstrumenterFactory::spanName)
|
openTelemetry,
|
||||||
|
INSTRUMENTATION_NAME,
|
||||||
|
spanNameExtractor) // AwsSdkInstrumenterFactory::spanName
|
||||||
.addAttributesExtractors(extractors)
|
.addAttributesExtractors(extractors)
|
||||||
.buildInstrumenter(spanKindExtractor);
|
.buildInstrumenter(spanKindExtractor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
|
||||||
|
|
||||||
import io.opentelemetry.api.trace.SpanKind;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
|
||||||
import software.amazon.awssdk.core.SdkRequest;
|
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
|
||||||
|
|
||||||
class AwsSdkSpanKindExtractor implements SpanKindExtractor<ExecutionAttributes> {
|
|
||||||
@Override
|
|
||||||
public SpanKind extract(ExecutionAttributes request) {
|
|
||||||
return isSqsProducer(request) ? SpanKind.PRODUCER : SpanKind.CLIENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isSqsProducer(ExecutionAttributes executionAttributes) {
|
|
||||||
SdkRequest request =
|
|
||||||
executionAttributes.getAttribute(TracingExecutionInterceptor.SDK_REQUEST_ATTRIBUTE);
|
|
||||||
return request
|
|
||||||
.getClass()
|
|
||||||
.getName()
|
|
||||||
.equals("software.amazon.awssdk.services.sqs.model.SendMessageRequest");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,7 +12,6 @@ import javax.annotation.Nullable;
|
||||||
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
|
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
|
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
|
||||||
import software.amazon.awssdk.http.SdkHttpResponse;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entrypoint to OpenTelemetry instrumentation of the AWS SDK. Register the {@link
|
* Entrypoint to OpenTelemetry instrumentation of the AWS SDK. Register the {@link
|
||||||
|
@ -41,8 +40,9 @@ public class AwsSdkTelemetry {
|
||||||
return new AwsSdkTelemetryBuilder(openTelemetry);
|
return new AwsSdkTelemetryBuilder(openTelemetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Instrumenter<ExecutionAttributes, SdkHttpResponse> requestInstrumenter;
|
private final Instrumenter<ExecutionAttributes, Response> requestInstrumenter;
|
||||||
private final Instrumenter<ExecutionAttributes, SdkHttpResponse> consumerInstrumenter;
|
private final Instrumenter<ExecutionAttributes, Response> consumerInstrumenter;
|
||||||
|
private final Instrumenter<ExecutionAttributes, Response> producerInstrumenter;
|
||||||
private final boolean captureExperimentalSpanAttributes;
|
private final boolean captureExperimentalSpanAttributes;
|
||||||
@Nullable private final TextMapPropagator messagingPropagator;
|
@Nullable private final TextMapPropagator messagingPropagator;
|
||||||
private final boolean useXrayPropagator;
|
private final boolean useXrayPropagator;
|
||||||
|
@ -61,6 +61,9 @@ public class AwsSdkTelemetry {
|
||||||
this.consumerInstrumenter =
|
this.consumerInstrumenter =
|
||||||
AwsSdkInstrumenterFactory.consumerInstrumenter(
|
AwsSdkInstrumenterFactory.consumerInstrumenter(
|
||||||
openTelemetry, captureExperimentalSpanAttributes);
|
openTelemetry, captureExperimentalSpanAttributes);
|
||||||
|
this.producerInstrumenter =
|
||||||
|
AwsSdkInstrumenterFactory.producerInstrumenter(
|
||||||
|
openTelemetry, captureExperimentalSpanAttributes);
|
||||||
this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
|
this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
|
||||||
this.messagingPropagator =
|
this.messagingPropagator =
|
||||||
useMessagingPropagator ? openTelemetry.getPropagators().getTextMapPropagator() : null;
|
useMessagingPropagator ? openTelemetry.getPropagators().getTextMapPropagator() : null;
|
||||||
|
@ -75,6 +78,7 @@ public class AwsSdkTelemetry {
|
||||||
return new TracingExecutionInterceptor(
|
return new TracingExecutionInterceptor(
|
||||||
requestInstrumenter,
|
requestInstrumenter,
|
||||||
consumerInstrumenter,
|
consumerInstrumenter,
|
||||||
|
producerInstrumenter,
|
||||||
captureExperimentalSpanAttributes,
|
captureExperimentalSpanAttributes,
|
||||||
messagingPropagator,
|
messagingPropagator,
|
||||||
useXrayPropagator,
|
useXrayPropagator,
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
||||||
|
|
||||||
|
import software.amazon.awssdk.core.SdkResponse;
|
||||||
|
import software.amazon.awssdk.http.SdkHttpResponse;
|
||||||
|
|
||||||
|
final class Response {
|
||||||
|
private final SdkHttpResponse sdkHttpResponse;
|
||||||
|
private final SdkResponse sdkResponse;
|
||||||
|
|
||||||
|
Response(SdkHttpResponse sdkHttpResponse) {
|
||||||
|
this(sdkHttpResponse, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(SdkHttpResponse sdkHttpResponse, SdkResponse sdkResponse) {
|
||||||
|
this.sdkHttpResponse = sdkHttpResponse;
|
||||||
|
this.sdkResponse = sdkResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SdkHttpResponse getSdkHttpResponse() {
|
||||||
|
return sdkHttpResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SdkResponse getSdkResponse() {
|
||||||
|
return sdkResponse;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||||
import io.opentelemetry.javaagent.tooling.muzzle.NoMuzzle;
|
import io.opentelemetry.javaagent.tooling.muzzle.NoMuzzle;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import software.amazon.awssdk.core.SdkRequest;
|
import software.amazon.awssdk.core.SdkRequest;
|
||||||
|
import software.amazon.awssdk.core.SdkResponse;
|
||||||
import software.amazon.awssdk.core.interceptor.Context;
|
import software.amazon.awssdk.core.interceptor.Context;
|
||||||
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
|
|
||||||
|
@ -42,4 +43,19 @@ final class SqsAccess {
|
||||||
? SqsImpl.modifyRequest(request, otelContext, useXrayPropagator, messagingPropagator)
|
? SqsImpl.modifyRequest(request, otelContext, useXrayPropagator, messagingPropagator)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NoMuzzle
|
||||||
|
static boolean isSqsProducerRequest(SdkRequest request) {
|
||||||
|
return enabled && SqsImpl.isSqsProducerRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoMuzzle
|
||||||
|
static String getQueueUrl(SdkRequest request) {
|
||||||
|
return enabled ? SqsImpl.getQueueUrl(request) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoMuzzle
|
||||||
|
static String getMessageId(SdkResponse response) {
|
||||||
|
return enabled ? SqsImpl.getMessageId(response) : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingAttributesGetter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import software.amazon.awssdk.core.SdkRequest;
|
||||||
|
import software.amazon.awssdk.core.SdkResponse;
|
||||||
|
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
||||||
|
|
||||||
|
enum SqsAttributesGetter implements MessagingAttributesGetter<ExecutionAttributes, Response> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSystem(ExecutionAttributes request) {
|
||||||
|
return "AmazonSQS";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDestination(ExecutionAttributes request) {
|
||||||
|
SdkRequest sdkRequest = request.getAttribute(TracingExecutionInterceptor.SDK_REQUEST_ATTRIBUTE);
|
||||||
|
String queueUrl = SqsAccess.getQueueUrl(sdkRequest);
|
||||||
|
if (queueUrl != null) {
|
||||||
|
int i = queueUrl.lastIndexOf('/');
|
||||||
|
if (i > 0) {
|
||||||
|
return queueUrl.substring(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTemporaryDestination(ExecutionAttributes request) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String getConversationId(ExecutionAttributes request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Long getMessagePayloadSize(ExecutionAttributes request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Long getMessagePayloadCompressedSize(ExecutionAttributes request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String getMessageId(ExecutionAttributes request, @Nullable Response response) {
|
||||||
|
if (response != null && response.getSdkResponse() != null) {
|
||||||
|
SdkResponse sdkResponse = response.getSdkResponse();
|
||||||
|
return SqsAccess.getMessageId(sdkResponse);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getMessageHeader(ExecutionAttributes request, String name) {
|
||||||
|
// TODO: not implemented
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse;
|
||||||
import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest;
|
import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest;
|
||||||
import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequestEntry;
|
import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequestEntry;
|
||||||
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;
|
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;
|
||||||
|
import software.amazon.awssdk.services.sqs.model.SendMessageResponse;
|
||||||
|
|
||||||
// this class is only used from SqsAccess from method with @NoMuzzle annotation
|
// this class is only used from SqsAccess from method with @NoMuzzle annotation
|
||||||
final class SqsImpl {
|
final class SqsImpl {
|
||||||
|
@ -75,7 +76,7 @@ final class SqsImpl {
|
||||||
parentContext = SqsParentContext.ofSystemAttributes(message.attributesAsStrings());
|
parentContext = SqsParentContext.ofSystemAttributes(message.attributesAsStrings());
|
||||||
}
|
}
|
||||||
|
|
||||||
Instrumenter<ExecutionAttributes, SdkHttpResponse> consumerInstrumenter =
|
Instrumenter<ExecutionAttributes, Response> consumerInstrumenter =
|
||||||
config.getConsumerInstrumenter();
|
config.getConsumerInstrumenter();
|
||||||
if (consumerInstrumenter.shouldStart(parentContext, executionAttributes)) {
|
if (consumerInstrumenter.shouldStart(parentContext, executionAttributes)) {
|
||||||
io.opentelemetry.context.Context context =
|
io.opentelemetry.context.Context context =
|
||||||
|
@ -85,7 +86,7 @@ final class SqsImpl {
|
||||||
// per-message?
|
// per-message?
|
||||||
// TODO: Should we really create root spans if we can't extract anything, or should we attach
|
// TODO: Should we really create root spans if we can't extract anything, or should we attach
|
||||||
// to the current context?
|
// to the current context?
|
||||||
consumerInstrumenter.end(context, executionAttributes, httpResponse, null);
|
consumerInstrumenter.end(context, executionAttributes, new Response(httpResponse), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,4 +201,26 @@ final class SqsImpl {
|
||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isSqsProducerRequest(SdkRequest request) {
|
||||||
|
return request instanceof SendMessageRequest || request instanceof SendMessageBatchRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getQueueUrl(SdkRequest request) {
|
||||||
|
if (request instanceof SendMessageRequest) {
|
||||||
|
return ((SendMessageRequest) request).queueUrl();
|
||||||
|
} else if (request instanceof SendMessageBatchRequest) {
|
||||||
|
return ((SendMessageBatchRequest) request).queueUrl();
|
||||||
|
} else if (request instanceof ReceiveMessageRequest) {
|
||||||
|
return ((ReceiveMessageRequest) request).queueUrl();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getMessageId(SdkResponse response) {
|
||||||
|
if (response instanceof SendMessageResponse) {
|
||||||
|
return ((SendMessageResponse) response).messageId();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,15 +58,16 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
private static final ExecutionAttribute<RequestSpanFinisher> REQUEST_FINISHER_ATTRIBUTE =
|
private static final ExecutionAttribute<RequestSpanFinisher> REQUEST_FINISHER_ATTRIBUTE =
|
||||||
new ExecutionAttribute<>(TracingExecutionInterceptor.class.getName() + ".RequestFinisher");
|
new ExecutionAttribute<>(TracingExecutionInterceptor.class.getName() + ".RequestFinisher");
|
||||||
|
|
||||||
private final Instrumenter<ExecutionAttributes, SdkHttpResponse> requestInstrumenter;
|
private final Instrumenter<ExecutionAttributes, Response> requestInstrumenter;
|
||||||
private final Instrumenter<ExecutionAttributes, SdkHttpResponse> consumerInstrumenter;
|
private final Instrumenter<ExecutionAttributes, Response> consumerInstrumenter;
|
||||||
|
private final Instrumenter<ExecutionAttributes, Response> producerInstrumenter;
|
||||||
private final boolean captureExperimentalSpanAttributes;
|
private final boolean captureExperimentalSpanAttributes;
|
||||||
|
|
||||||
static final AttributeKey<String> HTTP_ERROR_MSG =
|
static final AttributeKey<String> HTTP_ERROR_MSG =
|
||||||
AttributeKey.stringKey("aws.http.error_message");
|
AttributeKey.stringKey("aws.http.error_message");
|
||||||
static final String HTTP_FAILURE_EVENT = "HTTP request failure";
|
static final String HTTP_FAILURE_EVENT = "HTTP request failure";
|
||||||
|
|
||||||
Instrumenter<ExecutionAttributes, SdkHttpResponse> getConsumerInstrumenter() {
|
Instrumenter<ExecutionAttributes, Response> getConsumerInstrumenter() {
|
||||||
return consumerInstrumenter;
|
return consumerInstrumenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,14 +86,16 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
private final FieldMapper fieldMapper;
|
private final FieldMapper fieldMapper;
|
||||||
|
|
||||||
TracingExecutionInterceptor(
|
TracingExecutionInterceptor(
|
||||||
Instrumenter<ExecutionAttributes, SdkHttpResponse> requestInstrumenter,
|
Instrumenter<ExecutionAttributes, Response> requestInstrumenter,
|
||||||
Instrumenter<ExecutionAttributes, SdkHttpResponse> consumerInstrumenter,
|
Instrumenter<ExecutionAttributes, Response> consumerInstrumenter,
|
||||||
|
Instrumenter<ExecutionAttributes, Response> producerInstrumenter,
|
||||||
boolean captureExperimentalSpanAttributes,
|
boolean captureExperimentalSpanAttributes,
|
||||||
TextMapPropagator messagingPropagator,
|
TextMapPropagator messagingPropagator,
|
||||||
boolean useXrayPropagator,
|
boolean useXrayPropagator,
|
||||||
boolean recordIndividualHttpError) {
|
boolean recordIndividualHttpError) {
|
||||||
this.requestInstrumenter = requestInstrumenter;
|
this.requestInstrumenter = requestInstrumenter;
|
||||||
this.consumerInstrumenter = consumerInstrumenter;
|
this.consumerInstrumenter = consumerInstrumenter;
|
||||||
|
this.producerInstrumenter = producerInstrumenter;
|
||||||
this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
|
this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
|
||||||
this.messagingPropagator = messagingPropagator;
|
this.messagingPropagator = messagingPropagator;
|
||||||
this.useXrayPropagator = useXrayPropagator;
|
this.useXrayPropagator = useXrayPropagator;
|
||||||
|
@ -118,8 +121,9 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
executionAttributes.putAttribute(SDK_REQUEST_ATTRIBUTE, request);
|
executionAttributes.putAttribute(SDK_REQUEST_ATTRIBUTE, request);
|
||||||
|
Instrumenter<ExecutionAttributes, Response> instrumenter = getInstrumenter(request);
|
||||||
|
|
||||||
if (!requestInstrumenter.shouldStart(parentOtelContext, executionAttributes)) {
|
if (!instrumenter.shouldStart(parentOtelContext, executionAttributes)) {
|
||||||
// NB: We also skip injection in case we don't start.
|
// NB: We also skip injection in case we don't start.
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
@ -135,16 +139,16 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
&& "software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest"
|
&& "software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest"
|
||||||
.equals(request.getClass().getName())) {
|
.equals(request.getClass().getName())) {
|
||||||
otelContext =
|
otelContext =
|
||||||
InstrumenterUtil.suppressSpan(
|
InstrumenterUtil.suppressSpan(instrumenter, parentOtelContext, executionAttributes);
|
||||||
requestInstrumenter, parentOtelContext, executionAttributes);
|
|
||||||
requestFinisher =
|
requestFinisher =
|
||||||
(otelContext12, executionAttributes12, response, exception) -> {
|
(finisherOtelContext, finisherExecutionAttributes, response, exception) -> {
|
||||||
// generate request span when there was an error
|
// generate request span when there was an error
|
||||||
if (exception != null) {
|
if (exception != null
|
||||||
|
&& instrumenter.shouldStart(finisherOtelContext, finisherExecutionAttributes)) {
|
||||||
InstrumenterUtil.startAndEnd(
|
InstrumenterUtil.startAndEnd(
|
||||||
requestInstrumenter,
|
instrumenter,
|
||||||
parentOtelContext,
|
finisherOtelContext,
|
||||||
executionAttributes12,
|
finisherExecutionAttributes,
|
||||||
response,
|
response,
|
||||||
exception,
|
exception,
|
||||||
requestStart,
|
requestStart,
|
||||||
|
@ -152,8 +156,8 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
otelContext = requestInstrumenter.start(parentOtelContext, executionAttributes);
|
otelContext = instrumenter.start(parentOtelContext, executionAttributes);
|
||||||
requestFinisher = requestInstrumenter::end;
|
requestFinisher = instrumenter::end;
|
||||||
}
|
}
|
||||||
|
|
||||||
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, otelContext);
|
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, otelContext);
|
||||||
|
@ -237,7 +241,7 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
// For the httpAttributesExtractor dance, see afterMarshalling
|
// For the httpAttributesExtractor dance, see afterMarshalling
|
||||||
AttributesBuilder builder = Attributes.builder(); // NB: UnsafeAttributes are package-private
|
AttributesBuilder builder = Attributes.builder(); // NB: UnsafeAttributes are package-private
|
||||||
AwsSdkInstrumenterFactory.httpAttributesExtractor.onEnd(
|
AwsSdkInstrumenterFactory.httpAttributesExtractor.onEnd(
|
||||||
builder, otelContext, executionAttributes, httpResponse, null);
|
builder, otelContext, executionAttributes, new Response(httpResponse), null);
|
||||||
span.setAllAttributes(builder.build());
|
span.setAllAttributes(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +330,8 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
onHttpResponseAvailable(
|
onHttpResponseAvailable(
|
||||||
executionAttributes, otelContext, Span.fromContext(otelContext), httpResponse);
|
executionAttributes, otelContext, Span.fromContext(otelContext), httpResponse);
|
||||||
RequestSpanFinisher finisher = executionAttributes.getAttribute(REQUEST_FINISHER_ATTRIBUTE);
|
RequestSpanFinisher finisher = executionAttributes.getAttribute(REQUEST_FINISHER_ATTRIBUTE);
|
||||||
finisher.finish(otelContext, executionAttributes, httpResponse, null);
|
finisher.finish(
|
||||||
|
otelContext, executionAttributes, new Response(httpResponse, context.response()), null);
|
||||||
}
|
}
|
||||||
clearAttributes(executionAttributes);
|
clearAttributes(executionAttributes);
|
||||||
}
|
}
|
||||||
|
@ -414,11 +419,15 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
||||||
return attributes.getAttribute(CONTEXT_ATTRIBUTE);
|
return attributes.getAttribute(CONTEXT_ATTRIBUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Instrumenter<ExecutionAttributes, Response> getInstrumenter(SdkRequest request) {
|
||||||
|
return SqsAccess.isSqsProducerRequest(request) ? producerInstrumenter : requestInstrumenter;
|
||||||
|
}
|
||||||
|
|
||||||
private interface RequestSpanFinisher {
|
private interface RequestSpanFinisher {
|
||||||
void finish(
|
void finish(
|
||||||
io.opentelemetry.context.Context otelContext,
|
io.opentelemetry.context.Context otelContext,
|
||||||
ExecutionAttributes executionAttributes,
|
ExecutionAttributes executionAttributes,
|
||||||
SdkHttpResponse response,
|
Response response,
|
||||||
Throwable exception);
|
Throwable exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ import static io.opentelemetry.api.trace.StatusCode.ERROR
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
||||||
|
static final String QUEUE_URL = "http://xxx/somequeue"
|
||||||
|
|
||||||
void assumeSupportedConfig(service, operation) {
|
void assumeSupportedConfig(service, operation) {
|
||||||
Assumptions.assumeFalse(
|
Assumptions.assumeFalse(
|
||||||
service == "Sqs"
|
service == "Sqs"
|
||||||
|
@ -81,7 +83,7 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 1) {
|
trace(0, 1) {
|
||||||
span(0) {
|
span(0) {
|
||||||
name "$service.$operation"
|
name operation != "SendMessage" ? "$service.$operation" : "somequeue publish"
|
||||||
kind operation != "SendMessage" ? CLIENT : PRODUCER
|
kind operation != "SendMessage" ? CLIENT : PRODUCER
|
||||||
hasNoParent()
|
hasNoParent()
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -112,7 +114,10 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
||||||
} else if (service == "Sqs" && operation == "CreateQueue") {
|
} else if (service == "Sqs" && operation == "CreateQueue") {
|
||||||
"aws.queue.name" "somequeue"
|
"aws.queue.name" "somequeue"
|
||||||
} else if (service == "Sqs" && operation == "SendMessage") {
|
} else if (service == "Sqs" && operation == "SendMessage") {
|
||||||
"aws.queue.url" "someurl"
|
"aws.queue.url" QUEUE_URL
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "somequeue"
|
||||||
|
"$SemanticAttributes.MESSAGING_MESSAGE_ID" String
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
} else if (service == "Kinesis") {
|
} else if (service == "Kinesis") {
|
||||||
"aws.stream.name" "somestream"
|
"aws.stream.name" "somestream"
|
||||||
}
|
}
|
||||||
|
@ -135,7 +140,7 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
||||||
<ResponseMetadata><RequestId>7a62c49f-347e-4fc4-9331-6e8e7a96aa73</RequestId></ResponseMetadata>
|
<ResponseMetadata><RequestId>7a62c49f-347e-4fc4-9331-6e8e7a96aa73</RequestId></ResponseMetadata>
|
||||||
</CreateQueueResponse>
|
</CreateQueueResponse>
|
||||||
"""
|
"""
|
||||||
"Sqs" | "SendMessage" | "POST" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl("someurl").messageBody("").build()) } | """
|
"Sqs" | "SendMessage" | "POST" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl(QUEUE_URL).messageBody("").build()) } | """
|
||||||
<SendMessageResponse>
|
<SendMessageResponse>
|
||||||
<SendMessageResult>
|
<SendMessageResult>
|
||||||
<MD5OfMessageBody>d41d8cd98f00b204e9800998ecf8427e</MD5OfMessageBody>
|
<MD5OfMessageBody>d41d8cd98f00b204e9800998ecf8427e</MD5OfMessageBody>
|
||||||
|
@ -181,7 +186,7 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 1) {
|
trace(0, 1) {
|
||||||
span(0) {
|
span(0) {
|
||||||
name "$service.$operation"
|
name operation != "SendMessage" ? "$service.$operation" : "somequeue publish"
|
||||||
kind operation != "SendMessage" ? CLIENT : PRODUCER
|
kind operation != "SendMessage" ? CLIENT : PRODUCER
|
||||||
hasNoParent()
|
hasNoParent()
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -212,7 +217,10 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
||||||
} else if (service == "Sqs" && operation == "CreateQueue") {
|
} else if (service == "Sqs" && operation == "CreateQueue") {
|
||||||
"aws.queue.name" "somequeue"
|
"aws.queue.name" "somequeue"
|
||||||
} else if (service == "Sqs" && operation == "SendMessage") {
|
} else if (service == "Sqs" && operation == "SendMessage") {
|
||||||
"aws.queue.url" "someurl"
|
"aws.queue.url" QUEUE_URL
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "somequeue"
|
||||||
|
"$SemanticAttributes.MESSAGING_MESSAGE_ID" String
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
} else if (service == "Kinesis") {
|
} else if (service == "Kinesis") {
|
||||||
"aws.stream.name" "somestream"
|
"aws.stream.name" "somestream"
|
||||||
}
|
}
|
||||||
|
@ -247,7 +255,7 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
||||||
<ResponseMetadata><RequestId>7a62c49f-347e-4fc4-9331-6e8e7a96aa73</RequestId></ResponseMetadata>
|
<ResponseMetadata><RequestId>7a62c49f-347e-4fc4-9331-6e8e7a96aa73</RequestId></ResponseMetadata>
|
||||||
</CreateQueueResponse>
|
</CreateQueueResponse>
|
||||||
"""
|
"""
|
||||||
"Sqs" | "SendMessage" | "POST" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsAsyncClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl("someurl").messageBody("").build()) } | """
|
"Sqs" | "SendMessage" | "POST" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsAsyncClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl(QUEUE_URL).messageBody("").build()) } | """
|
||||||
<SendMessageResponse>
|
<SendMessageResponse>
|
||||||
<SendMessageResult>
|
<SendMessageResult>
|
||||||
<MD5OfMessageBody>d41d8cd98f00b204e9800998ecf8427e</MD5OfMessageBody>
|
<MD5OfMessageBody>d41d8cd98f00b204e9800998ecf8427e</MD5OfMessageBody>
|
||||||
|
|
|
@ -138,7 +138,7 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
||||||
}
|
}
|
||||||
trace(1, 2) {
|
trace(1, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
name "Sqs.SendMessage"
|
name "testSdkSqs publish"
|
||||||
kind PRODUCER
|
kind PRODUCER
|
||||||
hasNoParent()
|
hasNoParent()
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -154,12 +154,15 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
||||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
|
"$SemanticAttributes.MESSAGING_MESSAGE_ID" String
|
||||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
name "Sqs.ReceiveMessage"
|
name "testSdkSqs receive"
|
||||||
kind CONSUMER
|
kind CONSUMER
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
hasNoLinks() // TODO: Link to receive operation?
|
hasNoLinks() // TODO: Link to receive operation?
|
||||||
|
@ -174,6 +177,9 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
||||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
|
"$SemanticAttributes.MESSAGING_OPERATION" "receive"
|
||||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
}
|
}
|
||||||
|
@ -302,8 +308,8 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
||||||
}
|
}
|
||||||
trace(1, xrayInjectionEnabled ? 4 : 3) {
|
trace(1, xrayInjectionEnabled ? 4 : 3) {
|
||||||
span(0) {
|
span(0) {
|
||||||
name "Sqs.SendMessageBatch"
|
name "testSdkSqs publish"
|
||||||
kind CLIENT // TODO: Probably this should be producer, but that would be a breaking change
|
kind PRODUCER
|
||||||
hasNoParent()
|
hasNoParent()
|
||||||
attributes {
|
attributes {
|
||||||
"aws.agent" "java-aws-sdk"
|
"aws.agent" "java-aws-sdk"
|
||||||
|
@ -318,13 +324,15 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
||||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i: 1..(xrayInjectionEnabled ? 3 : 2)) {
|
for (int i: 1..(xrayInjectionEnabled ? 3 : 2)) {
|
||||||
span(i) {
|
span(i) {
|
||||||
name "Sqs.ReceiveMessage"
|
name "testSdkSqs receive"
|
||||||
kind CONSUMER
|
kind CONSUMER
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
hasNoLinks() // TODO: Link to receive operation?
|
hasNoLinks() // TODO: Link to receive operation?
|
||||||
|
@ -340,6 +348,9 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
||||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
|
"$SemanticAttributes.MESSAGING_OPERATION" "receive"
|
||||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
}
|
}
|
||||||
|
@ -349,7 +360,7 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
||||||
if (!xrayInjectionEnabled) {
|
if (!xrayInjectionEnabled) {
|
||||||
trace(2, 1) {
|
trace(2, 1) {
|
||||||
span(0) {
|
span(0) {
|
||||||
name "Sqs.ReceiveMessage"
|
name "testSdkSqs receive"
|
||||||
kind CONSUMER
|
kind CONSUMER
|
||||||
|
|
||||||
// TODO This is not nice at all, and can also happen if producer is not instrumented
|
// TODO This is not nice at all, and can also happen if producer is not instrumented
|
||||||
|
@ -367,6 +378,9 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
||||||
"net.peer.name" "localhost"
|
"net.peer.name" "localhost"
|
||||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||||
"net.peer.port" sqsPort
|
"net.peer.port" sqsPort
|
||||||
|
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
||||||
|
"$SemanticAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs"
|
||||||
|
"$SemanticAttributes.MESSAGING_OPERATION" "receive"
|
||||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,12 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satis
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import io.opentelemetry.api.trace.SpanKind;
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
|
||||||
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
||||||
import io.opentelemetry.semconv.SemanticAttributes;
|
import io.opentelemetry.semconv.SemanticAttributes;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
class AwsSpanAssertions {
|
class AwsSpanAssertions {
|
||||||
|
|
||||||
|
@ -37,9 +41,20 @@ class AwsSpanAssertions {
|
||||||
static SpanDataAssert sqs(
|
static SpanDataAssert sqs(
|
||||||
SpanDataAssert span, String spanName, String queueUrl, String queueName, SpanKind spanKind) {
|
SpanDataAssert span, String spanName, String queueUrl, String queueName, SpanKind spanKind) {
|
||||||
|
|
||||||
return span.hasName(spanName)
|
String rpcMethod;
|
||||||
.hasKind(spanKind)
|
if (spanName.startsWith("SQS.")) {
|
||||||
.hasAttributesSatisfyingExactly(
|
rpcMethod = spanName.substring(4);
|
||||||
|
} else if (spanName.endsWith("receive")) {
|
||||||
|
rpcMethod = "ReceiveMessage";
|
||||||
|
} else if (spanName.endsWith("publish")) {
|
||||||
|
rpcMethod = "SendMessage";
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("can't get rpc method from span name " + spanName);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AttributeAssertion> attributeAssertions = new ArrayList<>();
|
||||||
|
attributeAssertions.addAll(
|
||||||
|
Arrays.asList(
|
||||||
equalTo(stringKey("aws.agent"), "java-aws-sdk"),
|
equalTo(stringKey("aws.agent"), "java-aws-sdk"),
|
||||||
satisfies(stringKey("aws.endpoint"), val -> val.isInstanceOf(String.class)),
|
satisfies(stringKey("aws.endpoint"), val -> val.isInstanceOf(String.class)),
|
||||||
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200),
|
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200),
|
||||||
|
@ -83,10 +98,22 @@ class AwsSpanAssertions {
|
||||||
equalTo(SemanticAttributes.NET_PROTOCOL_NAME, "http"),
|
equalTo(SemanticAttributes.NET_PROTOCOL_NAME, "http"),
|
||||||
equalTo(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"),
|
equalTo(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"),
|
||||||
equalTo(stringKey("rpc.system"), "aws-api"),
|
equalTo(stringKey("rpc.system"), "aws-api"),
|
||||||
satisfies(
|
satisfies(stringKey("rpc.method"), stringAssert -> stringAssert.isEqualTo(rpcMethod)),
|
||||||
stringKey("rpc.method"),
|
equalTo(stringKey("rpc.service"), "AmazonSQS")));
|
||||||
stringAssert -> stringAssert.isEqualTo(spanName.substring(4))),
|
|
||||||
equalTo(stringKey("rpc.service"), "AmazonSQS"));
|
if (spanName.endsWith("receive") || spanName.endsWith("publish")) {
|
||||||
|
attributeAssertions.addAll(
|
||||||
|
Arrays.asList(
|
||||||
|
equalTo(SemanticAttributes.MESSAGING_DESTINATION_NAME, queueName),
|
||||||
|
equalTo(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS")));
|
||||||
|
if (spanName.endsWith("receive")) {
|
||||||
|
attributeAssertions.add(equalTo(SemanticAttributes.MESSAGING_OPERATION, "receive"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return span.hasName(spanName)
|
||||||
|
.hasKind(spanKind)
|
||||||
|
.hasAttributesSatisfyingExactly(attributeAssertions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0
|
@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0
|
||||||
|
|
|
@ -56,11 +56,11 @@ class SqsCamelTest {
|
||||||
span -> CamelSpanAssertions.sqsProduce(span, queueName).hasParent(trace.getSpan(0)),
|
span -> CamelSpanAssertions.sqsProduce(span, queueName).hasParent(trace.getSpan(0)),
|
||||||
span ->
|
span ->
|
||||||
AwsSpanAssertions.sqs(
|
AwsSpanAssertions.sqs(
|
||||||
span, "SQS.SendMessage", queueUrl, null, SpanKind.PRODUCER)
|
span, "sqsCamelTest publish", queueUrl, queueName, SpanKind.PRODUCER)
|
||||||
.hasParent(trace.getSpan(1)),
|
.hasParent(trace.getSpan(1)),
|
||||||
span ->
|
span ->
|
||||||
AwsSpanAssertions.sqs(
|
AwsSpanAssertions.sqs(
|
||||||
span, "SQS.ReceiveMessage", queueUrl, null, SpanKind.CONSUMER)
|
span, "sqsCamelTest receive", queueUrl, queueName, SpanKind.CONSUMER)
|
||||||
.hasParent(trace.getSpan(2)),
|
.hasParent(trace.getSpan(2)),
|
||||||
span ->
|
span ->
|
||||||
CamelSpanAssertions.sqsConsume(span, queueName).hasParent(trace.getSpan(2))),
|
CamelSpanAssertions.sqsConsume(span, queueName).hasParent(trace.getSpan(2))),
|
||||||
|
@ -91,11 +91,11 @@ class SqsCamelTest {
|
||||||
trace.hasSpansSatisfyingExactly(
|
trace.hasSpansSatisfyingExactly(
|
||||||
span ->
|
span ->
|
||||||
AwsSpanAssertions.sqs(
|
AwsSpanAssertions.sqs(
|
||||||
span, "SQS.SendMessage", queueUrl, null, SpanKind.PRODUCER)
|
span, "sqsCamelTest publish", queueUrl, queueName, SpanKind.PRODUCER)
|
||||||
.hasNoParent(),
|
.hasNoParent(),
|
||||||
span ->
|
span ->
|
||||||
AwsSpanAssertions.sqs(
|
AwsSpanAssertions.sqs(
|
||||||
span, "SQS.ReceiveMessage", queueUrl, null, SpanKind.CONSUMER)
|
span, "sqsCamelTest receive", queueUrl, queueName, SpanKind.CONSUMER)
|
||||||
.hasParent(trace.getSpan(0)),
|
.hasParent(trace.getSpan(0)),
|
||||||
span ->
|
span ->
|
||||||
CamelSpanAssertions.sqsConsume(span, queueName).hasParent(trace.getSpan(0))),
|
CamelSpanAssertions.sqsConsume(span, queueName).hasParent(trace.getSpan(0))),
|
||||||
|
@ -128,11 +128,19 @@ class SqsCamelTest {
|
||||||
span -> CamelSpanAssertions.sqsProduce(span, queueName).hasParent(trace.getSpan(0)),
|
span -> CamelSpanAssertions.sqsProduce(span, queueName).hasParent(trace.getSpan(0)),
|
||||||
span ->
|
span ->
|
||||||
AwsSpanAssertions.sqs(
|
AwsSpanAssertions.sqs(
|
||||||
span, "SQS.SendMessage", queueUrl, null, SpanKind.PRODUCER)
|
span,
|
||||||
|
"sqsCamelTestSdkConsumer publish",
|
||||||
|
queueUrl,
|
||||||
|
queueName,
|
||||||
|
SpanKind.PRODUCER)
|
||||||
.hasParent(trace.getSpan(1)),
|
.hasParent(trace.getSpan(1)),
|
||||||
span ->
|
span ->
|
||||||
AwsSpanAssertions.sqs(
|
AwsSpanAssertions.sqs(
|
||||||
span, "SQS.ReceiveMessage", queueUrl, null, SpanKind.CONSUMER)
|
span,
|
||||||
|
"sqsCamelTestSdkConsumer receive",
|
||||||
|
queueUrl,
|
||||||
|
queueName,
|
||||||
|
SpanKind.CONSUMER)
|
||||||
.hasParent(trace.getSpan(2))));
|
.hasParent(trace.getSpan(2))));
|
||||||
camelApp.stop();
|
camelApp.stop();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue