views:

45

answers:

1

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.

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:

http://stackoverflow.com/questions/175129/what-are-best-practices-for-using-thread-local-storage-in-net

http://stackoverflow.com/questions/1007277/net-logical-thread-and-thread-local-storage

Thanks in advance!

+1  A: 

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.

Jon Skeet