Логирование NOMAD: открываем новые возможности

12 0

Для логирования сервис NOMAD 2.x использует библиотеку NLog. Это значит, что огромное число возможностей NLog доступно при работе с логами сервиса. Настройки задаются в файле LogSettings.config. При старте сервиса создается рабочая копия файла конфигурации LogSettings.live.config, изменение которого подхватывается без перезагрузки сервиса и затирается значениями LogSettings.config при рестарте сервиса.

Как все устроено

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

<logger name="*" minlevel="Debug" writeTo="file"/>
<logger name="*" minlevel="Trace" writeTo="file-trace"/>
<logger name="Nomad.Request" writeTo="request"/>

Формат записи и путь определяются таргетами. Таргеты file и file-trace используются для записи основной информации о работе сервиса, request — для записи запросов к сервису и его ответов.

<target name="file" xsi:type="File"
        fileName="${logs-path}\server.${shortdate}.log"
        header="${newline}${date:Format=yyyy-MM-dd HH\:mm\:ss.fff K} ************** ${processname} started (${version}) **************${newline}"
        footer="${newline}${date:Format=yyyy-MM-dd HH\:mm\:ss.fff K} ************** ${processname} closed (${version}) **************${newline}"
        layout="${file-layout}"
        encoding="utf-8" />

Формат вывода задан в переменной file-layout:

<variable name="file-layout"
          value="${date:Format=yyyy-MM-dd HH\:mm\:ss.fff K}${char:Code=9}${level:padding=-5}${char:Code=9}${message}${ex-additional-info} ${onexception:${newline}${exception:format=tostring}} ${onexception:${event-context:item=description:WhenEmpty=Contact your system administrator}}${char:Code=9}${vc:LoginName}${char:Code=9}${vc:IPAddress}${char:Code=9}${vc:RequestURL}${char:Code=9}${vc:ApplicationName}${char:Code=9}${vc:UserAgent}${char:Code=9}RequestNumber=${vc:RequestNumber}${char:Code=9}${version}${char:Code=9}${fixed-length:inner=${logger}:maxLength=45:keepRightPart=true:padding=45}${char:Code=9}Process=${processid}:${threadid:padding=-2}" />

Архивирование лог-файлов

NLog умеет выполнять перенос архивных лог-файлов. Правила архивирования добавляются в уже существующие file targets.

