Как указать все цели файла nlog на дополнительный промежуточный путь? - PullRequest
1 голос
/ 23 апреля 2020

Предположим, у меня есть два регистратора A, B, которые записывают в файл цели A, B, E примерно так:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets async="true">
        <target name="A" xsi:type="File" fileName="${basepath}\A.log" archiveFileName="${basepath}\A.{##}.log" />
        <target name="B" xsi:type="File" fileName="${basepath}\B.log" archiveFileName="${basepath}\B{##}.log" />
        <target name="E" xsi:type="File" fileName="${basepath}\E.log" archiveFileName="${basepath}\E{##}.log" />
    </targets>
    <rules>
        <logger name="A" minlevel="Debug" writeTo="A"/>
        <logger name="B" minlevel="Debug" writeTo="B"/>
        <logger name="*" minlevel="Error" writeTo="E"/>
    </rules>
</nlog>

Теперь у меня есть требование, для некоторого временного окна во время выполнения программы, не только использовать ${basepath} но также ${InterimPath}. По истечении времени окно должно продолжать запись только в ${basepath}. Как бы выполнить sh это?

Единственное сложное решение, которое я могу придумать на данный момент, - это программно

  1. выполнять итерацию по всем целевым объектам файлов и добавлять новые цели на основе этих файлов. цели с измененным именем, свойства FileName и ArchiveFileName, указывающие на новый путь.
  2. перебирают все правила и добавляют новые правила с writeTo, обновленными для имен новых целей.
  3. в более поздний момент времени, чтобы удалите эти цели и правила.

Обновление: Оба пути ($basepath и $interimpath) должны использоваться для регистрации в течение временного окна. После временного окна следует использовать только $ basepath.

Ответы [ 2 ]

1 голос
/ 23 апреля 2020

Обновленный ответ

Невозможно, чтобы один FileTarget преобразовал один LogEvent в две записи файла в разных местах. Я предлагаю вам удвоить:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <variable name="InterimPath" value="${gdc:InterimPath}" />
    <variable name="InterimPathOff" value="${gdc:InterimPath:whenEmpty=Off}" />
    <targets async="true">
        <target name="A1" xsi:type="File" fileName="${basepath}\A.log" archiveFileName="${basepath}\A.{##}.log" />
        <target name="A2" xsi:type="File" fileName="${InterimPath}\A.log" archiveFileName="${interimpath}\A.{##}.log" />
        <target name="B1" xsi:type="File" fileName="${basepath}\B.log" archiveFileName="${basepath}\B{##}.log" />
        <target name="B2" xsi:type="File" fileName="${InterimPath}\B.log" archiveFileName="${interimpath}\B{##}.log" />
        <target name="E1" xsi:type="File" fileName="${basepath}\E.log" archiveFileName="${basepath}\E{##}.log" />
        <target name="E2" xsi:type="File" fileName="${InterimPath}\E.log" archiveFileName="${interimpath}\E{##}.log" />
    </targets>
    <rules>
        <logger name="A" minlevel="Debug" writeTo="A1"/>
        <logger name="A" minlevel="${whenEmpty:whenEmpty=${InterimPathOff}:inner=Debug" writeTo="A2"/>
        <logger name="B" minlevel="Debug" writeTo="B1"/>
        <logger name="B" minlevel="${whenEmpty:whenEmpty=${InterimPathOff}:inner=Debug" writeTo="B2"/>
        <logger name="*" minlevel="Error" writeTo="E1"/>
        <logger name="*" minlevel="${whenEmpty:whenEmpty=${InterimPathOff}:inner=Error" writeTo="E2"/>
    </rules>
</nlog>

Тогда вы можете включить нет. Делая это 2 цели:

GlobalDiagnosticsContext.Set("InterimPath", mySpecialPath);
LogManager.ReconfigExistingLoggers();

И вы можете отключить нет. 2 цели снова, как это (например, когда срабатывает таймер):

GlobalDiagnosticsContext.Set("InterimPath", "");
LogManager.ReconfigExistingLoggers();

Старый ответ

Вы можете сделать это:

${gdc:InterimPath:whenEmpty=${basepath}}

Тогда просто запустите таймер для очистки переменной InterimPath из GD C по истечении времени ожидания

GlobalDiagnosticsContext.Set("InterimPath", mySpecialPath);

См. Также: https://github.com/nlog/nlog/wiki/Gdc-Layout-Renderer

1 голос
/ 23 апреля 2020

Есть несколько способов заставить это работать. Я думаю, что ваши решения будут работать. Лично я бы выбрал одно из этих решений:

GD C подход

Это действительно простое решение. Используйте Глобальный контекст диагностики и при необходимости измените значение. Так что нет необходимости повторять в конфиге.

Установите элемент на начальное значение:

GlobalDiagnosticsContext.Set("myPath", basePath1);

И при необходимости, например, по таймеру или при нажатии кнопки, измените basepath

GlobalDiagnosticsContext.Set("myPath", basePath2);

В конфигурации: fileName="${gdc:myPath}\E.log"

См. GD C

Настраиваемый метод рендеринга макета

A немного более автоматизированный, создайте пользовательский макет рендеринга, который возвращает различные пути в зависимости от времени.

Регистрация (в main или app_start)

using NLog.LayoutRenderers;

LayoutRenderer.Register("myPath", () =>
{
    if (DateTime.Now.Hour > 16 && DateTime.Now.Hour < 18)
    {
        return myTempPath;
    }

    return myRegularPath;
});

В конфигурации: fileName="${myPath}\E.log"

См. Как написать собственный рендерер макета

Без подхода кода

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

  • Дублировать цели с помощью basepath и interimPath
  • Использовать условия в вашей конфигурации, 2 правила для каждой цели, как то так:
     <logger name="A" writeTo="A">
            <filters defaultAction="Ignore">
                <when condition="${date:format=h} > 16" action="Log" />
            </filters>
     </logger>
     <logger name="A" writeTo="A-interim">
            <filters defaultAction="Log">
                <when condition="${date:format=h} >= 16" action="Ignore" />
            </filters>
     </logger>
    

См. условия

...