Dan*_*mov 7 c# configuration redundancy nlog nlog-configuration
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>
Run Code Online (Sandbox Code Playgroud)
这很好,但我也想对不同级别的严重性使用不同的布局.例如,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>
Run Code Online (Sandbox Code Playgroud)
这段代码假定Errors总是带有异常,而Warnings则没有,但这不是重点.
问题是这种配置是错误的.它不起作用,因为logger没有layout属性.它只是定义的target.
正在使用的布局必须由目标本身声明,但我认为无法为不同的严重性级别指定不同的布局.
现在,我不得不复制粘贴相同的配置代码四次只是layout为同一组文件有四个不同的s:
<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>
Run Code Online (Sandbox Code Playgroud)
这只是伤害了我的眼睛.
有没有更好的方法来做到这一点,避免重复?
met*_*key 12
另一种解决方案是在布局中使用when条件.
target.Layout = "${longdate}|[${level}]|${logger}|${message}${onexception:inner=|${exception}${when:when=(level > LogLevel.Warn):inner=|[!] ${exception:format=ToString:innerFormat=Message:maxInnerExceptionLevel=5} }}"
Run Code Online (Sandbox Code Playgroud)
我想只在错误发生时提供异常消息.当出现错误时,我想要完整的堆栈跟踪.
我不确定,但我认为您可能会陷入重复。您希望在同一个文件上使用 4 种不同的布局,并且需要 3 个不同的文件。一个目标需要一种布局。因此,如果您只想记录 1 个文件,您仍然需要定义 4 个目标,每个目标都指向同一个文件,并且每个目标都有自己的布局。我认为 NLog 没有更方便的方法将多个布局与目标关联,然后根据日志消息的内容选择一个布局。
根据您想要通过格式实现的具体目标,您也许可以通过编写自定义 LayoutRenderer 来减少重复。在您的示例中,您显示“调试”布局中有“...”,信息有 [i],警告有 [!],错误有警告 + 异常。您可以编写一个 LayoutRenderer,根据消息的级别添加特殊标记。这样,您可以将“调试”、“信息”和“警告”全部整合到一个布局中,而“错误”将保留其自己的布局。
例如:
对于自定义 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;
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以配置两种布局:“正常”和“错误”。
就像是:
<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}}" />
Run Code Online (Sandbox Code Playgroud)
您甚至可以创建一个自定义 LayoutRenderer 来处理异常。如果没有异常,则不输出任何内容。如果出现异常,则连接换行符、填充和异常字符串。
如果您有一个“条件”异常布局渲染器,那么您可能只有一个布局,如下所示:
<variable name="normal" value="${stamp} ${LevelMarkerLayoutRenderer} ${message} ${ConditionalExceptionLayoutRenderer}" />
Run Code Online (Sandbox Code Playgroud)
大多数时候,ConditionalExceptionLayoutRenderer 会产生 null,因为不会出现异常。
希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
6386 次 |
| 最近记录: |