<target name="file" xsi:type="File"
        fileName="${logs-path}\server.${shortdate}.log"
        header="${newline}${date:Format=yyyy-MM-dd HH\:mm\:ss.fff K} ************** ${processname}started (${version}) **************${newline}"
        footer="${newline}${date:Format=yyyy-MM-dd HH\:mm\:ss.fff K} ************** ${processname}closed (${version}) **************${newline}"
        layout="${file-layout}"
        encoding="utf-8"
        archiveFileName="${archive-path}\server.{##}.${shortdate}.zip"
        archiveEvery="Day"
        archiveNumbering="Rolling"
        maxArchiveFiles="5"
        concurrentWrites="true"
        enableArchiveFileCompression="true" />
  • archiveFileName — имя архива, задается через layout;
  • archiveEvery — период автоматического архивирования лог-файлов (каждый день, час, месяц и т.д.), возможные значения: Day, Hour, Minute, Month, Year, None;
  • archiveAboveSize — размер файла в байтах, после превышения которого лог-файлы будут автоматически заархивированы (не поддерживается использование вместе с параметром ArchiveNumbering Date);
  • maxArchiveFiles — максимальное число файлов, хранимых в архиве. При значении 0 (по умолчанию), файлы удаляться не будут;
  • archiveNumbering — способ нумерации архивов. Возможное значения: Rolling, Sequence, Date, DateAndSequence. При создании архива плейсхолдеры {##}, указанные в формате имени, будут заменены на автоматически определяемый номер, а все существующие архивы, при необходимости, перенумеруются;
  • enableArchiveFileCompression — включить сжатие фалов в zip-архив.

Запись лог-файлов в базу данных

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

create database NOMAD_LOG_STORAGE
go

if not exists (select * from dbo.sysobjects where id = object_id(N'[NOMAD_LOG_STORAGE].[dbo].[NOMADLogs]') and objectproperty(id, N'IsUserTable') = 1)
begin
 create table [NOMAD_LOG_STORAGE].[dbo].[NOMADLogs](
  [Id] int primary key identity(1,1) not null,
  [LogDateTime] varchar (30),
  [LogLevel] varchar(5),
  [LogMessage] varchar(500),
  [Exception] varchar(1000),
  [UserLogin] varchar(30),
  [IpAddress] varchar (15),
  [Url] varchar(50),
  [UserAgent] varchar (100),
  [RequestNumber] varchar (10),
  [Version] varchar (50),
  [Logger] varchar (100),
  [ProcessId] varchar(10),
  [ThreadId] varchar(5)
 )
end

В параметрах database target необходимо указать строку подключения к базе данных, и написать запрос, добавляющий информацию в таблицу. Параметр dbProvider здесь не указан, так как используется значение по умолчанию sqlserver.

<target name="database" xsi:type="Database"
        connectionString="Data Source=***;Initial Catalog=NOMAD_LOG_STORAGE;Integrated Security=False;User ID=***;Password=***">
 <commandText>
  INSERT INTO [NOMAD_LOG_STORAGE].[dbo].[NOMADLogs]
  (
   [LogDateTime],
   [LogLevel],
   [LogMessage],
   [Exception],
   [UserLogin],
   [IpAddress],
   [Url],
   [UserAgent],
   [RequestNumber],
   [Version],
   [Logger],
   [ProcessId],
   [ThreadId]
  )
  VALUES
  (
   @logDateTime,
   @level,
   @message,
   @exception,
   @login,
   @ipAddress,
   @url,
   @userAgent,
   @requestNumber,
   @version,
   @logger,
   @processId,
   @threadId
  )
 </commandText>
 <parameter name="@logDateTime" layout="${date:Format=yyyy-MM-dd HH\:mm\:ss.fff K}"/>
 <parameter name="@level" layout="${fixed-length:inner=${level}:maxLength=5}"/>
 <parameter name="@message" layout="${fixed-length:inner=${message}:maxLength=500}"/>
 <parameter name="@exception" layout="${fixed-length:inner=${exception:format=tostring}:maxLength=1000}"/>
 <parameter name="@login" layout="${fixed-length:inner=${vc:LoginName}:maxLength=30}"/>
 <parameter name="@ipAddress" layout="${fixed-length:inner=${vc:IPAddress}:maxLength=15}"/>
 <parameter name="@url" layout="${fixed-length:inner=${vc:RequestURL}:maxLength=50:keepRightPart=true}"/>
 <parameter name="@userAgent" layout="${fixed-length:inner=${vc:UserAgent}:maxLength=100}"/>
 <parameter name="@requestNumber" layout="${fixed-length:inner=${vc:RequestNumber}:maxLength=10}"/>
 <parameter name="@version" layout="${fixed-length:inner=${version}:maxLength=50}"/>
 <parameter name="@logger" layout="${fixed-length:inner=${logger}:maxLength=50:keepRightPart=true:padding=50}"/>
 <parameter name="@processId" layout="${fixed-length:inner=${processid}:maxLength=10}"/>
 <parameter name="@threadId" layout="${fixed-length:inner=${threadid}:maxLength=5}"/>
</target>

Для отладки и поиска ошибок конфигурации полезно использовать атрибуты throwExceptions и internalLogFile элемента nlog.

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      throwExceptions="true"
      internalLogFile="${basedir}\NLogLogs\internal_log_file.txt" >

Отправка писем на email

NLog позволяет не только записать логи в файл, но и отправить сообщение на почту через сервер SMTP. Чтобы, например, отправлять администратору уведомления о произошедших критических ошибках достаточно добавить mail target и использовать его в logger с уровнем логирования Fatal.

<target name="email" xsi:type = "Mail"
        smtpServer="mail.companyname.com"
        smtpPort="25"
        smtpAuthentication="Basic"
        smtpUserName="bot@companyname.ru"
        smtpPassword="password"
        enableSsl="false"
        from="bot@companyname.ru"
        to="administrator@companyname.ru"
        body="${error-layout}"
/>

<logger name="*" minlevel="Fatal" writeTo="email" />

Фильтрация

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

Например, вот таким фильтром можно отловить событие превышения попыток входа пользователя и инициировать отправку сообщения на email:

<logger name="*" minlevel="Warn" writeTo="email">
 <filters>
  <when condition="not contains('${message}','Доступ запрещен. Неверный пароль введен 5 раз.') and not contains('${message}', 'Access denied. You have entered an incorrect password 5 times.')" action="Ignore" />
 </filters>
</logger>

Или сохранить статистику по экспорту и импорту документов в отдельную таблицу в базе данных:

<target name="documentDatabaseTable" xsi:type="Database"
  ...
/>

<logger name="*" writeTo="documentDatabaseTable">
 <filters>
  <when condition="not contains('${message}','DocumentExport') and not contains('${message}', 'DocumentImport')" action="Ignore" />
 </filters>
</logger>

Расширение NLog

Если вы будете самостоятельно разбираться с NLog и настраивать использование какой-либо возможности, помимо ссылок на вики: targets, layouts, layout-renderers, wrappers вам будут полезны изменения по версиям, чтобы уточнить с какой версии поддерживается фича (сейчас Nomad использует NLog версии 4.0).

Если уже вся вики прочитана, но вас не покидает ощущение, что чего-то не хватает, самый простой способ добавить необходимую функциональность — использовать methodCall target. Логика сбора, обработки и хранения логов реализуется в .NET сборке, которая должна содержать общедоступный статический метод, в параметры которого передается сообщение и другие необходимые параметры, например, уровень логирования.

namespace CustomLogging
{
	public class Logger
	{
		public static void AwesomeMethod(string message, string logLevel)
		{
			...
		}
	}
}

В файле конфигурации указывается название метода и класса, в котором он находится.

<target name="methodCall" xsi:type="MethodCall"
        methodName="AwesomeMethod"
        className="CustomLogging.Logger, CustomLogging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
 <parameter layout="${message}" name="String" type="System.Type" />
 <parameter layout="${level}" name="String" type="System.Type" />
</target>

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

Чтобы сборка загрузилась и была доступна во время работы сервиса, она должна лежать в папке /bin сайта.

В качестве заключения

Хочется отметить, что изменение формата вывода в файлы serverserver.trace и request не рекомендуется, так как сотрудники СПД работают именно с такими логами. А ещё такой формат файлов позволит использовать утилиту AppHealth, которая  идет в поставке с NOMAD . Для ваших собственных настроек следует создавать свой target и добавлять новый logger.

12
Авторизуйтесь, чтобы оценить материал.
Пока комментариев нет.

Авторизуйтесь, чтобы написать комментарий