Как ни странно, но оказалось, что пошаговой инструкции для такой популярной библиотеки, как log4net, еще нет на Хабре. Исправляю эту недоработку.

Подключаем Nuget-пакет


Правой клавишей на References и выбираем Manage Nuget Packages:

image

В поисковой строке набираем log4net и находим пакет (в выдаче на первом месте):

image

Жмём кнопку «Install» и после установки пакета закрываем окно.

Создаем класс — обработчик.


Добавляем новый класс:

image

И называем его Logger:

image

Добавляем следующий код:

public static class Logger
    {
        private static ILog log = LogManager.GetLogger("LOGGER");


        public static ILog Log
        {
            get { return log; }
        }

        public static void InitLogger()
        {
            XmlConfigurator.Configure();
        }
    }

Не забудьте поставить ссылку на сборки в начале файла:

using log4net;
using log4net.Config;

Настраиваем конфиг


Теперь переходим к конфигу. В файле конфигурации App.config (или Web.config — если у вас это веб приложение) нужно внутри секции configuration добавить секцию log4net со следующим содержимым:

 <log4net>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="Logs\Example.log"/>
      <param name="AppendToFile" value="true"/>
      <maxSizeRollBackups value="10"/>
      <maximumFileSize value="5MB"/>
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%d  %-5p %m%n"/>
      </layout>

    </appender>

    <logger name="LOGGER">
      <appender-ref ref="LogFileAppender"/>
    </logger>
  </log4net>

И сразу же после секции configuration должна стоять секция configSections, если её нет — добавьте (она должна быть первой) и внутри неё добавьте код для log4net. Если она одна — то выглядеть должно так:

   <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a" />
  </configSections>   

Полностью конфиг у меня выглядит так:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a" />
  </configSections>   
  <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>

  <log4net>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="Logs\Example.log"/>
      <param name="AppendToFile" value="true"/>
      <maxSizeRollBackups value="10"/>
      <maximumFileSize value="5MB"/>
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%d  %-5p %m%n"/>
      </layout>

    </appender>

    <logger name="LOGGER">
      <appender-ref ref="LogFileAppender"/>
    </logger>
  </log4net>
</configuration>

Как видите имя логгера:

<logger name="LOGGER">

Совпадает с именем которое мы задали в классе Logger:

private static ILog log = LogManager.GetLogger("LOGGER");

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

Logger.InitLogger();//инициализация - требуется один раз в начале

Logger.Log.Info("Ура заработало!");

После запуска будет создана папка Logs и внутри будет файл Example.log с записью лога:

2016-09-21 10:59:41,104  INFO  Ура заработало!

Использование


Давайте немного изменим логику логирования. Выделим записи уровня Error и выше в отдельный файл (например отладочных записей у нас достаточно много и спам читать неудобно). Для этого добавим в конфиг следующее:

<appender name="ErrorFile" type="log4net.Appender.RollingFileAppender">
      <file value="Logs\Equifax_SenderError.log"/>
      <appendToFile value="true"/>
      <maximumFileSize value="5MB"/>
      <maxSizeRollBackups value="10"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%level %thread %logger - %message%newline"/>
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR"/>
        <levelMax value="FATAL"/>
      </filter>
    </appender>

B добавим ссылку на аппендер:

    <logger name="LOGGER">
      <appender-ref ref="LogFileAppender"/>
      <appender-ref ref="ErrorFile"/>
    </logger>

Теперь секция log4net выглядит так:

<log4net>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="Logs\Example.log"/>
      <param name="AppendToFile" value="true"/>
      <maxSizeRollBackups value="10"/>
      <maximumFileSize value="5MB"/>
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%d  %-5p %m%n"/>
      </layout>

    </appender>
    <appender name="ErrorFile" type="log4net.Appender.RollingFileAppender">
      <file value="Logs\ExampleError.log"/>
      <appendToFile value="true"/>
      <maximumFileSize value="5MB"/>
      <maxSizeRollBackups value="10"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d %level %thread %logger - %message%newline"/>
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR"/>
        <levelMax value="FATAL"/>
      </filter>
    </appender>
    <logger name="LOGGER">
      <appender-ref ref="LogFileAppender"/>
      <appender-ref ref="ErrorFile"/>
    </logger>
  </log4net>

И если мы изменим код программы на:

            Logger.InitLogger();//инициализация - требуется один раз в начале
            Logger.Log.Info("Ура заработало!");
            Logger.Log.Error("Ошибочка вышла!");

