Nlog - Создание раздела заголовка для файла журнала - PullRequest
9 голосов
/ 16 ноября 2010

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

Executable name
File version
Release Date
Windows User ID
etc...

После некоторых поисков мне не удалось найти что-либо в существующей онлайновой документации или форумах по коду, которые бы указывали на этот тип функциональности. Это возможно? Ранее я всегда включал такую ​​информацию в файлы журналов и нашел ее полезной во многих случаях в прошлом при поиске информации о производственных проблемах на сайтах клиентов. Следует признать, что эта функциональность была специально разработана для решений и не основана ни на одной из существующих платформ ведения журналов .NET.

Ответы [ 3 ]

13 голосов
/ 02 марта 2013

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

<target name="logfile2" xsi:type="File" fileName="Logs\NLogDemo2.txt">
  <layout xsi:type="LayoutWithHeaderAndFooter">
    <header xsi:type="SimpleLayout" text="----------NLog Demo Starting---------&#xD;&#xA;"/>
    <layout xsi:type="SimpleLayout" text="${longdate}|${level:uppercase=true}|${logger}|${message}" />
    <footer xsi:type="SimpleLayout" text="----------NLog Demo Ending-----------&#xD;&#xA;"/>
  </layout>
</target>

Это дает мне вывод, который выглядит так:

----------NLog Demo Starting---------

2013-03-01 16:40:19.5404|INFO|Project.Form1|Sample informational message
2013-03-01 16:40:19.5714|WARN|Project.Form1|Sample warning message
2013-03-01 16:40:19.5714|ERROR|Project.Form1|Sample error message
2013-03-01 16:40:19.5714|FATAL|Project.Form1|Sample fatal error message
----------NLog Demo Ending-----------

Понятия не имею, почему это кажется недокументированным. Единственная ссылка, которую я мог найти, была здесь: https://github.com/nlog/NLog/wiki/LayoutWithHeaderAndFooter

-Jody

4 голосов
/ 16 ноября 2010

Я не знаю, как сделать это очень легко.Тем не менее, все приведенные вами примеры доступны (или довольно легко доступны с некоторым пользовательским кодом), которые можно добавить к каждому сообщению журнала.То есть каждое зарегистрированное сообщение может быть помечено именем исполняемого файла, версией файла, датой выпуска, идентификатором пользователя Windows и т. Д. С помощью Layout и LayoutRenderers.

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

С другой стороны, вы можете использовать технику, упомянутую в ответе Пата в этом посте , чтобы связать несколько средств визуализации макета ста же цель.Вы можете определить макет, который содержит поля, которые вы хотите в своем заголовке, и установить фильтр в FilteringWrapper, чтобы применять этот макет только для первого сообщения сеанса (или вы можете использовать другой метод, добавляемый в выходной файл).только один раз).

Используя его файл NLog.config, мы можем достичь желаемого.Обратите внимание, что я не пробовал это, поэтому я не знаю, является ли этот файл конфигурации действительным или, если это так, генерирует ли он требуемые результаты.

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.mono2.xsd" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      autoReload="true" 
      internalLogLevel="Warn" 
      internalLogFile="nlog log.log" 
      > 
    <variable name="HeaderLayout" value="${processname} ${gdc:item=version} ${gdc:item=releasedate} ${windows-identity}" /> 
    <variable name="NormalLayout" value="${longdate} ${logger} ${level} ${message} /> 

    <targets async="true"> 
        <target name="file" xsi:type="File" fileName="log.log" 
                layout="${NormalLayout}"> 
        </target> 

        <target name="fileHeader" xsi:type="File" fileName="log.log" 
                layout="${HeaderLayout}"> 
        </target>      
    </targets> 

    <rules> 
        <logger name="HeaderLogger" minlevel="Trace" writeTo="fileHeader" final="true" />           
        <logger name="*" minlevel="Trace" writeTo="file" /> 
    </rules> 

