Skip to content

Commit 9dc5bef

Browse files
committed
Add messaging v1.43 shared contract
1 parent 42f8313 commit 9dc5bef

19 files changed

Lines changed: 806 additions & 82 deletions

File tree

instrumentation-api-incubator/build.gradle.kts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,15 @@ tasks {
9292
testClassesDirs = sourceSets.test.get().output.classesDirs
9393
classpath = sourceSets.test.get().runtimeClasspath
9494
jvmArgs("-Dotel.semconv-stability.opt-in=database,code,service.peer,rpc")
95+
jvmArgs("-Dotel.semconv-stability.preview=messaging")
9596
inputs.dir(jflexOutputDir)
9697
}
9798

9899
val testBothSemconv = register<Test>("testBothSemconv") {
99100
testClassesDirs = sourceSets.test.get().output.classesDirs
100101
classpath = sourceSets.test.get().runtimeClasspath
101102
jvmArgs("-Dotel.semconv-stability.opt-in=database/dup,code/dup,service.peer/dup,rpc/dup")
103+
jvmArgs("-Dotel.semconv-stability.preview=messaging/dup")
102104
inputs.dir(jflexOutputDir)
103105
}
104106

@@ -117,6 +119,11 @@ tasks {
117119
}
118120

119121
check {
120-
dependsOn(testStableSemconv, testBothSemconv, testExceptionSignalLogs, testExceptionSignalLogsDup)
122+
dependsOn(
123+
testStableSemconv,
124+
testBothSemconv,
125+
testExceptionSignalLogs,
126+
testExceptionSignalLogsDup,
127+
)
121128
}
122129
}

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessageOperation.java

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,19 @@
55

66
package io.opentelemetry.instrumentation.api.incubator.semconv.messaging;
77

