Adding context to your logs

joysaphine @ flickr

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: + " 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);"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:

<conversionPattern value="%timestamp [%thread] %level %logger %property{uid} - %message%newline" />

That is all, ain’t this cleaner? BTW, have a look at NDC / ThreadContext.Stacks as well.

By Hitesh

Hi, I am your host, Hitesh. I am a tech enthusiast and dabble in a variety of subjects. Connect with me on Twitter or LinkedIn.