Search code examples
c#nlog

how to point all nlog file targets to an additional interim path?


Assume i have two loggers A, B which write to file targets A, B, E like so:

<?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>

Now i have the requirement, for some time window during program runtime, to not only use ${basepath} but also an ${InterimPath}. After the time window elapses, it should continue writing only to ${basepath}. How would one accomplish this?

The only complicated solution i can think of currently, is to programmatically

  1. iterate through all file targets and add new targets based on these file targets with changed name, FileName and ArchiveFileName properties pointing to the new path.
  2. iterate through all rules and add new rules with writeTo updated to the new targets names.
  3. at some later point time to remove these targets and rules.

Update: Both Paths ($basepath and $interimpath) should be used for logging during the time window. After the time window only $basepath should be used.


Solution

  • Updated Answer

    It is not possible for a single FileTarget to translate a single LogEvent into two file-writes at different locations. I suggest that you double-up:

    <?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>
    

    Then you can enable the no. 2 targets by doing this:

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

    And you can disable the no. 2 targets again like this (Ex. when timer fires):

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

    Old Answer

    You could do this:

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

    Then just have timer to clear the InterimPath variable from the GDC after timeout

    GlobalDiagnosticsContext.Set("InterimPath", mySpecialPath);
    

    See also: https://github.com/nlog/nlog/wiki/Gdc-Layout-Renderer