【问题标题】:How to apply different layouts to the same target in NLog?如何对 NLog 中的同一个目标应用不同的布局?
【发布时间】:2011-07-07 11:58:09
【问题描述】:

NLog 允许我使用SplitGroup 将我的消息记录到多个目标。我想使用此功能一次将每条消息记录到一个通用的、特定于用户和特定日期的日志中

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

这很好,但我还想针对不同的严重程度使用不同的布局。例如,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>

此代码假定Errors 总是带有异常,而Warnings 没有,但这不是重点。

问题是此配置错误。它不起作用,因为logger 没有layout 属性。它仅针对 target 定义。

正在使用的布局必须由目标本身声明,但我看不到为不同的严重级别指定不同的布局。

目前,我不得不复制粘贴相同的配置代码四次,才能为同一组文件提供四个不同的layouts:

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

这只是伤害了我的眼睛。
有没有更好的方法来做到这一点并避免重复?

【问题讨论】:

    标签: c# configuration nlog redundancy nlog-configuration


    【解决方案1】:

    另一种解决方案是在布局中使用 when 条件。

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

    我只想在没有错误的情况下提供异常消息。当出现错误时,我想要完整的堆栈跟踪。

    【讨论】:

    • 这应该是公认的答案。如果我正确理解了 OP,则应该改写问题以具体解决这个问题:“我还想针对不同的严重程度使用不同的布局”,那么这将是正确的答案。
    【解决方案2】:

    我不确定,但我认为您可能会遇到重复问题。您希望在同一个文件上使用 4 个不同的布局,并且需要 3 个不同的文件。一个目标需要一个布局。所以,如果你只想记录到 1 个文件,你仍然需要定义 4 个 Targets,每个 Targets 都指向同一个文件并且每个都有自己的 Layout。我认为 NLog 没有更方便的方式将多个 Layout 与一个 Target 关联,然后根据日志消息的内容选择一个 Layout。

    根据您希望使用格式实现的确切目标,您可以通过编写自定义 LayoutRenderer 来减少重复。在您的示例中,您显示 Debug 布局中有“...”,Info 有 [i],Warn 有 [!],Error 有 Warn + 异常。您可以编写一个添加特殊标记的 LayoutRenderer,具体取决于消息的级别。这样一来,您可以将 Debug、Info 和 Warn 全部整合到一个布局中,而 Error 将保留其自己的布局。

    例如:

    类似这样的自定义 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;     
        }
      } 
    

    现在您可以配置两种布局:“正常”和“错误”。

    类似:

    <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}}" />
    

    您甚至可以创建一个自定义 LayoutRenderer 来处理异常。如果没有异常,则不输出任何内容。如果出现异常,则连接换行符、填充和异常字符串。

    如果您有一个“条件”异常布局渲染器,那么您可能只有一个布局,如下所示:

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

    大多数时候,ConditionalExceptionLayoutRenderer 会产生 null,因为不会出现异常。

    希望这会有所帮助。

    【讨论】:

    • 感谢您的评论。现在我想坚持最小的依赖,但是当我重新设计系统时,也许我会实现它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多