'How can I reproduce Serilog's LogContext behavior?

this is a question of functioning issue, because I didn't understand correctly how you use information sharing.

I'm wanting to do something similar to LogContext, but I want to transfer a value between different threads within a context.

I made a very simple script using Serilog where I open several threads and it shares context information perfectly.

But I'm trying to do the same with another property, I don't necessarily want to inject it into the LogContext, what I'm trying to do is understand how you guys managed to make the sharing between threads work, respecting the context.

Note: It is not a problem in Serilog, nor am I trying to solve it with Serilog, I am wanting to understand and replicate it for another need in another project.

using Creditas.SDK.ToolKit.Authentication;
using Creditas.SDK.ToolKit.Client;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Context;
using System.Collections.Immutable;
using System.Transactions;

namespace Project.CorrelationId;

public class ThreadIDEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(
          "ThreadID", Thread.CurrentThread.ManagedThreadId.ToString("D4")));
    }
}

sealed public class MessageContext : IDisposable
{
    [ThreadStatic]
    private static MessageContext context;

    [ThreadStatic]
    private static int _instanceCounter;

    // [ThreadStatic]
    private static ImmutableStack<string> _correlationId;

    [ThreadStatic]
    private static string _correlationId2;

    private MessageContext()
    {
        // Console.WriteLine("MessageContext");
        var data = ImmutableStack<string>.Empty;
        data.Push(Guid.NewGuid().ToString());
        _correlationId = data;
        _correlationId2 = Guid.NewGuid().ToString();
        // Console.WriteLine("MessageContext:end");
        // Console.WriteLine(_correlationId.Count());
    }

    public string CorrelationId
    {
        get
        {
            // try
            // {
            //     Console.WriteLine(_correlationId.Count());
            // }
            // catch (Exception ex)
            // {
            //     Console.WriteLine(ex.Message);
            // }
            return _correlationId2;
        }
    }

    public static MessageContext Instance()
    {
        if (_instanceCounter == 0)
        {
            context = new MessageContext();
        }
        _instanceCounter++;


        return context;
    }

    public void Dispose()
    {
        Console.WriteLine("Dispose");
        _instanceCounter--;
        if (_instanceCounter == 0)
        {
            if (context != null)
                context.Dispose();
            context = null;
            _instanceCounter = 0;
        }
    }
}

