Когда использовать «вложенный диагностический контекст» (NDC)?
Вопрос
Играя с log4net, я видел возможность использовать для каждого потока стек контекстных меток, называемых NDC. Р>
Метки, помещенные в этот стек, отображаются в PatternLayout с указанием параметра формата % x
или % ndc
.
Использование выглядит примерно так:
ILog log = log4net.LogManager.GetLogger(...) ;
//pattern layout format: "[%ndc] - %message%newline"
log.Info("message 1");
using(log4net.NDC.Push("context")
{
using(log4net.NDC.Push("inner_context")
{
log.Info("message 2");
}
log.Info("message 3");
}
log.Info("message 4");
Вывод выглядит примерно так:
null - message 1
context inner_context - message 2
context - message 3
null - message 4
Когда вы находили эту функцию полезной в вашем опыте программирования с log4net?
Решение
В серверном приложении, таком как ASP.NET.
Например, вы можете отправить информацию о текущем запросе в НДЦ.
Другие советы
Хотите пример?
Возьмем следующий веб-API, написанный с использованием 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";
}
При выполнении одновременных HTTP-запросов к серверу ведение журнала может чередоваться. Например.
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
В этом простом примере вы могли бы использовать идентификатор потока, чтобы различать запросы, но это может оказаться непростым делом по мере усложнения файла журнала. Р>
Лучшей альтернативой является предоставление уникальных идентификаторов, которые группируют сообщения журнала для одного и того же запроса. Мы можем обновить код следующим образом:
// 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";
}
}
Это создает журнал, который вы можете использовать grep для просмотра проблем, связанных с конкретным запросом. Например. Р>
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
Эта функция пригодится, когда вам нужно просмотреть много журналов. Когда у вас будет много журналов? Диагностика странной ошибки в производственной системе с чередованием выходных данных. Наличие большего количества контекстов дает вам возможность фильтровать вывод или не выводить ненужные журналы.
В другом случае вложенные контексты могут быть полезны, если метод или некоторая функция вызывается несколько раз в разных контекстах, и вам нужен способ различать их.
NDC.Push
устарел. Теперь предпочтительный способ ( ThreadContext.Stacks [" NDC "]
) такой:
var disposable = ThreadContext.Stacks["NDC"].Push("context");
try
{
Log.Info("begin"); // optional, but nice
...
}
finally
{
Log.Info("end"); // optional, but nice
disposable.Dispose();
}
Не забудьте проверить шаблон конверсии, чтобы он включал в себя % property {NDC}
:
<layout type="log4net.Layout.PatternLayout">
<conversionPattern
value="%date [%2thread] %-5level [%property{NDC}] - %.10240message%newline" />
</layout>