Nlog - 为日志文件生成标题部分

Pau*_*son 9 c# logging nlog

刚刚开始尝试使用NLog,我发现我希望能够将头信息添加到日志文件的顶部,例如:

可执行文件名文件版本发布日期Windows用户ID等...

经过一些搜索后,我无法在现有的在线文档或代码论坛中找到任何表明此类功能的内容.这可能吗?我以前总是将这种信息包含在日志文件中,并且发现它在过去的许多事件中都很有用,当时在客户站点获取有关生产问题的信息.不可否认,此功能是为解决方案定制的,而不是基于任何当前的.NET日志框架.

JKo*_*plo 14

刚刚碰巧偶然发现了这个,同时在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>
Run Code Online (Sandbox Code Playgroud)

它给我输出看起来像这样:

----------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-----------
Run Code Online (Sandbox Code Playgroud)

我不知道为什么这似乎没有记录.我能找到的唯一参考是:https://github.com/nlog/NLog/wiki/LayoutWithHeaderAndFooter

-Jody


wag*_*ghe 6

我不知道很容易做到这一点的方法。话虽如此,您提供的所有示例都可以添加到(或相当容易地使用一些自定义代码)添加到每个日志消息中。也就是说,每个记录的消息都可以通过Layout和LayoutRenderers标记可执行文件名,文件版本,发行日期,Windows用户ID等。

显然,这与在日志文件顶部创建标头不同,因此对您可能没有用。

另一方面,您可以使用本文中Pat的答案提到的技术将多个布局渲染器与同一目标相关联。您可以定义一个包含标题中所需字段的布局,并在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> 
Run Code Online (Sandbox Code Playgroud)

在您的代码中,您的启动逻辑可能如下所示:

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.
}
Run Code Online (Sandbox Code Playgroud)

这里的想法是在程序启动时将文件版本,发行日期等放入GDC中。使用“ HeaderLogger”记录器记录一条消息。由于“ HeaderLogger”与与“ HeaderLayout”相关联的“ fileHeader”目标相关联,因此将使用“ HeaderLayout”将该消息写入日志文件。标头布局中定义的字段将写入日志文件。子序列日志消息将不使用“ HeaderLogger”,因此将使用“根”(*)布局。由于“ file”和“ fileHeader”目标最终都指向相同的文件名,因此它们将进入同一文件。

在开始键入此响应之前,我不确定您能多么轻松地将标头添加到日志文件。键入此内容后,我认为它实际上可能非常简单!

祝好运!

[EDIT]像这样的事情可能会根据级别更改布局。在第一部分中,我定义了几个变量,每个变量定义一个布局。在下一节中,我定义了几个目标,每个目标都使用相同的文件,但是被过滤以仅允许写入特定级别的消息。在最后一节中,我定义了一条规则,该规则会将所有消息(因此为“ *”记录器名称)发送给所有目标。由于每个目标都是按级别过滤的,因此“ trace”目标将仅写入“ trace”消息等。因此,“ trace”消息将使用“ trace”布局写入,“ debug”消息将使用“ debug”写入布局等。由于所有目标最终都写入同一文件,因此所有消息都将最终存储在同一文件中。我没有尝试过

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.
}
Run Code Online (Sandbox Code Playgroud)

(请注意,这里我仅包括3个级别)。

展示了如何(如果可行,无论如何)基于级别应用不同的布局,这似乎有点不寻常。我并不是说这是一个好主意还是一个坏主意,但我不能说我真的看到了很多。根据您希望最终输出的确切外观,我所展示的内容可能是也可能不是实现它的最佳方法。也许您可以发布一些示例,说明您希望输出如何显示。

您也可以考虑接受我的原始答案,然后提出一个新问题,以更改每个级别的输出布局,以便我们将有关该问题的讨论集中在级别/布局问题上。是否有用似乎取决于您。

这有效:

<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> 
Run Code Online (Sandbox Code Playgroud)

我为每个日志记录级别设置了一个布局,在开头添加了一个描述消息级别的文字字符串(这表明每个级别使用了不同的格式)。每个布局都与一个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");
Run Code Online (Sandbox Code Playgroud)

这是输出的样子:

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
Run Code Online (Sandbox Code Playgroud)

显然我较早的配置信息中的问题是"writeTo"值之间的空格。我猜NLog对此很敏感。我遇到了类似“ "writeTo=blah1, blah2, blah3". 当我将其更改为"writeTo=blah1,blah2,blah3"错误时”的错误。祝好运!