Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Logical Context): The equivalent to log4net.ThreadLogicalContext #272

Closed
bfcamara opened this issue Nov 15, 2013 · 2 comments
Closed

Comments

@bfcamara
Copy link

NLog has the GlobalDiagnosticsContext and the MappedDiagnosticsContext.

The MappedDiagnosticsContext stores the dictionary in the thread locall storage, which it does not flow in async points. For example, if I am using the async/await pattern in my web application, and I want to log a specific property (being set in the begining of the request processing), in all my log statements, if I use the MaapedDiagnosticsContext, I will lose the property in logs as soon the request jump to another thread.

I've explained this problem in my blog: http://www.bfcamara.com/post/66886024762/nlog-how-to-include-custom-context-variables-in-all

Log4Net supports this scenario by using the log4net.ThreadLogicalContext

In my current project, I've implemented this feature, but before doing a PR, I would like to have some opinions.

Basically I've used the CallContext (instead of thread local storage), which flows in async points.

public static class MappedDiagnosticsLogicalContext
{
    private const string LogicalContextDictKey = "NLog.MappedDiagnosticsLogicalContext";

    private static IDictionary<string, string> LogicalContextDict
    {
        get
        {
            var dict = CallContext.LogicalGetData(LogicalContextDictKey) as ConcurrentDictionary<string, string>;
            if (dict == null)
            {
                dict = new ConcurrentDictionary<string, string>();
                CallContext.LogicalSetData(LogicalContextDictKey, dict);
            }
            return dict;
        }
    }

    public static void Set(string item, string value)
    {
        LogicalContextDict[item] = value;
    }

    public static string Get(string item)
    {
        string s;

        if (!LogicalContextDict.TryGetValue(item, out s))
        {
            s = string.Empty;
        }

        return s;
    }
}

I also have a new Layout Render (mdlc - mapped diagnostics logical context)

/// <summary>
/// Mapped Diagnostic Logical Context item (based on CallContext).
/// </summary>
[LayoutRenderer("mdlc")]
public class MdlcLayoutRenderer : LayoutRenderer
{
    /// <summary>
    /// Gets or sets the name of the item.
    /// </summary>
    /// <docgen category='Rendering Options' order='10' />
    [RequiredParameter]
    [DefaultParameter]
    public string Item { get; set; }

    /// <summary>
    /// Renders the specified MDLC item and appends it to the specified <see cref="StringBuilder" />.
    /// </summary>
    /// <param name="builder">The <see cref="StringBuilder"/> to append the rendered data to.</param>
    /// <param name="logEvent">Logging event.</param>
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        string msg = MappedDiagnosticsLogicalContext.Get(this.Item);
        builder.Append(msg);
    }
}

What do you think?

@ghost
Copy link

ghost commented Nov 17, 2013

Looks like a nice addition to NLog. I would recommend that you created a pull request at the NLog-Contrib repository, then I'll make sure it get uploaded to NuGet. Please let me know if you need any help

@bfcamara
Copy link
Author

@Xharze

Here is the PR NLog/NLog-Contrib#7

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant