Skip to content
Rolf Kristensen edited this page Mar 17, 2024 · 138 revisions

NLog will only produce output if having configured one (or more) NLog targets. NLog can be configured using XML by adding a NLog.config, that will be described in the page.

Everything that could be configured from XML file, could be also configured in code. How to config from code is in short described in Configure from code.

Please note that most concepts of configuring (XML or from API) are described here with a XML example.

Contents

File locations
NLog config XML
Top-level elements
Targets
Log levels
Rules
Variables
Layouts and layout renderers
Asynchronous processing and wrapper targets
Default wrappers
Default target parameters
Extensions
Automatic reconfiguration
Include files
Content escaping
Troubleshooting logging

File locations

At startup, NLog searches for its configuration in various files as described below. It loads the first nlog configuration found. Search ends when the first nlog configuration is found. NLog will not perform any logging if configuration is not found.

For a stand-alone *.exe application, files are searched as follows:

  • standard application configuration file app.config (Ex. applicationname.exe.config)
  • applicationname.exe.nlog in application’s directory
  • NLog.config in application’s directory
  • NLog.dll.nlog in a directory where NLog.dll is located (only if NLog isn't installed in the GAC)

For an ASP.NET application, files are searched as follows:

  • standard web application configuration file web.config
  • web.nlog located in the same directory as web.config
  • NLog.config in application’s directory
  • NLog.dll.nlog in a directory where NLog.dll is located (only if NLog isn't installed in the GAC)

See also Explicit NLog configuration loading (Includes details about assets-folder for Xamarin Android).

NLog config XML

NLog configuration is formatted as XML and is either embedded in a Visual Studio project config file (app.config or web.config) or is a stand-alone XML file (Remember to configure File Properties: Copy If newer)

Example XML for a stand-alone NLog.config:

<?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>
        <target name="logfile" xsi:type="File" fileName="file.txt" />
        <target name="logconsole" xsi:type="Console" />
    </targets>

    <rules>
        <logger name="*" minlevel="Info" writeTo="logconsole" />
        <logger name="*" minlevel="Debug" writeTo="logfile" />
    </rules>
</nlog>

To embed NLog config XML inside app.config / web.config file, add an nlog section element under configSections and add an nlog element. For example:

<configuration>
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
  </configSections>
  ...
  <nlog>
    <targets>
       <target name="logconsole" xsi:type="Console" />
    </targets>
    <rules>
       <logger name="*" minlevel="Info" writeTo="logconsole" />
    </rules>
  </nlog>
</configuration>

The use of an XML namespace is optional, but enables Intellisense in Visual Studio.

NLog config XML is case-insensitive for Xml-Nodes and Xml-Attributes, when not using a namespace and is case-sensitive when using a namespace.

Top-level elements

You can use the following elements as children to nlog. targets and rules are required in any configuration The others are optional and can be useful in advanced scenarios.

  • targets – defines log targets/outputs
  • rules – defines log routing rules
  • extensions – loads NLog extensions from the *.dll file
  • include– includes external configuration file
  • variable – sets the value of a configuration variable

The simplest configuration consists of one target and one rule (logger) that routes messages to the target.

Targets

The targets section defines log Targets. Each target is represented by a target element. There are two attributes required for each target:

  • name – target name
  • type – target type – such as "File", "Database", "Mail". When using namespaces this attribute is named xsi:type.

In addition to these attributes, targets usually accept other parameters, which impact the way diagnostic traces are written. Each target has a different set of parameters, they are described in detail on project’s homepage and they are context-sensitive. Intellisense is also available in Visual Studio.

For example – the File target accepts the fileName parameter which defines output file name and the Console target has the error parameter which determines whether the diagnostic traces are written to standard error (stderr) instead of standard output (stdout) of the process.

This example demonstrates a targets section which defines multiple targets: two files, one network target and OutputDebugString target:

<targets>
  <target name="f1" xsi:type="File" fileName="file1.txt"/>
  <target name="f2" xsi:type="File" fileName="file2.txt"/>  
  <target name="n1" xsi:type="Network" address="tcp://localhost:4001"/>
  <target name="ds" xsi:type="OutputDebugString"/>
</targets>

NLog provides many predefined Targets. It’s actually very easy to create your own target - see How to write a custom Target.

Log levels

Each log entry has a level. And each logger is configured to include or ignore certain levels. A common configuration is to specify the minimum level where that level and higher levels are included. For example, if the minimum level is Info, then Info, Warn, Error and Fatal are logged, but Debug and Trace are ignored.

The log levels ordered by severity:

LogLevel Ordinal Severity Typical Use
Trace 0 Most verbose level. Used for development and seldom enabled in production. Ex. Request-payload, Response-payload, Begin-method-X or End-method-X
Debug 1 Debugging the application behavior from internal events of interest. Ex. Executed query, User authenticated, Session expired
Info 2 Information that highlights progress or application lifetime events.
Warn 3 Warnings about validation issues or temporary failures that can be recovered.
Error 4 Errors where functionality has failed or Exception have been caught.
Fatal 5 Most critical level. Application is about to abort.
Off 6 Artificial level for disabling logger output

The special loglevel Off has the highest ordinal value. It is not used for LogEvents, but can be used for filtering in logging rules.

Rules

The rules section controls how LogEvents from the Logger-objects are redirected to output targets. Where logger-name and log levels can be used for filtering.

When creating a NLog Logger-object then one must provide a logger-name like NLog.LogManager.GetLogger("my logger name"). The logger-name can also be extracted from class-context by using NLog.LogManager.GetCurrentClassLogger() where logger-name becomes "NameSpace.ClassName".

A single rule is defined with a logger element that filters what Logger-objects to match:

  • name – Match logger-name of the Logger-object - may include wildcard characters (* and ?)
  • minlevel – minimum level to log (matches the specified level and levels above)
  • maxlevel – maximum level to log (matches the specified level and levels below)
  • level – single level to log
  • levels - comma separated list of levels to log
  • writeTo – comma separated list of targets to write to
  • final – no rules are processed after a final rule matches
  • enabled - set to false to disable the rule without deleting it
  • ruleName - rule identifier to allow rule lookup with Configuration.FindRuleByName and Configuration.RemoveRuleByName. Introduced in NLog 4.6.4
  • finalMinLevel - Loggers matching will be restricted to specified minimum level for following rules. Introduced in NLog 5.0

The example below shows a single rule that will match ALL Logger-objects independent of their logger-name because of name="*". At the same time it will only match LogEvents with minimum LogLevel = Info (or more severe). LogEvents matching these criterias will be written to the console-target.

<targets>
       <target name="logconsole" xsi:type="Console" />
</targets>
<rules>
       <logger name="*" minlevel="Info" writeTo="logconsole" />
</rules>

Rules are processed in sequential order. Multiple rules may apply to a logger. Use final to stop processing rules after a match is found.

Note: Although a rule is named logger, it does not define a logger. It references one or more loggers based on the name-pattern.

Logger Name Filter

A rule is mapped to a logger by matching the rule name pattern to a logger name. A rule name attribute may include wildcard characters (* and ?) to match logger names by wildcard matching.

  • * - matches 0 or more characters
  • ? - matches exactly 1 character

When using NLog.LogManager.GetCurrentClassLogger() then the logger name will have the format "NameSpace.ClassName". This makes it very convenient to setup filtering for all classes within a namespace:

<logger name="Name.Space.*" writeTo="target1" />

By using logger-name filtering then one can also redirect output for a single ClassName-logger:

<logger name="Name.Space.Class1" writeTo="target2" /> <!-- Add final=true to stop output to target1 -->
<logger name="Name.Space.*" writeTo="target1" />

One can also reduce the logging from a single ClassName-logger:

<logger name="Name.Space.Class2" maxlevel="Warn" final="true" /> <!-- Blackhole that stops all but Error + Fatal -->
<logger name="Name.Space.*" writeTo="target1" />

One can also completely block a single ClassName-logger:

<logger name="Name.Space.Class3" maxlevel="Off" final="true" /> <!-- Blackhole that stops everything -->
<logger name="Name.Space.*" writeTo="target1" />

Before NLog 4.6 then one could only use wildcards (*) at the beginning and/or at the end of the pattern:

<rules>
  <logger name="*" minlevel="Info" writeTo="logconsole" />
  <logger name="Name.Space.*" minlevel="Debug" writeTo="f1" />  
  <logger name="*.Class1" minlevel="Trace" writeTo="f2" />
  <logger name="*.Library.*" minlevel="Warn" writeTo="f3" />
</rules>

Since NLog 4.6, wildcards (* and ?) are allowed in any position.

<rules>
  <logger name="*TcpTestServer[*].Connection[07].*" minlevel="Trace" writeTo="logconsole" final="true" />
  <logger name="*TcpTestServer[*].Connection[??].*" minlevel="Debug" writeTo="logconsole" final="true" />
  <logger name="*" minlevel="Info" writeTo="logconsole" />
</rules>

Logger Level Filter

A rule defines which log entry level(s) are matched. Entries with other levels will not match this rule. A commonly used specifier is minlevel. The other specifiers allow for more advanced configuration.

If a rule contains more than one level-declaring attribute (level, levels, minlevel and maxlevel) only the first level-declaring attribute or set is used and the rest are ignored.

The level-declaring attributes are processed in the following order:

  1. level
  2. levels
  3. minlevel and maxlevel (these have the same priority)
  4. none (all levels are logged)

For example: if minlevel="Warn" level="Info" is used, the rule will only use Info

In case a rule is marked as final and contains any level-declaring attributes, the final attribute applies only to the specified levels.

Dynamic Logger Level Filter

The logging rules provides high performance because of their static nature. The options for configuration has been very limited. But recent changes has now been made to improve this:

  • NLog 4.6 added support for using NLog Config Variables to configure level attributes. (level, minlevel etc):
<variable name='globalLevel' value='debug'/>

<rules>
  <logger minlevel='${globalLevel}'/>
</rules>
  • NLog 4.6.4 added support for lookup of Logging Rules using RuleName using Configuration API

  • NLog 4.6.7 added support for using NLog Layout like ${gdc:globalLevel} to dynamically change level attributes at runtime. See also Semi Dynamic Routing Rules

Variables

NLog Config Variables allows you to simplify configuration by reducing repeated text. Variable can be used to give a human name to a NLog Layout that is commonly used (or is long and complex). This makes it easier to organize and structure the NLog config.

Define a custom variable as follows:

<variable name="varname" value="xxx" />

The value of a variable can be inserted into an attribute value via the ${varname} syntax. A variable value can even be used to define the value of another variable. The following example shows using a pre-defined variable shortdate and defining and using a custom variable logDirectory.

<nlog>
  <variable name="logDirectory" value="logs/${shortdate}"/>
  <targets>
    <target name="file1" xsi:type="File" fileName="${logDirectory}/file1.txt"/>
    <target name="file2" xsi:type="File" fileName="${logDirectory}/file2.txt"/>
  </targets>
</nlog>

With this syntax, a variable must be defined before use. Otherwise configuration initialization will fail. Note ${gdc} can be used used as an alternative to configuration variables, as they work independent of loading / unloading / reloading different NLog configurations.

NLog Config variables can operate in two modes:

  • Constant mode - ${varName}
  • Dynamic mode - ${var:varName} (Introduced with NLog 4.1)

Constant mode (or static mode) works for all types of properties independent of their type, but they will not react to runtime changes.

Dynamic mode only works for properties of the type NLog Layout, and provides the following abilities:

  • Variables can be changed, deleted and created from the Configuration API
  • A default value can be configured for a variable, e.g. ${var:password:default=unknown}
  • By default all variables assigned at runtime are kept even after configuration reloads. Unless having configured keepVariablesOnReload="false".

    NLog 4.4 introduced keepVariablesOnReload and before NLog 5.0 the default value was false

NLog 5.0 extends NLog config variables to also handle complex Layout types like JsonLayout + CsvLayout. Ex:

<nlog>
  <variable name="myJsonLayout">
    <layout type="JsonLayout">
       <attribute name="message" value="${messsage}">
    </layout>
  </variable>
  <targets>
    <target name="debug" type="Debug" layout="${myJsonLayout}" />
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="debug" />
  </rules>
</nlog>

Layouts and layout renderers

One of NLog’s strongest assets is the ability to use layouts. In the simplest form, layouts are texts with embedded tags delimited by ${ and }. The tags are called Layout Renderers and can be used to insert pieces of contextual information into the text.

Layouts can be used in many places, for example they can control the format of information written on the screen or sent to a file, but also to control the file names themselves. This is very powerful, which we’ll see in a moment.

Let’s assume, that we want to annotate each message written to the console with:

  • current date and time
  • name of the class and method that emitted the log message
  • log level
  • message text

This is very easy:

<target name="c" xsi:type="Console"  layout="${longdate} ${callsite} ${level} ${message}"/>

We can make each messages for each logger go to a separate file, as in the following example:

<target name="f" xsi:type="File" fileName="${logger}.txt"/>

As you can see, the ${logger} layout renderer was used in the fileName attribute, which causes each log message to be written to the file whose name includes the logger name. The above example will create the following files:

  • Name.Space.Class1.txt
  • Name.Space.Class2.txt
  • Name.Space.Class3.txt
  • Other.Name.Space.Class1.txt
  • Other.Name.Space.Class2.txt
  • Other.Name.Space.Class3.txt

Asynchronous processing and wrapper targets

NLog provides wrapper and compound targets which modify other targets’ behavior by adding features like:

  • asynchronous processing (wrapped target runs in a separate thread)
  • retry-on-error
  • load balancing
  • buffering
  • filtering
  • failover (failover)

To define a wrapper in the configuration file, simply nest a target node within another target node. You can even wrap a wrapper target - there are no limits on depth. For example, to add asynchronous logging with retry-on-error functionality add this to your configuration file:

<targets>
  <target name="n" xsi:type="AsyncWrapper">
    <target xsi:type="RetryingWrapper">
      <target xsi:type="File" fileName="${file}.txt" />
    </target>
  </target>
</targets>

Because asynchronous processing is a common scenario, NLog supports a shorthand notation to enable it for all targets without the need to specify explicit wrappers. You can simply set async="true" on targets element and all your targets within that element will be wrapped with the AsyncWrapper target.

<nlog>
  <targets async="true">
    <!-- all targets in this section will automatically be asynchronous -->
  </targets>
</nlog>

Remember to Flush is very important, when using asynchronous background writing. It ensures all logging is written before application exit.

Default wrappers

Sometimes we require ALL targets to be wrapped in the same way, for example to add buffering and/or retrying. NLog provides <default-wrapper /> syntax for that. You simply put this element in the <targets /> section and all your targets will be automatically wrapped with the specified wrapper. Note that <default-wrapper /> applies to the single <targets /> section only and you can have multiple sections so you can define groups of targets that are wrapped in a similar manner.

<nlog>  
  <targets>  
    <default-wrapper xsi:type="BufferingWrapper" bufferSize="100"/>  
    <target name="f1" xsi:type="File" fileName="f1.txt"/>  
    <target name="f2" xsi:type="File" fileName="f2.txt"/>  
  </targets>  
  <targets>  
    <default-wrapper xsi:type="AsyncWrapper">  
      <wrapper-target xsi:type="RetryingWrapper"/>  
    </default-wrapper>  
    <target name="n1" xsi:type="Network" address="tcp://localhost:4001"/>  
    <target name="n2" xsi:type="Network" address="tcp://localhost:4002"/>  
    <target name="n3" xsi:type="Network" address="tcp://localhost:4003"/>  
  </targets>  
</nlog>

In the above example we’ve defined two buffered File targets and three asynchronous and retrying Network targets.

Default target parameters

Similar to default wrappers, NLog provides <default-target-parameters /> which enables you to specify default values of target parameters. For example, if you don’t want files to be kept open, you can either add keepFileOpen="false" to each target, as in the following example:

<nlog>
  <targets>
    <target name="f1" xsi:type="File" fileName="f1.txt" keepFileOpen="false"/>
    <target name="f2" xsi:type="File" fileName="f2.txt" keepFileOpen="false"/>
    <target name="f3" xsi:type="File" fileName="f3.txt" keepFileOpen="false"/>
   </targets>
</nlog>

Alternatively you can specify a single <default-target-parameters /> that applies to all targets in the <targets /> section. Default parameters are defined on a per-type basis and are applied BEFORE the actual attributes defined in the XML file:

<nlog>
  <targets>
    <default-target-parameters xsi:type="File" keepFileOpen="false"/>
    <target name="f1" xsi:type="File" fileName="f1.txt"/>
    <target name="f2" xsi:type="File" fileName="f2.txt"/>
    <target name="f3" xsi:type="File" fileName="f3.txt"/>
  </targets>
</nlog>

Extensions

Extensions can be configured to include additional NLog packages or custom ones:

Just reference the DLL in the config in the <extensions /> as shown below. The name should not include the .dll

Configuration file example:

<nlog> 
  <extensions> 
    <add assembly="MyAssembly"/> 
  </extensions> 
  <targets> 
    <target name="a1" type="MyTarget" host="localhost"/> 
  </targets> 
  <rules> 
    <logger name="*" minlevel="Info" appendTo="a1"/> 
  </rules> 
</nlog>

With NLog 5.0 it is also possible to specify fully qualified type-name, instead of needing to update <extensions>-section. This makes the snippets more isolated:

<nlog> 
  <targets> 
    <target name="a1" type="MyTarget, MyAssembly" host="localhost"/> 
  </targets> 
  <rules> 
    <logger name="*" minlevel="Info" appendTo="a1"/> 
  </rules> 
</nlog>

NLog 5.0 no longer automatically scans and loads extensions from assemblies with NLog-prefix. Because it introduced overhead during startup, and failed to work with <packagereference>. See also Register-your-custom-component

Automatic reconfiguration

The configuration file is read automatically at program startup. In a long running process (such as a Windows service or an ASP.NET application) it’s sometimes desirable to temporarily increase the log level without stopping the application. NLog can monitor logging configuration files and re-read them each time they are modified. To enable this mechanism, you simply add autoReload="true" parameter to the configuration file.

<nlog autoReload="true">
   ...
</nlog>

Note that automatic reconfiguration supports include files, so each time one of the included files is changed, the entire configuration gets reloaded.

Just to make it explicit, automatic reloading will NOT stop/recycle the IIS Application Pool.

Include files

NLog provides an include file feature so that configuration can be stored in multiple files.

<include file="nlog-common.config" />

Like most attributes in NLog config, the file attribute may reference variables. The following example includes a file named the same as the machine that nlog is running on.

<include file="${machinename}.config" ignoreErrors="true" />

Setting the attribute ignoreErrors to true prevents a startup failure if the include file cannot be loaded -- file not found, invalid XML, .... Use the Troubleshooting logging section to log errors. This attribute is optional and defaults to false.

Since NLog 4.4.2, wildcards (*) are allowed. E.g. <include file="nlog-*.config"/>

A larger example can be found here: XML config <include /> example

Content escaping

In the configuration file some characters needs to be escaped. Because it XML file, the < and > brackets should be escaped with &lt; and &gt;. This also holds for the attribute values, like a condition.

Inside a layout we need to escape the } bracket and the colon : should be escaped because:

  • : is the value separator.
  • } is the end of the layout

