Nlog - 为日志文件生成标题部分 [英] Nlog - Generating Header Section for a log file

查看:25
本文介绍了Nlog - 为日志文件生成标题部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近刚开始试验 NLog,我突然想到我希望能够将标题信息添加到日志文件的顶部,例如:

Just recently got into experimenting with NLog, and it occurs to me that I would like to be able to add header information to the top a log file such as:

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

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

After some searching I have been unable to find anything in the existing on-line documentation or code forums which indicates this type of functionality. Is this possible? I have always previously included this sort of information in log files, and have found it useful on numerous occsions in the past, when sourcing information on production issues at customer sites. Admittedly, this functionality was custom built for the solutions and not based on any of the current .NET logging frameworks.

推荐答案

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

I'm not aware of a way to do that very easily. Having said that, all of the examples you give are available (or pretty fairly easily available with some custom code) to be added to each log message. That is, each logged message can be tagged with executable name, file version, release date, windows user id, etc via the Layout and LayoutRenderers.

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

This is obviously not the same as just creating a header at the top of the log file, so it might not be useful to you.

另一方面,您可以使用 Pat 的回答中提到的技术在这篇文章中 将多个布局渲染器与同一目标相关联.您可以定义一个布局,其中包含您想要在标题中的字段,并在 FilteringWrapper 中设置过滤器以仅将该布局应用于会话的第一条消息(或者您可以使用其他一些技术将其添加到输出文件只有一次).

On the other hand, you could use a technique mentioned in Pat's answer in this post to associate multiple layout renderers with the same target. You could define a layout that contains the fields that you want in your header and set the filter in the FilteringWrapper to only apply that layout for the first message of a session (or you might use some other technique that it is added to the output file only once).

使用他的 NLog.config 文件,这是您可以实现所需的一种方法.请注意,我还没有尝试过,所以我不知道这个配置文件是否有效,或者,如果有效,它是否会生成您想要的结果.

Using his NLog.config file, here is one way that you might achieve what you want. Note that I have not tried this, so I don't know if this config file is valid or, if it is, if it will generate the results that you want.

<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> 

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

In your code, your startup logic might look like this:

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"与与HeaderLayout"相关联的fileHeader"目标相关联.标题布局中定义的字段将写入日志文件.后续日志消息,因为它们不会使用HeaderLogger",将使用root"(*)布局.它们将转到同一个文件,因为file"和fileHeader"目标最终都指向同一个文件名.

The idea here is that you would put the file version, release date, etc in the GDC when the program starts. Log a message with the "HeaderLogger" logger. This message would be written to the log file using the "HeaderLayout" since the "HeaderLogger" is associated with the "fileHeader" target which is associated with the "HeaderLayout". The fields defined in the header layout are written to the log file. Subsequence log messages, since they will not use the "HeaderLogger", will use the "root" (*) layout. They will go to the same file since both the "file" and "fileHeader" targets ultimately point to the same filename.

在我开始输入此回复之前,我不确定您是否可以轻松地将标题添加到日志文件中.打完这个,我想这实际上可能很容易!

Before I started typing this response I wasn't sure how easily you could accomplish adding a header to your log file. Having typed this, I think that it might actually be pretty easy!

祝你好运!

像这样的东西可能会根据级别更改布局.在第一部分中,我定义了几个变量,每个变量定义了一个布局.在下一节中,我定义了几个目标,每个目标都使用相同的文件,但经过过滤后只允许写入特定级别的消息.在最后一节中,我定义了一个规则,它将所有消息(因此是*"记录器名称)发送到所有目标.由于每个目标都是按级别过滤的,trace"目标将只写入trace"消息等.因此,trace"消息将使用trace"布局写入,debug"消息将使用debug"写入布局等.由于所有目标最终都写入同一个文件,因此所有消息都将在同一个文件中结束.我还没有尝试过,但我认为它可能会奏效.

Something like this might work to change the layout based on level. In the first section I have defined several variables, each of which defines a layout. In the next section I have defined several targets each of which uses the same file, but is filtered to only allow messages of a specific level to be written. In the final section I define a single rule that will send all messages (hence the "*" logger name) to all targets. Since each target is filtered by level, the "trace" target will write only "trace" messages etc. So, "trace" messages will be written using the "trace" layout, "debug" messages will be written using the "debug" layout, etc. Since all targets ultimately write to the same file, all messages will end up in the same file. I haven't tried this, but I think that it will probably work.

<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 个级别).

(Note that I have only included 3 levels here).

已经展示了如何(如果可行的话)基于级别应用不同的布局,这似乎是一个不寻常的用例.我并不是说这是一个好主意或一个坏主意,但我不能说我真的亲眼所见.具体取决于您希望最终输出的外观,我向您展示的内容可能是也可能不是实现它的最佳方式.也许您可以发布一些示例,说明您希望输出的外观.

Having shown how (if it works, anyway) to apply a different layout based on level, this seems like sort of an unusual use case. I'm not saying that it is a good idea or a bad idea, but I can't say that I have really seen this done very much. Depending on exactly how you want your final output to look, what I have shown you may or may not be the best way to achieve it. Maybe you could post some examples of how you want your output to look.

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

You might also consider accepting my original answer and then making a new question about varying the output layout per level so that we can focus the discussion in that question on the level/layout issue. It is up to you if that seems useful or not.

这有效:

  <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 都包装同一个输出文件,因此所有日志消息都将记录到同一个文件中.

I have set up one Layout for each logging level, adding a literal string at the beginning that describes the level of the message (this is to show that a different format is used for each level). Each Layout is associated with a FilteringWrapper that filters based on the level of the message and directs any messages that pass the filter to be logged in the output file. Each FilteringWrapper is wrapping the same output file, so all log messages will be logged to the same file.

这是我用于测试的一段代码:

Here is a section of code that I used for testing:

  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" 时,错误消失了.祝你好运!

Apparently the problem in my earlier config information was the space between the "writeTo" values. I guess NLog is sensitive to this. I had something like "writeTo=blah1, blah2, blah3". When I changed that to "writeTo=blah1,blah2,blah3" the error went away. Good luck!

这篇关于Nlog - 为日志文件生成标题部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