Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
import static io.opentelemetry.semconv.UrlAttributes.URL_FULL;
// These DB keys have been deprecated:
// https://github.com/open-telemetry/semantic-conventions-java/blob/release/v1.34.0/semconv-incubating/src/main/java/io/opentelemetry/semconv/incubating/DbIncubatingAttributes.java#L322-L327
// They have been replaced with new keys:
// https://github.com/open-telemetry/semantic-conventions-java/blob/release/v1.34.0/semconv/src/main/java/io/opentelemetry/semconv/DbAttributes.java#L77
// TODO: Supporting new keys. Cannot do this now as new keys are not available in OTel Agent 2.11.
// TODO: Delete deprecated keys once they no longer exist in binding version of the upstream code.
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_CONNECTION_STRING;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAME;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
Expand All @@ -34,7 +40,10 @@
import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_METHOD;
import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_STATUS_CODE;
import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_URL;
// https://github.com/open-telemetry/semantic-conventions-java/blob/release/v1.34.0/semconv-incubating/src/main/java/io/opentelemetry/semconv/incubating/MessagingIncubatingAttributes.java#L236-L242
// Deprecated, use {@code messaging.operation.type} instead.
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION_TYPE;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_SYSTEM;
import static io.opentelemetry.semconv.incubating.NetIncubatingAttributes.NET_PEER_NAME;
import static io.opentelemetry.semconv.incubating.NetIncubatingAttributes.NET_PEER_PORT;
Expand Down Expand Up @@ -87,6 +96,7 @@
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isAwsSDKSpan;
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isDBSpan;
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isKeyPresent;
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isKeyPresentWithFallback;

