Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions nservicebus/messaging/headers.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,11 +313,14 @@ These headers are added when [OpenTelemetry](/nservicebus/operations/opentelemet
The headers are:

# if-version [10.3,)
* [`traceparent`](https://www.w3.org/TR/trace-context/#traceparent-header) - used by the receiver only when a message lacks the `NServiceBus.TraceParent` header
*
* [`traceparent`](https://www.w3.org/TR/trace-context/#traceparent-header) - used by the receiver only when a message lacks the `NServiceBus.TraceParent` header
# end-if
* [`tracestate`](https://www.w3.org/TR/trace-context/#tracestate-header)
* [`baggage`](https://www.w3.org/TR/baggage/#baggage-http-header-format)
* [`baggage`](https://www.w3.org/TR/baggage/#baggage-http-header-format) - the baggage of the activity that sent the message

# if-version [10.3,)
Receivers read `tracestate` and `baggage` only from messages that also carry `NServiceBus.TraceParent` or `traceparent`. The baggage is applied to the process span even when a transport SDK receive span is its parent, because the transport SDKs do not propagate baggage. See [OpenTelemetry](/nservicebus/operations/opentelemetry.md) for details.
# end-if

# if-version [10.3,)
## NServiceBus.TraceParent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,26 @@ This keeps the forwarded message correlated to its original sender instead of th

Custom `RecoverabilityAction` and `AuditAction` implementations that forward the received message get the same behavior: the headers are dispatched as they were received, so the trace stays intact without any additional work.

#### Baggage

NServiceBus writes the [baggage](https://www.w3.org/TR/baggage/) of the current activity to the `baggage` header of every message that flows through the outgoing pipeline. On receive, NServiceBus applies the baggage from that header to the process span, so handlers and behaviors can read it with `Activity.Current.GetBaggageItem`. Baggage therefore flows end to end on every transport, including transports whose SDK has no OpenTelemetry instrumentation.

On receive, the following rules apply:

- Baggage and `tracestate` are read from the message only when it also carries NServiceBus trace context, that is a `NServiceBus.TraceParent` or `traceparent` header. The W3C specifications define both headers as companions of `traceparent`. A message without a trace header gets a process span that is a child of `Activity.Current`, if any, and inherits the baggage of that activity. The `baggage` header of such a message is ignored.
- When the process span is a child of a transport SDK receive span, as described under Transport SDK spans above, NServiceBus still applies the baggage from the message. The Azure Service Bus, RabbitMQ, and Amazon SQS clients do not propagate baggage, so without this step the baggage would not reach the handlers. Should the SDK receive span already carry a baggage key with the same name, the item from the message is not added again and the value on the SDK span is used. This prevents the same key from being written twice when the message is sent on.
- Baggage follows the message, not the trace. When the receiver starts a new trace, for example for a delayed message or because `StartNewTraceOnReceive` was used, the baggage from the message is still applied to the process span.

> [!NOTE]
> Baggage is meant for a small number of cross-cutting values, such as a tenant identifier or the identifier of the originating request. Baggage is never removed along a conversation and travels with every message to every receiver, including subscribers, the audit queue, and the error queue. Do not put sensitive or large values in baggage. NServiceBus does not enforce the limits of 64 items and 8,192 bytes defined by the W3C Baggage specification.

NServiceBus reads and writes baggage through `System.Diagnostics.Activity`. It does not use the `Baggage` API of the `OpenTelemetry.Api` package. The two are separate stores, and neither one reads the other:

- In handler, behavior, and library code, use `Activity.Current?.SetBaggage(...)` and `Activity.Current?.GetBaggageItem(...)`. NServiceBus writes those items to the `baggage` header of outgoing messages, and applies the header to the process span on receive.
- Baggage set through `Baggage.SetBaggage(...)` from `OpenTelemetry.Api` is not written to outgoing messages. Copy the value onto `Activity.Current` before sending when a message has to carry it.

The community [OpenTelemetry .NET instrumentation reference](https://github.com/Aaronontheweb/dotnet-skills/blob/master/skills/opentelementry-dotnet-instrumentation/traces-and-propagation-reference.md#net-baggage-api) describes both APIs and when to use each.

In version 10, NServiceBus uses a custom propagator by default. To opt in to propagation via the built-in .NET `DistributedContextPropagator` instead, set the following AppContext switch before the endpoint starts:

snippet: opentelemetry-distributed-context-propagator-switch
Expand Down
20 changes: 20 additions & 0 deletions nservicebus/operations/opentelemetry_traces_core_[11,).partial.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,26 @@ This keeps the forwarded message correlated to its original sender instead of th

Custom `RecoverabilityAction` and `AuditAction` implementations that forward the received message get the same behavior: the headers are dispatched as they were received, so the trace stays intact without any additional work.

#### Baggage

NServiceBus writes the [baggage](https://www.w3.org/TR/baggage/) of the current activity to the `baggage` header of every message that flows through the outgoing pipeline. On receive, NServiceBus applies the baggage from that header to the process span, so handlers and behaviors can read it with `Activity.Current.GetBaggageItem`. Baggage therefore flows end to end on every transport, including transports whose SDK has no OpenTelemetry instrumentation.

On receive, the following rules apply:

- Baggage and `tracestate` are read from the message only when it also carries NServiceBus trace context, that is a `NServiceBus.TraceParent` or `traceparent` header. The W3C specifications define both headers as companions of `traceparent`. A message without a trace header gets a process span that is a child of `Activity.Current`, if any, and inherits the baggage of that activity. The `baggage` header of such a message is ignored.
- When the process span is a child of a transport SDK receive span, as described under Transport SDK spans above, NServiceBus still applies the baggage from the message. The Azure Service Bus, RabbitMQ, and Amazon SQS clients do not propagate baggage, so without this step the baggage would not reach the handlers. Should the SDK receive span already carry a baggage key with the same name, the item from the message is not added again and the value on the SDK span is used. This prevents the same key from being written twice when the message is sent on.
- Baggage follows the message, not the trace. When the receiver starts a new trace, for example for a delayed message or because `StartNewTraceOnReceive` was used, the baggage from the message is still applied to the process span.

> [!NOTE]
> Baggage is meant for a small number of cross-cutting values, such as a tenant identifier or the identifier of the originating request. Baggage is never removed along a conversation and travels with every message to every receiver, including subscribers, the audit queue, and the error queue. Do not put sensitive or large values in baggage. NServiceBus does not enforce the limits of 64 items and 8,192 bytes defined by the W3C Baggage specification.

NServiceBus reads and writes baggage through `System.Diagnostics.Activity`. It does not use the `Baggage` API of the `OpenTelemetry.Api` package. The two are separate stores, and neither one reads the other:

- In handler, behavior, and library code, use `Activity.Current?.SetBaggage(...)` and `Activity.Current?.GetBaggageItem(...)`. NServiceBus writes those items to the `baggage` header of outgoing messages, and applies the header to the process span on receive.
- Baggage set through `Baggage.SetBaggage(...)` from `OpenTelemetry.Api` is not written to outgoing messages. Copy the value onto `Activity.Current` before sending when a message has to carry it.

The community [OpenTelemetry .NET instrumentation reference](https://github.com/Aaronontheweb/dotnet-skills/blob/master/skills/opentelementry-dotnet-instrumentation/traces-and-propagation-reference.md#net-baggage-api) describes both APIs and when to use each.

### Failed spans and the error.type tag

When a span fails, NServiceBus sets the span status to `Error` and adds an `error.type` tag containing the fully qualified exception type name. This tag is set on the innermost span where the exception was thrown.
Expand Down
Loading