18
18
import io .opentelemetry .instrumentation .api .instrumenter .Instrumenter ;
19
19
import io .opentelemetry .instrumentation .api .instrumenter .InstrumenterBuilder ;
20
20
import io .opentelemetry .instrumentation .api .instrumenter .SpanKindExtractor ;
21
+ import io .opentelemetry .instrumentation .api .instrumenter .SpanLinksExtractor ;
21
22
import io .opentelemetry .instrumentation .api .internal .InstrumenterUtil ;
23
+ import io .opentelemetry .instrumentation .api .internal .PropagatorBasedSpanLinksExtractor ;
22
24
import io .opentelemetry .instrumentation .api .internal .Timer ;
23
25
import io .opentelemetry .instrumentation .api .semconv .network .ServerAttributesExtractor ;
24
26
import io .opentelemetry .javaagent .bootstrap .internal .ExperimentalConfig ;
@@ -38,6 +40,8 @@ public final class PulsarSingletons {
38
40
TELEMETRY .getPropagators ().getTextMapPropagator ();
39
41
private static final List <String > capturedHeaders =
40
42
ExperimentalConfig .get ().getMessagingHeaders ();
43
+ private static final boolean receiveInstrumentationEnabled =
44
+ ExperimentalConfig .get ().messagingReceiveInstrumentationEnabled ();
41
45
42
46
private static final Instrumenter <PulsarRequest , Void > CONSUMER_PROCESS_INSTRUMENTER =
43
47
createConsumerProcessInstrumenter ();
@@ -64,15 +68,23 @@ private static Instrumenter<PulsarRequest, Void> createConsumerReceiveInstrument
64
68
MessagingAttributesGetter <PulsarRequest , Void > getter =
65
69
PulsarMessagingAttributesGetter .INSTANCE ;
66
70
67
- return Instrumenter .<PulsarRequest , Void >builder (
68
- TELEMETRY ,
69
- INSTRUMENTATION_NAME ,
70
- MessagingSpanNameExtractor .create (getter , MessageOperation .RECEIVE ))
71
- .addAttributesExtractor (
72
- createMessagingAttributesExtractor (getter , MessageOperation .RECEIVE ))
73
- .addAttributesExtractor (
74
- ServerAttributesExtractor .create (new PulsarNetClientAttributesGetter ()))
75
- .buildConsumerInstrumenter (MessageTextMapGetter .INSTANCE );
71
+ InstrumenterBuilder <PulsarRequest , Void > instrumenterBuilder =
72
+ Instrumenter .<PulsarRequest , Void >builder (
73
+ TELEMETRY ,
74
+ INSTRUMENTATION_NAME ,
75
+ MessagingSpanNameExtractor .create (getter , MessageOperation .RECEIVE ))
76
+ .addAttributesExtractor (
77
+ createMessagingAttributesExtractor (getter , MessageOperation .RECEIVE ))
78
+ .addAttributesExtractor (
79
+ ServerAttributesExtractor .create (new PulsarNetClientAttributesGetter ()));
80
+
81
+ if (receiveInstrumentationEnabled ) {
82
+ return instrumenterBuilder
83
+ .addSpanLinksExtractor (
84
+ new PropagatorBasedSpanLinksExtractor <>(PROPAGATOR , MessageTextMapGetter .INSTANCE ))
85
+ .buildInstrumenter (SpanKindExtractor .alwaysConsumer ());
86
+ }
87
+ return instrumenterBuilder .buildConsumerInstrumenter (MessageTextMapGetter .INSTANCE );
76
88
}
77
89
78
90
private static Instrumenter <PulsarBatchRequest , Void > createConsumerBatchReceiveInstrumenter () {
@@ -87,24 +99,29 @@ private static Instrumenter<PulsarBatchRequest, Void> createConsumerBatchReceive
87
99
createMessagingAttributesExtractor (getter , MessageOperation .RECEIVE ))
88
100
.addAttributesExtractor (
89
101
ServerAttributesExtractor .create (new PulsarNetClientAttributesGetter ()))
90
- .setEnabled (ExperimentalConfig .get ().messagingReceiveInstrumentationEnabled ())
91
- .addSpanLinksExtractor (
92
- new PulsarBatchRequestSpanLinksExtractor (
93
- GlobalOpenTelemetry .getPropagators ().getTextMapPropagator ()))
102
+ .addSpanLinksExtractor (new PulsarBatchRequestSpanLinksExtractor (PROPAGATOR ))
94
103
.buildInstrumenter (SpanKindExtractor .alwaysConsumer ());
95
104
}
96
105
97
106
private static Instrumenter <PulsarRequest , Void > createConsumerProcessInstrumenter () {
98
107
MessagingAttributesGetter <PulsarRequest , Void > getter =
99
108
PulsarMessagingAttributesGetter .INSTANCE ;
100
109
101
- return Instrumenter .<PulsarRequest , Void >builder (
102
- TELEMETRY ,
103
- INSTRUMENTATION_NAME ,
104
- MessagingSpanNameExtractor .create (getter , MessageOperation .PROCESS ))
105
- .addAttributesExtractor (
106
- createMessagingAttributesExtractor (getter , MessageOperation .PROCESS ))
107
- .buildInstrumenter ();
110
+ InstrumenterBuilder <PulsarRequest , Void > instrumenterBuilder =
111
+ Instrumenter .<PulsarRequest , Void >builder (
112
+ TELEMETRY ,
113
+ INSTRUMENTATION_NAME ,
114
+ MessagingSpanNameExtractor .create (getter , MessageOperation .PROCESS ))
115
+ .addAttributesExtractor (
116
+ createMessagingAttributesExtractor (getter , MessageOperation .PROCESS ));
117
+
118
+ if (receiveInstrumentationEnabled ) {
119
+ SpanLinksExtractor <PulsarRequest > spanLinksExtractor =
120
+ new PropagatorBasedSpanLinksExtractor <>(PROPAGATOR , MessageTextMapGetter .INSTANCE );
121
+ instrumenterBuilder .addSpanLinksExtractor (spanLinksExtractor );
122
+ return instrumenterBuilder .buildInstrumenter (SpanKindExtractor .alwaysConsumer ());
123
+ }
124
+ return instrumenterBuilder .buildConsumerInstrumenter (MessageTextMapGetter .INSTANCE );
108
125
}
109
126
110
127
private static Instrumenter <PulsarRequest , Void > createProducerInstrumenter () {
@@ -146,12 +163,17 @@ public static Context startAndEndConsumerReceive(
146
163
if (!CONSUMER_RECEIVE_INSTRUMENTER .shouldStart (parent , request )) {
147
164
return null ;
148
165
}
149
- // startAndEnd not supports extract trace context from carrier
150
- // start not supports custom startTime
151
- // extract trace context by using TEXT_MAP_PROPAGATOR here.
166
+ if (!receiveInstrumentationEnabled ) {
167
+ // suppress receive span when receive telemetry is not enabled and message is going to be
168
+ // processed by a listener
169
+ if (MessageListenerContext .isProcessing ()) {
170
+ return null ;
171
+ }
172
+ parent = PROPAGATOR .extract (parent , request , MessageTextMapGetter .INSTANCE );
173
+ }
152
174
return InstrumenterUtil .startAndEnd (
153
175
CONSUMER_RECEIVE_INSTRUMENTER ,
154
- PROPAGATOR . extract ( parent , request , MessageTextMapGetter . INSTANCE ) ,
176
+ parent ,
155
177
request ,
156
178
null ,
157
179
throwable ,
@@ -185,11 +207,17 @@ private static Context startAndEndConsumerReceive(
185
207
186
208
public static CompletableFuture <Message <?>> wrap (
187
209
CompletableFuture <Message <?>> future , Timer timer , Consumer <?> consumer ) {
210
+ boolean listenerContextActive = MessageListenerContext .isProcessing ();
188
211
Context parent = Context .current ();
189
212
CompletableFuture <Message <?>> result = new CompletableFuture <>();
190
213
future .whenComplete (
191
214
(message , throwable ) -> {
192
- Context context = startAndEndConsumerReceive (parent , message , timer , consumer , throwable );
215
+ // we create a "receive" span when receive telemetry is enabled or when we know that
216
+ // this message will not be passed to a listener that would create the "process" span
217
+ Context context =
218
+ receiveInstrumentationEnabled || !listenerContextActive
219
+ ? startAndEndConsumerReceive (parent , message , timer , consumer , throwable )
220
+ : parent ;
193
221
runWithContext (
194
222
context ,
195
223
() -> {
0 commit comments