Pull to refresh

Описание библиотек логирования

Reading time8 min
Views7.4K

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

Реализация собственных библиотек не занимает большого количества времени. Но данные решения будут малофункциональными и могут быть недотестированными. Поэтому разработчики используют готовые решения по управлению и записи логов во время работы программы.

Плюсы использования подобных решений заключается в том, что они являются более универсальными, т.к. должны работать с любым кодом и иметь возможность сохранять записи в различных форматах (от простой записи в консоль до записи результатов в базу данных).

Вторым плюсом можно выделить то, что готовые библиотеки многократно протестированы пользователями (другими разработчиками) и имеют меньший шанс отрицательно повлиять на программу, путем вылета приложения.

В данной статье представлен обзор трех наиболее популярных библиотек логирования: Log4Net, SeriLog, NLog.

Log4Net

Открытый исходный код: https://github.com/apache/logging-log4net

Лицензия: Apache-2.0 license

Официальный сайт: https://logging.apache.org/

Документация: https://logging.apache.org/log4net/

В данной библиотеке можно реализовывать поименные логгеры, т.е. можно получить собственный экземпляр логгера по типу класса или строковому ключу, использую статический класс LogManager.

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

Пример:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
   <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
 </configSections>
 <log4net>
   <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
     <file value="log.txt" />
     <appendToFile value="true" />
     <rollingStyle value="Size" />
     <maxSizeRollBackups value="10" />
     <maximumFileSize value="250KB" />
     <staticLogFileName value="true" />
     <layout type="log4net.Layout.PatternLayout">
       <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
     </layout>
   </appender>
   <root>
     <level value="ALL" />
     <appender-ref ref="RollingFileAppender" />
   </root>
 </log4net>
</configuration>

Паттерны отображения сообщения логов можно удобно собирать, используя следующую таблицу.

Также в файл конфигурации можно добавлять различные фильтры. Для этого нужно в конфиг лога добавить подобный блок:

Пример:

<filter type="log4net.Filter.LevelRangeFilter">
   <levelMin value="INFO" />
   <levelMax value="FATAL" />
</filter>

Другие фильтры представлены по ссылке.

Также в логгер можно помещать дополнительные модули (плагины), которые добавляют дополнительную возможность, например, удаленную запись логов на сервер. Подробнее о плагинах можно прочитать по ссылке.

Данная библиотека (как и все далее перечисленные) может устанавливать уровни сообщений от Debug до Fatal.

SeriLog

Открытый исходный код: https://github.com/serilog/serilog

Лицензия: Apache-2.0 license

Официальный сайт: https://logging.apache.org/

Документация: https://github.com/serilog/serilog/wiki

Данная библиотека изначально не имеет настройки путем изменения файлов конфигурации. Это влечет следующее неудобство – нельзя оперативно поменять конфигурацию для получения более подробных сведений у программы.

Пример создания логгера:

var log = new LoggerConfiguration()
   .MinimumLevel.Debug()
   .WriteTo.File("log.txt")
   .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information)
   .CreateLogger();

Для добавления возможности управления настройками логгера путем изменения конфигурации можно при установке пакета Serilog.Settings.AppSettings (подробный гайд по ссылке).

Также у данной библиотеки есть статическое свойство Logger класса Log, в которое помещается объект логгера.

При записи логов в строку можно добавлять операторы, которые помогают выводить значения объектов и простых структур.

Пример ввода сообщения:

var input = new { Latitude = 25, Longitude = 134 };
var time = 34;
log.Information("Processed {@SensorInput} in {TimeMS:000} ms.", input, time);

Оператор @ перед SensorInput инструктирует Serilog сохранять структуру переданного объекта. Если данный оператор опущен, Serilog распознает простые типы, такие как строки, числа, даты и время, словари и перечисления; все остальные объекты преобразуются в строки с помощью ToString(). «Структурирование» (вывод типа объекта) может быть принудительно выполнено с помощью оператора $ вместо @:

var unknown = new[] { 1, 2, 3 }
Log.Information("Received {$Data}", unknown);

В результате выведет:

Received "System.Int32[]"

Сегмент :000, следующий за TimeMS, представляет собой строку стандартного формата .NET, которая влияет на то, как свойство отображается (а не на то, как оно захватывается). Стандартный приемник консоли, включенный в Serilog, отобразит приведенное выше сообщение как:

09:14:22 [Information] Processed { Latitude: 25, Longitude: 134 } in 034 ms.

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

Log.Logger = new LoggerConfiguration()
   .WriteTo.Console()
   .WriteTo.File("log-.txt", rollingInterval: RollingInterval.Day)
   .CreateLogger();