8-
import java.util.Locale;
9-
10-
/**
11-
* Represents type of <a
12-
* href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/messaging/messaging-spans.md#operation-names">operations</a>
13-
* that may be used in a messaging system.
14-
*/
8+
/** Represents an operation that may be used in a messaging system. */
159
public enum MessageOperation {
16-
PUBLISH,
17-
RECEIVE,
18-
PROCESS;
10+
PUBLISH(MessagingOperationType.SEND),
11+
RECEIVE(MessagingOperationType.RECEIVE),
12+
PROCESS(MessagingOperationType.PROCESS);
13+
14+
private final MessagingOperationType operationType;
15+
16+
MessageOperation(MessagingOperationType operationType) {
17+
this.operationType = operationType;
18+
}
1919

20-
/**
21-
* Returns the operation name as defined in <a
22-
* href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/messaging/messaging-spans.md#operation-names">the
23-
* specification</a>.
24-
*/
25-
String operationName() {
26-
return name().toLowerCase(Locale.ROOT);
20+
MessagingOperationType type() {
21+
return operationType;
2722
}
2823
}

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractor.java

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
package io.opentelemetry.instrumentation.api.incubator.semconv.messaging;
77

8+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitOldMessagingSemconv;
9+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableMessagingSemconv;
10+
import static io.opentelemetry.semconv.ErrorAttributes.ERROR_TYPE;
11+
812
import io.opentelemetry.api.common.AttributeKey;
913
import io.opentelemetry.api.common.AttributesBuilder;
1014
import io.opentelemetry.context.Context;
@@ -17,7 +21,7 @@
1721

1822
/**
1923
* Extractor of <a
20-
* href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/messaging/messaging-spans.md">messaging
24+
* href="https://github.com/open-telemetry/semantic-conventions/blob/v1.43.0/docs/messaging/messaging-spans.md">messaging
2125
* attributes</a>.
2226
*
2327
* <p>This class delegates to a type-specific {@link MessagingAttributesGetter} for individual
@@ -29,8 +33,10 @@ public final class MessagingAttributesExtractor<REQUEST, RESPONSE>
2933
// copied from MessagingIncubatingAttributes
3034
private static final AttributeKey<Long> MESSAGING_BATCH_MESSAGE_COUNT =
3135
AttributeKey.longKey("messaging.batch.message_count");
32-
private static final AttributeKey<String> MESSAGING_CLIENT_ID =
36+
private static final AttributeKey<String> MESSAGING_CLIENT_ID_OLD =
3337
AttributeKey.stringKey("messaging.client_id");
38+
private static final AttributeKey<String> MESSAGING_CLIENT_ID =
39+
AttributeKey.stringKey("messaging.client.id");
3440
private static final AttributeKey<Boolean> MESSAGING_DESTINATION_ANONYMOUS =
3541
AttributeKey.booleanKey("messaging.destination.anonymous");
3642
private static final AttributeKey<String> MESSAGING_DESTINATION_NAME =
@@ -51,49 +57,79 @@ public final class MessagingAttributesExtractor<REQUEST, RESPONSE>
5157
AttributeKey.stringKey("messaging.message.id");
5258
private static final AttributeKey<String> MESSAGING_OPERATION =
5359
AttributeKey.stringKey("messaging.operation");
60+
private static final AttributeKey<String> MESSAGING_OPERATION_NAME =
61+
AttributeKey.stringKey("messaging.operation.name");
62+
private static final AttributeKey<String> MESSAGING_OPERATION_TYPE =
63+
AttributeKey.stringKey("messaging.operation.type");
5464
private static final AttributeKey<String> MESSAGING_SYSTEM =
5565
AttributeKey.stringKey("messaging.system");
5666

5767
static final String TEMP_DESTINATION_NAME = "(temporary)";
5868

59-
/**
60-
* Creates the messaging attributes extractor for the given {@link MessageOperation operation}
61-
* with default configuration.
62-
*/
69+
/** Creates the messaging attributes extractor for the given operation type. */
70+
public static <REQUEST, RESPONSE> AttributesExtractor<REQUEST, RESPONSE> createForOperationType(
71+
MessagingAttributesGetter<REQUEST, RESPONSE> getter,
72+
@Nullable MessagingOperationType operationType) {
73+
return builderForOperationType(getter, operationType).build();
74+
}
75+
76+
/** Creates the messaging attributes extractor for the given operation. */
6377
public static <REQUEST, RESPONSE> AttributesExtractor<REQUEST, RESPONSE> create(
64-
MessagingAttributesGetter<REQUEST, RESPONSE> getter, MessageOperation operation) {
78+
MessagingAttributesGetter<REQUEST, RESPONSE> getter, @Nullable MessageOperation operation) {
6579
return builder(getter, operation).build();
6680
}
6781

6882
/**
69-
* Returns a new {@link MessagingAttributesExtractorBuilder} for the given {@link MessageOperation
70-
* operation} that can be used to configure the messaging attributes extractor.
83+
* Returns a new {@link MessagingAttributesExtractorBuilder} configured for the given operation
84+
* type.
7185
*/
86+
public static <REQUEST, RESPONSE>
87+
MessagingAttributesExtractorBuilder<REQUEST, RESPONSE> builderForOperationType(
88+
MessagingAttributesGetter<REQUEST, RESPONSE> getter,
89+
@Nullable MessagingOperationType operationType) {
90+
return new MessagingAttributesExtractorBuilder<>(getter, operationType, true);
91+
}
92+
93+
/** Returns a new messaging attributes extractor builder for the given operation. */
7294
public static <REQUEST, RESPONSE> MessagingAttributesExtractorBuilder<REQUEST, RESPONSE> builder(
73-
MessagingAttributesGetter<REQUEST, RESPONSE> getter, MessageOperation operation) {
74-
return new MessagingAttributesExtractorBuilder<>(getter, operation);
95+
MessagingAttributesGetter<REQUEST, RESPONSE> getter, @Nullable MessageOperation operation) {
96+
return new MessagingAttributesExtractorBuilder<>(
97+
getter, operation == null ? null : operation.type(), false);
7598
}
7699

77100
private final MessagingAttributesGetter<REQUEST, RESPONSE> getter;
78-
private final MessageOperation operation;
101+
@Nullable private final MessagingOperationType operationType;
102+
@Nullable private final String operationName;
103+
private final boolean supportsStableSemconv;
79104
private final List<String> capturedHeaders;
80105

81106
MessagingAttributesExtractor(
82107
MessagingAttributesGetter<REQUEST, RESPONSE> getter,
83-
MessageOperation operation,
108+
@Nullable MessagingOperationType operationType,
109+
@Nullable String operationName,
110+
boolean supportsStableSemconv,
84111
List<String> capturedHeaders) {
85112
this.getter = getter;
86-
this.operation = operation;
113+
this.operationType = operationType;
114+
this.operationName = operationName;
115+
this.supportsStableSemconv = supportsStableSemconv;
87116
this.capturedHeaders = new ArrayList<>(capturedHeaders);
88117
}
89118

90119
@Override
91120
public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) {
121+
boolean emitOldSemconv = !supportsStableSemconv || emitOldMessagingSemconv();
122+
boolean emitStableSemconv = supportsStableSemconv && emitStableMessagingSemconv();
92123
attributes.put(MESSAGING_SYSTEM, getter.getSystem(request));
93124
boolean isTemporaryDestination = getter.isTemporaryDestination(request);
94125
if (isTemporaryDestination) {
95126
attributes.put(MESSAGING_DESTINATION_TEMPORARY, true);
96-
attributes.put(MESSAGING_DESTINATION_NAME, TEMP_DESTINATION_NAME);
127+
if (emitStableSemconv) {
128+
attributes.put(MESSAGING_DESTINATION_NAME, getter.getDestination(request));
129+
attributes.put(MESSAGING_DESTINATION_TEMPLATE, getter.getDestinationTemplate(request));
130+
} else {
131+
attributes.put(MESSAGING_DESTINATION_NAME, TEMP_DESTINATION_NAME);
132+
}
97133
} else {
98134
attributes.put(MESSAGING_DESTINATION_NAME, getter.getDestination(request));
99135
attributes.put(MESSAGING_DESTINATION_TEMPLATE, getter.getDestinationTemplate(request));
@@ -106,9 +142,20 @@ public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST
106142
attributes.put(MESSAGING_MESSAGE_CONVERSATION_ID, getter.getConversationId(request));
107143
attributes.put(MESSAGING_MESSAGE_BODY_SIZE, getter.getMessageBodySize(request));
108144
attributes.put(MESSAGING_MESSAGE_ENVELOPE_SIZE, getter.getMessageEnvelopeSize(request));
109-
attributes.put(MESSAGING_CLIENT_ID, getter.getClientId(request));
110-
if (operation != null) {
111-
attributes.put(MESSAGING_OPERATION, operation.operationName());
145+
if (emitOldSemconv) {
146+
attributes.put(MESSAGING_CLIENT_ID_OLD, getter.getClientId(request));
147+
}
148+
if (emitStableSemconv) {
149+
attributes.put(MESSAGING_CLIENT_ID, getter.getClientId(request));
150+
}
151+
if (emitOldSemconv && operationType != null) {
152+
attributes.put(MESSAGING_OPERATION, operationType.defaultOperationName());
153+
}
154+
if (emitStableSemconv) {
155+
attributes.put(MESSAGING_OPERATION_NAME, operationName);
156+
if (operationType != null) {
157+
attributes.put(MESSAGING_OPERATION_TYPE, operationType.value());
158+
}
112159
}
113160
}
114161

@@ -121,6 +168,13 @@ public void onEnd(
121168
@Nullable Throwable error) {
122169
attributes.put(MESSAGING_MESSAGE_ID, getter.getMessageId(request, response));
123170
attributes.put(MESSAGING_BATCH_MESSAGE_COUNT, getter.getBatchMessageCount(request, response));
171+
if (supportsStableSemconv && emitStableMessagingSemconv()) {
172+
String errorType = getter.getErrorType(request, response, error);
173+
if (errorType == null && error != null) {
174+
errorType = error.getClass().getName();
175+
}
176+
attributes.put(ERROR_TYPE, errorType);
177+
}
124178

125179
for (String name : capturedHeaders) {
126180
List<String> values = getter.getMessageHeader(request, name);
@@ -137,17 +191,21 @@ public void onEnd(
137191
@Override
138192
@Nullable
139193
public SpanKey internalGetSpanKey() {
140-
if (operation == null) {
194+
if (operationType == null) {
141195
return null;
142196
}
143197

144-
switch (operation) {
145-
case PUBLISH:
198+
switch (operationType) {
199+
case CREATE:
200+
return SpanKey.PRODUCER_CREATE;
201+
case SEND:
146202
return SpanKey.PRODUCER;
147203
case RECEIVE:
148204
return SpanKey.CONSUMER_RECEIVE;
149205
case PROCESS:
150206
return SpanKey.CONSUMER_PROCESS;
207+
case SETTLE:
208+
return SpanKey.CONSUMER_SETTLE;
151209
}
152210
throw new IllegalStateException("Can't possibly happen");
153211
}

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesExtractorBuilder.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,40 @@
66
package io.opentelemetry.instrumentation.api.incubator.semconv.messaging;
77

88
import static java.util.Collections.emptyList;
9+
import static java.util.Objects.requireNonNull;
910

1011
import com.google.errorprone.annotations.CanIgnoreReturnValue;
1112
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
1213
import java.util.ArrayList;
1314
import java.util.Collection;
1415
import java.util.List;
16+
import javax.annotation.Nullable;
1517

1618
/** A builder of {@link MessagingAttributesExtractor}. */
1719
public final class MessagingAttributesExtractorBuilder<REQUEST, RESPONSE> {
1820

1921
final MessagingAttributesGetter<REQUEST, RESPONSE> getter;
20-
final MessageOperation operation;
22+
@Nullable MessagingOperationType operationType;
23+
@Nullable String operationName;
24+
private final boolean supportsStableSemconv;
2125
List<String> capturedHeaders = emptyList();
2226

2327
MessagingAttributesExtractorBuilder(
24-
MessagingAttributesGetter<REQUEST, RESPONSE> getter, MessageOperation operation) {
28+
MessagingAttributesGetter<REQUEST, RESPONSE> getter,
29+
@Nullable MessagingOperationType operationType,
30+
boolean supportsStableSemconv) {
2531
this.getter = getter;
26-
this.operation = operation;
32+
this.operationType = operationType;
33+
this.operationName = operationType == null ? null : operationType.defaultOperationName();
34+
this.supportsStableSemconv = supportsStableSemconv;
35+
}
36+
37+
/** Configures the system-specific operation name emitted as {@code messaging.operation.name}. */
38+
@CanIgnoreReturnValue
39+
public MessagingAttributesExtractorBuilder<REQUEST, RESPONSE> setOperationName(
40+
String operationName) {
41+
this.operationName = requireNonNull(operationName, "operationName");
42+
return this;
2743
}
2844

2945
/**
@@ -47,6 +63,7 @@ public MessagingAttributesExtractorBuilder<REQUEST, RESPONSE> setCapturedHeaders
4763
* MessagingAttributesExtractorBuilder}.
4864
*/
4965
public AttributesExtractor<REQUEST, RESPONSE> build() {
50-
return new MessagingAttributesExtractor<>(getter, operation, capturedHeaders);
66+
return new MessagingAttributesExtractor<>(
67+
getter, operationType, operationName, supportsStableSemconv, capturedHeaders);
5168
}
5269
}

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/messaging/MessagingAttributesGetter.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ default String getDestinationPartitionId(REQUEST request) {
5555
return null;
5656
}
5757

58+
/**
59+
* Returns a description of a class of error the operation ended with.
60+
*
61+
* <p>If this method returns {@code null}, the exception class name (if any) will be used as error
62+
* type.
63+
*
64+
* <p>The cardinality of the error type should be low. The instrumentations implementing this
65+
* method are recommended to document the custom values they support.
66+
*/
67+
@Nullable
68+
default String getErrorType(
69+
REQUEST request, @Nullable RESPONSE response, @Nullable Throwable error) {
70+
return null;
71+
}
72+
5873
/**
5974
* Extracts all values of header named {@code name} from the request, or an empty list if there
6075
* were none.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.incubator.semconv.messaging;
7+
8+
/**
9+
* Represents a <a
10+
* href="https://github.com/open-telemetry/semantic-conventions/blob/v1.43.0/docs/messaging/messaging-spans.md#operation-types">messaging
11+
* operation type</a>.
12+
*/
13+
public enum MessagingOperationType {
14+
CREATE("create", "create"),
15+
SEND("send", "publish"),
16+
RECEIVE("receive", "receive"),
17+
PROCESS("process", "process"),
18+
SETTLE("settle", "settle");
19+
20+
private final String value;
21+
private final String defaultOperationName;
22+
23+
MessagingOperationType(String value, String defaultOperationName) {
24+
this.value = value;
25+
this.defaultOperationName = defaultOperationName;
26+
}
27+
28+
String value() {
29+
return value;
30+
}
31+
32+
String defaultOperationName() {
33+
return defaultOperationName;
34+
}
35+
}

0 commit comments

Comments
 (0)