Feel Good.

25 февраля 2010

Hello, NLog

Логирование - неотъемлемая часть любого проекта. Не секрет, что каждый из нас, хотя бы раз написал свою собственную систему логирования. А задумывались насколько она у Вас гибкая? Начиная новый проект, вы снова пишите новую систему логирования? До сих пор используете Console.WriteLine(...) в качестве ведения лога? Вывод один, используйте готовый logging framework, например: log4net, NLog, Logging Application Block от Microsoft и другие. Преимущества готовых logging framework-ов от самодельных:
  1. Гибкая настройка лога.
  2. Широкие возможности.
  3. Наличие конфигурационных xml-файлов с xsd-схемами.
  4. Готовое стабильное решение (экономия времени на отладке).
  5. Наличие документации (форумов, блогов).
У каждого из них есть свои плюсы и минусы. В статье мы познакомимся с одном из них - NLog.

На вой взгляд, NLog кажется более простым в конфигурировании(log4net) и менее требователен к ресурсам(Logging Application Block) при том, что он выполняет те же задачи, поэтому именно ему я и отдаю предпочтение. Начать работу с NLog действительно очень просто, ведь для этого от Вас требуется только понимание основных принципов NLog, а именно в правильном конфигурировании двух основных частей: targets и rules и в выборе оптимального уровня логирования.

Рассмотрим подробнее, каждое сообщение имеет уровень логирования(log level), в лог заноситься только то сообщение, уровень логирования которого ниже указанного в правиле логирования. NLog поддерживает следующие уровни:

  • Trace - детальное логирование (все сообщения)
  • Debug - отладочное логирование, менее детально чем Trace
  • Info - логирование информационных сообщений
  • Warn - логирование сообщений о предупреждениях
  • Error - логирование сообщений об ошибках
  • Fatal - логирование сообщений о критических ошибках(только критические сообщения)
  • Off - логирование сообщений не производиться
Например, выбрав уровень Error, в лог попадут сообщения типа Error и Fatal, остальные же проигнорируются. Выбрав уровень логирования необходимо задать правило логирования (logger), которое задается в блоке rules, другими словами, задать КАК будет осуществляться логирование: указав источник (name) сообщений(например класс, набор классов из пространства имен и прочие), уровень логирования (level), ссылку КУДА мы будем делать вывод (target). Описание КУДА осуществлять вывод производиться в блоке targets, в котором задается: вид логирования(type)(в файл, на консоль, почту, в базу и другие), формат сообщения(layout) (с указанием даты, уровня, имени источника и прочего).

Рассмотрим простой пример, допустим, нам надо осуществлять логирование следующим образом: сообщения уровня Debug выводить на консоль, а сообщения уровня Trace (все сообщения) выводить в файл. При этом, в лог должно записываться: время сообщения (а в случае записи в файл еще текущую дату), уровень сообщения и само сообщение.

Для того чтобы начать работу с NLog необходимо скачать с сайта последний дистрибутив и установить его на жесткий диск. После чего, можно приступать к созданию нового проекта NLogExample, в котором надо добавить ссылку на библиотеку NLog.dll. Как и любая система, NLog нуждается в настройке, для этого добавим в проект файл конфигурации NLog.config, задав файлу опцию "Copy to Output Directory" (это нужно для того, чтобы файл NLog.config при спорке проекта автоматически перемещался в выходную директорию):

<?xml version="1.0" encoding="utf-8" ?>

 

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 

    <targets>

        <target name="console" xsi:type="Console" layout="${date:format=HH\:mm\:ss}|${level}|${message}" />

        <target name="file"  xsi:type="File" fileName="${basedir}/nlog.txt" layout="${date}|${level}|${message}" />

    </targets>

 

    <rules>

        <logger name="*" minlevel="Debug" writeTo="console" />

        <logger name="*" minlevel="Trace" writeTo="file" />

    </rules>

 

</nlog>


