[caption id="" align=“alignright” width=“316” caption=“joysaphine @ flickr”][/caption]
If you have ever worked on a multi-threaded application or even any application of significant scope, one of the unwritten requirement is a log file that helps in supporting the application.
The challenge is to be able to piece together all the scattered log entries that belong together, may be as a single transaction, or a user’s session. So the goal is to have a unique identifier in each log entry that will aid greping. If you have ever faced this, you either did it cleanly as I will detail below, or you had to hack in a ‘context’ to each log entry by appending / prefixing some unique id.
I will talk about the two most commonly used logging frameworks are Apache’s log4j and log4net.
The bad (obvious) way:
logger.info(uid + " I am doing something important"); logger.debug(uid + " I am doing something else");
The problems with this approach are
- might not have access to the uid in each function that is called
- need to remember to append the uid everywhere
- no way to do it in common code, utility libraries, etc.
The good news is, support for such a use case is baked into log4j and log4net.
Mapped Diagnostics Context - log4j MDC
MDC class has a thread local hashtable, in which you need to inject your context at the beginning of the transaction. All subsequent log entries will automatically contain the context as well.
MDC.put(“uid”, uid); logger.info(“I am doing something important”); logger.debug(“I am doing something else”);
logger.debug(“I am in a completely different code block.");
You can inject as many key/value pairs into MDC as you like. To print the values contained in the MDC context, change the logging format to include the %X{uid} or whatever keys you have passed to the MDC. Something like:
log4j.appender.R.layout.ConversionPattern=%p %t %c %X{uid} - %m%n
Now each log entry will contain the uid that was set in the beginning of the transaction.
ThreadContext.Properties - log4net
The equivalent in log4net is the ThreadContext.Properties
The usage is pretty similar, instead of MDC.put, call
ThreadContext.Properties[“uid”] = uid;
and include %property{uid} in the output format. Something like:
That is all, ain’t this cleaner? BTW, have a look at NDC / ThreadContext.Stacks as well.