我在.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>
我的应用是动态加载程序集。我想将每个程序集日志记录到自己的文件中。实质上,我想将filename
元素的target
属性更新为:
fileName="${basedir}/logs/${shortdate}/assembly.[Name].log"
在此模式中,代码中定义了“[Name]”。我的问题是,有没有办法通过NLog以编程方式将变量传递给目标?如果是这样,怎么样?
答案 0 :(得分:1)
如果您希望这是完全动态的,我认为您有两种方法。
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>
答案 1 :(得分:0)
如果正在加载的程序集使用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>