Наш логгер настроен, и мы можем начать его использовать, для этого необходимо получить на него ссылку, это делается следующим образом:

Logger logger = LogManager.GetCurrentClassLogger();


Полученный нами экземпляр логгера содержит все необходимые методы (Trace, Debug, Info, Warn, Error, Fatal, и другие) для записи сообщения в лог. Каждый такой метод задает уровень логирования для сообщения. Поэтому если мы хотим записать в лог сообщение типа Info, мы должны использовать одноименный метод:

using System;

using NLog;

namespace NLogExample

{

    class Program

    {       

        private static Logger logger = LogManager.GetCurrentClassLogger();

 

        static void Main(string[] args)

        {

            logger.Trace("logger.Trace");           

            logger.Debug("logger.Debug");

            logger.Info("logger.Info");

            logger.Warn("logger.Warn");

            logger.Error("logger.Error");

            logger.Fatal("logger.Fatal");

        }

    }

}


В итоге, если запустить приложение, на консоли мы увидим сообщения Debug, Info, Warn, Error, Fatal, а в файле(расположенного в том же каталоге где и сборка) еще и Trace сообщения.


UPD: Смотрим логи. NLogViewer
UPD: Настройка логов на примере NLog

22 комментария:

  1. Проблема в том что при реализации функции записи в лог очень быстро можно получить загромождение основной логики приложения.

    ОтветитьУдалить
  2. @BayburinMarat
    Если код нуждается в логе, то тут ничего не поделаешь. Разумеется, вести лог надо там, где это действительно нужно и в разумных пределах.

    ОтветитьУдалить
  3. буквально вчера настраивал log4net и заметил удивительное сходство с NLog в плане xml настроек - если заменить "target" на "appender" и "rules" на "root" - то получится файл настроек log4net. Так в чем же тогда преимущество NLog?

    ОтветитьУдалить
  4. @Артём
    Удобство и простота NLog.
    Интеграция с Visual Studio 2002/2005/2008/2010.
    Дистрибутив NLog можно скачать в виде инсталл-файла, с возможностью гибкой инсталляции. Да и конфигурация NLog будет попроще. А сайт NLog(http://nlog-project.org) мне показался удобнее, чем у log4net.

    Кстати, вот еще сравнение:
    http://www.dotnetlogging.com/comparison/

    ОтветитьУдалить
  5. Да, сравнение показывает, что возможности NLog и Log4Net примерно одинаковы, но вот когда я зашел на официальный сайт NLog, залез в документацию и поглядел все доступные классы в пространстве имен
    NLog.Targets - был приятно удивлен разнообразием возможностей. Тут тебе и запись в базу, и в файл, и вызов сервиса, и EventLog, да что там говорить - даже вывод в MessageBox есть! Но вот telnet я не нашел, а в log4net он есть (хотя не представляю нужность этой опции). В общем, для себя я решил - опишу общий интерфейс для логирования, а экземпляр логера буду создавать через spring (ну, или через подобную библиотеку) - это позволит уменьшить связность модулей (что характерно для DI (или IoC)) и реализовать любые логеры, которые мне будет удобно использовать. В случае, если мне срочно понадобится использовать NLog вместо log4net - просто подключу библиотеку и кое что поменяю в настройках spring.

    ОтветитьУдалить
  6. @Артём
    Да, как вариант можно и так. Или смотрите, например, если Вы используете log4net, вы можете для него написать собственный Appender, который будет логировать в NLog. Получается следующая схема: Вы логируете в log4net, тот используя ваш Appender, который будет перенаправлять вывод в NLog.

    ОтветитьУдалить
  7. Дело в том, что в Вашем варианте у меня будут одновременно использоваться оба логера - что негативно скажется и на используемой памяти, и на быстродействии. К тому же, если я захочу использовать другой инструмент логирования или написать свой - то мне придется менять код системы везде, где использую log4net или снова писать аппендеры - а я слишком ленив для этого ;)

    ОтветитьУдалить
  8. А мне все ж по душе System.Diagnostics - там более чем достаточно средств для логирования, нет проблем написать обвязку для более сложного логирования, нет проблем дописать провайдер для логирования ("источник"). И не нужно ничего никуда встраивать - решение из разряда: "сел и поехал". Сначала было тяжеловато настраивать, но когда приноровился - стало даже очень удобно. И настройкки все в *.config, а не х.з. где.
    Кстати, большенство серьезных продутов от MS использует именно эту методику логирования.
    Кстати, не знаю как на счет остальных логеров, а вот методы логирования Debug не вставляются физически в код релизных сборок, что правильно. Хочешь отлаживать - отлаживай, все пишется; продакшен - там только методы Trace работают.

    ОтветитьУдалить
  9. Я же не спорю с тобой, какой инструмент логирования лучше - я просто хочу сказать, что удобней использовать не конкретный класс логгера, а самописный интерфейс. Тогда ты можешь написать адаптер к этому интерфейсу для любого инструмента логирования, а экземпляр логгера получать через DI фреймворк - в этом случае, системе будет по барабану, какой логер - log4net, nlog, да хоть самописный и настройки для этих логгеров можешь получать как угодно - всё это не повлияет никаким макаром на основную логику системы.

    ОтветитьУдалить
  10. @Артём
    Да идея написать собственный интерфейс и реализацию интересная.
    Я помню давно делал нечто подобное, а именно возможность переключения между DI фреймворками (общий интерфейс IDependencyResolver для Unity, Ninject и прочих). Скажу честно, это не так легко как кажется. Наверное некоторые вещи надо выбирать сразу и навсегда :), например, выбор конкретного DI фреймворка или логгера. Хотя логгер не сравним с DI.

    ОтветитьУдалить
  11. Здравствуйте Илья. Спасибо за обзор, очень кстати. С логгированием более менее ясно, а как быть с выводом содержимого лога пользователю? Есть ли готовые решения, в частности для NLog?

    ОтветитьУдалить
  12. @Dmitry Ilin

    Спасибо.
    Да есть такое, особенно среди платных :).
    Ключевые слова "log viewer", "log analyzer" и прочие. Но они не зависят от системы логирования, будь это NLog или log4net и прочие, так как по логу трудно будет сказать какой системой логирования его создали.

    ОтветитьУдалить
  13. @Dmitry Ilin

    Можно попробовать вот это:
    http://svn.nlog-project.org/repos/nlog/trunk/NLogViewer/

    ОтветитьУдалить
  14. Спасибо за наводку, посмотрю на досуге ;)

    ОтветитьУдалить
  15. Дело вкуса. Для меня log4net не плох и не так сложен.

    ОтветитьУдалить
  16. Для тех кто использует NLog в своих проектах, я на днях написал статью про NLogViewer.
    http://www.handcode.ru/2010/04/nlogviewer.html

    ОтветитьУдалить
  17. Подскажите, пожалуйста, как передавать свои параметры в NLog? К примеру, мне нужно занести некую информацию в "Host Name", "User Name" и т.д.

    ОтветитьУдалить
  18. Ответы
    1. Спасибо, но не совсем то. Мне нужно в UserName передать данные. А если я просто item использую - не то. Кроме того, в этом способе мне придётся в каждом вызове "логгера" писать:

      LogEventInfo theEvent = new LogEventInfo(LogLevel.Debug, "", "Pass my custom value");
      theEvent.Properties["MyValue"] = "My custom string";
      Program.logger.Log(theEvent);

      В log4net я раз указал параметры и они автоматически дописывались к каждой строке в лог-файле. А тут у меня получаются 2 разные строки:
      в первой у меня выводится информация, нужная мне (хотя и не совсем то), а во второй - нет... :(

      Удалить
  19. Logger.Trace("Got error:" + resp.StatusCode.ToString() + " getting from URI " + URI.ToString(), "HTTP",Logtype.Error); ошибка выходит в третьем параметре ошибка

    ОтветитьУдалить