Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

Distributed Spans and Causality

The same subscribe request that takes 800ms is spending 400ms in the payment adapter, 200ms in the projection update, 100ms in three other places. Without distributed tracing, the 800ms is opaque. @frenchexdev/ddd-tracing reifies the port that makes those 800ms decomposable into named spans with parent-child relationships, so the slow operation is identifiable rather than guessed at.


What Tracing Reifies

A span names a unit of work: a HTTP request, a database query, a domain service invocation. Spans have a start time, an end time, attributes, and a parent — the span that triggered them. The parent-child chain, propagated across process boundaries, is what makes a distributed trace coherent: a request enters one service, spawns a span; that service calls another; the trace context propagates; the second service's spans are children of the first; an aggregate viewer (Jaeger, Tempo, Honeycomb) stitches the chain into a single timeline.

The port reifies four operations. startSpan(name, attrs) opens a span. endSpan(id, status) closes it with success or error. inject(carrier) serialises the current trace context into a carrier (HTTP headers, message-bus headers, outbox row) so the next process can pick it up. extract(carrier) is the inverse — pull the trace context out of a carrier and use it as the parent for new spans. The four operations are the OpenTelemetry shape; the corpus types them and lets the adapter handle the wire format.


The Runtime: ddd-tracing and adapter

Two packages — ddd-tracing, ddd-tracing-otel-adapter — both M4/M5 stubs pinned to TelemetryStructuredObservabilityRequirement. The OpenTelemetry adapter is the obvious first substrate — OpenTelemetry is the closest the industry has come to a vendor-neutral tracing wire format, and most modern aggregators speak it.


The Analyzer: ddd-tracing-analyzer

Spec-first (spec.ts). Priority Medium. One info-severity rule, DDD-TRACING-001, recommending the Tracer suffix on the port class.

The cross-cutting nature of tracing means future analyzer rules are conceivable but not yet shipped — for example, verifying that every @CommandHandler opens at least one span, that every adapter call propagates the trace context, that every @DomainEvent carries the context across the @Outbox. These would be cross-AST rules; the spec is where they will be added.


Back to the series index.

⬇ Download