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
16 changes: 16 additions & 0 deletions Snippets/Core/Core_10/OpenTelemetry/ExceptionRecording.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Core.OpenTelemetry;

using NServiceBus;

public static class ExceptionRecording
{
public static void ConfigureLogsOnly(EndpointConfiguration endpointConfiguration)
{
#region opentelemetry-exception-recording-logs

var options = endpointConfiguration.Tracing();

Check failure on line 11 in Snippets/Core/Core_10/OpenTelemetry/ExceptionRecording.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

'EndpointConfiguration' does not contain a definition for 'Tracing' and no accessible extension method 'Tracing' accepting a first argument of type 'EndpointConfiguration' could be found (are you missing a using directive or an assembly reference?)
options.ExceptionRecordingMode = ExceptionRecordingMode.Logs;

Check failure on line 12 in Snippets/Core/Core_10/OpenTelemetry/ExceptionRecording.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

The name 'ExceptionRecordingMode' does not exist in the current context

#endregion
}
}
16 changes: 16 additions & 0 deletions Snippets/Core/Core_10/OpenTelemetry/MetersConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Core.OpenTelemetry;

using NServiceBus;

public static class MetersConfiguration
{
public static void DisableExecutionResultTags(EndpointConfiguration endpointConfiguration)
{
#region opentelemetry-meters-disable-execution-result-tags

var options = endpointConfiguration.Tracing();
options.Meters.EmitExecutionResultTags = false;

#endregion
}
}
22 changes: 22 additions & 0 deletions Snippets/Core/Core_10/OpenTelemetry/Metrics.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Core.OpenTelemetry;

using System.Collections.Generic;
using global::OpenTelemetry;
using global::OpenTelemetry.Metrics;

Expand All @@ -17,4 +18,25 @@ public static void EnableMetrics()

#endregion
}

public static void FilterMetrics(MeterProviderBuilder metrics)
{
#region opentelemetry-metrics-filter-view

// Only these NServiceBus metrics are collected; everything else the meter emits is dropped.
var enabledNServiceBusMetrics = new HashSet<string>(StringComparer.Ordinal)
{
"nservicebus.messaging.deserialize_time",
"nservicebus.messaging.serialize_time",
};

metrics.AddMeter("NServiceBus.*")
.AddView(instrument =>
instrument.Meter.Name.StartsWith("NServiceBus", StringComparison.Ordinal)
&& !enabledNServiceBusMetrics.Contains(instrument.Name)
? MetricStreamConfiguration.Drop
: null);

#endregion
}
}
102 changes: 102 additions & 0 deletions Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
namespace Core.OpenTelemetry;

using global::OpenTelemetry;
using global::OpenTelemetry.Trace;
using NServiceBus;

