Skip to content
blehnen edited this page Nov 10, 2026 · 7 revisions

Tracing

DotNetWorkQueue uses System.Diagnostics.ActivitySource for tracing, which plugs into OpenTelemetry. All activities come from a single named source you subscribe to in your telemetry pipeline.

ActivitySource name: dotnetworkqueue.instrumentationlibrary

Packages

You need the OpenTelemetry hosting extension and an exporter of your choice:

OpenTelemetry.Extensions.Hosting
OpenTelemetry.Exporter.Jaeger   (or any other exporter)
ASP.NET Core Setup
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddSource("dotnetworkqueue.instrumentationlibrary")
        .AddJaegerExporter());
Non-ASP.NET Core Setup
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddSource("dotnetworkqueue.instrumentationlibrary")
    .AddJaegerExporter()
    .Build();

Keep the tracerProvider instance alive for the lifetime of your application. Disposing it flushes and shuts down the exporter.

Trace Context Propagation

Trace context flows from the producer to the consumer automatically through message headers. When a producer enqueues a message, it captures the current Activity context and stores it in the message. The consumer restores that context before it runs your handler. Thus the full producer-to-consumer span chain shows up in your tracing backend without any extra configuration.

Activities Reference

DotNetWorkQueue emits these activities. It emits all of them under the dotnetworkqueue.instrumentationlibrary source.

Activity Description
ReceiveMessage Dequeue of a message from the transport
MessageHandler Synchronous user handler execution
MessageHandlerAsync Async user handler execution
LinqExecution LINQ handler execution
Commit Message commit after successful handler
RollBack Message rollback
Remove Message removal from the queue
Error Message moved to error state
PoisonMessage Poison message handling
ResetHeartBeat Stale heartbeat reset
SendHeartBeat Heartbeat update during processing
SendJobAsync Scheduler job enqueue
MessageSerializerMessageToBytes{Name} Serialization (name reflects the serializer)
MessageSerializerBytesToMessage{Name} Deserialization (name reflects the serializer)
MessageInterceptorMessageToBytes{Name} Interceptor encode (name reflects the interceptor)
MessageInterceptorBytesToMessage{Name} Interceptor decode (name reflects the interceptor)
SendMessage Message send (Memory transport)
SchedulerMessageHandler Scheduler handler execution

At runtime, the library replaces the {Name} suffix on serializer and interceptor activities with the display name of the specific serializer or interceptor implementation in use (e.g., MessageSerializerMessageToBytesJsonSerializer, MessageInterceptorMessageToBytesGZip).

Common Span Tags

The library tags every activity with context metadata:

Tag Source Notes
Server IConnectionInformation.Server Transport server/host
Queue IConnectionInformation.QueueName Queue name
CorrelationId Message headers Cross-system correlation
Route Message route Only present when routing is enabled
MessageId Queue message ID Added by message-specific activities

When you send a message, you can also attach custom tags through IAdditionalMessageData.TraceTags. The library propagates these tags to all downstream activities for that message.

Creating Child Spans

Inside a consumer handler, IWorkerNotification exposes the queue's ActivitySource through the Tracer property. Use it to create child spans. The library automatically makes the queue's current activity their parent:

consumer.Start<MyMessage>((message, notification) =>
{
    using var activity = notification.Tracer.StartActivity("ProcessOrder");
    activity?.SetTag("orderId", message.Body.OrderId);
    // your processing logic
}, notifications);

These child spans appear in your tracing backend as children of the MessageHandler or MessageHandlerAsync span.

Related Pages

Clone this wiki locally