OpenTelemetry
wow-opentelemetry creates tracing instrumenters for command/event sends, aggregates, EventStore, SnapshotStore, projections, Sagas, event processors, and wait plans. Use it to diagnose cross-service latency and failures. It is not required for Micrometer-only metrics.
The module creates spans and propagates context only. It does not initialize an OpenTelemetry SDK, Agent, sampler, exporter, or Collector. GlobalOpenTelemetry must be initialized before Wow instrumenters are created.
Installation
implementation("me.ahoo.wow:wow-spring-boot-starter") {
capabilities { requireCapability("me.ahoo.wow:opentelemetry-support") }
}Non-Spring applications may depend directly on me.ahoo.wow:wow-opentelemetry, but must decorate buses/stores/gateways and register filters themselves. Classpath presence alone does not wire them.
Quick Start with OTLP
The shortest runtime path is a Java Agent that initializes the global instance before application startup:
export JAVA_TOOL_OPTIONS="-javaagent:/opt/otel/opentelemetry-javaagent.jar"
export OTEL_SERVICE_NAME=order-service
export OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
java -jar app.jarThe Agent/SDK owns endpoint, protocol, headers, sampling, and resource attributes. A module check or local span proves instrumentation behavior only; Collector/backend receipt proves export.
Configuration
Wow has one switch, enabled by default:
wow:
opentelemetry:
enabled: truefalse disables only Wow tracing filters/decorators, not the Java Agent or spans from other libraries. Do not configure duplicate exporters. Micrometer Registry still owns metrics; see Observability configuration.
How Tracing Is Wired
WowOpenTelemetryAutoConfiguration registers filters for aggregates, projections, snapshots, stateless Sagas, and event processors. TracingBeanPostProcessor runs at highest precedence and decorates supported local/distributed buses, EventStore, SnapshotStore, and CommandGateway, using Traced to prevent double wrapping.
Reactor publishers start spans on subscription and end them on completion, error, cancellation, or synchronous subscribe failure. Producers inject message context; consumers/exchanges restore it. Attributes exist only on instrumenters that registered the corresponding extractor, so not every span has every wow.message.* or wow.aggregate.* field.
Verified failure boundaries: initializing the global SDK too late leaves already-created instrumenters on the old global instance; publisher failures are recorded and propagated; disabling Wow tracing does not change business calls. Focused check:
./gradlew :wow-opentelemetry:checkWhat a Trace Looks Like
A command commonly forms command send/wait → aggregate handler → event append/send → projection/Saga/snapshot parent-child spans. Actual spans depend on which path ran, sampling, and successful export.
Next, read Observability for span and attribute contracts, then retain a real trace receipt from the target Collector.