marsze
marsze

Reputation: 17094

Get ScopeContext properties in AsyncTaskTarget

I am implementing a custom NLog AsyncTaskTarget, and I need to retrieve values that I have added using Microsoft.Extensions.Logging.ILogger.BeginScope:

using (var scope = logger.BeginScope(new []
{
    new KeyValuePair<string, object>("userId", this.UserId)
}))
{
    logger.Log(..);
}

Rendering this in a layout using ${mdlc:userId} works fine, but I would like to get them directly from MappedDiagnosticsLogicalContext or ScopeContext.

This is what I've tried:

protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken token)
{
    // returns null
    ScopeContext.TryGetProperty("userId", out var userId);
    userId = MappedDiagnosticsLogicalContext.GetObject("userId");

    // this works fine
    var message = this.Layout.Render(logEvent);
}

How do I get the userId value from the scope?

NLog Version: 5.0.1 (newest)

This GitHub issue is related to this problem, but I found no real solution there.

Upvotes: 4

Views: 1597

Answers (3)

marsze
marsze

Reputation: 17094

Full solution:

using NLog;
using NLog.Targets;

class AsyncScopeTarget : AsyncTaskTarget
{
    public AsyncScopeTarget()
    {
        this.IncludeScopeProperties = true;
    }

    protected override bool SerializeScopeContextProperty(LogEventInfo logEvent, string name, object value, out object serializedValue)
    {
        // return the original (immutable) value
        serializedValue = value;
        return true;
    }

    protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken cancellationToken)
    {
        var scopeValues = GetScopeContextProperties(logEvent);
        if (scopeValues is not null)
        {
            scopeValues.TryGetValue("name", out object? scopeValue);
        }
    }
}

(Note: Also consider this post.)

Upvotes: 1

Rolf Kristensen
Rolf Kristensen

Reputation: 19867

In your Target-constructor enable the option:

And then you can use GetScopeContextProperties() method:

protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken token)
{
    var contextProperties = GetScopeContextProperties(logEvent);
    contextProperties?.TryGetValue("userid", out var userId);
}

You can also get a combined dictionary of all properties, by using GetAllProperties() and the do the lookup (Still need to enable IncludeScopeProperties )

Upvotes: 3

Alexander
Alexander

Reputation: 4537

You could use GetAllProperties method to get dictionary of all configured properties for logEvent, and then retrieve specific property from the dictionary. Just enable IncludeScopeProperties of the target in NLog configuration.

Upvotes: 1

Related Questions