UPDATED on 11/18/2014 - While browsing the log4net source repository, I found that the implementation of LogicalThreadContext was modified in November 2011 to that it stores its properties using CallContext.LogicalSetData (and gets them using LogicalGetData). This is important because that means that LogicalThreadContext should now work correctly. Any data stored in LogicalThreadContext should be "flowed" to any child threads or tasks. This compares to ThreadContext (and the old implementation of LogicalThreadContext) where data stored in the context would remain local to the current thread and NOT flowed to child threads/tasks.
If you are interested, here is the change:
Hopefully someone happening upon this old question will find this information useful.
log4net provides two different "thread context" objects: ThreadContext and LogicalThreadContext, each of which has a property bag, Properties. ThreadContext has a ThreadContextProperties bag while LogicalThreadContext has a LogicalThreadContextProperties bag.
ThreadContext is perhaps more commonly known as "MDC". LogicalContext is perhaps more commonly known as "LDC". I will use the short name for the rest of this post.
MDC.Properties is implemented using System.Threading.Thread.SetData while LDC.Properties is implemented using using System.Runtime.Remoting.Messaging.CallContext.SetData.
For comparison, NLog only exposes "MDC" (now known as MappedDiagnosticContext) to store thread local properties. NLog's implementation uses System.Threading.Thread.SetData, so its implementation is the same as log4net's.
In both log4net and NLog, the "MDC" properties are stored in a dictionary which is itself stored in the thread local storage.
In a case like this, would storing the dictionary in a class member variable decorated with [ThreadStatic] have been equivalent?
[ThreadStatic]
private static IDictionary<string, string> threadProperties;
What be the equivalent (or similar) declaration using .NET 4.0's new ThreadLocal class?
Ultimately, what is the real, practical, difference between LDC and MDC? Even after reading the MSDN topics linked above, it is not clear to me. When would you really use one over the other? It seems like the vast majority of the references/examples that I see for log4net and context is for GDC (global - which I understand), NDC (nested - which I also understand), and MDC. Most of the references that I can find to LDC (or LogicalThreadContext) when googling are related to checkins into the log4net source code repositories, not real-world usage. LDC almost never comes up in questions or examples.
I did find this link that offers some pretty good information about the difference from one of the log4net developers, Nicko Cadell, but it is still not clear to me.
A larger question, not directly related to log4net is what is the practical difference between Thread.SetData and CallContext.SetData?
According to the CallContext MSDN article, CallContext data can be propagated to another AppDomain. To be propagated, a data item stored in the CallContext must expose the ILogicalThreadAffinative interface. So, that seems to be one difference between Thread.SetData and CallContext.
According the Nicko Cadell link, log4net does not implement ILogicalThreadAffinative, so the LDC properties will not be propagated.
Maybe there is enough here that I should be able answer my own question, maybe not. I am still working on understanding.
If you use log4net, do you every use MDC, LDC, both? If you use MDC, is it because most of the "real world" examples seem to use it? If you use LDC, to you have a specific reason for using it? If you use both, how do you choose when to use which?
Note that I have seen some articles regarding MDC (and maybe LDC) maybe not working right in ASP.net applications due to thread switching. I am not particularly interested in this problem as I am not working in ASP.net.
Actually, I have found a couple of useful posts here on SO that might contribute to the discussion:
What are best practices for using thread local storage in .NET?
.Net: Logical thread and Thread Local Storage?
Thanks in advance!
Warning: this is guesswork.
Suppose you're writing a server, and serving a request means you have to talk to a bunch of different services. Being a thoroughly modern developer, you make these requests asynchronously, coordinating when everything's replied (or timed out) in order to respond to the original request.
That means the work corresponding to a single request is scattered amongst many different threads (processing the web service responses asynchronously). I suspect that CallContext
is used to propagate the "everything I'm doing is because of this one incoming request" to different threads, so that you can gather all the logs for that request together. ThreadContext
wouldn't help there. Note that I'm assuming all the work is being performed in a single AppDomain, so your concern there wouldn't be a problem.