import com.amazonaws.arn.Arn;
import io.opentelemetry.api.common.AttributeKey;
Expand Down Expand Up @@ -122,15 +132,6 @@
* represent "outgoing" traffic, and {@link SpanKind#INTERNAL} spans are ignored.
*/
final class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
// ToDo: These two keys were deleted by upstream. Code need to be updated to capture the same
// information by using new keys.
// https://github.com/open-telemetry/semantic-conventions-java/blob/release/v1.28.0/semconv/src/main/java/io/opentelemetry/semconv/SemanticAttributes.java#L3784-L3795
static final AttributeKey<String> SERVER_SOCKET_ADDRESS =
io.opentelemetry.api.common.AttributeKey.stringKey("server.socket.address");

static final AttributeKey<Long> SERVER_SOCKET_PORT =
io.opentelemetry.api.common.AttributeKey.longKey("server.socket.port");

private static final Logger logger =
Logger.getLogger(AwsMetricAttributeGenerator.class.getName());

Expand Down Expand Up @@ -293,9 +294,11 @@ private static void setRemoteServiceAndOperation(SpanData span, AttributesBuilde
} else if (isKeyPresent(span, FAAS_INVOKED_NAME) || isKeyPresent(span, FAAS_TRIGGER)) {
remoteService = getRemoteService(span, FAAS_INVOKED_NAME);
remoteOperation = getRemoteOperation(span, FAAS_TRIGGER);
} else if (isKeyPresent(span, MESSAGING_SYSTEM) || isKeyPresent(span, MESSAGING_OPERATION)) {
} else if (isKeyPresent(span, MESSAGING_SYSTEM)
|| isKeyPresentWithFallback(span, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION)) {
remoteService = getRemoteService(span, MESSAGING_SYSTEM);
remoteOperation = getRemoteOperation(span, MESSAGING_OPERATION);
remoteOperation =
getRemoteOperationWithFallback(span, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION);
} else if (isKeyPresent(span, GRAPHQL_OPERATION_TYPE)) {
remoteService = GRAPHQL;
remoteOperation = getRemoteOperation(span, GRAPHQL_OPERATION_TYPE);
Expand Down Expand Up @@ -772,15 +775,15 @@ private static Optional<String> getSnsResourceNameFromArn(Optional<String> strin
* {address} attribute is retrieved in priority order:
* - {@link SemanticAttributes#SERVER_ADDRESS},
* - {@link SemanticAttributes#NET_PEER_NAME},
* - {@link SemanticAttributes#SERVER_SOCKET_ADDRESS}
* - {@link SemanticAttributes#NETWORK_PEER_ADDRESS}
* - {@link SemanticAttributes#DB_CONNECTION_STRING}-Hostname
* </pre>
*
* <pre>
* {port} attribute is retrieved in priority order:
* - {@link SemanticAttributes#SERVER_PORT},
* - {@link SemanticAttributes#NET_PEER_PORT},
* - {@link SemanticAttributes#SERVER_SOCKET_PORT}
* - {@link SemanticAttributes#NETWORK_PEER_PORT}
* - {@link SemanticAttributes#DB_CONNECTION_STRING}-Port
* </pre>
*
Expand All @@ -799,9 +802,9 @@ private static Optional<String> getDbConnection(SpanData span) {
String networkPeerAddress = span.getAttributes().get(NET_PEER_NAME);
Long networkPeerPort = span.getAttributes().get(NET_PEER_PORT);
dbConnection = buildDbConnection(networkPeerAddress, networkPeerPort);
} else if (isKeyPresent(span, SERVER_SOCKET_ADDRESS)) {
String serverSocketAddress = span.getAttributes().get(SERVER_SOCKET_ADDRESS);
Long serverSocketPort = span.getAttributes().get(SERVER_SOCKET_PORT);
} else if (isKeyPresent(span, NETWORK_PEER_ADDRESS)) {
String serverSocketAddress = span.getAttributes().get(NETWORK_PEER_ADDRESS);
Long serverSocketPort = span.getAttributes().get(NETWORK_PEER_PORT);
dbConnection = buildDbConnection(serverSocketAddress, serverSocketPort);
} else if (isKeyPresent(span, DB_CONNECTION_STRING)) {
String connectionString = span.getAttributes().get(DB_CONNECTION_STRING);
Expand Down Expand Up @@ -954,6 +957,15 @@ private static String getRemoteOperation(SpanData span, AttributeKey<String> rem
return remoteOperation;
}

static String getRemoteOperationWithFallback(
SpanData span, AttributeKey<String> remoteOpKey, AttributeKey<String> remoteOpFallbackKey) {
String remoteOp = span.getAttributes().get(remoteOpKey);
if (remoteOp == null) {
return getRemoteOperation(span, remoteOpFallbackKey);
}
return remoteOp;
}

/**
* If no db.operation attribute provided in the span, we use db.statement to compute a valid
* remote operation in a best-effort manner. To do this, we take the first substring of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_REQUEST_METHOD;
import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_TARGET;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION_TYPE;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MessagingOperationTypeIncubatingValues.PROCESS;
import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SYSTEM;
import static software.amazon.opentelemetry.javaagent.providers.AwsApplicationSignalsCustomizerProvider.AWS_LAMBDA_FUNCTION_NAME_CONFIG;
Expand Down Expand Up @@ -153,6 +154,23 @@ static boolean isKeyPresent(SpanData span, AttributeKey<?> key) {
return span.getAttributes().get(key) != null;
}

static <T> boolean isKeyPresentWithFallback(
SpanData span, AttributeKey<T> key, AttributeKey<T> fallbackKey) {
if (span.getAttributes().get(key) != null) {
return true;
}
return isKeyPresent(span, fallbackKey);
}

static <T> T getKeyValueWithFallback(
SpanData span, AttributeKey<T> key, AttributeKey<T> fallbackKey) {
T value = span.getAttributes().get(key);
if (value != null) {
return value;
}
return span.getAttributes().get(fallbackKey);
}

static boolean isAwsSDKSpan(SpanData span) {
// https://opentelemetry.io/docs/specs/otel/trace/semantic_conventions/instrumentation/aws-sdk/#common-attributes
return "aws-api".equals(span.getAttributes().get(RPC_SYSTEM));
Expand All @@ -170,7 +188,8 @@ static boolean shouldGenerateDependencyMetricAttributes(SpanData span) {
}

static boolean isConsumerProcessSpan(SpanData spanData) {
String messagingOperation = spanData.getAttributes().get(MESSAGING_OPERATION);
String messagingOperation =
getKeyValueWithFallback(spanData, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION);
return SpanKind.CONSUMER.equals(spanData.getKind()) && PROCESS.equals(messagingOperation);
}

Expand All @@ -192,7 +211,8 @@ static boolean isLocalRoot(SpanData spanData) {
private static boolean isSqsReceiveMessageConsumerSpan(SpanData spanData) {
String spanName = spanData.getName();
SpanKind spanKind = spanData.getKind();
String messagingOperation = spanData.getAttributes().get(MESSAGING_OPERATION);
String messagingOperation =
getKeyValueWithFallback(spanData, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION);
InstrumentationScopeInfo instrumentationScopeInfo = spanData.getInstrumentationScopeInfo();

return SQS_RECEIVE_MESSAGE_SPAN_NAME.equalsIgnoreCase(spanName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_TARGET;
import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_URL;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION_TYPE;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_SYSTEM;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MessagingOperationTypeIncubatingValues.PROCESS;
import static io.opentelemetry.semconv.incubating.NetIncubatingAttributes.NET_PEER_NAME;
Expand Down Expand Up @@ -1264,31 +1265,31 @@ public void testDBClientSpanWithRemoteResourceAttributes() {
assertThat(actualAttributes.get(AWS_REMOTE_RESOURCE_IDENTIFIER)).isNull();
mockAttribute(NET_PEER_PORT, null);

// Validate behaviour of DB_NAME, SERVER_SOCKET_ADDRESS and SERVER_SOCKET_PORT exist, then
// Validate behaviour of DB_NAME, NETWORK_PEER_ADDRESS and NETWORK_PEER_PORT exist, then
// remove it.
mockAttribute(DB_NAME, "db_name");
mockAttribute(AwsMetricAttributeGenerator.SERVER_SOCKET_ADDRESS, "abc.com");
mockAttribute(AwsMetricAttributeGenerator.SERVER_SOCKET_PORT, 3306L);
mockAttribute(NETWORK_PEER_ADDRESS, "abc.com");
mockAttribute(NETWORK_PEER_PORT, 3306L);
validateRemoteResourceAttributes("DB::Connection", "db_name|abc.com|3306");
mockAttribute(DB_NAME, null);
mockAttribute(AwsMetricAttributeGenerator.SERVER_SOCKET_ADDRESS, null);
mockAttribute(AwsMetricAttributeGenerator.SERVER_SOCKET_PORT, null);
mockAttribute(NETWORK_PEER_ADDRESS, null);
mockAttribute(NETWORK_PEER_PORT, null);

// Validate behaviour of DB_NAME, SERVER_SOCKET_ADDRESS exist, then remove it.
// Validate behaviour of DB_NAME, NETWORK_PEER_ADDRESS exist, then remove it.
mockAttribute(DB_NAME, "db_name");
mockAttribute(AwsMetricAttributeGenerator.SERVER_SOCKET_ADDRESS, "abc.com");
mockAttribute(NETWORK_PEER_ADDRESS, "abc.com");
validateRemoteResourceAttributes("DB::Connection", "db_name|abc.com");
mockAttribute(DB_NAME, null);
mockAttribute(AwsMetricAttributeGenerator.SERVER_SOCKET_ADDRESS, null);
mockAttribute(NETWORK_PEER_ADDRESS, null);

// Validate behaviour of SERVER_SOCKET_PORT exist, then remove it.
mockAttribute(AwsMetricAttributeGenerator.SERVER_SOCKET_PORT, 3306L);
// Validate behaviour of NETWORK_PEER_PORT exist, then remove it.
mockAttribute(NETWORK_PEER_PORT, 3306L);
when(spanDataMock.getKind()).thenReturn(SpanKind.CLIENT);
actualAttributes =
GENERATOR.generateMetricAttributeMapFromSpan(spanDataMock, resource).get(DEPENDENCY_METRIC);
assertThat(actualAttributes.get(AWS_REMOTE_RESOURCE_TYPE)).isNull();
assertThat(actualAttributes.get(AWS_REMOTE_RESOURCE_IDENTIFIER)).isNull();
mockAttribute(AwsMetricAttributeGenerator.SERVER_SOCKET_PORT, null);
mockAttribute(NETWORK_PEER_PORT, null);

// Validate behaviour of only DB_NAME exist, then remove it.
mockAttribute(DB_NAME, "db_name");
Expand Down Expand Up @@ -1614,6 +1615,36 @@ public void testDbUserPresentAndIsDbSpanFalse() {
assertThat(actualAttributes.get(AWS_REMOTE_DB_USER)).isNull();
}

@Test
public void testGetRemoteOperationWithFallback_NewKeyPresent() {
mockAttribute(MESSAGING_OPERATION_TYPE, "send");
mockAttribute(MESSAGING_OPERATION, "publish");
String result =
AwsMetricAttributeGenerator.getRemoteOperationWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION);

assertThat(result).isEqualTo("send");
}

@Test
public void testGetRemoteOperationWithFallback_DeprecatedKeyPresent() {
mockAttribute(MESSAGING_OPERATION, "publish");
String result =
AwsMetricAttributeGenerator.getRemoteOperationWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION);

assertThat(result).isEqualTo("publish");
}

@Test
public void testGetRemoteOperationWithFallback_BothKeysAbsent() {
String result =
AwsMetricAttributeGenerator.getRemoteOperationWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION);

assertThat(result).isEqualTo(UNKNOWN_REMOTE_OPERATION);
}

@Test
public void testNormalizeRemoteServiceName_NoNormalization() {
String serviceName = "non aws service";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD;
import static io.opentelemetry.semconv.UrlAttributes.URL_PATH;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION_TYPE;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MessagingOperationTypeIncubatingValues.PROCESS;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MessagingOperationTypeIncubatingValues.RECEIVE;
import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SYSTEM;
Expand Down Expand Up @@ -365,13 +366,29 @@ public void testIsConsumerProcessSpanFalse() {
assertThat(AwsSpanProcessingUtil.isConsumerProcessSpan(spanDataMock)).isFalse();
}

@Test
public void testIsConsumerProcessSpanFalse_with_MESSAGING_OPERATION_TYPE() {
when(attributesMock.get(MESSAGING_OPERATION_TYPE)).thenReturn(RECEIVE);
when(attributesMock.get(MESSAGING_OPERATION)).thenReturn(PROCESS);
when(spanDataMock.getKind()).thenReturn(SpanKind.CONSUMER);
assertThat(AwsSpanProcessingUtil.isConsumerProcessSpan(spanDataMock)).isFalse();
}

@Test
public void testIsConsumerProcessSpanTrue() {
when(attributesMock.get(MESSAGING_OPERATION)).thenReturn(PROCESS);
when(spanDataMock.getKind()).thenReturn(SpanKind.CONSUMER);
assertThat(AwsSpanProcessingUtil.isConsumerProcessSpan(spanDataMock)).isTrue();
}

@Test
public void testIsConsumerProcessSpanTrue_with_MESSAGING_OPERATION_TYPE() {
when(attributesMock.get(MESSAGING_OPERATION_TYPE)).thenReturn(PROCESS);
when(attributesMock.get(MESSAGING_OPERATION)).thenReturn(RECEIVE);
when(spanDataMock.getKind()).thenReturn(SpanKind.CONSUMER);
assertThat(AwsSpanProcessingUtil.isConsumerProcessSpan(spanDataMock)).isTrue();
}

// check that AWS SDK v1 SQS ReceiveMessage consumer spans metrics are suppressed
@Test
public void testNoMetricAttributesForSqsConsumerSpanAwsSdkV1() {
Expand Down Expand Up @@ -436,6 +453,26 @@ public void testNoMetricAttributesForAwsSdkSqsConsumerProcessSpan() {
.isTrue();
}

@Test
public void
testNoMetricAttributesForAwsSdkSqsConsumerProcessSpan_with_MESSAGING_OPERATION_TYPE() {
InstrumentationScopeInfo instrumentationScopeInfo = mock(InstrumentationScopeInfo.class);
when(instrumentationScopeInfo.getName()).thenReturn("io.opentelemetry.aws-sdk-2.2");
when(spanDataMock.getInstrumentationScopeInfo()).thenReturn(instrumentationScopeInfo);
when(spanDataMock.getKind()).thenReturn(SpanKind.CONSUMER);
when(spanDataMock.getName()).thenReturn("Sqs.ReceiveMessage");
when(attributesMock.get(MESSAGING_OPERATION_TYPE)).thenReturn(PROCESS);

assertThat(AwsSpanProcessingUtil.shouldGenerateServiceMetricAttributes(spanDataMock)).isFalse();
assertThat(AwsSpanProcessingUtil.shouldGenerateDependencyMetricAttributes(spanDataMock))
.isFalse();

when(attributesMock.get(MESSAGING_OPERATION_TYPE)).thenReturn(RECEIVE);
assertThat(AwsSpanProcessingUtil.shouldGenerateServiceMetricAttributes(spanDataMock)).isTrue();
assertThat(AwsSpanProcessingUtil.shouldGenerateDependencyMetricAttributes(spanDataMock))
.isTrue();
}

@Test
public void testSqlDialectKeywordsOrder() {
List<String> keywords = getDialectKeywords();
Expand All @@ -454,4 +491,57 @@ public void testSqlDialectKeywordsMaxLength() {
assertThat(MAX_KEYWORD_LENGTH >= keyword.length());
}
}

@Test
public void testIsKeyPresentWithFallback_NewKeyPresent() {
when(attributesMock.get(MESSAGING_OPERATION_TYPE)).thenReturn("publish");
assertThat(
AwsSpanProcessingUtil.isKeyPresentWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION))
.isTrue();
}

@Test
public void testIsKeyPresentWithFallback_DeprecatedKeyPresent() {
when(attributesMock.get(MESSAGING_OPERATION)).thenReturn("publish");
assertThat(
AwsSpanProcessingUtil.isKeyPresentWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION))
.isTrue();
}

@Test
public void testIsKeyPresentWithFallback_BothKeysAbsent() {
assertThat(
AwsSpanProcessingUtil.isKeyPresentWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION))
.isFalse();
}

@Test
public void testGetKeyValueWithFallback_NewKeyPresent() {
when(attributesMock.get(MESSAGING_OPERATION_TYPE)).thenReturn("send");
when(attributesMock.get(MESSAGING_OPERATION)).thenReturn("publish");
assertThat(
AwsSpanProcessingUtil.getKeyValueWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION))
.isEqualTo("send");
}

@Test
public void testGetKeyValueWithFallback_DeprecatedKeyPresent() {
when(attributesMock.get(MESSAGING_OPERATION)).thenReturn("publish");
assertThat(
AwsSpanProcessingUtil.getKeyValueWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION))
.isEqualTo("publish");
}

@Test
public void testGetKeyValueWithFallback_BothKeysAbsent() {
assertThat(
AwsSpanProcessingUtil.getKeyValueWithFallback(
spanDataMock, MESSAGING_OPERATION_TYPE, MESSAGING_OPERATION))
.isNull();
}
}
Loading