Подключаем Nuget-пакет
Правой клавишей на References и выбираем Manage Nuget Packages:
В поисковой строке набираем log4net и находим пакет (в выдаче на первом месте):
Жмём кнопку «Install» и после установки пакета закрываем окно.
Создаем класс — обработчик.
Добавляем новый класс:
И называем его Logger:
Добавляем следующий код:
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)
KvanTTT
23.09.2016 01:07+4Слабоватая статья. Было бы интересней, например, читать о достоинствах и недостатках логгеров под .NET (log4net, NLog, Serilog и т.д.), а не об очередной реализации "Hello world" для логгера.
alz72
23.09.2016 10:11Порой программист начинает именно с реализации «Hello world» — кто знает, может для кого-то это станет первым шагом в использовании логгеров…
Melz
23.09.2016 17:06Ну основное преимущество NLog для обычного человека в том, что он все нужные файлы добавляет сам.
Включая сниппет для студии для более удобного использования, «nlogger».
Hydro
23.09.2016 06:55-1Вроде как весь прогрессивный мир использует Common.Logging как API логгирования.
ParaPilot
23.09.2016 09:53Простите, но чем ваша статья отличается от документации по log4net на оф.сайте кроме картинок из VS?
Вот если бы вы описали методы решения проблем при работе с log4net, тогда статье не было цены. Особенно описание решения проблем с некорректным конфигом или нежелания библиотеки читать конфиг были бы очень полезны.
Bonart
23.09.2016 10:08+1И зачем при живом serilog нужно это старье?
alz72
23.09.2016 10:13Вы можете озвучить преимущества serilog перед log4net?
Bonart
23.09.2016 10:52+2Структурное логирование.
Результат сразу имеет вид кортежа с именованными полями без дополнительных усилий, логировать можно напрямую в какой-нибудь Elastic Search без дорогого и косячного парсинга.
Это реально небо и земля.alz72
23.09.2016 11:13-1Вы имели в виду этот формат?
Ну да — он выводит данные в Json. Возможно это удобнее во многих случаях, но тот же log4net умеет писать напрямую во многие СУБД (MS SQL Server, Oracle, IBM DB2, SQLite), поддерживает протоколы tcp, smtp — кому-то это будет ближе.
А кому-то больше ничего и не надо — дело вкуса…Bonart
23.09.2016 11:34Вопрос не в конкретном формате вывода, а в том, что сообщение в serilog — это не просто строка, но строка плюс кортеж с именованными полями. Выходные данные структурированы сразу, а не после парсинга.
Это позволяет легко писать в любые базы данных.
Текстовые логи на этом фоне скорее вредны чем бесполезны.alz72
23.09.2016 11:42-1Это позволяет легко писать в любые базы данных.
Да — конечно, особенно легко в NoSql.
Но — вам все равно придется для этого писать код!
Выходные данные структурированы сразу, а не после парсинга.
В случае СУБД — отнюдь, там все прекрасно стурктуировано, и в конфиге вы сами определяете структуру.
Текстовые логи на этом фоне скорее вредны чем бесполезны.
Как я уже писал — это дело вкуса и конкретной ситуации…Bonart
23.09.2016 11:58+1В случае СУБД — отнюдь, там все прекрасно стурктуировано, и в конфиге вы сами определяете структуру.
И как вы будете поддерживать более одной структуры на весь лог?
В serilog структура определяется самим сообщением плюс можно централизованно навесить дополнительные поля. В "старой школе" сообщение — всего лишь строка. Из serilog разные сообщения можно естественным сохранять в разные структуры, получая готовую базу для анализа. После log4net сообщения для извлечения информации надо парсить.alz72
23.09.2016 12:04И как вы будете поддерживать более одной структуры на весь лог?
Да — тут преимущества NoSql раскрываются во всей красе. Тут согласен целиком и полностью.Bonart
23.09.2016 12:50Наличие готовой структуры в сообщениях поможет и при сохранении в реляционную базу — ценой потери универсальности алгоритма записи. Но экономия по сравнению с вариантом "отформатировали в строку-распарсили" все равно колоссальная.
alz72
23.09.2016 13:16Но экономия по сравнению с вариантом «отформатировали в строку-распарсили» все равно колоссальная.
При записи напрямую в СУБД никакого парсинга не происходитBonart
23.09.2016 13:26+1При записи напрямую в СУБД никакого парсинга не происходит
И после log4net в базе оказывается строка вида "Куплено 6 единиц товара Бритва по цене 75 рублей за штуку". Для анализа по логам эту строку надо парсить.
После serilog в таблице покупок добавится запись с полями:
- Count = 6
- Product = Бритва
- Price = 75
Исходные данные для анализа в уже готовом виде, парсинг не нужен.
alz72
23.09.2016 15:39И после log4net в базе оказывается строка вида «Куплено 6 единиц товара Бритва по цене 75 рублей за штуку». Для анализа по логам эту строку надо парсить.
Легко
Logger.Log.Info($"Куплено {Count} единиц товара {Product} по цене {Price} рублей за штуку");
alz72
23.09.2016 16:00Но в одном вы правы — после того как лог создан — для его анализа нужен парсинг. И для этой цели (анализа) намного удобнее serilog.
Bonart
23.09.2016 17:40А учитывая, что лог нужен ТОЛЬКО для анализа...
fromAlex
24.09.2016 11:28Судя по вашей долгой дискуссии — вы по разному понимаете анализ. Грамотно сформированный лог в анализе не нуждается сам по себе, анализируют результаты записанные в лог. Что вам автор и пытается донести. Вы же пытаетесь доказать что лог впоследствии надо «анализировать» — а это не всегда так…
EjikVTumane
На Хабре нужны пошаговые инструкции ко всем библиотекам? ;)
alz72
На самом деле для меня причиной был комментарий
— поэтому и написал инструкцию для быстрого внедрения, для случая когда вдумываться особо некогда. да и не хочется…workless
Ну тут хоть объяснили как добавить логгер. Мне надо было добавить два разных логгера в программе, методом «тыка» полчаса разбирался :)
В обычных статьях «Вот смотрите пишем в лог» и код типа
private static ILog log = LogManager.GetLogger(«LogManager»);
Думаешь «Агааа. Значит надо имя типа». А тут объяснили что имя логгера нужно указать.
Когда поймешь различия в логерах и аппендерах все понятно, а поначалу не все так явно.
p.s. Не, документацию не читал в тот момент.