Nested layout renderers doesn't need escaping. Also the backslash doesn't need an escape.

Examples:

  • ${appdomain:format={1\}{0\}} (escape of })
  • ${rot13:inner=${scopenested:topFrames=3:separator=x}} (no escaping needed)
  • ${when:when=1 == 1:Inner=Test\: Hello} (escape of :)

Troubleshooting logging

Sometimes our application doesn’t write anything to the log files, even though we have supposedly configured logging properly. There can be many reasons for logs not being written. The most common problems are permissions issues, usually in an ASP.NET process, where the aspnet_wp.exe or w3wp.exe process may not have write access to the directory where we want to store logs.

NLog is designed to swallow run-time exceptions that may result from logging. The following settings can change this behavior and/or redirect these messages.

  • <nlog throwExceptions="true" /> - adding the throwExceptions attribute in the config file causes NLog to stop masking exceptions and pass them to the calling application instead. This attribute is useful at deployment time to quickly locate any problems. It is critical that one configure throwExceptions to "false" as soon as the application is properly configured to run, so accidental logging problems will not cause application to hang or crash.
  • <nlog throwConfigExceptions="true" /> - Similar to throwExceptions but isolated to configuration exceptions only. Unlike throwExceptions then it is not dangerous to have enabled, and is recommended for production environments where it is critical that initial setup of logging configuration succeeds. Introduced in NLog 4.3. Default null (Means not configured and instead use value of throwExceptions)
  • <nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" /> – determines the internal log level. The higher the level, the less verbose the internal log output. The output is usually very helpful when needing to diagnose logging issues. See Internal-logging for options to setup output to File or Console.

See also Logging-troubleshooting

Clone this wiki locally