简体   繁体   English

如何将不同的布局应用于 NLog 中的同一目标?

[英]How to apply different layouts to the same target in NLog?

NLog allows me to use SplitGroup to log my messages to several targets. NLog 允许我使用SplitGroup将我的消息记录到多个目标。 I'd like to use this feature to log each message to a common, user-specific and date-specific logs at once:我想使用此功能将每条消息一次记录到一个通用的、特定于用户和特定于日期的日志中:

<variable name="commonLog" value="${logDir}\Common.log" />
<variable name="username" value="${identity:fSNormalize=true:authType=false:isAuthenticated=false}" />
<variable name="userLog" value="${logDir}\ByUser\${username}.log" />
<variable name="dateLog" value="${logDir}\ByDate\${shortdate}.log" />

<target name="logFiles" xsi:type="SplitGroup">
  <target xsi:type="File" fileName="${commonLog}" layout="${myLayout}" />
  <target xsi:type="File" fileName="${userLog}" layout="${myLayout}" />
  <target xsi:type="File" fileName="${dateLog}" layout="${myLayout}" />
</target>

This is great, but I also want to use different layouts for different levels of severity .这很好,但我也想针对不同的严重程度使用不同的布局 For example, errorLayout would include exception information and insert [!] marker so I could later highlight errors in log viewers like BareTail :例如, errorLayout将包含异常信息并插入[!]标记,以便我稍后可以在BareTail等日志查看器中突出显示错误:

<variable name="stamp" value="${date} ${username} ${logger}" />

<variable name="debugLayout" value="${stamp} ... ${message}" />
<variable name="infoLayout" value="${stamp} [i] ${message}" /> 
<variable name="warnLayout" value="${stamp} [!] ${message}" />
<variable name="errorLayout"
   value="${warnLayout}${newline}${pad:padding=10:inner=${exception:format=ToString}}" />

<!-- logFiles target -->

<rules>
  <logger name="*" level="Debug" writeTo="logFiles" layout="debugLayout"  />
  <logger name="*" level="Info" writeTo="logFiles" layout="infoLayout" />
  <logger name="*" level="Warn" writeTo="logFiles" layout="warnLayout" />
  <logger name="*" level="Error" writeTo="logFiles" layout="errorLayout" />
</rules>

This code assumes Error s always come with exceptions and Warning s don't but that's not the point.此代码假定Error总是带有异常,而Warning则没有,但这不是重点。

The problem is this configuration is wrong .问题是这个配置是错误的 It won't work because logger does not have layout attribute.它不会工作,因为logger没有layout属性。 It's defined for target only.它仅为target定义。

Layout which is being used must be declared by targets themselves but I see no means of specifying different layouts for different severity levels.正在使用的布局必须由目标本身声明,但我看不到为不同严重级别指定不同布局的方法。

For now, I had to copy-paste the same configuration code four times just to have four different layout s for same set of files:现在,我必须将相同的配置代码复制粘贴四次,才能为同一组文件设置四种不同的layout

<targets>
  <target name="logFilesDebug" xsi:type="SplitGroup">
    <target xsi:type="File" fileName="${commonLog}" layout="${debugLayout}" />
    <target xsi:type="File" fileName="${userLog}" layout="${debugLayout}" />
    <target xsi:type="File" fileName="${dateLog}" layout="${debugLayout}" />
  </target>

  <target name="logFilesInfo" xsi:type="SplitGroup">
    <target xsi:type="File" fileName="${commonLog}" layout="${infoLayout}" />
    <target xsi:type="File" fileName="${userLog}" layout="${infoLayout}" />
    <target xsi:type="File" fileName="${dateLog}" layout="${infoLayout}" />
  </target>

  <target name="logFilesWarn" xsi:type="SplitGroup">
    <target xsi:type="File" fileName="${commonLog}" layout="${warnLayout}" />
    <target xsi:type="File" fileName="${userLog}" layout="${warnLayout}" />
    <target xsi:type="File" fileName="${dateLog}" layout="${warnLayout}" />
  </target>

  <target name="logFilesError" xsi:type="SplitGroup">
    <target xsi:type="File" fileName="${commonLog}" layout="${errorLayout}" />
    <target xsi:type="File" fileName="${userLog}" layout="${errorLayout}" />
    <target xsi:type="File" fileName="${dateLog}" layout="${errorLayout}" />
  </target>
</targets>

<rules>
  <logger name="*" level="Debug" writeTo="logFilesDebug"  />
  <logger name="*" level="Info" writeTo="logFilesInfo" />
  <logger name="*" level="Warn" writeTo="logFilesWarn" />
  <logger name="*" level="Error" writeTo="logFilesError" />
</rules>

This just hurts my eyes.这只会伤害我的眼睛。
Is there any better way to do this and avoid duplication?有没有更好的方法来做到这一点并避免重复?

An alternate solution is to use the when condition in the layout. 另一种解决方案是在布局中使用when条件。

target.Layout = "${longdate}|[${level}]|${logger}|${message}${onexception:inner=|${exception}${when:when=(level > LogLevel.Warn):inner=|[!] ${exception:format=ToString:innerFormat=Message:maxInnerExceptionLevel=5} }}"

