Reconfigure NLog LoggingConfiguration filters programmatically

36,095

Solution 1

I know I'm a year late but I just ran into similar scenario where I needed to provide dynamic control of the logger to users. Fortunately, this is relatively easy with nlog. Here I'm just enabling Trace level logging to an already created Logger but obviously you could do anything you wanted including adding new Targets/Rules or just completely replace the LoggerConfiguration with your programmatically generated one.

Basic ColoredConsole nlog.config:

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target xsi:type="ColoredConsole" name="c"
            layout="${longdate} ${uppercase:${level}} ${message}" />
  </targets>
  <rules>
    <logger name="*" minlevel="Error" writeTo="c" />
  </rules>
</nlog>

Simple console application:

public class Program 
{
  //Initialize default Logger from config file
  private static readonly Logger m_log = LogManager.GetCurrentClassLogger();

  public static Logger Log 
  {
      get { return m_log; }
  }

  public static void Main(string[] args) 
  {
    Log.Trace("You won't see me because config is at LogLevel.Error");
    EnabledTraceForAllRules();
    Log.Trace("You will see me now though!");

    //Pause console window
    Console.WriteLine("Press any key to continue...");
    Console.ReadKey(true);

    /* Prints:
    2013-05-07 16:04:22.7050 TRACE You will see me now though!
    Press any key to continue...
    */
  }

  public static void EnabledTraceForAllRules() 
  {
    foreach(var rule in LogManager.Configuration.LoggingRules)
    {
      rule.EnableLoggingForLevel(LogLevel.Trace);
    }

    //Call to update existing Loggers created with GetLogger() or 
    //GetCurrentClassLogger()
    LogManager.ReconfigExistingLoggers();
  }
}

If you need to alter the Logging configuration from outside the process and it has to be done programmatically, I would suggest going with WCF. You could expose a small WCF service from either your application or website that provides methods for reconfiguring nlog.

Solution 2

I found "Configuration API" in NLog documentation (https://github.com/NLog/NLog/wiki/Configure-from-code), may be this help you. Look at NLog.Config namespace in NLog assembly too.

See also: https://github.com/NLog/NLog/wiki/Reinitialize-NLog-configuration

Solution 3

NLog 4.6.7 introduces the ability to use Layout-logic in the LoggingRules. So you can have a NLog.config with logging-rules that are easily adjusted at runtime:

<nlog>
   <variable name='myLevel' value='Warn'/>
    <rules>
      <logger minLevel='${var:myLevel}' writeTo="your-target-name" />
    </rules>
</nlog>

Then one can update myLevel at runtime:

LogManager.Configuration.Variables["myLevel"] = "Debug";
LogManager.ReconfigExistingLoggers();

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

Solution 4

I see answers enabling one level at a time, but if you want to mirror the behavior of NLog.config file, where setting a single level also enables all higher priority levels (and disables lower priority ones), you need to enable a range of levels using SetLoggingLevels like this:

NLog.config:

  <rules>
    <logger name="*" minlevel="Trace" writeTo="your-target-name" />
  </rules>

Code:

public static void SetLogLevel(LogLevel newLogLevel)
{
    foreach (var rule in LogManager.Configuration.LoggingRules)
    {
        foreach (var target in rule.Targets)
        {
            if (target.Name == "your-target-name")
            {
                rule.SetLoggingLevels(newLogLevel, LogLevel.Fatal);
            }

        }
    }

    LogManager.ReconfigExistingLoggers();
}

From NLog documentation:

public void SetLoggingLevels(LogLevel minLevel, LogLevel maxLevel);

Enables logging the levels between (included) minLevel and maxLevel. All the other levels will be disabled.

Solution 5

A programmatic initial setup example is given on the NLog tutorial page here which I've included below. (There's a slightly more extensive version here.)

public static void Startup()
{
    var config = new NLog.Config.LoggingConfiguration();

    // 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(LogLevel.Info, LogLevel.Fatal, logconsole);
    config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile);

    // Apply config           
    NLog.LogManager.Configuration = config;
    LogManager.ReconfigExistingLoggers();
}

Then, to change the log level, where logconsole is the target you want to change:

public static void SetConsoleLogLevel(LogLevel level)
{
    foreach (var rule in LogManager.Configuration.LoggingRules)
    {
        foreach (var ruleTarget in rule.Targets)
        {
            if (ruleTarget != logconsole) continue;

            DisableLoggingForLevels(rule, LogLevel.Trace, level);
            rule.EnableLoggingForLevels(level, LogLevel.Fatal);
            LogManager.GetCurrentClassLogger().Log(level, "Changed logger level to {0}", level);
        }
    }

    LogManager.ReconfigExistingLoggers();
}

where DisableLoggingForLevels is a private method exactly like NLog.Config.LoggingRule.EnableLoggingForLevels except that it disables:

private static void DisableLoggingForLevels(LoggingRule rule, LogLevel minLevel, LogLevel maxLevel)
{
    for (var ordinal = minLevel.Ordinal; ordinal <= maxLevel.Ordinal; ++ordinal)
        rule.DisableLoggingForLevel(LogLevel.FromOrdinal(ordinal));
}
Share:
36,095

Related videos on Youtube

snappymcsnap
Author by

snappymcsnap

Updated on April 24, 2021

Comments

  • snappymcsnap
    snappymcsnap about 3 years

    This is my first time using the NLog package for logging but so far its been great to work with.

    In my scenario I need to initialize my NLog LoggingConfiguration settings programmatically rather than thru the more typical config file scenario. I've tested this and got it all working the way I want it by default. But how would I go about modifying my settings programmatically at run-time?

    Probably the most common scenario here is one where the application's logging level is set to ERROR by default but a bug arises in a particular module that I want to switch the logging level to be much more verbose to track down the error.

    I'd like to write a little web interface so I can easily tweak these settings at runtime but I want to make sure I am taking the right approach with this.

    • Julian
      Julian over 7 years
      Please keep in mind that changing the min level to Trace could be done with the just the XML config without restarting the application.
  • Thomas
    Thomas over 7 years
    I would suggest a websocket service for this usage, it will be less heavy and easier to use than Wcf.
  • Nicolas Boisvert
    Nicolas Boisvert over 7 years
    LogManager.ReconfigExistingLoggers(); is the key here. Without this you won't be able to add logging target/rule
  • Rolf Kristensen
    Rolf Kristensen over 4 years
    NLog 4.6.7 allows you to make use of NLog Layout logic in logging-rules: stackoverflow.com/a/59535855/193178
  • Rolf Kristensen
    Rolf Kristensen over 4 years
    Remember also to call LogManager.ReconfigExistingLoggers(); when you are done updating all LoggingRules. Else the change will only take effect for newly created Logger-objects.
  • Eternal21
    Eternal21 over 4 years
    @RolfKristensen Thanks, forgot to copy it. Fixed now.