Skip to content

Configure from code

Rolf Kristensen edited this page Jun 7, 2023 · 30 revisions

NLog can be also configured programmatically.

All options match with the attribute names in the XML config, so for all config options you could check https://nlog-project.org/config/

There is also a SHFB docs, see https://nlog-project.org/documentation/

Fluent API Example

NLog 5.0 introduces a Fluent-Configuration-API so you can do this instead:

NLog.LogManager.Setup().LoadConfiguration(builder => {
   builder.ForLogger().FilterMinLevel(LogLevel.Info).WriteToConsole();
   builder.ForLogger().FilterMinLevel(LogLevel.Debug).WriteToFile(fileName: "file.txt");
});

Simple Example

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;

Extended Features

Passing Custom Values

There are many ways to capture current Context and output it to the final target. Simple example:

logger.Info("Message with {myProperty}", "myValue");

Render with ${event-properties:myProperty}

Add this to Layout, e.g.

var fileTarget = new FileTarget("target2")
{
    FileName = "${basedir}/file.txt",
    Layout = "${longdate} ${level} ${message}  ${exception} ${event-properties:myProperty}"
};

For many more examples, see ${event-properties} layout renderer.

Creating dynamic Layouts

NLog Layout will implicitly convert from string-objects. It will automatically parse the string and compile it into the recognized Layout-Renderers.

NLog will perform validation when parsing, but errors detected will be swallowed unless having enabled LogManager.ThrowConfigExceptions. But one can also force NLog to throw parsing error no matter what:

var layout = NLog.Layouts.Layout.FromString("${evil}", throwConfigExceptions: true); // will throw

NLog 4.7 also allows you to generate a Layout from a simple lambda-method:

var unixTime = NLog.Layouts.Layout.FromMethod(logEvent => ((DateTimeOffset)logEvent.TimeStamp).ToUnixTimeSeconds().ToString());
var jsonLayout = NLog.Layouts.JsonLayout()
{
    Attributes = { new NLog.Layouts.JsonAttribute("unixtime", unixTime) { Encode = false } }
};

!! NOTICE !! Ensure that custom method given to Layout.FromMethod is very simple. Deadlock or StackOverflow can occur if performing complex logic that triggers new logevents or acquiring locks.

Update config in code

It is possible to dive into the NLog LoggingConfiguration and assign properties directly. But NLog is much happier about using NLog Layout logic when possible. Example:

<target type="file" name="logfile" filename="${gdc:CompanyName:whenEmpty=Default}_${shortdate}.log" />

Then in code one can just update the GDC-item, and it will take effect right away:

NLog.GlobalDiagnosticsContext.Set("CompanyName", "SuperPower");

This removes the need to know the exact NLog-target names in the NLog.config, so it decouples the logic even further and makes it more resilient. This will also work excellent together with autoReload="true", as you don't have to re-apply the same settings again, as it will happen automatically. This can also be used for adjusting logging rules dynamically at runtime.

But if you really want to get your hands dirty, then here you go:

var configuration = LogManager.Configuration;

// Update single target
var myFileTarget = configuration.FindTargetByName<FileTarget>("myTargetName");
if (myFileTarget != null)
    myFileTarget.FileName = "SuperPower" + "_${shortdate}.log";
LogManager.Configuration = configuration; // re-init

// Update all targets
foreach (var fileTarget = configuration.AllTargets.OfType<FileTarget>())
{
   fileTarget.FileName = "SuperPower" + "_${shortdate}.log";
}
LogManager.Configuration = configuration; // re-init

Combine nlog.config and config from code

Please note that combining the config file (nlog.config) and changing it in code, the reload of nlog.config could undo your changes. If you combine both, then reapply the changes on the reload event. E.g.

// On start of your program
UpdateConfig();

LogManager.ConfigurationChanged += (sender, e) =>
{
    if (e.ActivatedConfiguration != null)
    {
        //Re apply if config reloaded
        UpdateConfig();
    }
};

Where UpdateConfig is

public void UpdateConfig()
{
     // Do NOT set LogManager.Configuration because that will cause recursion and stackoverflow
    var fileTarget = LogManager.Configuration.FindTargetByName<FileTarget>("myTargetName");
    fileTarget.FileName = "${basedir}/file.log";
    LogManager.ReconfigExistingLoggers(); // Soft refresh
}

Instead of trying to perform patching of NLog-configuration, then it is recommended to make use of NLog Layouts for Target configuration by forexample using ${gdc}

Clone this wiki locally