</nlog> 

В вашем коде вашЛогика запуска может выглядеть следующим образом:

public void Main()
{
  AddHeaderToLogFile();
}

public void AddHeaderToLogFile()
{
  Logger headerlogger = LogManager.GetLogger("HeaderLogger");

  //Use GlobalDiagnosticContext in 2.0, GDC in pre-2.0
  GlobalDiagnosticContext["releasedate"] = GetReleaseDate();    
  GlobalDiagnosticContext["version"] = GetFileVersion();     
  GlobalDiagnosticContext["someotherproperty"] = GetSomeOtherProperty();

  headerlogger.Info("message doesn't matter since it is not specified in the layout");

  //Log file should now have the header as defined by the HeaderLayout

  //You could remove the global properties now if you are not going to log them in any
  //more messages.
}

Идея в том, что вы должны поместить версию файла, дату выпуска и т. д. в GDC при запуске программы.Зарегистрируйте сообщение с помощью регистратора «HeaderLogger».Это сообщение будет записано в файл журнала с использованием «HeaderLayout», поскольку «HeaderLogger» связан с целью «fileHeader», которая связана с «HeaderLayout».Поля, определенные в макете заголовка, записываются в файл журнала.Сообщения журнала подпоследовательности, поскольку они не будут использовать «HeaderLogger», будут использовать макет «root» (*).Они будут идти к одному и тому же файлу, так как цели «file» и «fileHeader» в конечном итоге будут указывать на одно и то же имя файла.

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

Удачи!

[РЕДАКТИРОВАТЬ] Что-то вроде этого может работать для изменения макета в зависимости от уровня.В первом разделе я определил несколько переменных, каждая из которых определяет макет.В следующем разделе я определил несколько целей, каждая из которых использует один и тот же файл, но отфильтрован, чтобы разрешить запись только сообщений определенного уровня.В последнем разделе я определяю единственное правило, которое будет отправлять все сообщения (отсюда и имя «*») всем адресатам.Поскольку каждая цель фильтруется по уровню, цель «trace» будет писать только сообщения «trace» и т. Д. Таким образом, сообщения «trace» будут записываться с использованием макета «trace», сообщения «debug» будут записываться с использованием «debug».макет и т. д. Поскольку все цели в конечном итоге записывают в один и тот же файл, все сообщения будут в конечном итоге в одном файле.Я не пробовал это, но я думаю, что это, вероятно, будет работать.

<variable name="TraceLayout" value="THIS IS A TRACE: ${longdate} ${level:upperCase=true} ${message}" /> 
<variable name="DebugLayout" value="THIS IS A DEBUG: ${longdate} ${level:upperCase=true} ${message}" /> 
<variable name="InfoLayout" value="THIS IS AN INFO: ${longdate} ${level:upperCase=true} ${message}" /> 


<targets async="true"> 
    <target name="fileAsTrace" xsi:type="FilteringWrapper" condition="level==LogLevel.Trace"> 
        <target xsi:type="File" fileName="log.log" layout="${TraceLayout}" /> 
    </target> 
    <target name="fileAsDebug" xsi:type="FilteringWrapper" condition="level==LogLevel.Debug"> 
        <target xsi:type="File" fileName="log.log" layout="${DebugLayout}" /> 
    </target> 
    <target name="fileAsInfo" xsi:type="FilteringWrapper" condition="level==LogLevel.Info"> 
        <target xsi:type="File" fileName="log.log" layout="${InfoLayout}" /> 
    </target>  
</targets> 

<rules> 
    <logger name="*" minlevel="Trace" writeTo="fileAsTrace, fileAsDebug, fileAsInfo" /> 
</rules> 

(Обратите внимание, что я включил здесь только 3 уровня).

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

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

