[ACCEPTED]-When to use 'nested diagnostic context' (NDC)?-ndc

Accepted answer
Score: 86

Want an example?

Take the following Web API 11 written using ASP.NET MVC4:

// GET api/HypervResource
public string Get()
{
    logger.Debug("Start of service test");
    System.Threading.Thread.Sleep(5000); // simulate work
    logger.Debug("End of service test");
    return "HypervResource controller running, use POST to send JSON encoded RPCs";
}

When server concurrent 10 HTTP Requests are made, the logging can 9 get interleaved. E.g.

2013-06-27 13:28:11,967 [10] DEBUG HypervResource.WmiCalls [(null)] - Start of service test
2013-06-27 13:28:12,976 [12] DEBUG HypervResource.WmiCalls [(null)] - Start of service test
2013-06-27 13:28:14,116 [13] DEBUG HypervResource.WmiCalls [(null)] - Start of service test
2013-06-27 13:28:16,971 [10] DEBUG HypervResource.WmiCalls [(null)] - End of service test
2013-06-27 13:28:17,979 [12] DEBUG HypervResource.WmiCalls [(null)] - End of service test
2013-06-27 13:28:19,119 [13] DEBUG HypervResource.WmiCalls [(null)] - End of service test

In this simple example, you 8 could use the thread id to distinguish requests, but 7 that can get tricky as the log file grows 6 in complexity.

A better alternative is 5 to provide unique identifiers that group 4 together log messages for the same request. We 3 can update the code as to the following:

// GET api/HypervResource
public string Get()
{
    using(log4net.NDC.Push(Guid.NewGuid().ToString()))
    {
        logger.Debug("Start of service test");
        System.Threading.Thread.Sleep(5000); // simulate work
        logger.Debug("End of service test");
        return "HypervResource controller running, use POST to send JSON encoded RPCs";
    }
}

This 2 produces a log that you can grep to see 1 the issues associated with a specific request. E.g.

2013-06-27 14:04:31,431 [11] DEBUG HypervResource.WmiCalls [525943cb-226a-43c2-8bd5-03c258d58a79] - Start of service test
2013-06-27 14:04:32,322 [12] DEBUG HypervResource.WmiCalls [5a8941ee-6e26-4c1d-a1dc-b4d9b776630d] - Start of service test
2013-06-27 14:04:34,450 [13] DEBUG HypervResource.WmiCalls [ff2246f1-04bc-4451-9e40-6aa1efb94073] - Start of service test
2013-06-27 14:04:36,434 [11] DEBUG HypervResource.WmiCalls [525943cb-226a-43c2-8bd5-03c258d58a79] - End of service test
2013-06-27 14:04:37,325 [12] DEBUG HypervResource.WmiCalls [5a8941ee-6e26-4c1d-a1dc-b4d9b776630d] - End of service test
2013-06-27 14:04:39,453 [13] DEBUG HypervResource.WmiCalls [ff2246f1-04bc-4451-9e40-6aa1efb94073] - End of service test
Score: 25

In a server application such as ASP.NET.

For 2 example, you can push information about 1 the current request on to the NDC.

Score: 20

These feature come in handy when you have 10 lots of logs to go through. When would you 9 have lots of logs? Diagnosing weird bug 8 on a production system with interleaving 7 outputs. Having more contexts gives you 6 way to filter the output or not outputting 5 unneeded logs.

Another case nested contexts 4 could be useful is if a method or some feature 3 is called several times in different contexts 2 and you need a way to distinguish between 1 them.

Score: 10

NDC.Push has been deprecated. The preferred way 2 now (ThreadContext.Stacks["NDC"]) is this:

var disposable = ThreadContext.Stacks["NDC"].Push("context");
try
{
  Log.Info("begin"); // optional, but nice
  ...
}
finally
{
  Log.Info("end"); // optional, but nice
  disposable.Dispose();
}

Remember to check your conversion 1 pattern so that it includes %property{NDC}:

<layout type="log4net.Layout.PatternLayout">
  <conversionPattern
    value="%date [%2thread] %-5level [%property{NDC}] - %.10240message%newline" />
</layout>

More Related questions