Обновить имя файла NLog target во время выполнения

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

Вокруг Интернета я нашел, как создать цель, программируя меня. Я бы просто обновил имя файла, программируя. Я попробовал код ниже. Ошибка, которую я получаю, - "LayoutRender не найден" logDirectory.

Любая идея?

Спасибо,

var target = (FileTarget)LogManager.Configuration.FindTargetByName("logfile");
target.FileName = "${logDirectory}/file2.txt";

LoggingConfiguration config = new LoggingConfiguration();
var asyncFileTarget = new AsyncTargetWrapper(target);
config.AddTarget("logfile", asyncFileTarget);

LogManager.Configuration = config;

Конфигурационный файл:

  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <variable name="logDirectory" value="C:/MyLogs"/>
    <targets>
      <target name="logfile" xsi:type="File" layout="${date:format=dd/MM/yyyy HH\:mm\:ss.fff}|${level}|${stacktrace}|${message}" fileName="${logDirectory}/file.txt" />
    </targets>

    <rules>
      <logger name="*" minlevel="Info" writeTo="logfile" />
    </rules>    
  </nlog>

Ответы

Ответ 1

Попробуйте ReconfigExistingLoggers метод:

var target = (FileTarget)LogManager.Configuration.FindTargetByName("logfile");
target.FileName = "${logDirectory}/file2.txt";
LogManager.ReconfigExistingLoggers();

Как написано в документах:

Прокручивает все регистраторы, ранее возвращенные GetLogger. а также пересчитывает список своих целей и фильтров. Полезно после изменения конфигурации, чтобы гарантировать, что все регистраторы были правильно настроен.

ИЗМЕНИТЬ

Попробуйте использовать персонализированный рендеринг макета: файл конфигурации NLog, чтобы получить значения параметров конфигурации из web.config

Ответ 2

Решение Tony не работает, если вы используете NLog Async (<targets async="true">). Мне пришлось использовать цель-оболочку, чтобы получить файл FileTarget, иначе я получаю много ошибок. Я использую NLog 2.1.

if (LogManager.Configuration != null && LogManager.Configuration.ConfiguredNamedTargets.Count != 0)
{
    Target target = LogManager.Configuration.FindTargetByName("yourFileName");
    if (target == null)
    {
        throw new Exception("Could not find target named: " + "file");
    }

    FileTarget fileTarget = null;
    WrapperTargetBase wrapperTarget = target as WrapperTargetBase;

    // Unwrap the target if necessary.
    if (wrapperTarget == null)
    {
        fileTarget = target as FileTarget;
    }
    else
    {
        fileTarget = wrapperTarget.WrappedTarget as FileTarget;
    }

    if (fileTarget == null)
    {
        throw new Exception("Could not get a FileTarget from " + target.GetType());
    }

    fileTarget.FileName = "SetFileNameHere";
    LogManager.ReconfigExistingLoggers();
}

Это также не изменяет конфигурационный файл, он просто меняет значение времени выполнения. Поэтому я также вручную отредактирую файл конфигурации на свое новое значение, используя следующий код:

var nlogConfigFile = "NLog.config";
var xdoc = XDocument.Load(nlogConfigFile);
var ns = xdoc.Root.GetDefaultNamespace();
var fTarget = xdoc.Descendants(ns + "target")
         .FirstOrDefault(t => (string)t.Attribute("name") == "yourFileName");
fTarget.SetAttributeValue("fileName", "SetFileNameHere");
xdoc.Save(nlogConfigFile);

Ответ 3

Если вам не нужно менять LogDirectory во время выполнения, вы можете сделать это:

target.FileName = "${var:logDirectory}\\file2.txt");

Если нужно изменить logDirectory во время выполнения, используйте GDC:

https://github.com/NLog/NLog/wiki/Gdc-layout-renderer

NLog.GlobalDiagnosticsContext.Set("logDirectory","C:\Temp\");

Тогда вы можете использовать следующий макет:

target.FileName = "${gdc:item=logDirectory}\\file2.txt";

Ответ 4

Причина, по которой вы получаете сообщение об ошибке, состоит в том, что NLog ничего не знает о "logDirectory" . Вы можете реализовать его самостоятельно (прочтите инструкции здесь) или используйте предопределенные из здесь.

Затем вы можете использовать инструкции здесь для изменения целей NLog во время выполнения.

Ответ 5

Я написал ответ, который подходит и для вашего вопроса.

По сути, вместо того, чтобы пытаться переписать конфигурацию, вам лучше просто создать конфигурацию, которая позволит вам динамически выбирать желаемое имя файла.


Адаптированный пример для вашего варианта использования:

Logger myLog = LogManager.GetLogger(name);
LogLevel level = LogLevel.Error;
string message = "This is an error message!";

Вы превращаете эту информацию в объект LogEventInfo:

LogEventInfo logEvent = new LogEventInfo(level , myLog.Name, message);

Затем вы можете добавить свойства к этому событию (строковые индексы могут свободно выбирать):

logEvent.Properties["CustomFileName"] = "mycustomfilename";

И тогда вы пишете в журнал:

myLog.Log(logEvent);

Интересно, что в вашей конфигурации NLog вы можете использовать это настраиваемое свойство в любом поле, которое в документации Nlog называется значением "Layout".

Вы используете ${event-properties:item=CustomFileName} в макете для доступа к свойству. Например:

<target xsi:type="File" 
        name="file" 
        fileName="${basedir}/logs/${event-properties:item=CustomFileName}.log"
        layout="${message}" />

Следуя опубликованному примеру, это сообщение будет зарегистрировано в файле mycustomfilename.log. Это позволяет вам динамически переключать целевой файл по logEvent.Properties["CustomFileName"] устанавливая значение logEvent.Properties["CustomFileName"] в любое имя файла, которое вы хотите использовать.

Обратите внимание, что вы можете дополнительно оптимизировать это, и, например, иметь возможность выбрать только часть имени файла.

Дополнительным преимуществом является то, что для этой работы вам нужен только один целевой объект и одно правило в вашем конфигурационном файле.

Ответ 6

Для тех, кто застрял на этом, я наконец нашел решение. Я пытался обновить некоторые настройки цели системного журнала во время выполнения, и ничего не работало. Простое обновление конфигурации не работает, вам нужно сбросить объект конфигурации, что так же просто, как сделать это:

LogManager.Configuration = LogManager.Configuration;

Это вызывает внутреннее событие и фактически использует обновленную конфигурацию.

Ответ 7

Это сработало для меня.

using NLog;
using NLog.Targets;
using NLog.Targets.Wrappers;

var target = LogManager.Configuration.FindTargetByName("logfile");
var asyncTarget = target as AsyncTargetWrapper;
var fileTarget = asyncTarget.WrappedTarget as FileTarget;
var file = fileTarget.FileName;
var archiveFile = fileTarget.ArchiveFileName;

//FileName и ArchiveFileName имеют тип Layout. ToString дает строковое представление. Мы можем изменить его и вернуть обратно. Не забудьте поставить .Trim('\' ') для удаления лишних одинарных кавычек, которые добавляются при преобразовании в строку.