C# 如何在NLog中对同一目标应用不同的布局?

C# 如何在NLog中对同一目标应用不同的布局?,c#,configuration,nlog,redundancy,nlog-configuration,C#,Configuration,Nlog,Redundancy,Nlog Configuration,NLog允许我使用将消息记录到多个目标。我想使用此功能将每条消息同时记录到一个通用、特定于用户和特定于日期的日志中: 这很好,但是我还想针对不同的严重性级别使用不同的布局。例如,errorLayout将包含异常信息,并插入[!]标记,以便以后我可以在日志查看器中突出显示错误,如: 此代码假定错误s总是出现异常,而警告s则不会出现异常,但这不是重点 问题是此配置错误。它无法工作,因为记录器没有布局属性。它仅为目标定义 使用的布局必须由目标本身声明,但我看不到为不同的严重性级别指定不同布局的

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


这很好,但是我还想针对不同的严重性级别使用不同的布局。例如,
errorLayout
将包含异常信息,并插入
[!]
标记,以便以后我可以在日志查看器中突出显示错误,如:


此代码假定
错误
s总是出现异常,而
警告
s则不会出现异常,但这不是重点

问题是此配置错误。它无法工作,因为
记录器
没有
布局
属性。它仅为
目标定义

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

现在,我必须复制粘贴相同的配置代码四次,才能为同一组文件创建四个不同的
layout
s:


这只会伤到我的眼睛。

有没有更好的方法来做到这一点并避免重复?

我不确定,但我认为您可能被重复所困扰。您希望在同一文件上使用4种不同的布局,并且希望在3种不同的文件上使用。一个目标需要一个布局。因此,如果您只想登录到一个文件,那么仍然需要定义4个目标,每个目标指向同一个文件,并且每个目标都有自己的布局。我认为NLog没有更方便的方法将多个布局与目标关联,然后根据日志消息的内容选择一个布局

根据您希望使用格式实现的具体内容,您可能可以通过编写自定义LayoutRenderer在一定程度上减少重复。在您的示例中,您显示调试布局中有“…”,Info有[i],Warn有[!],Error有Warn+exception。根据消息的级别,可以编写添加特殊标记的LayoutRenderer。这样,您可以将调试、信息和警告全部滚动到一个布局中,错误将保留其自己的布局

例如:

对于自定义LayoutRenderer(基于NLog 1.0刷新,而不是2.0刷新),类似于此:

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

比如:

<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,因为不会出现异常


希望这有帮助。

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

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

我只想在出现任何错误时提供异常消息。出现错误时,我需要完整堆栈跟踪。

谢谢您的评论。目前,我希望保持最小的依赖性,但当我重新设计系统时,也许我会实现它。这应该是公认的答案。如果我对OP的理解正确,那么应该对问题进行重新表述,以明确说明这一点:“我还希望针对不同的严重程度使用不同的布局”,然后这将是正确的答案。
target.Layout = "${longdate}|[${level}]|${logger}|${message}${onexception:inner=|${exception}${when:when=(level > LogLevel.Warn):inner=|[!] ${exception:format=ToString:innerFormat=Message:maxInnerExceptionLevel=5} }}"