This sample shows how to extend the OpenTelemetry activities in different ways.
Running the project
The code consists of a single endpoint project that sends messages to itself.
Press O to send a CreateOrder
message with a randomized OrderId
. When the message is handled, two more messages are created: BillOrder
and ShipOrder
.
As the messages are sent and processed, trace data is exported to the console. Some of the trace data originates from NServiceBus and some from custom code in the sample.
Code walk through
Global configuration
NServiceBus OpenTelemetry instrumentation is not enabled by default. It must be enabled on the endpoint configuration.
var endpointConfiguration = new EndpointConfiguration("CustomTelemetry");
endpointConfiguration.EnableOpenTelemetry();
OpenTelemetry is configured to export all traces to the command line. It includes the NServiceBus.
source which is built into NServiceBus and a custom activity source defined in the sample (see below).
var resourceBuilder = ResourceBuilder.CreateDefault()
.AddService("CustomTelemetry");
var tracerProviderBuilder = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(resourceBuilder)
.AddSource("NServiceBus.Core")
.AddSource(CustomActivitySources.Name)
.AddProcessor(new NetHostProcessor())
.AddConsoleExporter();
A custom processor is registered which adds the machine name as a tag to every activity created by this trace listener.
class NetHostProcessor : BaseProcessor<Activity>
{
string hostName;
public NetHostProcessor()
{
hostName = Dns.GetHostName();
}
public override void OnStart(Activity data)
{
data.SetTag("net.host.name", hostName);
}
}
Custom activities
The sample includes a custom activity source.
static class CustomActivitySources
{
public const string Name = "Sample.ActivitySource";
public static ActivitySource Main = new ActivitySource(Name);
}
The handler for CreateOrder
includes a custom activity that wraps around the billing section.
public async Task Handle(CreateOrder message, IMessageHandlerContext context)
{
using(var activity = CustomActivitySources.Main.StartActivity("Billing Order"))
{
Console.WriteLine($"Billing order {message.OrderId}");
activity?.AddTag("sample.billing.system", "paypal");
// Calculate order cost
await context.SendLocal(new BillOrder { OrderId = message.OrderId });
}
Console.WriteLine($"Shipping order {message.OrderId}");
await context.SendLocal(new ShipOrder { OrderId = message.OrderId });
}
This will automatically be created as a child activity of the invoke handler activity created by NServiceBus. The NServiceBus send message activity will treat this custom activity as its parent.
Send CreateOrder
Process CreateOrder
Invoke CreateOrderHandler
Billing Order <-- Custom activity
Send BillOrder
Send ShipOrder
Adding tags
The handler for ShipOrder
adds tags to the ambient behavior.
In the sample, these tags will be added to the NServiceBus invoke handler activity.
Send ShipOrder
Process ShipOrder
Invoke ShipOrderHandler <-- Custom tag gets added here
A behavior in the outgoing pipeline adds the size of the message as a tag for all outgoing message activities.
Activity.
may be null
if there are no configured trace listeners. Always check if the value is null before calling methods on an Activity
instance, or use the null-conditional operator (?.
).