-
Notifications
You must be signed in to change notification settings - Fork 16
Trace
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
You will need the OpenTelemetry hosting extension plus an exporter of your choice:
OpenTelemetry.Extensions.Hosting
OpenTelemetry.Exporter.Jaeger (or any other exporter)
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("dotnetworkqueue.instrumentationlibrary")
.AddJaegerExporter());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 flows from producer to consumer automatically via message headers. When a producer enqueues a message, the current Activity context gets captured and stored in the message. The consumer restores that context before running your handler, so the full producer-to-consumer span chain shows up in your tracing backend without any extra configuration.
The following activities are emitted by DotNetWorkQueue. All activity names are emitted 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 |
The {Name} suffix on serializer and interceptor activities is substituted at runtime with the display name of the specific serializer or interceptor implementation in use (e.g., MessageSerializerMessageToBytesJsonSerializer, MessageInterceptorMessageToBytesGZip).
Every activity is tagged with contextual 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 |
You can also attach custom tags via IAdditionalMessageData.TraceTags when sending a message. These tags are propagated to all downstream activities for that message.
Inside a consumer handler, IWorkerNotification exposes the queue's ActivitySource via the Tracer property. Use it to create child spans that are automatically parented to the queue's current activity:
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.
For any issues please use the GitHub issues