Search code examples
.netloggingnlog

NLog load configuration from both file and code


I'm using NLog 4.7.2. I would like to configure it from code. However, I would like to retain the possibility to modify logging configuration without having to restart my application. I know I could roll something on my own (for instance, a switch on the UI that would modify the appropiate rules and call LogManager.ReconfigExistingLoggers()) but I would like to take advantadge of the existing functionality of XML configuration file autoreload.

My intention is to make a default configuration in code and then if something pops up and I need to increase the logging level, I would modify the XML configuration file without restarting the application.


Solution

  • Updated answer

    If using a NLog.config like this:

    <nlog autoreload="true" keepVariablesOnReload="true">
       <variable name="AppMinLevel" value="Warn" />
       <targets>
       </targets>
       <rules>
          <logger name="*" minLevel="${var:AppMinLevel}" writeTo="..." />
       </rules>
    </nlog>
    

    Then by referencing ${var:AppMinLevel} in the logging-rule, then you can just update the NLog config variable like this:

    NLog.LogManager.Variables["AppMinLevel"] = "Debug";
    LogManager.ReconfigExistingLoggers();
    

    See also: https://github.com/NLog/NLog/wiki/Filtering-log-messages#semi-dynamic-routing-rules

    Old Answer

    If using a NLog.config like this:

    <nlog autoreload="true">
       <variable name="minlevel" value="Warn" />
    </nlog>
    

    Then perform initial setup of LoggingConfiguration like this:

    SetupNLogConfig();
    LogManager.ConfigurationReloaded += (sender, args) => {
       SetupNLogConfig();
    }
    

    And have SetupNLogConfig like this:

    void SetupNLogConfig()
    {
         var config = LogManager.Configuration ?? new NLog.Config.LoggingConfiguration();
         Layout minLevel = config.Variables["minlevel"] ?? "Warn";
         string minLevelString = minLevel.Render(LogEventInfo.CreateNullEvent());
         LogLevel minLevelValue = LogLevel.FromString(minLevelString);
    
         // Targets where to log to: File and Console
         var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "file.txt" };
         var logconsole = new NLog.Targets.ConsoleTarget("logconsole");
            
         // Rules for mapping loggers to targets            
         config.AddRule(minLevelValue, LogLevel.Fatal, logconsole);
         config.AddRule(minLevelValue, LogLevel.Fatal, logfile);
            
         // Re-Apply config           
         NLog.LogManager.Configuration = config;
    }
    

    Then you can modify the minlevel-variable in NLog.config and it should re-configure with the updated value.

    See also: https://github.com/NLog/NLog/wiki/Configure-from-code#combine-nlogconfig-and-config-from-code