NLog - 文件目标FileName的参数

时间:2018-04-23 16:43:19

标签: c# nlog

我在.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以编程方式将变量传递给目标?如果是这样,怎么样?

2 个答案:

答案 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>