Nlog фиксированное имя файла для каждого сеанса приложения

Я использую Nlog для входа из своего приложения С#. Ниже приведен раздел <targets> из моего Nlog.config:

<targets>
    <target name="logfile" xsi:type="File" fileName="..\logs\${date:format=yyyyMMdd_HHmmss}_trg.log"
    layout="${counter} | ${date:format=yyyy-MM-dd HH\:mm\:ss.ffff} | ${machinename} | ${level:uppercase=true} | ${logger:shortName=true} | ${stacktrace} | ${message:exceptionSeparator=EXCEPTION:withException=true}" 
    keepFileOpen="true"/>
</targets>

Для filename я использую ${date:format=yyyyMMdd_HHmmss}_trg.log, чтобы назвать журнал, основанный на том, когда он был создан. Однако, пока мое приложение запускается, регистратор создает новый файл журнала каждую секунду. Как заставить Nlog исправить имя файла и создать только один журнал за сеанс?

Ответ 1

По-видимому, существует рендеринг макета ${cached}, который будет отображать макет один раз и повторно использовать его. https://github.com/nlog/nlog/wiki/Cached-Layout-Renderer

Однако, благодаря @wageoghe для вашего ввода. Ваше решение с помощью GlobalDiagnosticContext заставило меня задуматься о передаче других значений в NLog.config.

Ответ 2

Я не знаю точно, но я предполагаю, что NLog проверяет наличие файла журнала на основе свойства filename (которое является динамическим, поскольку вы используете средство отображения макета даты). Таким образом, поскольку имя файла изменяется (то есть каждый раз, когда значение имени файла извлекается, оно отличается (или может быть другим)), NLog создает новый файл.

Попробуйте использовать средство рендеринга макета в следующем виде:

<targets>     
  <target name="logfile" xsi:type="File"    
          fileName="..\logs\${shortdate}_trg.log"     
          layout="${counter} | ${date:format=yyyy-MM-dd HH\:mm\:ss.ffff} | ${machinename} | ${level:uppercase=true} | ${logger:shortName=true} | ${stacktrace} | ${message:exceptionSeparator=EXCEPTION:withException=true}"      
          keepFileOpen="true"/> 
</targets> 

Я думаю, вы увидите, что ваше имя файла не изменится (до полуночи).

Ключ в том, что NLog всегда будет проверять, существует ли файл (в соответствии с значением имени файла во время написания сообщения журнала) и создаст файл, если он еще не существует.

В качестве альтернативы, если вы хотите назвать свой файл журнала более точным именем файла (т.е. что он был создан в какой-то дате в какое-то время), вы можете сохранить это время в GlobalDiagnosticContext и использовать средство визуализации макета gdc, чтобы помочь назвать файл. Что-то вроде этого:

//Early in your program do something like this:
NLog.GlobalDiagnosticContext["StartTime"] = DateTime.Now.ToString("yyyyMMdd_HHmmss");

В файле NLog.config сделайте следующее:

<targets>     
  <target name="logfile" xsi:type="File"    
          fileName="..\logs\${gdc:item=StartTime}_trg.log"     
          layout="${counter} | ${date:format=yyyy-MM-dd HH\:mm\:ss.ffff} | ${machinename} | ${level:uppercase=true} | ${logger:shortName=true} | ${stacktrace} | ${message:exceptionSeparator=EXCEPTION:withException=true}"      
          keepFileOpen="true"/> 
</targets> 

Наконец, вы можете написать пользовательский LayoutRenderer для заполнения даты/времени. Он получает время один раз, а затем возвращает одно и то же значение каждый раз.

Он будет выглядеть примерно так:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;

using System.Globalization;

using NLog;
using NLog.Config;
using NLog.LayoutRenderers;

namespace MyNLogExtensions
{
  [LayoutRenderer("StartTime")]
  class StartTimeLayoutRenderer : LayoutRenderer
  {
    private DateTime start = DateTime.Now;

    public StartTimeLayoutRenderer()
    {
      this.Format = "G";
      this.Culture = CultureInfo.InvariantCulture;
    }

    //
    // In NLog 1.x, LayoutRenderer defines a Culture property.
    // In NLog 2.0, LayoutRenderer does not define a Culture property.
    //
    public CultureInfo Culture { get; set; }

    [DefaultParameter]
    public string Format { get; set; }

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
      builder.Append(start.ToString(this.Format, this.Culture));
    }

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
    {
      return 10;
    }
  }
}

В вашем файле NLog.config вам нужно что-то вроде этого, чтобы указать, где ваши расширения:

  <extensions>
    <add assembly="MyAssembly.dll"
  </extensions>

И тогда ваша целевая конфигурация будет выглядеть примерно так:

<targets>     
  <target name="logfile" xsi:type="File"    
          fileName="..\logs\${StartTime:format=yyyyMMdd_HHmmss}_trg.log"     
          layout="${counter} | ${date:format=yyyy-MM-dd HH\:mm\:ss.ffff} | ${machinename} | ${level:uppercase=true} | ${logger:shortName=true} | ${stacktrace} | ${message:exceptionSeparator=EXCEPTION:withException=true}"      
          keepFileOpen="true"/> 
</targets>

Ответ 3

Пример использования ${cached} wrapper (https://github.com/nlog/NLog/wiki/Cached-Layout-Renderer) для создания файла журнала сеанса приложения:

<target 
    name="logfile" 
    xsi:type="File" 
    fileName="log-${date:cached=True:format=yyyy-MM-dd HH-mm-ss-fff}.txt"
/>

Ответ 4

Я так думаю, изменив файл журнала, указанный в конфигурационном файле NLog в главной функции или в начале вашей программы. Это целевой "файл журнала" в качестве файла цели в файле конфигурации вашего примера.

FileTarget target = LogManager.Configuration.FindTargetByName("logfile") as FileTarget;
String logfile = "..\logs\" +  DateTime.Now.ToString("yyyyMMdd_HHmmss") + "_trg.log";
target.FileName = logfile;