Это работает:

  <variable name="TraceLayout" value="This is a TRACE - ${longdate} | ${logger} | ${level} | ${message}"/>
  <variable name="DebugLayout" value="This is a DEBUG - ${longdate} | ${logger} | ${level} | ${message}"/>
  <variable name="InfoLayout" value="This is an INFO - ${longdate} | ${logger} | ${level} | ${message}"/>
  <variable name="WarnLayout" value="This is a WARN - ${longdate} | ${logger} | ${level} | ${message}"/>
  <variable name="ErrorLayout" value="This is an ERROR - ${longdate} | ${logger} | ${level} | ${message}"/>
  <variable name="FatalLayout" value="This is a FATAL - ${longdate} | ${logger} | ${level} | ${message}"/>
  <targets>
    <target name="fileAsTrace" xsi:type="FilteringWrapper" condition="level==LogLevel.Trace">
      <target xsi:type="File" fileName="xxx.log" layout="${TraceLayout}" />
    </target>
    <target name="fileAsDebug" xsi:type="FilteringWrapper" condition="level==LogLevel.Debug">
      <target xsi:type="File" fileName="xxx.log" layout="${DebugLayout}" />
    </target>
    <target name="fileAsInfo" xsi:type="FilteringWrapper" condition="level==LogLevel.Info">
      <target xsi:type="File" fileName="xxx.log" layout="${InfoLayout}" />
    </target>
    <target name="fileAsWarn" xsi:type="FilteringWrapper" condition="level==LogLevel.Warn">
      <target xsi:type="File" fileName="xxx.log" layout="${WarnLayout}" />
    </target>
    <target name="fileAsError" xsi:type="FilteringWrapper" condition="level==LogLevel.Error">
      <target xsi:type="File" fileName="xxx.log" layout="${ErrorLayout}" />
    </target>
    <target name="fileAsFatal" xsi:type="FilteringWrapper" condition="level==LogLevel.Fatal">
      <target xsi:type="File" fileName="xxx.log" layout="${FatalLayout}" />
    </target>
  </targets>


    <rules>
      <logger name="*" minlevel="Trace" writeTo="fileAsTrace,fileAsDebug,fileAsInfo,fileAsWarn,fileAsError,fileAsFatal" />
      <logger name="*" minlevel="Info" writeTo="dbg" />
    </rules>

Я установил один макет для каждого уровня ведения журнала, добавив в начале буквальную строку, которая описывает уровень сообщения (это показывает, что для каждого уровня используется другой формат). Каждый макет связан с FilteringWrapper, который фильтрует на основе уровня сообщения и направляет любые сообщения, которые проходят через фильтр, для регистрации в выходном файле. Каждый FilteringWrapper упаковывает один и тот же выходной файл, поэтому все сообщения журнала будут записываться в один и тот же файл.

Вот фрагмент кода, который я использовал для тестирования:

  logger.Trace("Trace msg");
  logger.Debug("Debug msg");
  logger.Info("Info msg");
  logger.Warn("Warn msg");
  logger.Error("Error msg");
  logger.Fatal("Fatal msg");

А вот как выглядит результат:

This is a TRACE - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Trace | Trace msg
This is a DEBUG - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Debug | Debug msg
This is an INFO - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Info | Info msg
This is a WARN - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Warn | Warn msg
This is an ERROR - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Error | Error msg
This is a FATAL - 2010-11-22 13:20:00.4131 | NLogTest.Form1 | Fatal | Fatal msg

Видимо, проблема в моей более ранней информации о конфигурации заключалась в пробеле между значениями "writeTo". Я думаю, что NLog чувствителен к этому. У меня было что-то вроде "writeTo=blah1, blah2, blah3". Когда я изменил это на "writeTo=blah1,blah2,blah3", ошибка исчезла. Удачи!

1 голос
/ 20 августа 2013

Вы можете создать раздел верхнего / нижнего колонтитула для "экземпляра" (т. Е. В первый раз, когда приложение и в последний раз приложение записывает в любой файл), используя Layouts как , указанный предыдущим ответом

Подробнее:

...