Add documentation for Observability (#3896)

* Add documentation for Observability

* Adapt Observation code to the latest dependencies
* Add doc generation tasks for meters and spans
* Document new Observation API features
* Include generated meters and spans docs to a general `metrics.adoc` chapter

* * Adapt `ObservationPropagationChannelInterceptorTests` for the latest `SpansAssert` API

* * Adjust to the latest Micrometer SNAPSHOT
* Make Observation doc generation tasks only as local.
We don't need ambiguous changes to source code on CI

* * Automate metrics/spans docs generation as a part of `reference` build phase
* Replace 'org.springframework.integration' content in the generated files with a 'o.s.i'
to make it easier to read, especially in the tables
* Break `DefaultMessageReceiverObservationConvention <=> IntegrationObservation` classes tangle
using literal for `KeyValues` in the `DefaultMessageReceiverObservationConvention`
instead of nested enums from the `IntegrationObservation`
* Some other minor build script clean up

* Fix indent in `build.gradle` for `micrometerVersion` property code line

* Add new line after observation section in whats-new.adoc

* * Adapt to the latest Micrometer changes

* * Use Reactor `2022.0.0-SNAPSHOT` version
This commit is contained in:
Artem Bilan
2022-10-06 12:42:26 -04:00
committed by GitHub
parent a667171c4f
commit f24fbd992b
10 changed files with 122 additions and 56 deletions

View File

@@ -81,7 +81,7 @@ public abstract class AbstractMessageHandler extends MessageHandlerSupport
IntegrationObservation.HANDLER.observation(
this.observationConvention,
DefaultMessageReceiverObservationConvention.INSTANCE,
new MessageReceiverContext(message, getComponentName()),
() -> new MessageReceiverContext(message, getComponentName()),
observationRegistry)
.observe(() -> doHandleMessage(message));
}

View File

@@ -36,9 +36,11 @@ public class DefaultMessageReceiverObservationConvention implements MessageRecei
@Override
public KeyValues getLowCardinalityKeyValues(MessageReceiverContext context) {
return KeyValues.of(
IntegrationObservation.HandlerTags.COMPONENT_NAME.withValue(context.getHandlerName()),
IntegrationObservation.HandlerTags.COMPONENT_TYPE.withValue("handler"));
return KeyValues
// See IntegrationObservation.HandlerTags.COMPONENT_NAME - to avoid class tangle
.of("spring.integration.name", context.getHandlerName())
// See IntegrationObservation.HandlerTags.COMPONENT_TYPE - to avoid class tangle
.and("spring.integration.type", "handler");
}
}

View File

@@ -17,26 +17,21 @@
package org.springframework.integration.support.management.observation;
import io.micrometer.common.docs.KeyName;
import io.micrometer.observation.docs.DocumentedObservation;
import io.micrometer.observation.docs.ObservationDocumentation;
/**
* The {@link DocumentedObservation} implementation for Spring Integration infrastructure.
* The {@link ObservationDocumentation} implementation for Spring Integration infrastructure.
*
* @author Artem Bilan
*
* @since 6.0
*/
public enum IntegrationObservation implements DocumentedObservation {
public enum IntegrationObservation implements ObservationDocumentation {
/**
* Observation for message handlers.
*/
HANDLER {
@Override
public String getName() {
return "spring.integration.handler";
}
@Override
public String getPrefix() {
return "spring.integration.";

View File

@@ -29,8 +29,12 @@ import io.micrometer.observation.transport.ReceiverContext;
*
* @since 6.0
*/
public interface MessageReceiverObservationConvention
extends ObservationConvention<MessageReceiverContext> {
public interface MessageReceiverObservationConvention extends ObservationConvention<MessageReceiverContext> {
@Override
default String getName() {
return "spring.integration.handler";
}
@Override
default boolean supportsContext(Observation.Context context) {

View File

@@ -19,7 +19,6 @@ package org.springframework.integration.channel.interceptor;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
@@ -67,7 +66,6 @@ import io.micrometer.observation.tck.TestObservationRegistryAssert;
import io.micrometer.tracing.Span;
import io.micrometer.tracing.TraceContext;
import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.exporter.FinishedSpan;
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
@@ -223,7 +221,7 @@ public class ObservationPropagationChannelInterceptorTests {
.setHeader(MessageHeaders.REPLY_CHANNEL, replyChannel)
.build();
Observation.createNotStarted("sending", new MessageSenderContext(message), this.observationRegistry)
Observation.createNotStarted("sending", () -> new MessageSenderContext(message), this.observationRegistry)
.observe(() -> this.testTracingChannel.send(message));
Message<?> receive = replyChannel.receive();
@@ -240,7 +238,7 @@ public class ObservationPropagationChannelInterceptorTests {
TracerAssert.assertThat(this.simpleTracer)
.reportedSpans()
.hasSize(2)
.satisfies(simpleSpans -> assertSpans(simpleSpans)
.satisfies(simpleSpans -> SpansAssert.assertThat(simpleSpans)
.hasASpanWithName("sending")
.assertThatASpanWithNameEqualTo("testBridge receive")
.hasTag("foo", "some foo value")
@@ -259,11 +257,6 @@ public class ObservationPropagationChannelInterceptorTests {
assertThat(this.meterRegistry.get("spring.integration.handler").timer().count()).isEqualTo(1);
}
@SuppressWarnings("unchecked")
private static SpansAssert assertSpans(Collection<? extends FinishedSpan> actual) {
return SpansAssert.assertThat((Collection<FinishedSpan>) actual);
}
@Configuration
@EnableIntegration
public static class ContextConfiguration {

View File

@@ -73,13 +73,13 @@ public class IntegrationObservabilityZipkinTests extends SampleTestRunner {
PollableChannel queueChannel = applicationContext.getBean("queueChannel", PollableChannel.class);
PollableChannel replyChannel = new QueueChannel();
MutableMessage<String> testMessage =
MutableMessage<String> message =
(MutableMessage<String>) MutableMessageBuilder.withPayload("test data")
.setHeader(MessageHeaders.REPLY_CHANNEL, replyChannel)
.build();
Observation.createNotStarted("Test send", new MessageSenderContext(testMessage), observationRegistry)
.observe(() -> queueChannel.send(testMessage));
Observation.createNotStarted("Test send", () -> new MessageSenderContext(message), observationRegistry)
.observe(() -> queueChannel.send(message));
Message<?> receive = replyChannel.receive(10_000);
assertThat(receive).isNotNull()