My concrete need is to store remote IP so it can be printed while logging, without explicitly passing it down every method call. A sort of per thread environment variable scope.
I thought of having a per thread Singleton so logger can access it. Is there a better/safer way?
Make it work with async is a plus.
My ideal API should look like this:
using (new LogScope("key1", "value1"))
{
Call1();
}
using (new LogScope("key1", "value1"))
{
Call1();
}
void Call1()
{
using (new LogScope("key2", "value2"))
{
Call2(); // key1:value1 key2:value2
using (new LogScope("key1", "value3"))
{
Call2(); // key1:value3 key2:value2
}
}
using (new LogScope("key1", "value3"))
{
Call2(); // key1:value3
}
}
void Call2()
{
foreach (var kv in LogScope.Context) Console.Write("'{0}':'{1}' ");
Console.WriteLine();
}
a) If you would like to use a per thread singleton, you definitely should not write your own, there are out of the box solutions. Mainly all modern DI framework supports instantiate option like singletons, and singletons per thread. Just an example from Ninject:
or if you would not like to use / implement interface:
After that binding whereever you ask for your DI container an instance of AnyThing you got a per thread singleton. AnyThing could be really anything: say a POCO.
EDIT: In case you would like any custom scoping, then just implement your scope definition, leave the rest of the container look for Custom in this page
b) You could use
ThreadLocal<T>
.EDIT: Before suggesting ThreadLocal one note about async expectation you mentioned in your question. Yes, ThreadLocal is not "compatible" with async.
However this is not the root of the problem: Thread affinity is not "compatible" with most of the concurrent programming design patterns (CDP), because many CDP uses the concept of thread "unaffinity", like pool, serializing to a message queue, marshaling to other thread etc. So having a thread affinity as an expectation, and having async work as an expectation seems to be not a good idea together, one should be dropped or replaced. Note this is not about the async keyword, this is about the async controlflow. END EDIT
Please refer to sample code in msdn doc