Или устанавливать формат вывода:

 .WriteTo.File("log.txt",        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")

Также есть возможность устанавливать как общий минимальный уровень вывода логов, так и для каждого отдельного типа вывода сообщений:

Log.Logger = new LoggerConfiguration()
   .MinimumLevel.Debug()
   .WriteTo.File("log.txt")
   .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information)
   .CreateLogger();

В библиотеке Serilog можно добавлять фильтры для записей логов.

Пример:

Log.Logger = new LoggerConfiguration()
   .WriteTo.Console()
   .Filter.ByExcluding(Matching.WithProperty<int>("Count", p => p < 10))
   .CreateLogger();

Для каждой записи будет проверяться свойство Count, если оно удовлетворяет условию, то произведётся запись.

Также Serilog поддерживает подлоги, т.е. в основной объект класса лога можно поместить другой способ вывода лога, в котором можно определить свои правила, фильтры и обвертки (sink).

Пример:

Log.Logger = new LoggerConfiguration()
   .WriteTo.Console()
   .WriteTo.Logger(lc => lc
       .Filter.ByIncludingOnly(...)
       .WriteTo.File("log.txt"))
   .CreateLogger();

Serilog позволяет динамически изменять уровень логирования, путем использования класса LoggingLevelSwitch:

var levelSwitch = new LoggingLevelSwitch();
levelSwitch.MinimumLevel = LogEventLevel.Warning;
var log = new LoggerConfiguration()
 .MinimumLevel.ControlledBy(levelSwitch)
 .WriteTo.ColoredConsole()
 .CreateLogger();

В дальнейшем можно будет изменять объект levelSwitch для вывода нужного уровня.

NLog

Открытый исходный код: https://github.com/NLog/NLog

Лицензия: BSD-3-Clause license

Официальный сайт: https://nlog-project.org/

Документация: https://github.com/nlog/nlog/wiki

Данная библиотека позволяет создавать объекты логов двумя способами: через код и через файл конфиг

Пример:

<?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="logfile" xsi:type="File" fileName="file.txt" />
   <target name="logconsole" xsi:type="Console" />
 </targets>
 <rules>
   <logger name="*" minlevel="Info" writeTo="logconsole" />
   <logger name="*" minlevel="Debug" writeTo="logfile" />
 </rules>
</nlog>

Подробнее о файлах конфигурации логов по ссылке.

Пример создание объекта через код:

var config = new NLog.Config.LoggingConfiguration();
// Куда выводим: Файл и Консоль
var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "file.txt" };
var logconsole = new NLog.Targets.ConsoleTarget("logconsole");
// Правила сопоставления регистраторов          
config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole);
config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile);
// Установка конфигурации         
NLog.LogManager.Configuration = config;

Подробнее о конфигурации в коде по ссылке

Формат вывода сообщений можно устанавливать путем добавления в target элемент layout:

<target xsi:type="File" name="jsonFile" fileName="c:\temp\nlog-json-${shortdate}.log">
     <layout>${longdate}|${level}|${logger}|${message}|${all-event-properties}{exception:format=tostring}</layout>
</target>

Данная библиотека поддерживает следующие структурные форматы:

  • CsvLayout

  • JsonLayout

  • XmlLayout

Формат в файле конфигурации будет выглядеть следующим образом:

<target xsi:type="File" name="jsonFile" fileName="c:\temp\nlog-json-${shortdate}.log">
     <layout xsi:type="JsonLayout" includeAllProperties="true">
       <attribute name="time" layout="${longdate}" />
       <attribute name="level" layout="${level:upperCase=true}"/>
       <attribute name="message" layout="${message}" />
     </layout>
</target>

NLog содержит в себе такие операторы для формирования строк, как и Serilog.

Библиотека содержит асинхронную обертку, что позволяет логировать несколько потоков в одном объекте логгера.

NLog позволяет создавать переменные внутри файла конфигурации, которые могут использоваться в последующих частях конфигурации:

<nlog>
 <variable name="logDirectory" value="logs/${shortdate}"/>
 <targets>
   <target name="file1" xsi:type="File" fileName="${logDirectory}/file1.txt"/>
   <target name="file2" xsi:type="File" fileName="${logDirectory}/file2.txt"/>
 </targets>
</nlog>

Заключение

Основные возможности ранее перечисленных библиотек малоотличимы. Чтобы выбрать решение, нужно углубиться в возможности данных библиотек. Автором было дано предпочтение библиотеке NLog. Данная библиотека уже содержит асинхронную обертку, что позволяет логировать многопоточные приложения. Следующим преимуществом стала изначальная возможность измения настройки логгера через файл конфигурации. Последним приемуществом, почему автор отдает предпочтение библиотеки NLog – возможность создавать переменные в файлах конфигурации логгера.

Tags:
Hubs:
Total votes 4: ↑2 and ↓20
Comments37

Articles