Skip to content

Support ActivityTrackingOptions to enrich logs with Activity tags and baggage #245

Closed
@david-obee

Description

@david-obee

Hi, I'm raising this initially just as an issue, to check my thinking and see if there would be interest in this feature. If so, then I can potentially have a go at fully implementing this and raising a PR.

Is your feature request related to a problem? Please describe.

The Microsoft.Extensions.Logging library supports automatically enriching your logs with tags and/or baggage from the associated System.Diagnostics Activity at the time of logging. This is enabled by setting the ActivityTrackingOptions setting to either Tags or Baggage (or both). This is as introduced in this PR dotnet/runtime#48722 which comes off the back of this issue dotnet/runtime#46571.

I've found that setting this property doesn't seem to work when I'm using Serilog behind the Microsoft.Extensions.Logging API. Looking into it, I believe the reason is this line here in the Microsoft.Extensions.Logging library:

https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Logging/src/LoggerFactory.cs#L204

private void AddProviderRegistration(ILoggerProvider provider, bool dispose)
{
    _providerRegistrations.Add(new ProviderRegistration
    {
        Provider = provider,
        ShouldDispose = dispose
    });

    if (provider is ISupportExternalScope supportsExternalScope)
    {
        _scopeProvider ??= new LoggerFactoryScopeProvider(_factoryOptions.ActivityTrackingOptions);

        supportsExternalScope.SetScopeProvider(_scopeProvider);
    }
}

Here, the LoggerFactoryScopeProvider is what does the work of pulling out the tags and baggage defined on the Activity and making available for logging scopes. If the ILoggerProvider supports external scopes, by implementing ISupportExternalScope, then it can receive this LoggerFactoryScopeProvider to use later to enrich its logs.

Unfortunately, it seems that the SerilogLoggerProvider doesn't implement that ISupportExternalScope interface (https://github.com/serilog/serilog-extensions-logging/blob/main/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs), and hence misses out on this feature.

Describe the solution you'd like

Ideally, Serilog could support these Tags and Baggage switches on the ActivityTrackingOptions setting, so that logs can be enriched with tags and baggage from the ongoing Activity.

I don't have much deep experience with Serilog, so I might be a bit naïve here, but I think this might be a relatively straightforward addition to implement the ISupportExternalScope interface.

I think we can modify the Enrich method in SerilogLoggerProvider, with something like (this is a quick sketch of a solution):

public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
+    _externalScopeProvider?.ForEachScope((scope, state) =>
+    {
+        if (scope is IEnumerable<KeyValuePair<string, object?>> dict)
+        {
+            foreach (var kvp in dict)
+            {
+                state.AddPropertyIfAbsent(propertyFactory.CreateProperty(kvp.Key, kvp.Value));
+            }
+        }
+    }, logEvent);

    List<LogEventPropertyValue>? scopeItems = null;
    for (var scope = CurrentScope; scope != null; scope = scope.Parent)
    {
        scope.EnrichAndCreateScopeItem(logEvent, propertyFactory, out var scopeItem);

        if (scopeItem != null)
        {
            scopeItems ??= new List<LogEventPropertyValue>();
            scopeItems.Add(scopeItem);
        }
    }

    if (scopeItems != null)
    {
        scopeItems.Reverse();
        logEvent.AddPropertyIfAbsent(new LogEventProperty(ScopePropertyName, new SequenceValue(scopeItems)));
    }
}

where we implement the ISupportExternalScope.SetScopeProvider(IExternalScopeProvider scopeProvider) method by just storing the IExternalScopeProvider as the field _externalScopeProvider like:

public void SetScopeProvider(IExternalScopeProvider scopeProvider)
{
    _externalScopeProvider = scopeProvider;
}

Describe alternatives you've considered

An alternative is to manually define a Serilog enricher, to do the same thing, pulling out tags and baggage and enriching the logs. This is the approach taken by in this blog post: https://www.jimmybogard.com/increasing-trace-cardinality-with-tags-and-baggage/.

However, it would be great if Serilog could support all the available options on the ActivityTrackingOptions setting, and then allow us to rely on Microsoft's implementation for doing this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions