74
74
import org .springframework .amqp .rabbit .support .MessagePropertiesConverter ;
75
75
import org .springframework .amqp .rabbit .support .RabbitExceptionTranslator ;
76
76
import org .springframework .amqp .rabbit .support .ValueExpression ;
77
+ import org .springframework .amqp .rabbit .support .micrometer .DefaultRabbitTemplateObservationConvention ;
78
+ import org .springframework .amqp .rabbit .support .micrometer .RabbitMessageSenderContext ;
79
+ import org .springframework .amqp .rabbit .support .micrometer .RabbitTemplateObservation ;
80
+ import org .springframework .amqp .rabbit .support .micrometer .RabbitTemplateObservationConvention ;
77
81
import org .springframework .amqp .support .converter .MessageConverter ;
78
82
import org .springframework .amqp .support .converter .SimpleMessageConverter ;
79
83
import org .springframework .amqp .support .converter .SmartMessageConverter ;
83
87
import org .springframework .beans .factory .BeanFactoryAware ;
84
88
import org .springframework .beans .factory .BeanNameAware ;
85
89
import org .springframework .beans .factory .DisposableBean ;
90
+ import org .springframework .context .ApplicationContext ;
91
+ import org .springframework .context .ApplicationContextAware ;
86
92
import org .springframework .context .expression .BeanFactoryResolver ;
87
93
import org .springframework .context .expression .MapAccessor ;
88
94
import org .springframework .core .ParameterizedTypeReference ;
108
114
import com .rabbitmq .client .Return ;
109
115
import com .rabbitmq .client .ShutdownListener ;
110
116
import com .rabbitmq .client .ShutdownSignalException ;
117
+ import io .micrometer .observation .Observation ;
118
+ import io .micrometer .observation .ObservationRegistry ;
111
119
112
120
/**
113
121
* <p>
152
160
* @since 1.0
153
161
*/
154
162
public class RabbitTemplate extends RabbitAccessor // NOSONAR type line count
155
- implements BeanFactoryAware , RabbitOperations , ChannelAwareMessageListener ,
163
+ implements BeanFactoryAware , RabbitOperations , ChannelAwareMessageListener , ApplicationContextAware ,
156
164
ListenerContainerAware , PublisherCallbackChannel .Listener , BeanNameAware , DisposableBean {
157
165
158
166
private static final String UNCHECKED = "unchecked" ;
@@ -198,6 +206,8 @@ public class RabbitTemplate extends RabbitAccessor // NOSONAR type line count
198
206
199
207
private final AtomicInteger containerInstance = new AtomicInteger ();
200
208
209
+ private ApplicationContext applicationContext ;
210
+
201
211
private String exchange = DEFAULT_EXCHANGE ;
202
212
203
213
private String routingKey = DEFAULT_ROUTING_KEY ;
@@ -258,13 +268,20 @@ public class RabbitTemplate extends RabbitAccessor // NOSONAR type line count
258
268
259
269
private ErrorHandler replyErrorHandler ;
260
270
271
+ private boolean useChannelForCorrelation ;
272
+
273
+ private boolean observationEnabled ;
274
+
275
+ @ Nullable
276
+ private RabbitTemplateObservationConvention observationConvention ;
277
+
261
278
private volatile boolean usingFastReplyTo ;
262
279
263
280
private volatile boolean evaluatedFastReplyTo ;
264
281
265
282
private volatile boolean isListener ;
266
283
267
- private boolean useChannelForCorrelation ;
284
+ private volatile boolean observationRegistryObtained ;
268
285
269
286
/**
270
287
* Convenient constructor for use with setter injection. Don't forget to set the connection factory.
@@ -297,6 +314,29 @@ public final void setConnectionFactory(ConnectionFactory connectionFactory) {
297
314
}
298
315
}
299
316
317
+ @ Override
318
+ public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
319
+ this .applicationContext = applicationContext ;
320
+ }
321
+
322
+ /**
323
+ * Enable observation via micrometer.
324
+ * @param observationEnabled true to enable.
325
+ * @since 3.0
326
+ */
327
+ public void setObservationEnabled (boolean observationEnabled ) {
328
+ this .observationEnabled = observationEnabled ;
329
+ }
330
+
331
+ /**
332
+ * Set an observation convention; used to add additional key/values to observations.
333
+ * @param observationConvention the convention.
334
+ * @since 3.0
335
+ */
336
+ public void setObservationConvention (RabbitTemplateObservationConvention observationConvention ) {
337
+ this .observationConvention = observationConvention ;
338
+ }
339
+
300
340
/**
301
341
* The name of the default exchange to use for send operations when none is specified. Defaults to <code>""</code>
302
342
* which is the default exchange in the broker (per the AMQP specification).
@@ -2348,7 +2388,7 @@ private boolean isPublisherConfirmsOrReturns(ConnectionFactory connectionFactory
2348
2388
* @throws IOException If thrown by RabbitMQ API methods.
2349
2389
*/
2350
2390
public void doSend (Channel channel , String exchangeArg , String routingKeyArg , Message message ,
2351
- boolean mandatory , @ Nullable CorrelationData correlationData ) throws IOException {
2391
+ boolean mandatory , @ Nullable CorrelationData correlationData ) {
2352
2392
2353
2393
String exch = nullSafeExchange (exchangeArg );
2354
2394
String rKey = nullSafeRoutingKey (routingKeyArg );
@@ -2378,14 +2418,34 @@ public void doSend(Channel channel, String exchangeArg, String routingKeyArg, Me
2378
2418
logger .debug ("Publishing message [" + messageToUse
2379
2419
+ "] on exchange [" + exch + "], routingKey = [" + rKey + "]" );
2380
2420
}
2381
- sendToRabbit (channel , exch , rKey , mandatory , messageToUse );
2421
+ observeTheSend (channel , messageToUse , mandatory , exch , rKey );
2382
2422
// Check if commit needed
2383
2423
if (isChannelLocallyTransacted (channel )) {
2384
2424
// Transacted channel created by this template -> commit.
2385
2425
RabbitUtils .commitIfNecessary (channel );
2386
2426
}
2387
2427
}
2388
2428
2429
+ protected void observeTheSend (Channel channel , Message message , boolean mandatory , String exch , String rKey ) {
2430
+
2431
+ if (!this .observationRegistryObtained ) {
2432
+ obtainObservationRegistry (this .applicationContext );
2433
+ this .observationRegistryObtained = true ;
2434
+ }
2435
+ Observation observation ;
2436
+ ObservationRegistry registry = getObservationRegistry ();
2437
+ if (!this .observationEnabled || registry == null ) {
2438
+ observation = Observation .NOOP ;
2439
+ }
2440
+ else {
2441
+ observation = RabbitTemplateObservation .TEMPLATE_OBSERVATION .observation (this .observationConvention ,
2442
+ DefaultRabbitTemplateObservationConvention .INSTANCE ,
2443
+ new RabbitMessageSenderContext (message , this .beanName , exch + "/" + rKey ), registry );
2444
+
2445
+ }
2446
+ observation .observe (() -> sendToRabbit (channel , exch , rKey , mandatory , message ));
2447
+ }
2448
+
2389
2449
/**
2390
2450
* Return the exchange or the default exchange if null.
2391
2451
* @param exchange the exchange.
@@ -2407,10 +2467,16 @@ public String nullSafeRoutingKey(String rk) {
2407
2467
}
2408
2468
2409
2469
protected void sendToRabbit (Channel channel , String exchange , String routingKey , boolean mandatory ,
2410
- Message message ) throws IOException {
2470
+ Message message ) {
2471
+
2411
2472
BasicProperties convertedMessageProperties = this .messagePropertiesConverter
2412
2473
.fromMessageProperties (message .getMessageProperties (), this .encoding );
2413
- channel .basicPublish (exchange , routingKey , mandatory , convertedMessageProperties , message .getBody ());
2474
+ try {
2475
+ channel .basicPublish (exchange , routingKey , mandatory , convertedMessageProperties , message .getBody ());
2476
+ }
2477
+ catch (IOException ex ) {
2478
+ throw RabbitExceptionTranslator .convertRabbitAccessException (ex );
2479
+ }
2414
2480
}
2415
2481
2416
2482
private void setupConfirm (Channel channel , Message message , @ Nullable CorrelationData correlationDataArg ) {
0 commit comments