17
17
package org .springframework .integration .channel ;
18
18
19
19
import java .util .ArrayDeque ;
20
+ import java .util .Arrays ;
20
21
import java .util .Collections ;
21
22
import java .util .Comparator ;
22
23
import java .util .Deque ;
26
27
import java .util .concurrent .ConcurrentHashMap ;
27
28
import java .util .concurrent .CopyOnWriteArrayList ;
28
29
30
+ import io .micrometer .observation .ObservationRegistry ;
31
+
29
32
import org .springframework .beans .factory .BeanFactory ;
30
33
import org .springframework .core .OrderComparator ;
31
34
import org .springframework .core .log .LogAccessor ;
34
37
import org .springframework .integration .context .IntegrationContextUtils ;
35
38
import org .springframework .integration .context .IntegrationObjectSupport ;
36
39
import org .springframework .integration .history .MessageHistory ;
40
+ import org .springframework .integration .support .MutableMessage ;
37
41
import org .springframework .integration .support .management .IntegrationManagedResource ;
38
42
import org .springframework .integration .support .management .IntegrationManagement ;
39
43
import org .springframework .integration .support .management .TrackableComponent ;
40
44
import org .springframework .integration .support .management .metrics .MeterFacade ;
41
45
import org .springframework .integration .support .management .metrics .MetricsCaptor ;
42
46
import org .springframework .integration .support .management .metrics .SampleFacade ;
43
47
import org .springframework .integration .support .management .metrics .TimerFacade ;
48
+ import org .springframework .integration .support .management .observation .DefaultMessageSenderObservationConvention ;
49
+ import org .springframework .integration .support .management .observation .IntegrationObservation ;
50
+ import org .springframework .integration .support .management .observation .MessageSenderContext ;
51
+ import org .springframework .integration .support .management .observation .MessageSenderObservationConvention ;
44
52
import org .springframework .integration .support .utils .IntegrationUtils ;
45
53
import org .springframework .lang .Nullable ;
46
54
import org .springframework .messaging .Message ;
@@ -75,22 +83,27 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
75
83
76
84
protected final Set <MeterFacade > meters = ConcurrentHashMap .newKeySet (); // NOSONAR
77
85
78
- private volatile boolean shouldTrack = false ;
86
+ private ObservationRegistry observationRegistry = ObservationRegistry .NOOP ;
87
+
88
+ @ Nullable
89
+ private MessageSenderObservationConvention observationConvention ;
79
90
80
- private volatile Class <?>[] datatypes = new Class <?>[ 0 ] ;
91
+ private boolean shouldTrack = false ;
81
92
82
- private volatile String fullChannelName ;
93
+ private Class <?>[] datatypes = new Class <?>[ 0 ] ;
83
94
84
- private volatile MessageConverter messageConverter ;
95
+ private MessageConverter messageConverter ;
85
96
86
- private volatile boolean loggingEnabled = true ;
97
+ private boolean loggingEnabled = true ;
87
98
88
99
private MetricsCaptor metricsCaptor ;
89
100
90
101
private TimerFacade successTimer ;
91
102
92
103
private TimerFacade failureTimer ;
93
104
105
+ private volatile String fullChannelName ;
106
+
94
107
@ Override
95
108
public String getComponentType () {
96
109
return "channel" ;
@@ -138,10 +151,7 @@ public void setLoggingEnabled(boolean loggingEnabled) {
138
151
* @see #setMessageConverter(MessageConverter)
139
152
*/
140
153
public void setDatatypes (Class <?>... datatypes ) {
141
- this .datatypes =
142
- (datatypes != null && datatypes .length > 0 )
143
- ? datatypes
144
- : new Class <?>[0 ];
154
+ this .datatypes = Arrays .copyOf (datatypes , datatypes .length );
145
155
}
146
156
147
157
/**
@@ -192,6 +202,10 @@ public void setMessageConverter(MessageConverter messageConverter) {
192
202
this .messageConverter = messageConverter ;
193
203
}
194
204
205
+ public void setObservationConvention (@ Nullable MessageSenderObservationConvention observationConvention ) {
206
+ this .observationConvention = observationConvention ;
207
+ }
208
+
195
209
/**
196
210
* Return a read-only list of the configured interceptors.
197
211
*/
@@ -224,6 +238,12 @@ public ManagementOverrides getOverrides() {
224
238
return this .managementOverrides ;
225
239
}
226
240
241
+ @ Override
242
+ public void registerObservationRegistry (ObservationRegistry observationRegistry ) {
243
+ Assert .notNull (observationRegistry , "'observationRegistry' must not be null" );
244
+ this .observationRegistry = observationRegistry ;
245
+ }
246
+
227
247
@ Override
228
248
protected void onInit () {
229
249
super .onInit ();
@@ -276,15 +296,14 @@ public boolean send(Message<?> message) {
276
296
* Send a message on this channel. If the channel is at capacity, this
277
297
* method will block until either the timeout occurs or the sending thread
278
298
* is interrupted. If the specified timeout is 0, the method will return
279
- * immediately. If less than zero, it will block indefinitely (see
280
- * {@link #send(Message)}).
299
+ * immediately. If less than zero, it will block indefinitely (see {@link #send(Message)}).
281
300
* @param messageArg the Message to send
282
301
* @param timeout the timeout in milliseconds
283
302
* @return <code>true</code> if the message is sent successfully,
284
303
* <code>false</code> if the message cannot be sent within the allotted
285
304
* time or the sending thread is interrupted.
286
305
*/
287
- @ Override // NOSONAR complexity
306
+ @ Override
288
307
public boolean send (Message <?> messageArg , long timeout ) {
289
308
Assert .notNull (messageArg , "message must not be null" );
290
309
Assert .notNull (messageArg .getPayload (), "message payload must not be null" );
@@ -293,11 +312,44 @@ public boolean send(Message<?> messageArg, long timeout) {
293
312
message = MessageHistory .write (message , this , getMessageBuilderFactory ());
294
313
}
295
314
315
+ if (!ObservationRegistry .NOOP .equals (this .observationRegistry )) {
316
+ return sendWithObservation (message , timeout );
317
+ }
318
+ else if (this .metricsCaptor != null ) {
319
+ return sendWithMetrics (message , timeout );
320
+ }
321
+ else {
322
+ return sendInternal (message , timeout );
323
+ }
324
+ }
325
+
326
+ private boolean sendWithObservation (Message <?> message , long timeout ) {
327
+ MutableMessage <?> messageToSend = MutableMessage .of (message );
328
+ return IntegrationObservation .PRODUCER .observation (
329
+ this .observationConvention ,
330
+ DefaultMessageSenderObservationConvention .INSTANCE ,
331
+ () -> new MessageSenderContext (messageToSend , getComponentName ()),
332
+ this .observationRegistry )
333
+ .observe (() -> sendInternal (messageToSend , timeout ));
334
+ }
335
+
336
+ private boolean sendWithMetrics (Message <?> message , long timeout ) {
337
+ SampleFacade sample = this .metricsCaptor .start ();
338
+ try {
339
+ boolean sent = sendInternal (message , timeout );
340
+ sample .stop (sendTimer (sent ));
341
+ return sent ;
342
+ }
343
+ catch (RuntimeException ex ) {
344
+ sample .stop (buildSendTimer (false , ex .getClass ().getSimpleName ()));
345
+ throw ex ;
346
+ }
347
+ }
348
+
349
+ private boolean sendInternal (Message <?> message , long timeout ) {
296
350
Deque <ChannelInterceptor > interceptorStack = null ;
297
351
boolean sent = false ;
298
- boolean metricsProcessed = false ;
299
352
ChannelInterceptorList interceptorList = this .interceptors ;
300
- SampleFacade sample = null ;
301
353
try {
302
354
message = convertPayloadIfNecessary (message );
303
355
boolean debugEnabled = this .loggingEnabled && this .logger .isDebugEnabled ();
@@ -311,14 +363,8 @@ public boolean send(Message<?> messageArg, long timeout) {
311
363
return false ;
312
364
}
313
365
}
314
- if (this .metricsCaptor != null ) {
315
- sample = this .metricsCaptor .start ();
316
- }
366
+
317
367
sent = doSend (message , timeout );
318
- if (sample != null ) {
319
- sample .stop (sendTimer (sent ));
320
- }
321
- metricsProcessed = true ;
322
368
323
369
if (debugEnabled ) {
324
370
logger .debug ("postSend (sent=" + sent + ") on channel '" + this + "', message: " + message );
@@ -330,9 +376,6 @@ public boolean send(Message<?> messageArg, long timeout) {
330
376
return sent ;
331
377
}
332
378
catch (Exception ex ) {
333
- if (!metricsProcessed && sample != null ) {
334
- sample .stop (buildSendTimer (false , ex .getClass ().getSimpleName ()));
335
- }
336
379
if (interceptorStack != null ) {
337
380
interceptorList .afterSendCompletion (message , this , sent , ex , interceptorStack );
338
381
}
@@ -411,7 +454,7 @@ private Message<?> convertPayloadIfNecessary(Message<?> message) {
411
454
* accepted or the blocking thread is interrupted.
412
455
* @param message The message.
413
456
* @param timeout The timeout.
414
- * @return true if the send was successful.
457
+ * @return true if the {@code send} was successful.
415
458
*/
416
459
protected abstract boolean doSend (Message <?> message , long timeout );
417
460
0 commit comments