自定义 NLog 布局渲染器在某些项目中不产生输出
Custom NLog Layout Renderer Produces No Output In Some Projects
.NET 框架 4.8,NLog 4.7.6
我已经实现了两个简单的 LayoutRenderer
子类,它们只编写一个 Guid(从 Web 上下文或静态 Stack<T>
中获取)。它们在两个 Web 项目中运行良好,但它们在第三个 Web 应用程序或几个控制台中都不起作用 apps/services。应用程序之间的配置是一致的,但有些有效,有些无效。
示例:
[LayoutRenderer("request-guid")]
public class RequestGuidLayoutRenderer:
LayoutRenderer
{
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
var guid = RequestIdentityService.Current.RequestGuid?.ToString() ?? Constants.NullSession;
builder.Append(guid);
}
}
还有一个几乎相同的 session-guid
布局渲染器,除了获得 SessionGuid
而不是 RequestGuid
。
我的配置部分如下所示,其中 MyAssemblyName 包含布局渲染器:
<nlog autoReload="true">
<extensions>
<assembly name="MyAssemblyName" />
</extensions>
<variable name="brief" value="${longdate} ${session-guid} ${request-guid} ${level} ${replace:searchFor=^.*\.([^.]+)$:replaceWith=:regex=true:inner=${logger}} ${message}${onexception:inner= ${exception:format=toString,Data}}" />
<variable name="verbose" value="${longdate} | ${machinename} | ${processid} | ${processname} | ${session-guid} ${request-guid} | ${level} | ${logger} | ${message}${onexception:inner= ${exception:format=toString,Data}}" />
<targets>
<target name="all_in" type="File" layout="${verbose}" fileName="C:/log/appx/current.txt" archiveFileName="C:/log/appx/archive/{#}.txt" archiveNumbering="DateAndSequence" archiveAboveSize="10485760" archiveDateFormat="yyyyMMdd" keepFileOpen="false" maxArchiveFiles="100" encoding="iso-8859-2" />
<target name="LogStreaming" type="Trace" layout="${verbose}" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="all_in" />
<logger name="*" minlevel="Error" writeTo="LogStreaming" />
</rules>
</nlog>
为了确保注册这些布局渲染器,我也在 Application_Start()
开始时为 Web 应用程序注册它们,并在 Main()
或其他应用程序类型中注册它们。
public static void Register()
{
LayoutRenderer.Register<RequestGuidLayoutRenderer>("request-guid");
LayoutRenderer.Register<SessionGuidLayoutRenderer>("session-guid");
LogManager.GetCurrentClassLogger().Error($"Registered NLog LayoutRenderers request-guid and session-guid.");
}
对于两个 Web 应用程序,这工作完美,但对于第三个,它没有为这些布局渲染器生成任何输出。内部日志确认它无法找到它们,或者它可能在注册之前尝试使用它们。
Error parsing layout session-guid will be ignored. Exception: System.ArgumentException: LayoutRenderer cannot be found: 'session-guid'
at NLog.Config.Factory`2.CreateInstance(String itemName)
at NLog.Layouts.LayoutParser.GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, String name, Nullable`1 throwConfigExceptions)
Error parsing layout request-guid will be ignored. Exception: System.ArgumentException: LayoutRenderer cannot be found: 'request-guid'
at NLog.Config.Factory`2.CreateInstance(String itemName)
at NLog.Layouts.LayoutParser.GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, String name, Nullable`1 throwConfigExceptions)
我无意中发现,如果我在配置中设置 throwConfigExceptions="true"
,它就会突然在 Web 应用程序中起作用,而在其他情况下却不起作用!但为什么?有没有其他方法可以修复它,这样我就不必冒因日志记录破坏我们的应用程序而导致运行时错误的风险?
出于某种原因,您注册得太晚了。
可能有一个静态调用在注册之前解析配置。
注册后可以重新加载配置:
LogManager.Configuration = LogManager.Configuration.Reload();
LogManager.ReconfigExistingLoggers();
.NET 框架 4.8,NLog 4.7.6
我已经实现了两个简单的 LayoutRenderer
子类,它们只编写一个 Guid(从 Web 上下文或静态 Stack<T>
中获取)。它们在两个 Web 项目中运行良好,但它们在第三个 Web 应用程序或几个控制台中都不起作用 apps/services。应用程序之间的配置是一致的,但有些有效,有些无效。
示例:
[LayoutRenderer("request-guid")]
public class RequestGuidLayoutRenderer:
LayoutRenderer
{
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
var guid = RequestIdentityService.Current.RequestGuid?.ToString() ?? Constants.NullSession;
builder.Append(guid);
}
}
还有一个几乎相同的 session-guid
布局渲染器,除了获得 SessionGuid
而不是 RequestGuid
。
我的配置部分如下所示,其中 MyAssemblyName 包含布局渲染器:
<nlog autoReload="true">
<extensions>
<assembly name="MyAssemblyName" />
</extensions>
<variable name="brief" value="${longdate} ${session-guid} ${request-guid} ${level} ${replace:searchFor=^.*\.([^.]+)$:replaceWith=:regex=true:inner=${logger}} ${message}${onexception:inner= ${exception:format=toString,Data}}" />
<variable name="verbose" value="${longdate} | ${machinename} | ${processid} | ${processname} | ${session-guid} ${request-guid} | ${level} | ${logger} | ${message}${onexception:inner= ${exception:format=toString,Data}}" />
<targets>
<target name="all_in" type="File" layout="${verbose}" fileName="C:/log/appx/current.txt" archiveFileName="C:/log/appx/archive/{#}.txt" archiveNumbering="DateAndSequence" archiveAboveSize="10485760" archiveDateFormat="yyyyMMdd" keepFileOpen="false" maxArchiveFiles="100" encoding="iso-8859-2" />
<target name="LogStreaming" type="Trace" layout="${verbose}" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="all_in" />
<logger name="*" minlevel="Error" writeTo="LogStreaming" />
</rules>
</nlog>
为了确保注册这些布局渲染器,我也在 Application_Start()
开始时为 Web 应用程序注册它们,并在 Main()
或其他应用程序类型中注册它们。
public static void Register()
{
LayoutRenderer.Register<RequestGuidLayoutRenderer>("request-guid");
LayoutRenderer.Register<SessionGuidLayoutRenderer>("session-guid");
LogManager.GetCurrentClassLogger().Error($"Registered NLog LayoutRenderers request-guid and session-guid.");
}
对于两个 Web 应用程序,这工作完美,但对于第三个,它没有为这些布局渲染器生成任何输出。内部日志确认它无法找到它们,或者它可能在注册之前尝试使用它们。
Error parsing layout session-guid will be ignored. Exception: System.ArgumentException: LayoutRenderer cannot be found: 'session-guid'
at NLog.Config.Factory`2.CreateInstance(String itemName)
at NLog.Layouts.LayoutParser.GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, String name, Nullable`1 throwConfigExceptions)
Error parsing layout request-guid will be ignored. Exception: System.ArgumentException: LayoutRenderer cannot be found: 'request-guid'
at NLog.Config.Factory`2.CreateInstance(String itemName)
at NLog.Layouts.LayoutParser.GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, String name, Nullable`1 throwConfigExceptions)
我无意中发现,如果我在配置中设置 throwConfigExceptions="true"
,它就会突然在 Web 应用程序中起作用,而在其他情况下却不起作用!但为什么?有没有其他方法可以修复它,这样我就不必冒因日志记录破坏我们的应用程序而导致运行时错误的风险?
出于某种原因,您注册得太晚了。
可能有一个静态调用在注册之前解析配置。
注册后可以重新加载配置:
LogManager.Configuration = LogManager.Configuration.Reload();
LogManager.ReconfigExistingLoggers();