根据方法参数使用不同的日志文件

时间:2014-08-25 09:21:38

标签: c# logging nlog

我有一个函数: processData(string taskName),我想使用NLog生成多个包含其路径中的taskName参数的日志文件。

例如:

  

processData(" task1")只应记录到C:\ log_task1.txt

     

processData(" task2")只应记录到C:\ log_task2.txt

     

processData(" task3")只应记录到C:\ log_task3.txt

等等。

注意:我事先并不知道参数的值。这只是一个例子。

2 个答案:

答案 0 :(得分:2)

在NLog配置中,为每个日志文件创建不同的规则:

<targets>
    <target name="logfile1"
        xsi:type="File"
        fileName="C:\log_task1.log" />
    <target name="logfile2"
        xsi:type="File"
        fileName="C:\log_task2.log" />
    <target name="logfile3"
        xsi:type="File"
        fileName="C:\log_task3.log" />
</targets>
<rules>
    <logger name="task1"
        minlevel="Trace"
        writeTo="logfile1" />
    <logger name="task2"
        minlevel="Trace"
        writeTo="logfile2" />
    <logger name="task3"
        minlevel="Trace"
        writeTo="logfile3" />
</rules>

然后,在您的方法中,使用相应的NLog记录器:

public void ProcessData(string param)
{
    var logger = NLog.LogManager.GetLogger(param);
}

如果您事先不知道参数的值,可以在运行时以编程方式创建NLog配置(但不要忘记仅允许列入白名单的参数值以防止覆盖选定位置的现有文件的攻击攻击者)。如何以编程方式配置NLog如下所述:

  

<强> NLog Configuration API

代码就是这样的(只是在没有测试的情况下写下来):

public void AddLogTarget(string param)
{
    if (NLog.LogManager.Configuration.FindTargetByName(param) == null)
    {
        var target = new FileTarget
        {
            Name = param,
            FileName = @"C:\" + param + ".log"
        };
        NLog.LogManager.Configuration.AddTarget(param, target);
        NLog.LogManager.Configuration.LoggingRules.Add(new LoggingRule(param, LogLevel.Debug, target));
    }
}

答案 1 :(得分:0)

有一个选项可能有效,但您需要付出一些努力才能使用它。

NLog能够通过大多数LayoutRenderers命名日志文件。在您的情况下,您可以将File目标配置为:

<target name="FileTarget" xsi:type="File" fileName="${gdc:item=Task}.log" layout=${longdate} | ${logger} | ${level} | ${message}" />

然后,当您执行任务时,您可以根据您的任务名称设置GlobalDiagnosticContext:

void processData(String taskName)
{
   GlobalDiagnosticContext.Set("Task", taskName);
   log.Info("Hello from processData.  This should be in {0}.log", taskName);
   GlobalDiagnosticContext.Remove("Task");
}

这将导致写入的所有日志消息都写入所需的日志文件。

如果您的应用程序是单线程的,那么这可能会正常工作,因此您不必担心同时执行processData之间的冲突。

如果您正在使用线程,则可以使用ThreadDiagnosticContext以相同的方式获得良好的结果。

另一个想法是手动创建LogEventInfo对象并使用Log方法自己记录它们。像这样:

var LogEventInfo le = new LogEventInfo(LogLevel.Info, logger.Name, "Hello!");
le.Properties["Task"] = taskName;
logger.Log(le);

在这种情况下,您将使用EventContext LayoutRenderer来构建日志文件名:

<target name="FileTarget" xsi:type="File" fileName="${event-context:item=Task}.log" layout=${longdate} | ${logger} | ${level} | ${message}" />

您可以包装NLog记录器,或者您可以编写扩展方法,这样您就不必在每个记录站点处理构建LogEventInfo对象。

例如:

public static class NLogExtensions
{
  public static void Log(this Logger logger, string task, LogLevel level, string message)
  {
    var LogEventInfo le = new LogEventInfo(level, logger.Name, message);
    le.Properties["Task"] = task;
    logger.Log(typeof(NLogExtensions), le);
  }
}

使用将Type作为第一个参数的日志签名的原因是为了确保呼叫站点信息的日志记录正常工作。

请在此处查看我的回答,以便对&#34;包装&#34;进行非常简短的讨论。 NLog通过扩展方法:

Can NLog preserve callsite information through c# extension methods?