public static class TraceConfiguration
{
public static void ConfigureSendTraceMode(EndpointConfiguration endpointConfiguration)
{
#region opentelemetry-trace-mode-send

var options = endpointConfiguration.Tracing();

Check failure on line 13 in Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

'EndpointConfiguration' does not contain a definition for 'Tracing' and no accessible extension method 'Tracing' accepting a first argument of type 'EndpointConfiguration' could be found (are you missing a using directive or an assembly reference?)
// Default: ContinueExisting - the receiver continues the sender's trace.
// Set to StartNew to always start a new linked trace on the receiver.
options.SendTraceMode = TraceMode.StartNew;

Check failure on line 16 in Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

The name 'TraceMode' does not exist in the current context

#endregion
}

public static void ConfigurePublishTraceMode(EndpointConfiguration endpointConfiguration)
{
#region opentelemetry-trace-mode-publish

var options = endpointConfiguration.Tracing();

Check failure on line 25 in Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

'EndpointConfiguration' does not contain a definition for 'Tracing' and no accessible extension method 'Tracing' accepting a first argument of type 'EndpointConfiguration' could be found (are you missing a using directive or an assembly reference?)
// Default: StartNew - subscribers start a new trace linked to the publish span.
// Set to ContinueExisting to continue the publisher's trace in the subscriber.
options.PublishTraceMode = TraceMode.ContinueExisting;

Check failure on line 28 in Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

The name 'TraceMode' does not exist in the current context

#endregion
}

public static void ConfigureDelayedTraceMode(EndpointConfiguration endpointConfiguration)
{
#region opentelemetry-trace-mode-delayed

var options = endpointConfiguration.Tracing();

Check failure on line 37 in Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

'EndpointConfiguration' does not contain a definition for 'Tracing' and no accessible extension method 'Tracing' accepting a first argument of type 'EndpointConfiguration' could be found (are you missing a using directive or an assembly reference?)
// Default for all three is StartNew (new linked trace at delivery time).
// Set to ContinueExisting to continue the originating trace instead.
options.DelayedDelivery.SendOperationTraceMode = TraceMode.ContinueExisting;

Check failure on line 40 in Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

The name 'TraceMode' does not exist in the current context
options.DelayedDelivery.SagaTimeoutTraceMode = TraceMode.ContinueExisting;

Check failure on line 41 in Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

The name 'TraceMode' does not exist in the current context
options.Recoverability.DelayedRetryTraceMode = TraceMode.ContinueExisting;

Check failure on line 42 in Snippets/Core/Core_10/OpenTelemetry/TraceConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build samples & snippets

The name 'TraceMode' does not exist in the current context

#endregion
}

public static void SubscribeToAllTraceSources()
{
#region opentelemetry-enabletracing-all-sources

var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("NServiceBus.Core")
.AddSource("NServiceBus.Core.Handler")
.AddSource("NServiceBus.Core.Recoverability")
// ... Add exporters
.Build();

#endregion
}

public static void EnableHandlerActivitySource()
{
#region opentelemetry-handler-activity-source-switch

// Must be set before the endpoint starts.
AppContext.SetSwitch("NServiceBus.Core.OpenTelemetry.UseHandlerActivitySource", true);

#endregion
}

public static void UseDestinationInSpanNames(EndpointConfiguration endpointConfiguration)
{
#region opentelemetry-span-names-destination

var options = endpointConfiguration.Tracing();
options.UseMessageDestinationInSpanNames = true;

#endregion
}

public static void DisableDispatchingEvents(EndpointConfiguration endpointConfiguration)
{
#region opentelemetry-dispatching-events-disable

var options = endpointConfiguration.Tracing();
options.EmitMessageDispatchingEvents = false;

#endregion
}

public static void EnableDistributedContextPropagator()
{
#region opentelemetry-distributed-context-propagator-switch

// Must be set before the endpoint starts.
// Opts in to W3C DistributedContextPropagator-based trace context propagation.
// This becomes the default in version 11.
AppContext.SetSwitch("NServiceBus.Core.OpenTelemetry.UseDistributedContextPropagator", true);

#endregion
}
}
13 changes: 13 additions & 0 deletions nservicebus/operations/opentelemetry_logs_core_[8,).partial.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## Logging

NServiceBus supports logging out of the box. To collect OpenTelemetry-compatible logging in NServiceBus endpoints, it's possible to configure the endpoint to connect traces and logging when using `Microsoft.Extensions.Logging` package. See the [_Connecting OpenTelemetry traces and logs_ sample](/samples/open-telemetry/logging) for more details.

### Recoverability structured log properties

Recoverability action log entries are emitted via `Microsoft.Extensions.Logging` and include named structured properties. When using a structured logging backend such as Serilog, Seq, or Application Insights, these properties are captured as queryable key-value pairs rather than text embedded in the message string:

| Recoverability action | Structured properties |
|---|---|
| Immediate retry | `MessageId` |
| Delayed retry | `MessageId`, `Delay` |
| Move to error queue | `MessageId`, `ErrorQueue` |
| Discard | `MessageId`, `Reason` |

For example, all messages moved to a specific error queue can be queried by filtering on `ErrorQueue`, or all delayed retries for a specific message can be found by filtering on `MessageId`, without needing to parse log message strings.
23 changes: 23 additions & 0 deletions nservicebus/operations/opentelemetry_metrics_core_[10,).partial.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ NServiceBus endpoints can be configured to expose metrics related to message pro

snippet: opentelemetry-enablemeters

Because all metrics from a meter source are emitted by default, use an OpenTelemetry view to drop any that are not needed:

snippet: opentelemetry-metrics-filter-view

### Meter options

#### execution.result tag