То увидим что появился еще один файл ExampleError.log — в него будут выводиться только ошибки:

2016-09-21 11:14:58,933 ERROR 8 LOGGER - Ошибочка вышла!

Ну а за подробностями стоит обратиться к официальной документации. Спасибо за внимание!
Поделиться с друзьями
-->

Комментарии (31)


  1. EjikVTumane
    23.09.2016 00:02
    +7

    Как ни странно, но оказалось, что пошаговой инструкции для такой популярной библиотеки, как log4net, еще нет на Хабре.

    На Хабре нужны пошаговые инструкции ко всем библиотекам? ;)


    1. alz72
      23.09.2016 07:05

      На самом деле для меня причиной был комментарий

      "… Уже давно собираюсь продвинуться на новую систему логирования, посмотрю в эту сторону, однако я люблю такие простенькие вещи писать полностью без дополнительных библиотек, в сложном проекте — конечно же буду ..."
      — поэтому и написал инструкцию для быстрого внедрения, для случая когда вдумываться особо некогда. да и не хочется…


    1. workless
      23.09.2016 08:52

      Ну тут хоть объяснили как добавить логгер. Мне надо было добавить два разных логгера в программе, методом «тыка» полчаса разбирался :)

      В обычных статьях «Вот смотрите пишем в лог» и код типа
      private static ILog log = LogManager.GetLogger(«LogManager»);

      Думаешь «Агааа. Значит надо имя типа». А тут объяснили что имя логгера нужно указать.
      Когда поймешь различия в логерах и аппендерах все понятно, а поначалу не все так явно.

      p.s. Не, документацию не читал в тот момент.


  1. IL_Agent
    23.09.2016 00:24

    оно uwp умеет?


    1. alz72
      23.09.2016 07:17

      Врать не буду, не пробовал. Но интуитивно мне кажется что никаких сложностей быть не должно.


    1. workless
      23.09.2016 08:57

      первая ссылка гугла говорит что нет
      http://stackoverflow.com/questions/32886613/logger-for-windows-10-uwp-app


      1. alz72
        23.09.2016 09:36

        как только столкнусь с uwp — обязательно попробую и напишу


  1. KvanTTT
    23.09.2016 01:07
    +4

    Слабоватая статья. Было бы интересней, например, читать о достоинствах и недостатках логгеров под .NET (log4net, NLog, Serilog и т.д.), а не об очередной реализации "Hello world" для логгера.


    1. alz72
      23.09.2016 10:11

      Порой программист начинает именно с реализации «Hello world» — кто знает, может для кого-то это станет первым шагом в использовании логгеров…


    1. Melz
      23.09.2016 17:06

      Ну основное преимущество NLog для обычного человека в том, что он все нужные файлы добавляет сам.
      Включая сниппет для студии для более удобного использования, «nlogger».


  1. Hydro
    23.09.2016 06:55
    -1

    Вроде как весь прогрессивный мир использует Common.Logging как API логгирования.


  1. ParaPilot
    23.09.2016 09:53

    Простите, но чем ваша статья отличается от документации по log4net на оф.сайте кроме картинок из VS?
    Вот если бы вы описали методы решения проблем при работе с log4net, тогда статье не было цены. Особенно описание решения проблем с некорректным конфигом или нежелания библиотеки читать конфиг были бы очень полезны.


  1. alz72
    23.09.2016 09:59

    Частично я уже ответил на данный вопрос чуть выше, а отличие в том что можно по шагам воспроизвести инструкцию и пользоваться логом «здесь и сейчас».
    Но за пожелания спасибо, я обязательно учту их в будущем.


  1. Bonart
    23.09.2016 10:08
    +1

    И зачем при живом serilog нужно это старье?


    1. alz72
      23.09.2016 10:13

      Вы можете озвучить преимущества serilog перед log4net?


      1. Bonart
        23.09.2016 10:52
        +2

        Структурное логирование.
        Результат сразу имеет вид кортежа с именованными полями без дополнительных усилий, логировать можно напрямую в какой-нибудь Elastic Search без дорогого и косячного парсинга.
        Это реально небо и земля.


        1. alz72
          23.09.2016 11:13
          -1

          Вы имели в виду этот формат?

          Ну да — он выводит данные в Json. Возможно это удобнее во многих случаях, но тот же log4net умеет писать напрямую во многие СУБД (MS SQL Server, Oracle, IBM DB2, SQLite), поддерживает протоколы tcp, smtp — кому-то это будет ближе.

          А кому-то больше ничего и не надо — дело вкуса…


          1. Bonart
            23.09.2016 11:34

            Вопрос не в конкретном формате вывода, а в том, что сообщение в serilog — это не просто строка, но строка плюс кортеж с именованными полями. Выходные данные структурированы сразу, а не после парсинга.
            Это позволяет легко писать в любые базы данных.
            Текстовые логи на этом фоне скорее вредны чем бесполезны.


            1. alz72
              23.09.2016 11:42
              -1

              Это позволяет легко писать в любые базы данных.

              Да — конечно, особенно легко в NoSql.
              Но — вам все равно придется для этого писать код!

              Выходные данные структурированы сразу, а не после парсинга.

              В случае СУБД — отнюдь, там все прекрасно стурктуировано, и в конфиге вы сами определяете структуру.

              Текстовые логи на этом фоне скорее вредны чем бесполезны.

              Как я уже писал — это дело вкуса и конкретной ситуации…


              1. Bonart
                23.09.2016 11:58
                +1

                В случае СУБД — отнюдь, там все прекрасно стурктуировано, и в конфиге вы сами определяете структуру.

                И как вы будете поддерживать более одной структуры на весь лог?
                В serilog структура определяется самим сообщением плюс можно централизованно навесить дополнительные поля. В "старой школе" сообщение — всего лишь строка. Из serilog разные сообщения можно естественным сохранять в разные структуры, получая готовую базу для анализа. После log4net сообщения для извлечения информации надо парсить.


                1. alz72
                  23.09.2016 12:04

                  И как вы будете поддерживать более одной структуры на весь лог?

                  Да — тут преимущества NoSql раскрываются во всей красе. Тут согласен целиком и полностью.


                  1. Bonart
                    23.09.2016 12:50

                    Наличие готовой структуры в сообщениях поможет и при сохранении в реляционную базу — ценой потери универсальности алгоритма записи. Но экономия по сравнению с вариантом "отформатировали в строку-распарсили" все равно колоссальная.


                    1. alz72
                      23.09.2016 13:16

                      Но экономия по сравнению с вариантом «отформатировали в строку-распарсили» все равно колоссальная.

                      При записи напрямую в СУБД никакого парсинга не происходит


                      1. Bonart
                        23.09.2016 13:26
                        +1

                        При записи напрямую в СУБД никакого парсинга не происходит

                        И после log4net в базе оказывается строка вида "Куплено 6 единиц товара Бритва по цене 75 рублей за штуку". Для анализа по логам эту строку надо парсить.
                        После serilog в таблице покупок добавится запись с полями:


                        1. Count = 6
                        2. Product = Бритва
                        3. Price = 75

                        Исходные данные для анализа в уже готовом виде, парсинг не нужен.


                        1. alz72
                          23.09.2016 15:39

                          И после log4net в базе оказывается строка вида «Куплено 6 единиц товара Бритва по цене 75 рублей за штуку». Для анализа по логам эту строку надо парсить.

                          Легко
                          Logger.Log.Info($"Куплено {Count} единиц товара {Product} по цене {Price} рублей за штуку");
                          


                          1. KvanTTT
                            23.09.2016 16:42

                            Это не парсинг, а форматирование строки. При парсинге нужно будет наоборот извлечь свойства Count, Product и Price из этой строки.


                            1. alz72
                              23.09.2016 16:58

                              Да — конечно, после того как лог сформирован — однозначно.


                        1. alz72
                          23.09.2016 16:00

                          Но в одном вы правы — после того как лог создан — для его анализа нужен парсинг. И для этой цели (анализа) намного удобнее serilog.


                          1. Bonart
                            23.09.2016 17:40

                            А учитывая, что лог нужен ТОЛЬКО для анализа...


                            1. fromAlex
                              24.09.2016 11:28

                              Судя по вашей долгой дискуссии — вы по разному понимаете анализ. Грамотно сформированный лог в анализе не нуждается сам по себе, анализируют результаты записанные в лог. Что вам автор и пытается донести. Вы же пытаетесь доказать что лог впоследствии надо «анализировать» — а это не всегда так…


  1. fromAlex
    24.09.2016 11:36

    Мне инструкция понравилась — четко и по полочкам. Взял на вооружение.