1

I'm trying to generate targets & logger at runtime, based on another target. Let's assume that I have a functionnal Foo logger: I'd like to generate separate rules for Foo.1, Foo.2, etc etc, but I can't know what will be the last logger I'll have to create (thus, I can't define them declaratively).

So far, I did something like this:

public GetNewClonedLogger(int fooId)
{
    var config = NLog.LogManager.Configuration;
    var newFooName = $"Foo.{fooId}";
    FileTarget baseTarget = NLog.LogManager.Configuration.FindTargetByName<FileTarget>("Foo");

    // Copy the base target
    var newTarget = new FileTarget(newFooName)
    {
        Layout = baseTarget.Layout,
        CreateDirs = true,
        FileName = baseTarget .FileName.ToString().Replace("${var:filename}", newFooName),
        ArchiveAboveSize = baseTarget.ArchiveAboveSize,
        BufferSize = baseTarget.BufferSize,
        ArchiveFileName = baseTarget.ArchiveFileName,
        MaxArchiveFiles = baseTarget.MaxArchiveFiles,
        ArchiveDateFormat = baseTarget.ArchiveDateFormat,
        ArchiveEvery = baseTarget.ArchiveEvery,
        FileAttributes = baseTarget.FileAttributes,
        KeepFileOpen = baseTarget.KeepFileOpen,
        ArchiveNumbering = baseTarget.ArchiveNumbering,
    };

    // Add configs & flush
    NLog.LogManager.Configuration.AddTarget(newTarget);
    NLog.LogManager.Configuration.AddRuleForAllLevels(newTarget, newFooName);

    // I tried every combinations of the following, without success
    NLog.LogManager.ReconfigExistingLoggers();
    NLog.LogManager.Configuration = config;
    NLog.LogManager.Configuration.Reload();

    NLog.LogManager.GetLogger(newFooName);
}

This function returns a logger, that seems OK on every points: the target name is OK, the filename is OK, the NLog.LogManager.Configuration has a new rule with the correct name (Foo.1, Foo.2, ...), and so are AllTargets. But when I log using the returned logger, no file is created, and it is exacly like nothing happened at all....

I've tried the solution proposed in this thread, without success.... What am I missing?

Thanks for your help!

  • 1
    I think we can get this working, but I doubt if you really want this. What is the case this is needed for? A lot of properties of the targets are templatable, so most of the time no dynamic rules and targets are needed. – Julian Oct 11 '18 at 14:01
  • Please also note that changing (global) config isn't threadsafe. – Julian Oct 11 '18 at 14:01
  • I have to merge the template configuration with some other sources (such as database-sourced config, for example). We are aware about the thread-unsafe aspect of this approach, so we implemented our actual logger generation using `lock` keywords where required. Also, I solved the problem (see below), but thank you for your advices – Alexandre Germain Oct 11 '18 at 14:57

1 Answers1

1

Actually, this was a really silly error, as this may work as I expected. The problem was that baseTarget.FileName is a Layout object, and the stringification using .ToString() made bad conversions, by adding quotes to the output ('C:\...'). Thus, NLog threw errors, that were partially silented by NLog config & quite hard to understand anyway. I fixed it by checking if baseTarget.FileName is a SimpleLayout (the only class I had to handle in my case), then retrieve the OriginalText out from that layout. Then, it worked like a charm.