55
66package 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 ;
811import static java .util .concurrent .TimeUnit .SECONDS ;
912import static java .util .logging .Level .FINE ;
1013
2326import io .opentelemetry .instrumentation .api .instrumenter .OperationMetrics ;
2427import io .opentelemetry .instrumentation .api .internal .OperationMetricsUtil ;
2528import java .util .logging .Logger ;
29+ import javax .annotation .Nullable ;
2630
2731/**
2832 * {@link OperationListener} which keeps track of <a
29- * href="https://github.com/open-telemetry/semantic-conventions/blob/v1.26 .0/docs/messaging/messaging-metrics.md#consumer-metrics">Consumer
33+ * href="https://github.com/open-telemetry/semantic-conventions/blob/v1.43 .0/docs/messaging/messaging-metrics.md#consumer-metrics">consumer
3034 * metrics</a>.
3135 */
3236public final class MessagingConsumerMetrics implements OperationListener {
@@ -35,34 +39,52 @@ public final class MessagingConsumerMetrics implements OperationListener {
3539 // copied from MessagingIncubatingAttributes
3640 private static final AttributeKey <Long > MESSAGING_BATCH_MESSAGE_COUNT =
3741 AttributeKey .longKey ("messaging.batch.message_count" );
42+ private static final AttributeKey <String > MESSAGING_OPERATION_TYPE =
43+ AttributeKey .stringKey ("messaging.operation.type" );
3844 private static final ContextKey <MessagingConsumerMetrics .State > MESSAGING_CONSUMER_METRICS_STATE =
3945 ContextKey .named ("messaging-consumer-metrics-state" );
4046 private static final Logger logger = Logger .getLogger (MessagingConsumerMetrics .class .getName ());
4147
42- private final DoubleHistogram receiveDurationHistogram ;
43- private final LongCounter receiveMessageCount ;
48+ private final boolean consumedMessagesOnly ;
49+ @ Nullable private final DoubleHistogram receiveDurationHistogram ;
50+ @ Nullable private final LongCounter receiveMessageCount ;
51+ @ Nullable private final DoubleHistogram clientOperationDurationHistogram ;
52+ @ Nullable private final LongCounter consumedMessagesCounter ;
4453
45- private MessagingConsumerMetrics (Meter meter ) {
46- DoubleHistogramBuilder durationBuilder =
47- meter
48- .histogramBuilder ("messaging.receive.duration" )
49- .setDescription ("Measures the duration of receive operation." )
50- .setExplicitBucketBoundariesAdvice (MessagingMetricsAdvice .DURATION_SECONDS_BUCKETS )
51- .setUnit ("s" );
52- MessagingMetricsAdvice .applyReceiveDurationAdvice (durationBuilder );
53- receiveDurationHistogram = durationBuilder .build ();
54+ private MessagingConsumerMetrics (Meter meter , boolean supportsStableSemconv ) {
55+ this (meter , supportsStableSemconv , false );
56+ }
5457
55- LongCounterBuilder longCounterBuilder =
56- meter
57- .counterBuilder ("messaging.receive.messages" )
58- .setDescription ("Measures the number of received messages." )
59- .setUnit ("{message}" );
60- MessagingMetricsAdvice .applyReceiveMessagesAdvice (longCounterBuilder );
61- receiveMessageCount = longCounterBuilder .build ();
58+ private MessagingConsumerMetrics (
59+ Meter meter , boolean supportsStableSemconv , boolean consumedMessagesOnly ) {
60+ this .consumedMessagesOnly = consumedMessagesOnly ;
61+ boolean emitOldSemconv = !supportsStableSemconv || emitOldMessagingSemconv ();
62+ boolean emitStableSemconv = supportsStableSemconv && emitStableMessagingSemconv ();
63+ receiveDurationHistogram =
64+ !consumedMessagesOnly && emitOldSemconv ? buildReceiveDuration (meter ) : null ;
65+ receiveMessageCount =
66+ !consumedMessagesOnly && emitOldSemconv ? buildReceiveMessages (meter ) : null ;
67+ clientOperationDurationHistogram =
68+ !consumedMessagesOnly && emitStableSemconv ? buildClientOperationDuration (meter ) : null ;
69+ consumedMessagesCounter = emitStableSemconv ? buildConsumedMessages (meter ) : null ;
6270 }
6371
72+ /** Returns metrics for extractors configured with {@link MessageOperation}. */
6473 public static OperationMetrics get () {
65- return OperationMetricsUtil .create ("messaging consumer" , MessagingConsumerMetrics ::new );
74+ return OperationMetricsUtil .create (
75+ "messaging consumer" , meter -> new MessagingConsumerMetrics (meter , false ));
76+ }
77+
78+ /** Returns metrics for extractors configured with {@link MessagingOperationType}. */
79+ public static OperationMetrics getForOperationType () {
80+ return OperationMetricsUtil .create (
81+ "messaging consumer" , meter -> new MessagingConsumerMetrics (meter , true ));
82+ }
83+
84+ /** Returns only the stable consumed-messages metric for a delivered message. */
85+ public static OperationMetrics getConsumedMessages () {
86+ return OperationMetricsUtil .create (
87+ "messaging consumed messages" , meter -> new MessagingConsumerMetrics (meter , true , true ));
6688 }
6789
6890 @ Override
@@ -85,21 +107,98 @@ public void onEnd(Context context, Attributes endAttributes, long endNanos) {
85107 }
86108
87109 Attributes attributes = state .startAttributes ().toBuilder ().putAll (endAttributes ).build ();
88- receiveDurationHistogram .record (
89- (endNanos - state .startTimeNanos ()) / NANOS_PER_S , attributes , context );
110+ double duration = (endNanos - state .startTimeNanos ()) / NANOS_PER_S ;
111+ if (receiveDurationHistogram != null ) {
112+ receiveDurationHistogram .record (duration , attributes , context );
113+ }
114+ // Metric view attribute advice can only select keys statically. The concrete destination name
115+ // must be omitted when a template is available or the destination is temporary or anonymous,
116+ // so this conditional requirement must be enforced before recording.
117+ Attributes filteredAttributes =
118+ clientOperationDurationHistogram != null || consumedMessagesCounter != null
119+ ? MessagingMetricsAdvice .filterAttributes (attributes )
120+ : attributes ;
121+ String operationType = attributes .get (MESSAGING_OPERATION_TYPE );
122+ if (clientOperationDurationHistogram != null
123+ && !MessagingOperationType .PROCESS .value ().equals (operationType )) {
124+ clientOperationDurationHistogram .record (duration , filteredAttributes , context );
125+ }
90126
91- long receiveMessagesCount = getReceiveMessagesCount (state .startAttributes (), endAttributes );
92- receiveMessageCount .add (receiveMessagesCount , attributes , context );
127+ Long batchMessageCount = getBatchMessageCount (state .startAttributes (), endAttributes );
128+ if (receiveMessageCount != null ) {
129+ receiveMessageCount .add (
130+ batchMessageCount == null ? 1 : batchMessageCount , attributes , context );
131+ }
132+ if (consumedMessagesCounter != null
133+ && (consumedMessagesOnly || MessagingOperationType .RECEIVE .value ().equals (operationType ))) {
134+ long consumedMessagesCount =
135+ getConsumedMessagesCount (attributes , batchMessageCount , consumedMessagesOnly );
136+ if (consumedMessagesCount > 0 ) {
137+ consumedMessagesCounter .add (consumedMessagesCount , filteredAttributes , context );
138+ }
139+ }
93140 }
94141
95- private static long getReceiveMessagesCount (Attributes ... attributesList ) {
142+ @ Nullable
143+ private static Long getBatchMessageCount (Attributes ... attributesList ) {
96144 for (Attributes attributes : attributesList ) {
97145 Long value = attributes .get (MESSAGING_BATCH_MESSAGE_COUNT );
98146 if (value != null ) {
99147 return value ;
100148 }
101149 }
102- return 1 ;
150+ return null ;
151+ }
152+
153+ private static long getConsumedMessagesCount (
154+ Attributes attributes , @ Nullable Long batchMessageCount , boolean consumedMessagesOnly ) {
155+ if (batchMessageCount != null ) {
156+ return batchMessageCount ;
157+ }
158+ return consumedMessagesOnly || attributes .get (ERROR_TYPE ) == null ? 1 : 0 ;
159+ }
160+
161+ private static DoubleHistogram buildReceiveDuration (Meter meter ) {
162+ DoubleHistogramBuilder builder =
163+ meter
164+ .histogramBuilder ("messaging.receive.duration" )
165+ .setDescription ("Measures the duration of receive operation." )
166+ .setExplicitBucketBoundariesAdvice (MessagingMetricsAdvice .DURATION_SECONDS_BUCKETS )
167+ .setUnit ("s" );
168+ MessagingMetricsAdvice .applyOldDurationAdvice (builder );
169+ return builder .build ();
170+ }
171+
172+ private static LongCounter buildReceiveMessages (Meter meter ) {
173+ LongCounterBuilder builder =
174+ meter
175+ .counterBuilder ("messaging.receive.messages" )
176+ .setDescription ("Measures the number of received messages." )
177+ .setUnit ("{message}" );
178+ MessagingMetricsAdvice .applyOldMessagesAdvice (builder );
179+ return builder .build ();
180+ }
181+
182+ private static DoubleHistogram buildClientOperationDuration (Meter meter ) {
183+ DoubleHistogramBuilder builder =
184+ meter
185+ .histogramBuilder ("messaging.client.operation.duration" )
186+ .setDescription (
187+ "Duration of messaging operation initiated by a producer or consumer client." )
188+ .setExplicitBucketBoundariesAdvice (MessagingMetricsAdvice .DURATION_SECONDS_BUCKETS )
189+ .setUnit ("s" );
190+ MessagingMetricsAdvice .applyClientOperationDurationAdvice (builder );
191+ return builder .build ();
192+ }
193+
194+ private static LongCounter buildConsumedMessages (Meter meter ) {
195+ LongCounterBuilder builder =
196+ meter
197+ .counterBuilder ("messaging.client.consumed.messages" )
198+ .setDescription ("Number of messages that were delivered to the application." )
199+ .setUnit ("{message}" );
200+ MessagingMetricsAdvice .applyConsumedMessagesAdvice (builder );
201+ return builder .build ();
103202 }
104203
105204 @ AutoValue
0 commit comments