diff --git a/instrumentation-api-incubator/build.gradle.kts b/instrumentation-api-incubator/build.gradle.kts
index 707fd2217c1b..7d62bb2cede8 100644
--- a/instrumentation-api-incubator/build.gradle.kts
+++ b/instrumentation-api-incubator/build.gradle.kts
@@ -42,11 +42,11 @@ tasks {
}
val testStableSemconv by registering(Test::class) {
- jvmArgs("-Dotel.semconv-stability.opt-in=database,code")
+ jvmArgs("-Dotel.semconv-stability.opt-in=database,code,messaging")
}
val testBothSemconv by registering(Test::class) {
- jvmArgs("-Dotel.semconv-stability.opt-in=database/dup,code/dup")
+ jvmArgs("-Dotel.semconv-stability.opt-in=database/dup,code/dup,messaging/dup")
}
check {
diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessageOperation.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessageOperation.java
index e7ef5c479ed0..cdbb2227da66 100644
--- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessageOperation.java
+++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessageOperation.java
@@ -9,20 +9,37 @@
/**
* Represents type of operations
+ * href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/messaging/messaging-spans.md#operation-types">operations
* that may be used in a messaging system.
*/
public enum MessageOperation {
+ @Deprecated
PUBLISH,
+
RECEIVE,
- PROCESS;
+ PROCESS,
+ CREATE,
+ SEND,
+ SETTLE;
/**
* Returns the operation name as defined in the
* specification.
+ *
+ * @deprecated Use {@link #operationType} instead.
*/
+ @Deprecated
String operationName() {
return name().toLowerCase(Locale.ROOT);
}
+
+ /**
+ * Returns the operation type as defined in the
+ * specification.
+ */
+ String operationType() {
+ return name().toLowerCase(Locale.ROOT);
+ }
}
diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractor.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractor.java
index bdf5ab879786..b8ca526ff2cc 100644
--- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractor.java
+++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractor.java
@@ -11,6 +11,7 @@
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
+import io.opentelemetry.instrumentation.api.internal.SemconvStability;
import io.opentelemetry.instrumentation.api.internal.SpanKey;
import io.opentelemetry.instrumentation.api.internal.SpanKeyProvider;
import java.util.List;
@@ -27,35 +28,54 @@
public final class MessagingAttributesExtractor
implements AttributesExtractor, SpanKeyProvider {
- // copied from MessagingIncubatingAttributes
+ // copied from io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes (stable
+ // attributes)
+ private static final AttributeKey MESSAGING_OPERATION_NAME =
+ AttributeKey.stringKey("messaging.operation.name");
+ private static final AttributeKey MESSAGING_SYSTEM =
+ AttributeKey.stringKey("messaging.system");
private static final AttributeKey MESSAGING_BATCH_MESSAGE_COUNT =
AttributeKey.longKey("messaging.batch.message_count");
- private static final AttributeKey MESSAGING_CLIENT_ID =
- AttributeKey.stringKey("messaging.client_id");
+ // Messaging specific
+ private static final AttributeKey MESSAGING_CONSUMER_GROUP_NAME =
+ AttributeKey.stringKey("messaging.consumer.group.name");
private static final AttributeKey MESSAGING_DESTINATION_ANONYMOUS =
AttributeKey.booleanKey("messaging.destination.anonymous");
private static final AttributeKey MESSAGING_DESTINATION_NAME =
AttributeKey.stringKey("messaging.destination.name");
- private static final AttributeKey MESSAGING_DESTINATION_PARTITION_ID =
- AttributeKey.stringKey("messaging.destination.partition.id");
+ // Messaging specific
+ private static final AttributeKey MESSAGING_DESTINATION_SUBSCRIPTION_NAME =
+ AttributeKey.stringKey("messaging.destination.subscription.name");
private static final AttributeKey MESSAGING_DESTINATION_TEMPLATE =
AttributeKey.stringKey("messaging.destination.template");
private static final AttributeKey MESSAGING_DESTINATION_TEMPORARY =
AttributeKey.booleanKey("messaging.destination.temporary");
- private static final AttributeKey MESSAGING_MESSAGE_BODY_SIZE =
- AttributeKey.longKey("messaging.message.body.size");
+ private static final AttributeKey MESSAGING_OPERATION_TYPE =
+ AttributeKey.stringKey("messaging.operation.type");
+ private static final AttributeKey MESSAGING_CLIENT_ID_STABLE =
+ AttributeKey.stringKey("messaging.client.id");
+ private static final AttributeKey MESSAGING_DESTINATION_PARTITION_ID =
+ AttributeKey.stringKey("messaging.destination.partition.id");
private static final AttributeKey MESSAGING_MESSAGE_CONVERSATION_ID =
AttributeKey.stringKey("messaging.message.conversation_id");
- private static final AttributeKey MESSAGING_MESSAGE_ENVELOPE_SIZE =
- AttributeKey.longKey("messaging.message.envelope.size");
private static final AttributeKey MESSAGING_MESSAGE_ID =
AttributeKey.stringKey("messaging.message.id");
+ private static final AttributeKey MESSAGING_MESSAGE_BODY_SIZE =
+ AttributeKey.longKey("messaging.message.body.size");
+ private static final AttributeKey MESSAGING_MESSAGE_ENVELOPE_SIZE =
+ AttributeKey.longKey("messaging.message.envelope.size");
+
+ // copied from MessagingIncubatingAttributes (old attributes)
+ @Deprecated
+ private static final AttributeKey MESSAGING_CLIENT_ID =
+ AttributeKey.stringKey("messaging.client_id");
+
+ @Deprecated
private static final AttributeKey MESSAGING_OPERATION =
AttributeKey.stringKey("messaging.operation");
- private static final AttributeKey MESSAGING_SYSTEM =
- AttributeKey.stringKey("messaging.system");
static final String TEMP_DESTINATION_NAME = "(temporary)";
+ static final String ANONYMOUS_DESTINATION_NAME = "(anonymous)";
/**
* Creates the messaging attributes extractor for the given {@link MessageOperation operation}
@@ -89,31 +109,60 @@ public static MessagingAttributesExtractorBuilder {
- @Nullable
String getSystem(REQUEST request);
@Nullable
- String getDestination(REQUEST request);
+ default Long getBatchMessageCount(REQUEST request, @Nullable RESPONSE response) {
+ return null;
+ }
@Nullable
- String getDestinationTemplate(REQUEST request);
-
- boolean isTemporaryDestination(REQUEST request);
+ default String getConsumerGroupName(REQUEST request) {
+ return null;
+ }
boolean isAnonymousDestination(REQUEST request);
@Nullable
- String getConversationId(REQUEST request);
+ String getDestination(REQUEST request);
@Nullable
- @Deprecated
- default Long getMessagePayloadSize(REQUEST request) {
+ default String getDestinationSubscriptionName(REQUEST request) {
return null;
}
@Nullable
- @Deprecated
- default Long getMessagePayloadCompressedSize(REQUEST request) {
+ default String getDestinationTemplate(REQUEST request) {
return null;
}
+ boolean isTemporaryDestination(REQUEST request);
+
@Nullable
- Long getMessageBodySize(REQUEST request);
+ default String getOperationName(REQUEST request, MessageOperation operation) {
+ return operation.operationType();
+ }
@Nullable
- Long getMessageEnvelopeSize(REQUEST request);
+ String getClientId(REQUEST request);
+
+ @Nullable
+ default String getDestinationPartitionId(REQUEST request) {
+ return null;
+ }
+
+ @Nullable
+ default String getConversationId(REQUEST request) {
+ return null;
+ }
@Nullable
String getMessageId(REQUEST request, @Nullable RESPONSE response);
@Nullable
- String getClientId(REQUEST request);
+ Long getMessageBodySize(REQUEST request);
@Nullable
- Long getBatchMessageCount(REQUEST request, @Nullable RESPONSE response);
+ Long getMessageEnvelopeSize(REQUEST request);
@Nullable
- default String getDestinationPartitionId(REQUEST request) {
+ @Deprecated
+ default Long getMessagePayloadSize(REQUEST request) {
+ return null;
+ }
+
+ @Nullable
+ @Deprecated
+ default Long getMessagePayloadCompressedSize(REQUEST request) {
return null;
}
diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingSpanNameExtractor.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingSpanNameExtractor.java
index 624d3b8e00bf..8362710bcd3b 100644
--- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingSpanNameExtractor.java
+++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingSpanNameExtractor.java
@@ -6,13 +6,16 @@
package io.opentelemetry.instrumentation.api.incubator.semconv.messaging;
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
+import io.opentelemetry.instrumentation.api.internal.SemconvStability;
+import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesGetter;
+import javax.annotation.Nullable;
public final class MessagingSpanNameExtractor implements SpanNameExtractor {
/**
* Returns a {@link SpanNameExtractor} that constructs the span name according to
- * messaging semantic conventions: {@code }.
+ * messaging semantic conventions: {@code }.
*
* @see MessagingAttributesGetter#getDestination(Object) used to extract {@code }.
@@ -20,20 +23,50 @@ public final class MessagingSpanNameExtractor implements SpanNameExtrac
*/
public static SpanNameExtractor create(
MessagingAttributesGetter getter, MessageOperation operation) {
- return new MessagingSpanNameExtractor<>(getter, operation);
+ return new MessagingSpanNameExtractor<>(getter, operation, null);
+ }
+
+ /**
+ * Returns a {@link SpanNameExtractor} that constructs the span name according to
+ * messaging semantic conventions: {@code }.
+ *
+ * @see MessagingAttributesGetter#getDestination(Object) used to extract {@code }
+ * and {@code }.
+ * @see MessageOperation used to extract {@code } (backwards compatibility with
+ * old conventions).
+ * @see ServerAttributesGetter used to extract data for {@code }
+ */
+ public static SpanNameExtractor create(
+ MessagingAttributesGetter getter,
+ MessageOperation operation,
+ ServerAttributesGetter serverAttributesGetter) {
+ return new MessagingSpanNameExtractor<>(getter, operation, serverAttributesGetter);
}
private final MessagingAttributesGetter getter;
+ private final ServerAttributesGetter serverAttributesGetter;
private final MessageOperation operation;
private MessagingSpanNameExtractor(
- MessagingAttributesGetter getter, MessageOperation operation) {
+ MessagingAttributesGetter getter,
+ MessageOperation operation,
+ @Nullable ServerAttributesGetter serverAttributesGetter) {
this.getter = getter;
+ this.serverAttributesGetter = serverAttributesGetter;
this.operation = operation;
}
@Override
+ @SuppressWarnings("deprecation") // using deprecated semconv
public String extract(REQUEST request) {
+ if (SemconvStability.emitStableMessagingSemconv()) {
+ String destination = getDestination(request);
+ if (destination == null) {
+ return getter.getOperationName(request, this.operation);
+ }
+ return getter.getOperationName(request, this.operation) + " " + destination;
+ }
String destinationName =
getter.isTemporaryDestination(request)
? MessagingAttributesExtractor.TEMP_DESTINATION_NAME
@@ -44,4 +77,28 @@ public String extract(REQUEST request) {
return destinationName + " " + operation.operationName();
}
+
+ @Nullable
+ private String getDestination(REQUEST request) {
+ String destination = null;
+ if (getter.getDestinationTemplate(request) != null) {
+ destination = getter.getDestinationTemplate(request);
+ } else if (getter.isTemporaryDestination(request)) {
+ destination = MessagingAttributesExtractor.TEMP_DESTINATION_NAME;
+ } else if (getter.isAnonymousDestination(request)) {
+ destination = MessagingAttributesExtractor.ANONYMOUS_DESTINATION_NAME;
+ } else if (getter.getDestination(request) != null) {
+ destination = getter.getDestination(request);
+ } else {
+ if (serverAttributesGetter != null
+ && serverAttributesGetter.getServerAddress(request) != null
+ && serverAttributesGetter.getServerPort(request) != null) {
+ destination =
+ serverAttributesGetter.getServerAddress(request)
+ + ":"
+ + serverAttributesGetter.getServerPort(request);
+ }
+ }
+ return destination;
+ }
}
diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/package-info.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/package-info.java
new file mode 100644
index 000000000000..eb5bdf29b745
--- /dev/null
+++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/package-info.java
@@ -0,0 +1,4 @@
+@ParametersAreNonnullByDefault
+package io.opentelemetry.instrumentation.api.incubator.semconv.messaging;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractorTest.java b/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractorTest.java
index b395fe4a053e..a83025b1fe16 100644
--- a/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractorTest.java
+++ b/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractorTest.java
@@ -13,6 +13,7 @@
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
+import io.opentelemetry.instrumentation.api.internal.SemconvStability;
import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes;
import java.util.ArrayList;
import java.util.Collections;
@@ -43,7 +44,7 @@ void shouldExtractAllAvailableAttributes(
request.put("system", "myQueue");
request.put("destinationKind", "topic");
request.put("destination", destination);
- request.put("destinationTemplate", destination);
+ request.put("destinationTemplate", destination + "-template");
if (temporary) {
request.put("temporaryDestination", "y");
}
@@ -56,6 +57,7 @@ void shouldExtractAllAvailableAttributes(
request.put("envelopeSize", "120");
request.put("clientId", "43");
request.put("batchMessageCount", "2");
+ request.put("operationName", "ack");
AttributesExtractor