I wanted to just provide the exception message when anything less than error. 我想只在错误发生时提供异常消息。 When there was an error I wanted full stack trace. 当出现错误时,我想要完整的堆栈跟踪。

I'm not sure, but I think that you are probably stuck with the duplication. 我不确定,但我认为你可能会遇到重复问题。 You want 4 different layouts to be used on the same file and you want 3 different files. 您希望在同一文件上使用4种不同的布局,并且需要3种不同的文件。 One target requires one Layout. 一个目标需要一个布局。 So, if you only wanted to log to 1 file, you would still have to define 4 Targets, each pointing to the same file and each with its own Layout. 因此,如果您只想记录到1个文件,则仍需要定义4个目标,每个目标指向同一个文件,每个目标都有自己的布局。 I don't think that NLog has a more convenient way to associate multiple Layouts with a Target and then choosing one Layout based on the content of the logging message. 我不认为NLog有更方便的方法将多个布局与目标关联,然后根据日志消息的内容选择一个布局。

Depending on exactly what you want to achieve with your formats, you might be able to reduce the duplication somewhat by writing a custom LayoutRenderer. 根据您希望通过格式实现的目标,您可以通过编写自定义LayoutRenderer来减少重复。 In your example, you show that the Debug layout has "..." in it, Info has [i], Warn has [!], and Error has Warn + exception. 在您的示例中,您显示Debug布局中包含“...”,Info具有[i],Warn具有[!],并且Error具有警告+异常。 You could write a LayoutRenderer that adds the special marker, depending on what the level of the message is. 您可以编写一个LayoutRenderer来添加特殊标记,具体取决于消息的级别。 That way, you would roll Debug, Info, and Warn all into one Layout and Error would retain its own Layout. 这样,您可以将Debug,Info和Warn all滚动到一个Layout中,Error将保留自己的Layout。

For example: 例如:

Something like this for a custom LayoutRenderer (based on NLog 1.0 refresh, not 2.0): 对于自定义LayoutRenderer(基于NLog 1.0刷新,而不是2.0),这样的事情:

  [LayoutRenderer("LevelMarkerLayoutRenderer")]   
  class LevelMarkerLayoutRenderer : LayoutRenderer   
  {     
    int estimatedSize = 3;      
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {       
      string marker;
      switch (logEvent.Level)
      {
        case Debug:
          marker = "...";
          break;
        case Info:
          marker = "[i]";
          break;
        case Warn:
          marker = "[!]";
          break;
        case Error:
          marker = "[!]";
          break;
        case Fatal:
          marker = "[!]";
          break;
        default:
          marker = "?";
      }

      builder.Append(marker);     
    }      

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)     
    {       
      return estimatedSize;     
    }
  } 

Now you could configure two Layouts: "normal", and "error". 现在您可以配置两个布局:“正常”和“错误”。

Something like: 就像是:

<variable name="stamp" value="${date} ${username} ${logger}" />

<variable name="normal" value="${stamp} ${LevelMarkerLayoutRenderer} ${message}" />
<variable name="error"
   value="${warnLayout}${newline}${pad:padding=10:inner=${exception:format=ToString}}" />

You could probably even create a custom LayoutRenderer to handle exceptions. 您甚至可以创建自定义LayoutRenderer来处理异常。 If no exception, don't output anything. 如果没有异常,请不要输出任何内容。 If exception, concatentate newline, padding, and the exception string. 如果是异常,则连接换行符,填充和异常字符串。

If you had a "conditional" exception layout renderer, then you could have just one layout that might look like this: 如果您有一个“条件”异常布局渲染器,那么您可能只有一个布局可能如下所示:

<variable name="normal" value="${stamp} ${LevelMarkerLayoutRenderer} ${message} ${ConditionalExceptionLayoutRenderer}" />

Most of the time, ConditionalExceptionLayoutRenderer would yield null because there would not be an exception. 大多数情况下,ConditionalExceptionLayoutRenderer将产生null,因为不会有异常。

Hope this helps. 希望这可以帮助。

If you want different NLog Layout depending on LogLevel (or some other condition), then you can use NLog Conditions:如果你想根据 LogLevel(或其他一些条件)使用不同的 NLog 布局,那么你可以使用 NLog 条件:

<nlog throwConfigExceptions="true">
  <variable name="infoLayout" value="${longdate} ${logger} ${message}" />
  <variable name="errorLayout" value="${longdate} ${logger} ${message} ${exception}" />
  <variable name="defaultLayout" value="${when:when=level<=LogLevel.Info:inner=${infoLayout}:else=${errorLayout}}" />
    
  <targets>
    <target xsi:type="file" name="logfile" fileName="App.Log" layout="${defaultLayout}" />
  </target>

  <rules>
    <logger name="*" minlevel="Debug" writeTo="logfile"  />
  </rules>
</nlog>

See also: https://github.com/NLog/NLog/wiki/When-Layout-Renderer另见: https://github.com/NLog/NLog/wiki/When-Layout-Renderer

See also: https://github.com/NLog/NLog/wiki/OnException-Layout-Renderer另见: https://github.com/NLog/NLog/wiki/OnException-Layout-Renderer

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM