Add observation for message channels (#3944)

* Add observation for message channels

* Add observation for message channels

The `MessageChannel.send()` is, essentially, only the point in Spring Integration where we produce a message
and can emit a `PRODUCER` kind span.

* Implement `IntegrationObservation.PRODUCER` infrastructure based on the `MessageSenderContext`
* Implement an observation emission in the `AbstractMessageChannel` based on the mentioned `IntegrationObservation.PRODUCER`
* Build a `MutableMessage.of(message)` to be able to modify message header in the `MessageSenderContext` via tracer `Propagator`
or other tracing injection instrument
* Document which components are instrumented with an `ObservationRegistry`

* Fix language in docs

Co-authored-by: Gary Russell <grussell@vmware.com>

Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
Artem Bilan
2022-11-15 14:11:12 -05:00
committed by GitHub
parent 4d2a4cad76
commit 88e259ccf2
9 changed files with 271 additions and 41 deletions

View File

@@ -58,10 +58,8 @@ import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.config.GlobalChannelInterceptor;
import org.springframework.integration.handler.BridgeHandler;
import org.springframework.integration.support.MutableMessage;
import org.springframework.integration.support.MutableMessageBuilder;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.management.observation.IntegrationObservation;
import org.springframework.integration.support.management.observation.MessageSenderContext;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
@@ -215,13 +213,12 @@ public class ObservationPropagationChannelInterceptorTests {
QueueChannel replyChannel = new QueueChannel();
MutableMessage<String> message =
(MutableMessage<String>) MutableMessageBuilder.withPayload("test")
Message<String> message =
MessageBuilder.withPayload("test")
.setHeader(MessageHeaders.REPLY_CHANNEL, replyChannel)
.build();
Observation.createNotStarted("sending", () -> new MessageSenderContext(message), this.observationRegistry)
.observe(() -> this.testTracingChannel.send(message));
this.testTracingChannel.send(message);
Message<?> receive = replyChannel.receive();
@@ -238,7 +235,11 @@ public class ObservationPropagationChannelInterceptorTests {
.reportedSpans()
.hasSize(2)
.satisfies(simpleSpans -> SpansAssert.assertThat(simpleSpans)
.hasASpanWithName("sending")
.assertThatASpanWithNameEqualTo("testTracingChannel send")
.hasTag("spring.integration.type", "producer")
.hasTag("spring.integration.name", "testTracingChannel")
.hasKindEqualTo(Span.Kind.PRODUCER)
.backToSpans()
.assertThatASpanWithNameEqualTo("testBridge receive")
.hasTag("foo", "some foo value")
.hasTag("bar", "some bar value")
@@ -315,8 +316,10 @@ public class ObservationPropagationChannelInterceptorTests {
}
@Bean
public ExecutorChannel testTracingChannel() {
return new ExecutorChannel(Executors.newSingleThreadExecutor());
public ExecutorChannel testTracingChannel(ObservationRegistry observationRegistry) {
ExecutorChannel channel = new ExecutorChannel(Executors.newSingleThreadExecutor());
channel.registerObservationRegistry(observationRegistry);
return channel;
}
@Bean

View File

@@ -92,7 +92,11 @@ public class IntegrationObservabilityZipkinTests extends SampleTestRunner {
.hasTag(IntegrationObservation.HandlerTags.COMPONENT_NAME.asString(), "observedEndpoint")
.hasTag(IntegrationObservation.HandlerTags.COMPONENT_TYPE.asString(), "handler")
.hasKindEqualTo(Span.Kind.CONSUMER))
.hasSize(2);
.hasASpanWithName("queueChannel send", spanAssert -> spanAssert
.hasTag(IntegrationObservation.ProducerTags.COMPONENT_NAME.asString(), "queueChannel")
.hasTag(IntegrationObservation.ProducerTags.COMPONENT_TYPE.asString(), "producer")
.hasKindEqualTo(Span.Kind.PRODUCER))
.hasSize(3);
MeterRegistryAssert.assertThat(getMeterRegistry())
.hasTimerWithNameAndTags("spring.integration.handler",
@@ -108,7 +112,7 @@ public class IntegrationObservabilityZipkinTests extends SampleTestRunner {
@EnableIntegration
@EnableIntegrationManagement(
observationPatterns = {
"${spring.integration.management.observation-patterns:observedEndpoint,testInboundGateway}",
"${spring.integration.management.observation-patterns:testInboundGateway,queueChannel,observedEndpoint}",
"${spring.integration.management.observation-patterns:}"
})
public static class ObservationIntegrationTestConfiguration {