public class Correlation
{
    public static async Task Perform()
    {
        string shortdate = DateTime.Now.ToString("yyyy-MM-dd_HH");
        const string template = "[{Timestamp:yyyy-MM-dd HH:mm:ss.ffff}][{Level}][{ThreadID}][{CorrelationId}] ({A}{B}) {Message}{NewLine}{Exception}";


        var logger = new LoggerConfiguration()
            // .Enrich.WithCorrelationId()
            .Enrich.With(new ThreadIDEnricher())
            .Enrich.FromLogContext()
            .WriteTo.Console(outputTemplate: template)
            .CreateLogger();

        logger.Information($"Start");
        using (var context = MessageContext.Instance())
        using (LogContext.PushProperty("CorrelationId", "ABC"))
        {
            logger.Information($"interno");
            logger.Information($"using: {context.CorrelationId}");
            logger.Information($"main: {MessageContext.Instance().CorrelationId}");
            // log.

            var a = new Thread(() =>
            {
                logger.Information($"thread 1");
                logger.Information($"thread 1: {MessageContext.Instance().CorrelationId}");

                var b = new Thread(() =>
                {
                    logger.Information($"thread 2");
                    logger.Information($"thread 2: {MessageContext.Instance().CorrelationId}");

                    var c = new Thread(() =>
                    {
                        logger.Information($"thread 3");
                        logger.Information($"thread 3: {MessageContext.Instance().CorrelationId}");

                        var d = new Thread(() =>
                        {
                            logger.Information($"thread 4");
                            logger.Information($"thread 4: {MessageContext.Instance().CorrelationId}");
                        });
                        d.Start();
                    });
                    c.Start();
                });
                b.Start();
            });
            a.Start();
        }

        using (var context = MessageContext.Instance())
        using (LogContext.PushProperty("CorrelationId", "DFE"))
        {
            logger.Information($"interno");
            logger.Information($"using: {context.CorrelationId}");
            logger.Information($"main: {MessageContext.Instance().CorrelationId}");
            // log.

            var a = new Thread(() =>
            {
                logger.Information($"thread 1");
                logger.Information($"thread 1: {MessageContext.Instance().CorrelationId}");

                var b = new Thread(() =>
                {
                    logger.Information($"thread 2");
                    logger.Information($"thread 2: {MessageContext.Instance().CorrelationId}");

                    var c = new Thread(() =>
                    {
                        logger.Information($"thread 3");
                        logger.Information($"thread 3: {MessageContext.Instance().CorrelationId}");

                        var d = new Thread(() =>
                        {
                            logger.Information($"thread 4");
                            logger.Information($"thread 4: {MessageContext.Instance().CorrelationId}");
                        });
                        d.Start();
                    });
                    c.Start();
                });
                b.Start();
            });
            a.Start();
        }

        logger.Information($"End");
    }
}
2022-05-13 15:32:13.5989][Information][0001][] Start
[2022-05-13 15:32:13.6341][Information][0001][ABC] interno
[2022-05-13 15:32:13.6345][Information][0001][ABC] using: 629d31c5-418c-49d1-b3a6-7c5468074966
[2022-05-13 15:32:13.6345][Information][0001][ABC] main: 629d31c5-418c-49d1-b3a6-7c5468074966
[Dispose
2022-05-13 15:32:13.6352][Information][0005][ABC] thread 1
[2022-05-13 15:32:13.6353][Information][0005][ABC] thread 1: bbbabef6-aa97-48c5-82f9-a5075ad982e9
[2022-05-13 15:32:13.6357][Information][0001][DFE] interno
[2022-05-13 15:32:13.6358][Information][0001][DFE] using: 629d31c5-418c-49d1-b3a6-7c5468074966
[2022-05-13 15:32:13.6359][Information][0006][ABC] thread 2
[2022-05-13 15:32:13.6361][Information][0006][ABC] thread 2: de479282-0c93-4bfd-b0e3-ac68c6a73cec
[2022-05-13 15:32:13.6359][Information][0001][DFE] main: 629d31c5-418c-49d1-b3a6-7c5468074966
Dispose
[2022-05-13 15:32:13.6365][Information][0001][] End
[2022-05-13 15:32:13.6366][Information][0007][ABC] thread 3
[2022-05-13 15:32:13.6367][Information][0008][DFE] thread 1
[2022-05-13 15:32:13.6367][Information][0008][DFE] thread 1: 9490cd91-49b1-41b9-b6fe-8f169d71e7b2
[2022-05-13 15:32:13.6367][Information][0007][ABC] thread 3: 0bebc827-de96-4f95-b7d0-3f218dd73054
[2022-05-13 15:32:13.6371][Information][0009][DFE] thread 2
[2022-05-13 15:32:13.6372][Information][0010][ABC] thread 4
[2022-05-13 15:32:13.6373][Information][0010][ABC] thread 4: e705fcba-6477-42b1-9a61-e5d3782c3f65
[2022-05-13 15:32:13.6372][Information][0009][DFE] thread 2: 1d5628d7-742a-452e-8f6d-9a3bf20a3719
[2022-05-13 15:32:13.6381][Information][0011][DFE] thread 3
[2022-05-13 15:32:13.6382][Information][0011][DFE] thread 3: 2986a54c-fc2e-4f6f-a42b-488f2bb40aaf
[2022-05-13 15:32:13.6386][Information][0012][DFE] thread 4
[2022-05-13 15:32:13.6387][Information][0012][DFE] thread 4: 091551be-da02-4f5c-be0a-013619b3e390

I needed MessageContext.Instance().CorrelationId to return the same value within the context.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source