diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java index b580bd2e..f5f85284 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,8 +26,8 @@ import io.micrometer.observation.docs.ObservationDocumentation; * Spring Rabbit Observation for listeners. * * @author Gary Russell + * @author Vincent Meunier * @since 3.0 - * */ public enum RabbitListenerObservation implements ObservationDocumentation { @@ -36,7 +36,6 @@ public enum RabbitListenerObservation implements ObservationDocumentation { */ LISTENER_OBSERVATION { - @Override public Class> getDefaultConvention() { return DefaultRabbitListenerObservationConvention.class; @@ -69,6 +68,34 @@ public enum RabbitListenerObservation implements ObservationDocumentation { return "spring.rabbit.listener.id"; } + }, + + /** + * The queue the listener is plugged to. + * + * @since 3.2 + */ + DESTINATION_NAME { + + @Override + public String asString() { + return "messaging.destination.name"; + } + + }, + + /** + * The delivery tag. + * + * @since 3.2 + */ + DELIVERY_TAG { + + @Override + public String asString() { + return "messaging.rabbitmq.message.delivery_tag"; + } + } } @@ -86,8 +113,14 @@ public enum RabbitListenerObservation implements ObservationDocumentation { @Override public KeyValues getLowCardinalityKeyValues(RabbitMessageReceiverContext context) { - return KeyValues.of(RabbitListenerObservation.ListenerLowCardinalityTags.LISTENER_ID.asString(), - context.getListenerId()); + final var messageProperties = context.getCarrier().getMessageProperties(); + return KeyValues.of( + RabbitListenerObservation.ListenerLowCardinalityTags.LISTENER_ID.asString(), context.getListenerId(), + RabbitListenerObservation.ListenerLowCardinalityTags.DESTINATION_NAME.asString(), + messageProperties.getConsumerQueue(), + RabbitListenerObservation.ListenerLowCardinalityTags.DELIVERY_TAG.asString(), + String.valueOf(messageProperties.getDeliveryTag()) + ); } @Override diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java index f3bc17f1..6008e1e0 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import io.micrometer.observation.docs.ObservationDocumentation; * Spring RabbitMQ Observation for {@link org.springframework.amqp.rabbit.core.RabbitTemplate}. * * @author Gary Russell + * @author Vincent Meunier * @since 3.0 * */ @@ -68,8 +69,35 @@ public enum RabbitTemplateObservation implements ObservationDocumentation { return "spring.rabbit.template.name"; } + }, + + /** + * The destination exchange (empty if default exchange). + * @since 3.2 + */ + EXCHANGE { + + @Override + public String asString() { + return "messaging.destination.name"; + } + + }, + + /** + * The destination routing key. + * @since 3.2 + */ + ROUTING_KEY { + + @Override + public String asString() { + return "messaging.rabbitmq.destination.routing_key"; + } + } + } /** @@ -85,8 +113,11 @@ public enum RabbitTemplateObservation implements ObservationDocumentation { @Override public KeyValues getLowCardinalityKeyValues(RabbitMessageSenderContext context) { - return KeyValues.of(RabbitTemplateObservation.TemplateLowCardinalityTags.BEAN_NAME.asString(), - context.getBeanName()); + return KeyValues.of( + TemplateLowCardinalityTags.BEAN_NAME.asString(), context.getBeanName(), + TemplateLowCardinalityTags.EXCHANGE.asString(), context.getExchange(), + TemplateLowCardinalityTags.ROUTING_KEY.asString(), context.getRoutingKey() + ); } @Override diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java index 41c7facb..920deec4 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.EnableRabbit; @@ -35,6 +34,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import io.micrometer.common.KeyValue; import io.micrometer.common.KeyValues; import io.micrometer.core.tck.MeterRegistryAssert; import io.micrometer.observation.ObservationRegistry; @@ -47,7 +47,6 @@ import io.micrometer.tracing.test.simple.SpansAssert; /** * @author Artem Bilan * @author Gary Russell - * * @since 3.0 */ @RabbitAvailable(queues = { "int.observation.testQ1", "int.observation.testQ2" }) @@ -72,40 +71,69 @@ public class ObservationIntegrationTests extends SampleTestRunner { .hasSize(4); List producerSpans = finishedSpans.stream() .filter(span -> span.getKind().equals(Kind.PRODUCER)) - .collect(Collectors.toList()); + .toList(); List consumerSpans = finishedSpans.stream() .filter(span -> span.getKind().equals(Kind.CONSUMER)) - .collect(Collectors.toList()); + .toList(); SpanAssert.assertThat(producerSpans.get(0)) - .hasTag("spring.rabbit.template.name", "template"); + .hasTag("spring.rabbit.template.name", "template") + .hasTag("messaging.destination.name", "") + .hasTag("messaging.rabbitmq.destination.routing_key", "int.observation.testQ1"); SpanAssert.assertThat(producerSpans.get(0)) .hasRemoteServiceNameEqualTo("RabbitMQ"); SpanAssert.assertThat(producerSpans.get(1)) - .hasTag("spring.rabbit.template.name", "template"); + .hasTag("spring.rabbit.template.name", "template") + .hasTag("messaging.destination.name", "") + .hasTag("messaging.rabbitmq.destination.routing_key", "int.observation.testQ2"); SpanAssert.assertThat(consumerSpans.get(0)) - .hasTagWithKey("spring.rabbit.listener.id"); + .hasTagWithKey("spring.rabbit.listener.id") + .hasTag("messaging.destination.name", "int.observation.testQ1") + .hasTag("messaging.rabbitmq.message.delivery_tag", "1"); SpanAssert.assertThat(consumerSpans.get(0)) .hasRemoteServiceNameEqualTo("RabbitMQ"); assertThat(consumerSpans.get(0).getTags().get("spring.rabbit.listener.id")).isIn("obs1", "obs2"); SpanAssert.assertThat(consumerSpans.get(1)) .hasTagWithKey("spring.rabbit.listener.id"); assertThat(consumerSpans.get(1).getTags().get("spring.rabbit.listener.id")).isIn("obs1", "obs2"); + SpanAssert.assertThat(consumerSpans.get(1)) + .hasTagWithKey("spring.rabbit.listener.id") + .hasTag("messaging.destination.name", "int.observation.testQ2") + .hasTag("messaging.rabbitmq.message.delivery_tag", "1"); assertThat(consumerSpans.get(0).getTags().get("spring.rabbit.listener.id")) .isNotEqualTo(consumerSpans.get(1).getTags().get("spring.rabbit.listener.id")); MeterRegistryAssert.assertThat(getMeterRegistry()) .hasTimerWithNameAndTags("spring.rabbit.template", - KeyValues.of("spring.rabbit.template.name", "template")) + KeyValues.of( + KeyValue.of("spring.rabbit.template.name", "template"), + KeyValue.of("messaging.destination.name", ""), + KeyValue.of("messaging.rabbitmq.destination.routing_key", "int.observation.testQ1") + ) + ) .hasTimerWithNameAndTags("spring.rabbit.template", - KeyValues.of("spring.rabbit.template.name", "template")) + KeyValues.of( + KeyValue.of("spring.rabbit.template.name", "template"), + KeyValue.of("messaging.destination.name", ""), + KeyValue.of("messaging.rabbitmq.destination.routing_key", "int.observation.testQ2") + ) + ) .hasTimerWithNameAndTags("spring.rabbit.listener", - KeyValues.of("spring.rabbit.listener.id", "obs1")) + KeyValues.of( + KeyValue.of("spring.rabbit.listener.id", "obs1"), + KeyValue.of("messaging.destination.name", "int.observation.testQ1"), + KeyValue.of("messaging.rabbitmq.message.delivery_tag", "1") + ) + ) .hasTimerWithNameAndTags("spring.rabbit.listener", - KeyValues.of("spring.rabbit.listener.id", "obs2")); + KeyValues.of( + KeyValue.of("spring.rabbit.listener.id", "obs2"), + KeyValue.of("messaging.destination.name", "int.observation.testQ2"), + KeyValue.of("messaging.rabbitmq.message.delivery_tag", "1") + ) + ); }; } - @Configuration @EnableRabbit public static class Config { @@ -159,5 +187,4 @@ public class ObservationIntegrationTests extends SampleTestRunner { } - }