serilog-sinks-opentelemetry
serilog-sinks-opentelemetry copied to clipboard
Recognize spans and send via OTLP traces endpoint
SerilogTracing is a front-end for Serilog that hooks into System.Diagnostics.Activity
and records completed activities (spans) as LogEvent
s:
using var activity = Log.Logger.StartActivity("Request weather for postcode {Postcode}", postcode);
// ...
activity.Complete();
This makes it possible to use all of Serilog's message template support, enrichment, sinks, and formatting infrastructure to handle spans as if they're regular logs, while lighting these up to become full hierarchical, distributed traces in back-ends that support them:
It's turned out to be a great little library, allowing apps that use Serilog to adopt tracing with very minimal overhead. In the long term, I think some basic tracing support is destined to make its way to the serilog/serilog
project one way or another. But, for the time being, we're still exploring how tracing fits in with other Serilog features, and honing the approach.
The SerilogTracing project maintains a fork of this sink that converts LogEvents
representing spans into OTLP traces. The fork is otherwise pretty much identical to the codebase here.
While it's not onerous maintaining both codebases, very minimal changes would be needed over here in order for them to be combined, and the fork retired. Aside from the maintenance time advantage, the Serilog ecosystem would gain more cohesion and consistency.
There are two main alterations that would occur:
- The
endpoint
configuration parameter would become the (optional)logsEndpoint
, - A new (optional)
tracesEndpoint
parameter would be added, and - Log events carrying a
SpanStartTimestamp
property would be interpreted as spans and sent to the traces endpoint rather than the logs endpoint
I think the retirement of endpoint
could be done in a reasonably backwards-compatible manner, with the existing configuration method/property marked [Obsolete]
for at least one release cycle.
When a log event is interpreted as a span, there are three properties that gain special meaning:
/// <summary>
/// The name of the entry in <see cref="LogEvent.Properties"/> that carries a
/// span's <see cref="System.Diagnostics.Activity.ParentId"/>, if there is one.
/// </summary>
public const string ParentSpanIdPropertyName = "ParentSpanId";
/// <summary>
/// The name of the entry in <see cref="LogEvent.Properties"/> that carries a
/// span's start timestamp. All spans emitted by SerilogTracing carry this property.
/// </summary>
public const string SpanStartTimestampPropertyName = "SpanStartTimestamp";
/// <summary>
/// The name of the entry in <see cref="LogEvent.Properties"/> that carries a
/// span's kind. The value will be an <see cref="ActivityKind"/>. The span kind is
/// unset for <see cref="ActivityKind.Internal"/> spans: any span without an explicit
/// kind should be assumed to be internal.
/// </summary>
public const string SpanKindPropertyName = "SpanKind";
Only when SpanStartTimestamp
is present do the other two get special treatment. (This property name is chosen to be reasonably verbose and specific to the task, so that for instance a slightly different name could be chosen if a revision of the Activity
→ LogEvent
mapping were to be required in the future.)
I'd like to start working on a PR for this sometime in the next few weeks. I'm keen to gauge interest and field questions - let me know what you think! :-)