In .NETCore I want to support such scenario where I wrap code in some context like:
using(new LoggingContext("Method 1"))
{
}
Those contexts can also be embedded in one another
using(new LoggingContext("Method 1"))
{
Method2();
}
void Method2()
{
using(new LoggingContext("Method 2"))
{
logger.Log("ERROR")
}
}
After calling logger.Log("ERROR") I want it to log passed message along with those stacked contexts identifiers like:
Method 1 > Method 2 > ERROR
It is very easy in single thread scenario - it requires a globally accessible stack of contexts. In .NET Core it is for example some public static AsyncLocal<Stack<LoggingContext>>.
However I don't know what is the best way to achieve similar behavior in multithreaded scenario like this:
using(LoggingContext("Method 1"))
{
Task.WaitAll(
new Task(() => Method("Method A", "A"),
new Task(() => Method("Method B", "B")))
}
void Method(string contextName, string message)
{
using(new LoggingContext(contextName)
{
_logger.Log(message)
}
}
The desired log would look like this:
Method 1 > Method A > A
Method 1 > Method B > B
Of course one task can start in another task and situation gets even more complicated.
One more thing to note: For some legacy reasons it is impossible to pass dependency everywhere I create LoggingContext it must be some static solution.
The only idea I can think of is to use ExecutionContext.SupressFlow whenever I create a new Task and copy current stack to the new AsyncLocal object but is it a good solution? Messing with execution context seems a bit unsafe for me.