OpenTelemetry trace continuation #4193
-
|
I'm experimenting with Brighter, OpenTelemetry and Sentry. So far I've got messages being written with a Sentry baggage header and an OpenTelemetry traceparent value in the message headers. Currently I'm trying something like this: using OpenTelemetry.Context.Propagation;
using Paramore.Brighter;
using SentryTest.Messages;
using System.Diagnostics;
namespace SentryTest.Receiver;
public class TestMessageHandler : RequestHandlerAsync<TestMessage>
{
private static readonly ActivitySource ActivitySource = new(typeof(TestMessageHandler).Assembly.GetName().Name!);
private readonly ILogger<TestMessageHandler> _logger;
public TestMessageHandler(ILogger<TestMessageHandler> logger)
{
_logger = logger;
}
public override async Task<TestMessage> HandleAsync(TestMessage command, CancellationToken cancellationToken = default)
{
var propagationContext = Propagators.DefaultTextMapPropagator.Extract(
default,
Context?.OriginatingMessage,
static (carrier, key) =>
{
if (carrier is null)
{
return [];
}
return key switch
{
"traceparent" when !string.IsNullOrWhiteSpace(carrier.Header.TraceParent?.Value) => [carrier.Header.TraceParent.Value],
"baggage" when !string.IsNullOrWhiteSpace(carrier.Header.Baggage.ToString()) => [carrier.Header.Baggage.ToString()],
_ => []
};
});
using var activity = ActivitySource.StartActivity(
$"{nameof(TestMessageHandler)}.{nameof(HandleAsync)}",
ActivityKind.Consumer,
propagationContext.ActivityContext);
Context?.Span = activity;
_logger.LogError("Errorororoororor");
return await base.HandleAsync(command, cancellationToken).ConfigureAwait(ContinueOnCapturedContext);
}
}What I'm finding is that in my handler there is no value in Context.OriginatingMessage.Header.TraceParent, even though it's present in the received message log: {
"header": {
"bag": {
"handledCount": 0,
"messageType": "MT_EVENT",
"topic": "apiservice.*",
"baggage": "sentry-trace_id = 28ca60c6c56a9a295f573484c2a3a455, sentry-public_key = 4fd4b088d61f503711af2705e6cb58de, sentry-sampled = true, sentry-sample_rate = 1, sentry-sample_rand = 0.0507, sentry-release = SentryTest.Web@1.0.0+9e6541b7ce4a29786363e59cb1d542b4ba1e777e, sentry-environment = development, sentry-transaction = Event%20onclick%20->%20SentryTest.Web.Components.Pages.Home.SendMessageAsync, sentry-org_id = 4510911624839168",
"cloudEvents_id": "019edb21-cf09-7f2b-9a7e-e4e82e918743",
"cloudEvents_source": "http://goparamore.io/",
"cloudEvents_specversion": "1.0",
"cloudEvents_time": "2026-06-18T14:28:06.665Z",
"cloudEvents_type": "testMessage",
"traceparent": "00-28ca60c6c56a9a295f573484c2a3a455-8a9d23ce0c585080-01",
"x-dotnet-pub-seq-no": 1,
"deliveryTag": 1,
"redelivered": false
},
"baggage": [
{
"Key": "sentry-trace_id",
"Value": "28ca60c6c56a9a295f573484c2a3a455"
},
{
"Key": "sentry-public_key",
"Value": "4fd4b088d61f503711af2705e6cb58de"
},
{
"Key": "sentry-sampled",
"Value": "true"
},
{
"Key": "sentry-sample_rate",
"Value": "1"
},
{
"Key": "sentry-sample_rand",
"Value": "0.0507"
},
{
"Key": "sentry-release",
"Value": "SentryTest.Web@1.0.0+9e6541b7ce4a29786363e59cb1d542b4ba1e777e"
},
{
"Key": "sentry-environment",
"Value": "development"
},
{
"Key": "sentry-transaction",
"Value": "Event%20onclick%20->%20SentryTest.Web.Components.Pages.Home.SendMessageAsync"
},
{
"Key": "sentry-org_id",
"Value": "4510911624839168"
}
],
"contentType": {
"boundary": null,
"charSet": null,
"mediaType": "application/cloudevents+json",
"name": null,
"parameters": [
]
},
"correlationId": "",
"dataSchema": null,
"dataRef": null,
"delayed": "00:00:00",
"handledCount": 0,
"jobId": null,
"messageId": "019edb21-cf09-7f2b-9a7e-e4e82e918743",
"messageType": "MT_EVENT",
"partitionKey": "",
"replyTo": "",
"subject": null,
"specVersion": "1.0",
"source": "http://goparamore.io/",
"topic": "apiservice.*",
"timeStamp": "2026-06-18T14:28:06+00:00",
"traceParent": "",
"traceState": "",
"type": {
"value": "testMessage"
},
"workflowId": null
},
"body": {
"bytes": "eyJpZCI6IjAxOWVkYjIxLWNmMDktN2YyYi05YTdlLWU0ZTgyZTkxODc0MyIsInNwZWN2ZXJzaW9uIjoiMS4wIiwic291cmNlIjoiaHR0cDovL2dvcGFyYW1vcmUuaW8iLCJ0eXBlIjoidGVzdE1lc3NhZ2UiLCJkYXRhY29udGVudHR5cGUiOiJhcHBsaWNhdGlvbi9qc29uIiwiZGF0YXNjaGVtYSI6bnVsbCwic3ViamVjdCI6bnVsbCwidGltZSI6IjIwMjYtMDYtMThUMTQ6Mjg6MDYuNjcxMTYzKzAwOjAwIiwiZGF0YSI6eyJjb3JyZWxhdGlvbklkIjpudWxsLCJpZCI6IjAxOWVkYjIxLWNmMDktN2YyYi05YTdlLWU0ZTgyZTkxODc0MyJ9fQ==",
"memory": "eyJpZCI6IjAxOWVkYjIxLWNmMDktN2YyYi05YTdlLWU0ZTgyZTkxODc0MyIsInNwZWN2ZXJzaW9uIjoiMS4wIiwic291cmNlIjoiaHR0cDovL2dvcGFyYW1vcmUuaW8iLCJ0eXBlIjoidGVzdE1lc3NhZ2UiLCJkYXRhY29udGVudHR5cGUiOiJhcHBsaWNhdGlvbi9qc29uIiwiZGF0YXNjaGVtYSI6bnVsbCwic3ViamVjdCI6bnVsbCwidGltZSI6IjIwMjYtMDYtMThUMTQ6Mjg6MDYuNjcxMTYzKzAwOjAwIiwiZGF0YSI6eyJjb3JyZWxhdGlvbklkIjpudWxsLCJpZCI6IjAxOWVkYjIxLWNmMDktN2YyYi05YTdlLWU0ZTgyZTkxODc0MyJ9fQ==",
"contentType": {
"boundary": null,
"charSet": "utf-8",
"mediaType": "application/json",
"name": null,
"parameters": [
{
"key": "charset",
"value": "utf-8"
}
]
},
"characterEncoding": "UTF8",
"value": "{\"id\":\"019edb21-cf09-7f2b-9a7e-e4e82e918743\",\"specversion\":\"1.0\",\"source\":\"http://goparamore.io\",\"type\":\"testMessage\",\"datacontenttype\":\"application/json\",\"dataschema\":null,\"subject\":null,\"time\":\"2026-06-18T14:28:06.671163+00:00\",\"data\":{\"correlationId\":null,\"id\":\"019edb21-cf09-7f2b-9a7e-e4e82e918743\"}}"
},
"isEmpty": false,
"id": "019edb21-cf09-7f2b-9a7e-e4e82e918743"
}Am I on the right track? Or is there some system in Brighter and/or OpenTelemetry so that the Forgive my ignorance, I'm new to Sentry and OpenTelemetry, and Brighter for that matter. P.S. I have one more question about the traces produced by Brighter's provided instrumentation. I keep getting traces named |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
|
Currently, this is working to correlate the handler activity with the parent trace in the message, but it's leaving orphan using Paramore.Brighter;
using SentryTest.Messages;
using System.Diagnostics;
namespace SentryTest.Receiver;
public class TestMessageHandler : RequestHandlerAsync<TestMessage>
{
private readonly ILogger<TestMessageHandler> _logger;
private static readonly ActivitySource _activitySource = new(typeof(TestMessageHandler).Assembly.GetName().Name!);
public TestMessageHandler(
ILogger<TestMessageHandler> logger)
{
_logger = logger;
}
public override async Task<TestMessage> HandleAsync(TestMessage command, CancellationToken cancellationToken = default)
{
var traceParent = Context?.OriginatingMessage?.Header.Bag["traceparent"] as string;
using var activity = _activitySource.StartActivity(
$"{nameof(TestMessageHandler)}.{nameof(HandleAsync)}",
ActivityKind.Consumer,
traceParent);
if (activity is not null)
{
Context?.Span = activity;
}
_logger.LogError("Errorororoororor");
return await base.HandleAsync(command, cancellationToken).ConfigureAwait(ContinueOnCapturedContext);
}
} |
Beta Was this translation helpful? Give feedback.
-
|
I think there are essentially two things going on here:
If I do that custom I was able to solve it with a propagator like this: public class TextMapPropagator : SentryPropagator
{
public override void Inject<T>(PropagationContext context, T carrier, Action<T, string, string> setter)
{
if (carrier is Message)
{
var traceId = context.ActivityContext.TraceId.ToHexString();
var spanId = context.ActivityContext.SpanId.ToHexString();
var flags = context.ActivityContext.TraceFlags.HasFlag(ActivityTraceFlags.Recorded) ? "01" : "00";
setter(carrier, "traceparent", $"00-{traceId}-{spanId}-{flags}");
}
else
{
base.Inject(context, carrier, setter);
}
}
}So the solution is:
var tracer = new BrighterTracer(TimeProvider.System);
builder.Services.AddSingleton<BrighterTracer>(tracer);
builder.Services.AddSingleton<IAmABrighterTracer>(tracer);
|
Beta Was this translation helpful? Give feedback.
I think there are essentially two things going on here:
Paramore.Brighter.Extensions.DependencyInjection.ServiceCollectionExtensions.Traceris looking for a registeredBrighterTracerto pass into theIAmAnOutboxProducerMediatorit builds on line 737, but in other places it's looking for anIAmABrighterTracer, and that's what is registered inParamore.Brighter.Extensions.Diagnostics.BrighterTracerBuilderExtensions.AddBrighterInstrumentation#17. I think this may be an error, but it can be gotten around by registering one's ownBrighterTracerinstance.Sentry has a "sentry-trace" key instead of a "traceparent" key which
Message.PropogateContextdoesn't understand. Maybe I need to set a d…