NLog 4.6 is live!

20 Mar 2019

NLog 4.6 contains lots of new features and performance improvements.

Main features

DatabaseTarget supports parameter types

It is now possible to configure the type for the DatabaseTarget parameters. Instead of always sending string-value then one can write the actual value-type.

<target name="db" xsi:type="Database" connectionstring="..." >
  <commandtext>INSERT INTO FooBar VALUES(@ts, @lvl, @msg)</commandtext>
  <parameter name="@ts" layout="${date}" dbType="SqlDbType.DateTime2" />
  <parameter name="@lvl" layout="${level}" dbType="DbType.Int32" />
  <parameter name="@msg" layout="${message}" dbType="SqlDbType.VarChar" size="-1" parameterType="String" />

When using a non-string DbType then it will attempt to convert the raw value directly to the expected type.

NetworkTarget supports SSL & TLS

NetworkTarget can now perform SSL/TLS handshake for the TCP-protocol:

<target name="net" type="network" address="tcp://" sslProtocols="Tls12" />

NetworkTarget has also received a new TCP option for activating KeepAliveTime. keepAliveTimeSeconds=”30” can be used to keep TCP connection going when no traffic (with very little overhead).

New XmlLayout

XmlLayout is now available for creating XML files.

Just like with JsonLayout then XmlLayout supports object reflection, so it can be used in combination with structured logging.

<layout xsi:type="XmlLayout" includeAllProperties="True" elementName='logevent'>
  <attribute name="time" layout="${longdate}" />
  <attribute name="level" layout="${level:upperCase=true}"/>
  <element name="message" layout="${message}" />

Will write:

<logevent time="2010-01-01 12:34:56.0000" level="ERROR">
  <message>hello, world</message>

This can also be used together with the DatabaseTarget for writing XML to a database:

<parameter name="@props" dbType="SqlDbType.Xml" size="-1">
  <layout type="xmllayout" includeAllProperties="true" />

Variables in level attributes

In the XML configuration you could now variables in the level attributes (minlevel, maxlevel, level and levels),


   <variable name='myLevel' value='debug'/>
      <logger minLevel='${myLevel}'/>

Note: for performance reasons, ${var:myLevel} or other layout renderers won’t work.

Added default action for filtering

Currently the default action for filtering - when not matching any rule - is “neutral”.

This is a bit tricky. This could be now configured with the attribute defaultAction. Possible values: Neutral, Ignore, Log, LogFinal, IgnoreFinal

    <logger name='*' level='Warn' writeTo='myTarget'>
        <filters defaultAction='Ignore'>
            <when condition="starts-with(message, 't')" action='Log' />

In NLog 5 the default will be probably changed to “ignore”

Substring, left and right

New layout renders has been added:

${substring:${level}:start=2:length=2}    // from index 2, length 2
${substring:${level}:start=-2:length=2}   // from end -2, length 2
${left:${level}:length=2}    // from start, length 2
${right:${level}:length=2}   // from end, length 2

Name filter: support for multiple wildcards and in any position

In NLog 4.5 and before, the wildcards in the name filter of the element was limited.

  • ? was not supported
  • Only one * was allowed the name filter.

With a new implementation, those restrictions are now gone and ? wildcard has been added.

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


<logger name="*.Library.*" minlevel="Warn" writeTo="f3" />
<logger name="*TcpTestServer[*].Connection[??].*" writeTo="logconsole" />

InternalLogFile variables

The internalLogFile attribute is for stability limited in features, no layout renderers where allowed.

In NLog 4.6 we added support for: ${currentdir}, ${basedir} & ${tempdir}, and for environment variables, like %myPath%


<nlog internalLogFile="${basedir}\log.txt" internalLogLevel="Trace">
      <!-- target configuration here -->
      <!-- log routing rules -->

AsyncWrapper uses ConcurrentQueue

ConcurrentQueue has been optimized with .NET Standard 2.0, so it provides high performance and little allocation.

NLog AsyncWrapper will now automatically make use of ConcurrentQueue when running on .NET Core 2 platform. This will greatly reduce the congestion overhead of having multiple threads writing to the same AsyncWrapper.

AsyncWrapper with faster timer

AsyncWrapper no longer schedules a timer every 50 ms even if nothing to write. Instead, it will schedule a single timer on first write and the timer will trigger after 1 ms.

This allows the AsyncWrapper to handle high loads out of the box, but will also make it more aggressive on the target it is wrapping. Instead of writing 40000 msgs/sec then it will handle 400000 msgs/sec.

ColoredConsoleTarget supports Ansi output

Console coloring now also works on VS Code or other console terminal using ANSI color escape sequences.

<target name="console" xsi:type="ColoredConsole" enableAnsiOutput="true" />

AppSetting without NLog.Extended

NLog.Extended was needed when wanting to use ${appsetting} on .NET Framework. However it also had dependencies on System.Messaging (MSMQ). Since NLog already dependends on System.Configuration then it didn’t make sense also to need NLog.Extended for reading app.config / web.config.


The new releases will also publish a snupkg to, for improved package debugging experience. See also the NuGet blog

LibLog Breaking change

damianh/LibLog#181 - Sub-components using LibLog ver. 5.0.3 (or newer) will now use MDLC + NDLC (Instead of MDC + NDC) when detecting application is using NLog ver. 4.6.

  • Make sure to update NLog.config to match this change.
  • Make sure that all sub-components have upgraded to LibLog ver. 5.0.3 (or newer) if they make use of OpenNestedContext or OpenMappedContext.

Many other improvements

For a full list of all the enhancements and performance improvements: NLog 4.6 Release Notes

Happy logging!