Several metrics include an `execution.result` tag with a value of `"success"` or `"failure"`. This tag increases metric cardinality and the associated ingestion cost. To opt out, set `EmitExecutionResultTags` to `false`:

snippet: opentelemetry-meters-disable-execution-result-tags

The `execution.result` tag is emitted by default. Disabling it affects all metrics that carry it: `nservicebus.messaging.successes`, `nservicebus.messaging.failures`, `nservicebus.messaging.processing_time`, `nservicebus.messaging.critical_time`, `nservicebus.messaging.handler_time`, `nservicebus.messaging.deserialize_time`, `nservicebus.messaging.serialize_time`, and `nservicebus.sagas.fetch_time`.

### Emitted meters

Meter source `NServiceBus.Core.Pipeline.Incoming`:
Expand All @@ -17,9 +31,17 @@ Meter source `NServiceBus.Core.Pipeline.Incoming`:
- [`nservicebus.messaging.handler_time`](/monitoring/metrics/definitions.md#metrics-captured-handler-time) - The time the user handling code takes to handle a message
- [`nservicebus.messaging.processing_time`](/monitoring/metrics/definitions.md#metrics-captured-processing-time) - The time the endpoint takes to process a message
- [`nservicebus.messaging.critical_time`](/monitoring/metrics/definitions.md#metrics-captured-critical-time) - The time between when a message is sent and when it is fully processed
- `nservicebus.messaging.active_messages` (UpDownCounter) - Number of messages currently being processed by the endpoint. Tags: `nservicebus.queue`, `nservicebus.discriminator`, `nservicebus.enclosed_message_types`
- `nservicebus.messaging.deserialize_time` - The time in seconds for deserializing an incoming message. Tags: `nservicebus.queue`, `nservicebus.discriminator`, `nservicebus.enclosed_message_types`, `execution.result`, `error.type`
- `nservicebus.messaging.serialize_time` - The time in seconds for serializing an outgoing message. Tags: `nservicebus.message_type`, `execution.result`, `error.type`
- [`nservicebus.recoverability.immediate`](/monitoring/metrics/definitions.md#metrics-captured-immediate-retries) - Total number of immediate retries requested
- [`nservicebus.recoverability.delayed`](/monitoring/metrics/definitions.md#metrics-captured-delayed-retries) - Total number of delayed retries requested
- [`nservicebus.recoverability.error`](/monitoring/metrics/definitions.md#metrics-captured-moved-to-error-queue) - Total number of messages sent to the error queue
- `nservicebus.sagas.fetch_time` - The time in seconds for loading saga data from the persister. Tags: `nservicebus.queue`, `nservicebus.discriminator`, `nservicebus.message_type`, `nservicebus.saga_type`, `execution.result`, `error.type`
- `nservicebus.outbox.duplicates` - Total number of messages deduplicated by the outbox. Tags: `nservicebus.queue`, `nservicebus.discriminator`, `nservicebus.message_type`
- `nservicebus.outbox.fetch_time` - The time in seconds for querying the outbox storage for deduplication. Tags: `nservicebus.queue`, `nservicebus.discriminator`
- `nservicebus.outbox.store_time` - The time in seconds for storing a message in the outbox storage. Tags: `nservicebus.queue`, `nservicebus.discriminator`
- `nservicebus.persistence.commit_time` - The time in seconds for completing the synchronized storage session. Tags: `nservicebus.queue`, `nservicebus.discriminator`, `nservicebus.message_type`, `nservicebus.message_handler_types`

Starting NServiceBus V10.1 envelope unwrapping metrics are emitted as part of the `NServiceBus.Core.Pipeline.Incoming` source:

Expand All @@ -38,4 +60,5 @@ Meter source `NServiceBus.Envelope.CloudEvents`:
- [`nservicebus.envelope.cloud_events.received.invalid_message`](/monitoring/metrics/definitions.md#metrics-captured-envelope-handling-metrics-cloudevents-specific-metrics) - Total number of received messages not conforming to the specification
- [`nservicebus.envelope.cloud_events.received.unexpected_version`](/monitoring/metrics/definitions.md#metrics-captured-envelope-handling-metrics-cloudevents-specific-metrics) - Total number of received messages with unexpected version field value


See the [OpenTelemetry samples](/samples/open-telemetry/) for instructions on how to send metric information to different tools.
Loading
Loading