NLog - 文件目标文件名的参数
NLog - Parameter for File Target FileName
我在 .NET 应用程序中使用 NLog。目前,我的 App.config 中的配置部分如下所示:
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="assemblyLogFile" xsi:type="File" fileName="${basedir}/logs/${shortdate}/assembly.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}"></target>
<target name="appLogFile" xsi:type="File" fileName="${basedir}/logs/app.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}"></target>
</targets>
<rules>
<logger name="Assembly" minlevel="Trace" writeTo="assemblyLogFile" />
<logger name="*" minlevel="Trace" writeTo="appLogFile" />
</rules>
</nlog>
我的应用正在动态加载程序集。我想将每个程序集日志记录到它们自己的文件中。本质上,我想将 target
元素上的 filename
属性更新为如下内容:
fileName="${basedir}/logs/${shortdate}/assembly.[Name].log"
在此模式中,代码中定义了“[Name]”。我的问题是,有没有办法通过 NLog 以编程方式将变量传递给目标?如果可以,怎么做?
如果正在加载的程序集使用 NLog.LogManager.GetLogger("assemblyName")
创建记录器,那么您可以这样做(最适合 NLog 版本 4.5 或更高版本):
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="assemblyLogFile" xsi:type="File" fileName="${basedir}/logs/${shortdate}/${logger}.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}"></target>
<target name="appLogFile" xsi:type="File" fileName="${basedir}/logs/app.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}"></target>
</targets>
<rules>
<logger name="AssemblyName" minlevel="Trace" writeTo="assemblyLogFile" />
<logger name="*" minlevel="Trace" writeTo="appLogFile" />
</rules>
</nlog>
如果你想让它完全动态,我想你有两种方法。
1) 为 NLog.ILogger
创建自定义日志工厂和包装器,跟踪程序集名称并将其注入 NLog logEvent。这意味着所有程序集都必须使用您的记录器工厂,而不是直接使用 NLog。
2) 创建一个 NLog 扩展,允许您将程序集名称作为布局变量访问,派生自记录器名称。如果您在所有程序集中使用默认值 LogManager.GetCurrentClassLogger()
,这将起作用。
这是一个简单的缓存渲染器,它使用反射来找到正确的程序集。您可以通过在加载程序集时扫描程序集来提高效率 - 或者可能只是对记录器名称进行字符串整理。
[NLog.LayoutRenderers.LayoutRenderer("assemblyName")]
public class AssemblyNameLayoutRenderer : NLog.LayoutRenderers.LayoutRenderer
{
static ConcurrentDictionary<string, string> loggerNameToAssemblyNameCache = new ConcurrentDictionary<string, string>();
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
var fullClassName = logEvent.LoggerName;
var assemblyName = FindAssemblyNameFromClassName(fullClassName);
if (!string.IsNullOrEmpty(assemblyName))
builder.Append(assemblyName);
}
private string FindAssemblyNameFromClassName(string fullClassName)
{
return loggerNameToAssemblyNameCache.GetOrAdd(fullClassName, cl =>
{
var klass = (
from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes()
where t.FullName == fullClassName
select t).FirstOrDefault();
return klass?.Assembly.GetName().Name;
});
}
}
然后像这样在配置文件中使用它:
<extensions>
<add assembly="AssemblyContainingCustomRenderer" />
</extensions>
<targets>
<target xsi:type="FilteringWrapper" name="assemblyLogFile" condition="'${assemblyName}' != ''">
<target name="realAssemblyLogFile" xsi:type="File" fileName="logs/${shortdate}/assembly.${assemblyName}.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}" /
</target>
</targets>
我在 .NET 应用程序中使用 NLog。目前,我的 App.config 中的配置部分如下所示:
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="assemblyLogFile" xsi:type="File" fileName="${basedir}/logs/${shortdate}/assembly.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}"></target>
<target name="appLogFile" xsi:type="File" fileName="${basedir}/logs/app.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}"></target>
</targets>
<rules>
<logger name="Assembly" minlevel="Trace" writeTo="assemblyLogFile" />
<logger name="*" minlevel="Trace" writeTo="appLogFile" />
</rules>
</nlog>
我的应用正在动态加载程序集。我想将每个程序集日志记录到它们自己的文件中。本质上,我想将 target
元素上的 filename
属性更新为如下内容:
fileName="${basedir}/logs/${shortdate}/assembly.[Name].log"
在此模式中,代码中定义了“[Name]”。我的问题是,有没有办法通过 NLog 以编程方式将变量传递给目标?如果可以,怎么做?
如果正在加载的程序集使用 NLog.LogManager.GetLogger("assemblyName")
创建记录器,那么您可以这样做(最适合 NLog 版本 4.5 或更高版本):
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="assemblyLogFile" xsi:type="File" fileName="${basedir}/logs/${shortdate}/${logger}.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}"></target>
<target name="appLogFile" xsi:type="File" fileName="${basedir}/logs/app.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}"></target>
</targets>
<rules>
<logger name="AssemblyName" minlevel="Trace" writeTo="assemblyLogFile" />
<logger name="*" minlevel="Trace" writeTo="appLogFile" />
</rules>
</nlog>
如果你想让它完全动态,我想你有两种方法。
1) 为 NLog.ILogger
创建自定义日志工厂和包装器,跟踪程序集名称并将其注入 NLog logEvent。这意味着所有程序集都必须使用您的记录器工厂,而不是直接使用 NLog。
2) 创建一个 NLog 扩展,允许您将程序集名称作为布局变量访问,派生自记录器名称。如果您在所有程序集中使用默认值 LogManager.GetCurrentClassLogger()
,这将起作用。
这是一个简单的缓存渲染器,它使用反射来找到正确的程序集。您可以通过在加载程序集时扫描程序集来提高效率 - 或者可能只是对记录器名称进行字符串整理。
[NLog.LayoutRenderers.LayoutRenderer("assemblyName")]
public class AssemblyNameLayoutRenderer : NLog.LayoutRenderers.LayoutRenderer
{
static ConcurrentDictionary<string, string> loggerNameToAssemblyNameCache = new ConcurrentDictionary<string, string>();
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
var fullClassName = logEvent.LoggerName;
var assemblyName = FindAssemblyNameFromClassName(fullClassName);
if (!string.IsNullOrEmpty(assemblyName))
builder.Append(assemblyName);
}
private string FindAssemblyNameFromClassName(string fullClassName)
{
return loggerNameToAssemblyNameCache.GetOrAdd(fullClassName, cl =>
{
var klass = (
from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes()
where t.FullName == fullClassName
select t).FirstOrDefault();
return klass?.Assembly.GetName().Name;
});
}
}
然后像这样在配置文件中使用它:
<extensions>
<add assembly="AssemblyContainingCustomRenderer" />
</extensions>
<targets>
<target xsi:type="FilteringWrapper" name="assemblyLogFile" condition="'${assemblyName}' != ''">
<target name="realAssemblyLogFile" xsi:type="File" fileName="logs/${shortdate}/assembly.${assemblyName}.log" createDirs="true" keepFileOpen="true" encoding="utf-8" layout="${longdate} ${message}${exception:format=ToString}" /
</target>
</targets>