NLog2023-12-07T18:41:49+00:00https://nlog-project.org/NLogNLog 5.2 without trim warnings2023-05-30T00:00:00+00:00https://nlog-project.org/2023/05/30/nlog-5-2-trim-warnings<p>NLog v5.2 changes the recommended way for explicit registration of NLog extensions.
Already now the automatic scanning for assemblies containing NLog extensions was disabled with NLog v5.
Instead NLog users are encouraged to explicitly specify what NLog extensions to load.</p>
<p>NLog extensions are normally loaded by just specifying the assembly-name, and then NLog will dynamically
load the assembly, and NLog will then use reflection to enumerate the types inside the assembly.</p>
<p>When using NET trimming to strip away all unreferenced code, then dynamic assembly loading will not work well.
Dynamically loaded assemblies might reference code that have been stripped from the application. To prevent
all these issues then NET trimming will make build warnings about such possible pitfalls. Thus previous versions
of NLog are reported as being unsafe for NET trimming, because of the ability to dynamically load assemblies.</p>
<p>NLog v5.2 now recommends that one registers the individual NLog extension types like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupExtensions</span><span class="p">(</span><span class="n">ext</span> <span class="p">=></span> <span class="p">{</span>
<span class="n">ext</span><span class="p">.</span><span class="n">RegisterTarget</span><span class="p"><</span><span class="n">MyCustomTarget</span><span class="p">>();</span>
<span class="n">ext</span><span class="p">.</span><span class="n">RegisterLayout</span><span class="p"><</span><span class="n">MyCustomLayout</span><span class="p">>();</span>
<span class="n">ext</span><span class="p">.</span><span class="n">RegisterLayoutRenderer</span><span class="p"><</span><span class="n">MyCustomLayoutRenderer</span><span class="p">>();</span>
<span class="p">});</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">NLog.Web.AspNetCore</code> and <code class="language-plaintext highlighter-rouge">NLog.Extensions.Logging</code> have been updated to automatically register
their NLog extensions the recommended way when calling <code class="language-plaintext highlighter-rouge">UseNLog()</code> or <code class="language-plaintext highlighter-rouge">AddNLog()</code>.</p>
<p>If one needs the NLog Logger in ASP.NET Core before the HostBuilder has been created, then
<code class="language-plaintext highlighter-rouge">LoadConfigurationFromAppSettings()</code> will ensure to register NLog extensions before loading the NLog
configuration:</p>
<pre><code class="language-charp">var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
</code></pre>
<p>NLog v5.2 will no longer perform any assembly loading and scanning during initialization, unless explicitly requested
by the user. NLog will also automatically skip requests for assembly loading, when it detects that assembly types are already registered.
This means NLog will skip the <code class="language-plaintext highlighter-rouge"><extensions></code>-section when NLog detects relevant types are already registered the recommended way.</p>
<p>When enabling NET trimming on application publish, then make sure that NLog-configuration file, doesn’t depend on <code class="language-plaintext highlighter-rouge"><extensions></code>-section and dynamic assembly loading.
The NET trimming build-warnings about dynamic assembly loading issue has been suppressed in NLog v5.2, since it is no longer used unless explictly requested.
The next major version of NLog will extract all logic for dynamic assembly loading into a separate nuget-package.</p>
<h2 id="obsoleted-methods-that-conflicts-with-application-trimming">Obsoleted methods that conflicts with application trimming</h2>
<p>NLog v5.2 marks several methods as obsolete, to move towards the following goals:</p>
<ul>
<li>Move all dynamic assembly loading logic from <code class="language-plaintext highlighter-rouge">ConfigurationItemFactory</code> into <code class="language-plaintext highlighter-rouge">Setup()</code> extensions methods. Later moved into separate NLog-nuget-package with next major version.</li>
<li>Move all file loading logic from <code class="language-plaintext highlighter-rouge">LogManager</code> / <code class="language-plaintext highlighter-rouge">LogFactory</code> into <code class="language-plaintext highlighter-rouge">Setup()</code> extensions methods. Later moved into separate NLog-nuget-package with next major version.</li>
<li>Promote the <code class="language-plaintext highlighter-rouge">Setup()</code> extensions methods, instead of having many different static-methods.</li>
</ul>
<p>The following methods has been marked obsolete on <code class="language-plaintext highlighter-rouge">ConfigurationItemFactory</code>, with redirection to <code class="language-plaintext highlighter-rouge">Setup()</code> extensions methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">ConfigurationItemFactory(params Assembly[] assemblies)</code>-Constructor</li>
<li><code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.CreateInstance</code>-Method for legacy dependency-injection replaced by Register-extension-methods with custom factory-method.</li>
<li><code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.RegisterItemsFromAssembly</code>-Method for explicit assembly loading replaced by extension methods.</li>
<li><code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.AssemblyLoading</code>-EventHandler together with <code class="language-plaintext highlighter-rouge">AssemblyLoadingEventArgs</code></li>
<li><code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.PreloadAssembly</code>-Method for explicit assembly loading replaced by extension methods.</li>
<li><code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.RegisterType</code>-Method for explicit assembly loading replaced by extension methods.</li>
<li><code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.RegisterType</code>-Method for explicit assembly loading replaced by extension methods.</li>
<li><code class="language-plaintext highlighter-rouge">INamedItemFactory</code>-Interface prevents correct trimming annotations.</li>
<li><code class="language-plaintext highlighter-rouge">INamedItemFactory ConfigurationItemFactory.Targets</code>-Property prevents correct trimming annotations.</li>
<li><code class="language-plaintext highlighter-rouge">INamedItemFactory ConfigurationItemFactory.Layouts</code>-Property prevents correct trimming annotations.</li>
<li><code class="language-plaintext highlighter-rouge">INamedItemFactory ConfigurationItemFactory.LayoutRenderers</code>-Property prevents correct trimming annotations.</li>
<li><code class="language-plaintext highlighter-rouge">INamedItemFactory ConfigurationItemFactory.AmbientProperties</code>-Property prevents correct trimming annotations.</li>
<li><code class="language-plaintext highlighter-rouge">INamedItemFactory ConfigurationItemFactory.TimeSources</code>-Property prevents correct trimming annotations.</li>
<li><code class="language-plaintext highlighter-rouge">INamedItemFactory ConfigurationItemFactory.Filters</code>-Property prevents correct trimming annotations.</li>
<li><code class="language-plaintext highlighter-rouge">INamedItemFactory ConfigurationItemFactory.ConditionMethods</code>-Property prevents correct trimming annotations.</li>
</ul>
<p>The following methods has been marked obsolete on <code class="language-plaintext highlighter-rouge">LogManager</code> / <code class="language-plaintext highlighter-rouge">LogFactory</code>, with redirection to <code class="language-plaintext highlighter-rouge">Setup()</code> extension methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">LogManager.LoadConfiguration(string configFile)</code>-Method replaced by <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfigurationFromFile(...)</code></li>
<li><code class="language-plaintext highlighter-rouge">LogManager.ConfigurationReloaded</code>-EventHandler replaced by <code class="language-plaintext highlighter-rouge">LogManager.ConfigurationChanged</code>-EventHandler</li>
<li><code class="language-plaintext highlighter-rouge">LogManager.GetCandidateConfigFilePaths()</code>-Method replaced by chaining <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfigurationFromFile(...)</code></li>
<li><code class="language-plaintext highlighter-rouge">LogManager.SetCandidateConfigFilePaths()</code>-Method replaced by chaining <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfigurationFromFile(...)</code></li>
<li><code class="language-plaintext highlighter-rouge">LogManager.ResetCandidateConfigFilePath()</code>-Method replaced by chaining <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfigurationFromFile(...)</code></li>
</ul>
<p>The following methods has been marked obsolete on <code class="language-plaintext highlighter-rouge">SimpleConfigurator</code>, with redirection to <code class="language-plaintext highlighter-rouge">Setup()</code> extension methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">SimpleConfigurator.ConfigureForConsoleLogging</code>-Method replaced by <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfiguration(c => c.ForLogger().WriteToConsole())</code></li>
<li><code class="language-plaintext highlighter-rouge">SimpleConfigurator.ConfigureForFileLogging</code>-Method replaced by <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfiguration(c => c.ForLogger().WriteToFile(fileName))</code></li>
<li><code class="language-plaintext highlighter-rouge">SimpleConfigurator.ConfigureForTargetLogging</code>-Method replaced by <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfiguration(c => c.ForLogger().WriteTo(target))</code></li>
</ul>
<p>The following methods has been marked obsolete on <code class="language-plaintext highlighter-rouge">XmlLoggingConfiguration</code>, with redirection to <code class="language-plaintext highlighter-rouge">Setup()</code> extension methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">XmlLoggingConfiguration.GetCandidateConfigFilePaths()</code>-Method replaced by chaining <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfigurationFromFile(...)</code></li>
<li><code class="language-plaintext highlighter-rouge">XmlLoggingConfiguration.SetCandidateConfigFilePaths()</code>-Method replaced by chaining <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfigurationFromFile(...)</code></li>
<li><code class="language-plaintext highlighter-rouge">XmlLoggingConfiguration.ResetCandidateConfigFilePath()</code>-Method replaced by chaining <code class="language-plaintext highlighter-rouge">LogManager.Setup().LoadConfigurationFromFile(...)</code></li>
</ul>
<p>The following methods has been marked obsolete on <code class="language-plaintext highlighter-rouge">LayoutRenderer</code>, with redirection to <code class="language-plaintext highlighter-rouge">Setup()</code> extension methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Target.Register</code>-Method replaced by <code class="language-plaintext highlighter-rouge">LogManager.Setup().SetupExtensions(ext => ext.RegisterTarget<T>())</code>-extension-method</li>
<li><code class="language-plaintext highlighter-rouge">Layout.Register</code>-Method replaced by <code class="language-plaintext highlighter-rouge">LogManager.Setup().SetupExtensions(ext => ext.RegisterLayout<T>())</code>-extension-method</li>
<li><code class="language-plaintext highlighter-rouge">LayoutRenderer.Register</code>-Method replaced by <code class="language-plaintext highlighter-rouge">LogManager.Setup().SetupExtensions(ext => ext.RegisterLayoutRenderer<T>())</code>-extension-method</li>
</ul>
<p>For normal NLog users these changes should not give any noise. The more advanced NLog users and maintainers of NLog-extension-libraries,
are encouraged to move away from the obsoleted methods, and provide alternative way without using dynamic assembly loading.</p>
<p>If having questions or problems about these changes, then one is wellcome to open <a href="https://github.com/NLog/NLog/issues">GitHub Issue</a></p>
<h2 id="dependency-injection-without-createinstance">Dependency Injection without CreateInstance</h2>
<p>NLog <code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.CreateInstance</code> has for a long time been the default way to handle <a href="https://github.com/NLog/NLog/wiki/Dependency-injection-with-NLog">dependency injection</a>.
It allows override of how to create instance of class-type, and parse input-dependencies as constructor parameters.</p>
<p>The <code class="language-plaintext highlighter-rouge">CreateInstance</code>-delegate has now been marked obsolete, as it doesn’t work well with annotations for application trimming.</p>
<p>NLog v5 introduced the ability to acquire dependencies during <code class="language-plaintext highlighter-rouge">InitializeTarget</code>-method with help from <code class="language-plaintext highlighter-rouge">ResolveService<T></code>-method.</p>
<p>NLog v5.2 now also introduces the ability to register extensions together with a custom factory-method:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupExtensions</span><span class="p">(</span><span class="n">ext</span> <span class="p">=></span> <span class="n">ext</span><span class="p">.</span><span class="n">RegisterTarget</span><span class="p"><</span><span class="n">MyTarget</span><span class="p">>(()</span> <span class="p">=></span> <span class="k">new</span> <span class="nf">MyTarget</span><span class="p">(</span><span class="n">someDependency</span><span class="p">));</span>
</code></pre></div></div>
NLog 5.0 Finally Ready!2022-05-16T00:00:00+00:00https://nlog-project.org/2022/05/16/nlog-5-0-finally-ready<p>NLog 5.0 has completed preview testing, and is ready for release.</p>
<h2 id="major-features">Major Features</h2>
<ul>
<li>NLog is now faster and lighter</li>
<li>ScopeContext to replace MDC + MDLC + NDC + NDLC</li>
<li>NLog Layout stored as NLog Configuration Variables (Ex. JsonLayout)</li>
<li>NLog Layout for everything</li>
<li>Fluent API for NLog LoggingConfiguration</li>
<li>NLog Callsite from caller member attributes</li>
<li>LogFactory with Dependency Injection</li>
<li>Updated default values for better out-of-the-box experience</li>
<li>Multiple type-aliases can be defined for targets, layouts, layout renderers and conditions</li>
<li>Parsing of type-alias will now ignore dashes (-)</li>
<li>NLog v5.1 enables support for ISpanFormattable in FormattedMessage and serializing JSON.</li>
<li>NLog v5.2 includes annotations for application trimming without build warnings.</li>
</ul>
<p>See details <a href="https://nlog-project.org/2021/08/25/nlog-5-0-preview1-ready.html">here</a></p>
<h2 id="major-breaking-changes">Major Breaking Changes</h2>
<p>NLog v5.2 marks additional methods as obsolete as they conflict with <a href="https://nlog-project.org/2023/05/30/nlog-5-2-trim-warnings.html">application trimming</a>.</p>
<p>See rationale <a href="https://nlog-project.org/2021/08/25/nlog-5-0-preview1-ready.html">here</a></p>
<ul>
<li>Strong Version Changed</li>
<li>Obsolete methods have been removed</li>
<li>LoggingRule Filters DefaultAction changed to FilterResult.Ignore, that can cause NO output.</li>
<li>NLog.Extensions.Logging without any filter, that can give LOTS of unexpected output.</li>
<li>NLog.Extensions.Logging changes capture of EventId, so missing EventId_Id-property.</li>
<li>NLog.Extensions.Logging makes NLog-section reserved in appsettings.json</li>
<li>NLog Extensions assemblies will not be loaded automatically, so <a href="https://github.com/NLog/NLog/wiki/Register-your-custom-component">extensions must be explicitly added</a>.</li>
<li>NLog DatabaseTarget extracted into its own <a href="https://www.nuget.org/packages/NLog.Database">NLog.Database</a> nuget-package</li>
<li>NLog OutputDebugStringTarget extracted into its own <a href="https://www.nuget.org/packages/NLog.OutputDebugString">NLog.OutputDebugString</a> nuget-package</li>
<li>NLog PerformanceCounterTarget extracted into its own <a href="https://www.nuget.org/packages/NLog.PerformanceCounter">NLog.PerformanceCounter</a> nuget-package</li>
<li>NLog ImpersonatingTargetWrapper extracted into its own <a href="https://www.nuget.org/packages/NLog.WindowsIdentity">NLog.WindowsIdentity</a> nuget-package</li>
<li>NLog LogReceiverWebServiceTarget extracted into its own <a href="https://www.nuget.org/packages/NLog.Wcf">NLog.Wcf</a> nuget-package</li>
<li>NLog PerformanceCounterLayoutRenderer extracted into its own <a href="https://www.nuget.org/packages/NLog.PerformanceCounter">NLog.PerformanceCounter</a> nuget-package</li>
<li>NLog RegistryLayoutRenderer extracted into its own <a href="https://www.nuget.org/packages/NLog.WindowsRegistry">NLog.WindowsRegistry</a> nuget-package</li>
<li>NLog WindowsIdentityLayoutRenderer extracted into its own <a href="https://www.nuget.org/packages/NLog.WindowsIdentity">NLog.WindowsIdentity</a> nuget-package</li>
<li>Deprecated NLog.Extended nuget-package</li>
<li>Deprecated NLog.Config nuget-package</li>
<li>Xamarin, Windows Phone and Silverlight platforms replaced by .NET Standard</li>
<li>.NET Framework v4.0 platform replaced by .NET Framework v3.5 platform</li>
<li>Automatic loading of NLog.config now first check for exe.nlog</li>
<li>NLog Configuration will have KeepVariablesOnReload enabled by default</li>
<li>Layout and LayoutRenderer are now threadsafe by default</li>
<li>Default Layout for NLog Targets has been updated</li>
<li>Default Format for NLog Exception layoutrenderer has been updated</li>
<li>NLog InternalLogger will not initialize itself from app.config or environment variables</li>
<li>Removed obsolete methods and properties</li>
<li>ScopeContext changes MappedDiagnosticContext (MDC) to use AsyncLocal</li>
<li>MappedDiagnosticContext (MDC), MappedDiagnosticLogicalContext (MDLC), GlobalDiagnosticContext (GDC) now case-insensitive</li>
<li>FileTarget KeepFileOpen = true by default</li>
<li>FileTarget ConcurrentWrites = false by default</li>
<li>FileTarget Encoding default value changed to UTF8</li>
<li>FileTarget will include BOM by default for UTF16 and UTF32 encoding</li>
<li>NetworkTarget will Discard by default on overflow</li>
<li>JsonLayout MaxRecursionLimit default value changed to 1</li>
<li>JsonLayout EscapeForwardSlash default value changed to false</li>
<li>JsonLayout always includes decimal point for floating-point types</li>
<li>CallSite-renderer will automatically clean async callstacks</li>
<li>The Simplelayout.ToString() has been changed</li>
</ul>
<p>For full list of all changes: <a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+is%3Amerged+milestone:%225.0%22">NLog 5.0 Pull Requests</a></p>
<ul>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22breaking%20change%22+is%3Amerged+milestone:%225.0%22">Breaking Changes</a></li>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22breaking%20behavior%20change%22+is%3Amerged+milestone:%225.0%22">Breaking Behavior Changes</a></li>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22Feature%22+is%3Amerged+milestone:%225.0%22">Features</a></li>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22Enhancement%22+is%3Amerged+milestone:%225.0%22">Improvements</a></li>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22Performance%22+is%3Amerged+milestone:%225.0%22">Performance</a></li>
</ul>
<h2 id="credits">Credits</h2>
<p>Additional thanks to contributers:</p>
<ul>
<li>@TalAloni</li>
<li>@njqdev</li>
<li>@menishmueli</li>
<li>@ErickJeffries</li>
<li>@AlanLiu90</li>
<li>@aled</li>
<li>@tetrodoxin</li>
<li>@noamyogev84</li>
<li>@simoneserra93</li>
<li>@sjafarianm</li>
<li>@Orace</li>
<li>@GitHubPang</li>
<li>@KurnakovMaksim</li>
<li>@mickelsonmichael</li>
<li>@ThomasArdal</li>
</ul>
NLog 5.0 - List of major changes2021-08-25T00:00:00+00:00https://nlog-project.org/2021/08/25/nlog-5-0-preview1-ready<p>NLog 5.0 is a major version bump, and includes several breaking changes and lots of improvements.</p>
<h2 id="new-features">New Features</h2>
<h3 id="nlog-is-now-faster-and-lighter">NLog is now faster and lighter</h3>
<p>The NLog mantra has been to come running with all guns loaded. But some guns are bigger than others, and their weight have
changed the running into a fast walk. New platforms have arrived that has a strong focus on only bringing the absolute
necessary and nothing else.</p>
<p>NLog now performs faster initialization because it now skips automatic scanning and loading of NLog-extensions,
unless it has been explicitly specified by the NLog.config. The extensions autoload feature was introduced with NLog 4.0,
but is now disabled by default with NLog 5.0. The autoload feature also doesn’t work that great, when using packagereferences
which is the default for .NET Core platform. This means custom targets requires explicit <code class="language-plaintext highlighter-rouge"><add assembly="NLog.MyAssembly" /></code>,
or use the new ability to specify type with assembly-name: <code class="language-plaintext highlighter-rouge"><target type="MyTarget, NLog.MyAssembly" name="hello" /></code>.</p>
<p>NLog also skips initialization of NLog InternalLogger from environment variables and app.config. This also reduces the
impact on initialization time.</p>
<p>NLog-nuget-package has also been split into several isolated nuget-packages to reduce dependencies. The out-of-box
experience with NLog is affected by this, as now one must add extra nuget-package for database writing. This reduces
the number of System-dependencies, but also prevents false positive security risk warnings about DatabaseTarget
being able to execute SQL.</p>
<p>These references will no longer be added automatically, when wanting to use the NLog Logger in a .NET Framework-project:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge"><Reference Include="System.Data" /></code></li>
<li><code class="language-plaintext highlighter-rouge"><Reference Include="System.Runtime.Serialization" /></code></li>
<li><code class="language-plaintext highlighter-rouge"><Reference Include="System.ServiceModel" /></code></li>
<li><code class="language-plaintext highlighter-rouge"><Reference Include="System.Transactions" /></code></li>
</ul>
<p>This also makes it easier for users running on other operating system platforms to navigate the NLog source-repository.
Several Windows specific dependencies have now been extracted into their own nuget-packages.</p>
<h3 id="nlog-layout-for-everything">NLog Layout for everything</h3>
<p>NLog Layout logic is almost magical especially when creating string output, but less magical when handling simple output types.</p>
<p>This is the usual code when using <code class="language-plaintext highlighter-rouge">Layout</code> for an integer value:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">eventId</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
<span class="kt">string</span> <span class="n">renderEventId</span> <span class="p">=</span> <span class="n">EventIdLayout</span><span class="p">.</span><span class="nf">Render</span><span class="p">(</span><span class="n">logEvent</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">renderEventId</span><span class="p">)</span> <span class="p">||</span> <span class="p">!</span><span class="kt">int</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">renderEventId</span><span class="p">,</span> <span class="k">out</span> <span class="n">eventId</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">eventId</span> <span class="p">=</span> <span class="m">42</span><span class="p">;</span> <span class="c1">// fallback default value</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This has now been improved with the introduction of <code class="language-plaintext highlighter-rouge">Layout<T></code> that automatically handles parsing and fallback value,
and at the same time provides better performance than normal <code class="language-plaintext highlighter-rouge">Layout</code> when handling static values.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">eventId</span> <span class="p">=</span> <span class="n">EventIdLayout</span><span class="p">.</span><span class="nf">RenderValue</span><span class="p">(</span><span class="n">logEvent</span><span class="p">,</span> <span class="n">defaultValue</span><span class="p">:</span> <span class="m">42</span><span class="p">);</span>
</code></pre></div></div>
<p>This makes it easier for NLog Target developers to use NLog Layout everywhere without having to worry about handling
parsing and conversion issues.</p>
<p>NLog Targets that has been extracted from the default NLog-nuget-package has now also been updated to make use of the
new <code class="language-plaintext highlighter-rouge">Layout<T></code>-features.</p>
<h3 id="nlog-scopecontext-to-replace-mdc--mdlc--ndc--ndlc">NLog ScopeContext to replace MDC + MDLC + NDC + NDLC</h3>
<p>NLog ScopeContext has been introduced to cater for Microsoft Extension Logging (MEL) <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger.beginscope">ILogger.BeginScope</a>.
Instead of building dictionary-objects upfront to hold context-state, then creation of lookup-dictionary is deferred
until logging requires lookup of scope-properties. When using NLog as Logging Provider in MEL, then performance of
<a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger.beginscope">ILogger.BeginScope</a> has
been improved dramatically.</p>
<p>These are the performance numbers when just using <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger.beginscope">ILogger.BeginScope</a> but no logevents are written.</p>
<table>
<thead>
<tr>
<th>Test Name</th>
<th>Time (ms)</th>
<th>Calls/sec</th>
<th>GC2</th>
<th>GC1</th>
<th>GC0</th>
<th>CPU (ms)</th>
<th>Alloc (MB)</th>
</tr>
</thead>
<tbody>
<tr>
<td>NLog v5.0</td>
<td>6.026</td>
<td>1.659.339</td>
<td>0</td>
<td>0</td>
<td>393</td>
<td>6.156</td>
<td>5.493,2</td>
</tr>
<tr>
<td>NLog v4.7</td>
<td>20.144</td>
<td>496.415</td>
<td>0</td>
<td>0</td>
<td>1187</td>
<td>20.796</td>
<td>16.479,5</td>
</tr>
</tbody>
</table>
<p>ScopeContext merges MDC and MDLC together, as it has been a long standing wish not to have two different ways of handling context-properties.
ScopeContext also includes NDC and NDLC to better support <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger.beginscope">ILogger.BeginScope</a>
way of pushing context-properties and nested context-state in a single call.</p>
<p>NLog Logger object also includes new methods <code class="language-plaintext highlighter-rouge">Logger.PushScopeProperty</code> and <code class="language-plaintext highlighter-rouge">Logger.PushScopeNested</code> to make it easy to update the NLog ScopeContext.</p>
<h3 id="nlog-layout-stored-as-nlog-configuration-variables">NLog Layout stored as NLog Configuration Variables</h3>
<p>NLog Configuration Variables now has support for other types of Layouts than <code class="language-plaintext highlighter-rouge">SimpleLayout</code>. This means a NLog Configuration Variable
can hold a <code class="language-plaintext highlighter-rouge">JsonLayout</code>, and it can be referenced by multiple targets.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog></span>
<span class="nt"><variable</span> <span class="na">name=</span><span class="s">"myJson"</span><span class="nt">></span>
<span class="nt"><layout</span> <span class="na">type=</span><span class="s">"JsonLayout"</span><span class="nt">></span>
<span class="nt"><attribute</span> <span class="na">name=</span><span class="s">"shortdate"</span> <span class="na">layout=</span><span class="s">"${shortdate}"</span> <span class="nt">/></span>
<span class="nt"><attribute</span> <span class="na">name=</span><span class="s">"message"</span> <span class="na">layout=</span><span class="s">"${message}"</span> <span class="nt">/></span>
<span class="nt"></layout></span>
<span class="nt"></variable></span>
<span class="nt"><targets></span>
<span class="nt"><target</span> <span class="na">type=</span><span class="s">"console"</span> <span class="na">layout=</span><span class="s">"${myJson}"</span> <span class="nt">/></span>
<span class="nt"><target</span> <span class="na">type=</span><span class="s">"file"</span> <span class="na">layout=</span><span class="s">"${myJson}"</span> <span class="nt">/></span>
<span class="nt"></targets></span>
<span class="nt"><rules></span>
<span class="nt"><logger</span> <span class="na">minLevel=</span><span class="s">"Debug"</span> <span class="na">writeTo=</span><span class="s">"console,file"</span> <span class="nt">/></span>
<span class="nt"></rules></span>
<span class="nt"></nlog></span>
</code></pre></div></div>
<h3 id="fluent-api-for-nlog-loggingconfiguration">Fluent API for NLog LoggingConfiguration</h3>
<p>NLog has from the beginning supported configuration from both API and NLog.config. But the main focus has been to
provide an elegant experience with NLog.config. Lately other frameworks like Microsoft Extension Logging have shown
how the programmatically API can be just as elegant, and at the same time removing issues from dynamic type loading.</p>
<p>NLog has extended its <code class="language-plaintext highlighter-rouge">NLog.LogManager.Setup()</code> to make it easy to setup NLog Targets and filtering with NLog LoggingRules:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">logger</span> <span class="p">=</span> <span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">LoadConfiguration</span><span class="p">(</span><span class="n">c</span> <span class="p">=></span>
<span class="p">{</span>
<span class="n">c</span><span class="p">.</span><span class="nf">ForLogger</span><span class="p">(</span><span class="s">"*"</span><span class="p">).</span><span class="nf">FilterMinLevel</span><span class="p">(</span><span class="n">NLog</span><span class="p">.</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Info</span><span class="p">).</span><span class="nf">WriteTo</span><span class="p">(</span><span class="k">new</span> <span class="nf">ConsoleTarget</span><span class="p">(</span><span class="s">"logconsole"</span><span class="p">)).</span><span class="nf">WithAsync</span><span class="p">();</span>
<span class="n">c</span><span class="p">.</span><span class="nf">ForLogger</span><span class="p">().</span><span class="nf">WriteTo</span><span class="p">(</span><span class="k">new</span> <span class="nf">FileTarget</span><span class="p">(</span><span class="s">"logfile"</span><span class="p">)</span> <span class="p">{</span> <span class="n">FileName</span> <span class="p">=</span> <span class="s">"file.txt"</span> <span class="p">}).</span><span class="nf">WithAsync</span><span class="p">();</span>
<span class="p">}).</span><span class="nf">GetCurrentClassLogger</span><span class="p">();</span>
</code></pre></div></div>
<p>NLog has very strong support for filtering, where multiple LoggingRules are redirecting to the same NLog target.
This is also possible with the new fluent API:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">logger</span> <span class="p">=</span> <span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">LoadConfiguration</span><span class="p">(</span><span class="n">c</span> <span class="p">=></span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">consoleTarget</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="nf">ForTarget</span><span class="p">(</span><span class="s">"console"</span><span class="p">).</span><span class="nf">WriteTo</span><span class="p">(</span><span class="k">new</span> <span class="nf">ConsoleTarget</span><span class="p">()).</span><span class="nf">WithAsync</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">fileTarget</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="nf">ForTarget</span><span class="p">(</span><span class="s">"logfile"</span><span class="p">).</span><span class="nf">WriteTo</span><span class="p">(</span><span class="k">new</span> <span class="nf">FileTarget</span><span class="p">()</span> <span class="p">{</span> <span class="n">FileName</span> <span class="p">=</span> <span class="s">"file.txt"</span> <span class="p">}).</span><span class="nf">WithAsync</span><span class="p">();</span>
<span class="n">c</span><span class="p">.</span><span class="nf">ForLogger</span><span class="p">(</span><span class="s">"System.*"</span><span class="p">).</span><span class="nf">WriteToNil</span><span class="p">(</span><span class="n">NLog</span><span class="p">.</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Warn</span><span class="p">);</span>
<span class="n">c</span><span class="p">.</span><span class="nf">ForLogger</span><span class="p">(</span><span class="s">"Microsoft.*"</span><span class="p">).</span><span class="nf">WriteToNil</span><span class="p">(</span><span class="n">NLog</span><span class="p">.</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Warn</span><span class="p">);</span>
<span class="n">c</span><span class="p">.</span><span class="nf">ForLogger</span><span class="p">(</span><span class="s">"Microsoft.Hosting.Lifetime*"</span><span class="p">).</span><span class="nf">WriteToNil</span><span class="p">(</span><span class="n">NLog</span><span class="p">.</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Info</span><span class="p">);</span> <span class="c1">// finalMinLevel overrides previous rule</span>
<span class="n">c</span><span class="p">.</span><span class="nf">ForLogger</span><span class="p">().</span><span class="nf">FilterMinLevel</span><span class="p">(</span><span class="n">NLog</span><span class="p">.</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Info</span><span class="p">).</span><span class="nf">WriteTo</span><span class="p">(</span><span class="n">consoleTarget</span><span class="p">);</span>
<span class="n">c</span><span class="p">.</span><span class="nf">ForLogger</span><span class="p">().</span><span class="nf">FilterMinLevel</span><span class="p">(</span><span class="n">NLog</span><span class="p">.</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">).</span><span class="nf">WriteTo</span><span class="p">(</span><span class="n">fileTarget</span><span class="p">);</span>
<span class="p">}).</span><span class="nf">GetCurrentClassLogger</span><span class="p">();</span>
</code></pre></div></div>
<h3 id="nlog-callsite-from-caller-member-attributes">NLog Callsite from caller member attributes</h3>
<p>NLog already had support for caller member attributes through the NLog.Fluent-API. But it saved the CallSite-information into
<code class="language-plaintext highlighter-rouge">LogEventInfo.Properties</code>. This has now changed so it will use the method <code class="language-plaintext highlighter-rouge">LogEventInfo.SetCallerInfo</code>, so it is no longer
necessary to exclude the sometimes unwanted properties.</p>
<p><code class="language-plaintext highlighter-rouge">${callsite}</code> no longer requires the capture of StackTrace to render the callsite, but can rely on the input from
<code class="language-plaintext highlighter-rouge">LogEventInfo.SetCallerInfo</code>. This means that <code class="language-plaintext highlighter-rouge">${callsite}</code> will have much less overhead when using API that uses
<code class="language-plaintext highlighter-rouge">LogEventInfo.SetCallerInfo</code>.</p>
<p>The old NLog.Fluent-API had some overhead, where it performed memory allocation even when the LogLevel was disabled. It also
had some overloads that didn’t work well, when working with an isolated NLog LogFactory. Now the old NLog.Fluent-API has
been marked obsolete, and instead a new <code class="language-plaintext highlighter-rouge">LogEventBuilder</code> has been introduced in the standard NLog-namespace:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">logger</span><span class="p">.</span><span class="nf">ForErrorEvent</span><span class="p">()</span>
<span class="p">.</span><span class="nf">Message</span><span class="p">(</span><span class="s">"This is a test fluent message."</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Property</span><span class="p">(</span><span class="s">"Test"</span><span class="p">,</span> <span class="s">"TraceWrite"</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Log</span><span class="p">();</span>
</code></pre></div></div>
<p>When using <code class="language-plaintext highlighter-rouge">LogEventBuilder</code> for logging, then it will automatically captures callsite details with very little overhead
with help from <code class="language-plaintext highlighter-rouge">C#</code> caller member attributes.</p>
<h3 id="logfactory-with-dependency-injection">LogFactory with Dependency Injection</h3>
<p>NLog now includes better support for dependency injection, so instead of having a global object-factory-delegate
that affects all instances of NLog LogFactory:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">Config</span><span class="p">.</span><span class="n">ConfigurationItemFactory</span><span class="p">.</span><span class="n">Default</span><span class="p">.</span><span class="n">CreateInstance</span> <span class="p">=</span> <span class="p">(</span><span class="n">type</span><span class="p">)</span> <span class="p">=></span> <span class="n">System</span><span class="p">.</span><span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
</code></pre></div></div>
<p>Then NLog LogFactory now has an isolated ServiceRepository, where one can register own custom interface-implementations or
external <code class="language-plaintext highlighter-rouge">System.IServiceProvider</code>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupExtensions</span><span class="p">(</span><span class="n">ext</span> <span class="p">=></span> <span class="n">ext</span><span class="p">.</span><span class="n">RegisterSingletonService</span><span class="p"><</span><span class="n">IMyInterface</span><span class="p">>(</span><span class="n">singletonInstance</span><span class="p">));</span>
<span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupExtensions</span><span class="p">(</span><span class="n">ext</span> <span class="p">=></span> <span class="n">ext</span><span class="p">.</span><span class="nf">RegisterServiceProvider</span><span class="p">((</span><span class="n">IServiceProvider</span><span class="p">)</span><span class="n">externalDependencyInjection</span><span class="p">));</span>
</code></pre></div></div>
<p>External dependencies can now be resolved during Target- or Layout-initialization like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">InitializeTarget</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">wantedDependency</span> <span class="p">=</span> <span class="n">ResolveService</span><span class="p"><</span><span class="n">IMyInterface</span><span class="p">>();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The challenge with dependency injection is that logging is expected to be working and running before dependency injection has been configured.
NLog tries to handle this by making <code class="language-plaintext highlighter-rouge">ResolveService()</code> throw exception when wanted dependency is not yet available.
When <code class="language-plaintext highlighter-rouge">InitializeTarget()</code> fails because of unresolved dependency, then NLog will automatically retry when expected type
becomes available in the NLog ServiceRepository. This means a simple console-target will always work, and targets with
dependency injection requirement will be lazy initialized with retry if necessary.</p>
<p>Another problem with logging and dependency injection is that logging is one of the lowest layers of the application.
Having the logging-layer making calls into the dependency-injection-layer can cause issue like call-recursion with stackoverflow
or deadlocks. Both issues are extremely annoying to debug and diagnose, so one should be very careful to ensure interfaces
are implemented with singleton-lifetime.</p>
<h3 id="multiple-type-aliases-can-be-defined-for-use-in-nlog-configuration">Multiple type-aliases can be defined for use in NLog configuration</h3>
<p>It’s now possible to add multiple type-aliases for your targets, layouts, layout renderers and conditions.</p>
<p>For example, this is now allowed:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="nf">Target</span><span class="p">(</span><span class="s">"MyTarget"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">Target</span><span class="p">(</span><span class="s">"MyFancyTarget"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MyTarget</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</code></pre></div></div>
<p>The following attributes can now be defined multiple times for a class:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">[Target]</code></li>
<li><code class="language-plaintext highlighter-rouge">[Layout]</code></li>
<li><code class="language-plaintext highlighter-rouge">[LayoutRenderer]</code></li>
<li><code class="language-plaintext highlighter-rouge">[Filter]</code></li>
</ul>
<p>The following aliases are added in NLog:</p>
<ul>
<li>The Mail Target has now the type-aliases Email, SMTP and SMTP-Client</li>
<li>The Trace Target has now the type-alias TraceSystem</li>
<li><code class="language-plaintext highlighter-rouge">${Event-properties}</code> has now the type-alias <code class="language-plaintext highlighter-rouge">${Event-property}</code></li>
<li><code class="language-plaintext highlighter-rouge">${logger}</code> has now the type-alias <code class="language-plaintext highlighter-rouge">${loggername}</code></li>
</ul>
<p>All type-aliases are also listed and searchable on https://nlog-project.org/config/</p>
<h3 id="parsing-of-type-alias-will-now-ignore-dashes--">Parsing of type-alias will now ignore dashes (-)</h3>
<p>Dashes in type-alias names for targets, layout renderers, layouts, filters are ignored. For example: <code class="language-plaintext highlighter-rouge">${loggername}</code> can also be written as <code class="language-plaintext highlighter-rouge">${logger-name}</code>, and target-type ColoredConsole can be written as Colored-Console.</p>
<p>Reason: It’s hard to maintain consistency between the different type-aliases, and there were some inconsistencies already.</p>
<p>Also, when registering custom extensions, then it is confusing to have type-aliases with only dashes as difference. For example: <code class="language-plaintext highlighter-rouge">${activityid}</code> and <code class="language-plaintext highlighter-rouge">${activity-id}</code></p>
<h2 id="breaking-changes">Breaking Changes</h2>
<h3 id="strong-version-changed">Strong Version Changed</h3>
<p>The major version has been bumped for the strong-version to v5.0.0.0 (from v4.0.0.0).</p>
<ul>
<li>
<p><strong>Impact:</strong> .NET framework applications will have to be recompiled to use NLog 5.0.</p>
</li>
<li>
<p><strong>Reason:</strong> Major version must be bumped to protect application from runtime compile errors.</p>
</li>
<li>
<p><strong>Workaround:</strong> Upgrade to .NET Core where assembly strong version doesn’t have the same meaning.
Alternative one can make use of <a href="https://docs.microsoft.com/dotnet/framework/configure-apps/redirect-assembly-versions">binding-redirects</a>,
as the NLog 5 API includes the NLog 4 API except for methods that has been deprecated for a long time.</p>
</li>
</ul>
<h3 id="obsolete-methods-have-been-removed">Obsolete methods have been removed</h3>
<p>Lots of obsolete methods and properties in the NLog API has now been removed.</p>
<ul>
<li>
<p><strong>Impact:</strong> Applications that depends on the deprecated NLog API will fail to compile and run.</p>
</li>
<li>
<p><strong>Reason:</strong> Removing obsolete logic reduces code complexity and code maintenance.</p>
</li>
<li>
<p><strong>Workaround:</strong> If unable to built with NLog 5 directly, then downgrade to latest NLog v4 and
follow the guidelines from the obsolete-attribute. When having fixed the obsolete warnings then update to NLog 5.</p>
</li>
</ul>
<h3 id="loggingrule-filters-defaultaction-changed-to-filterresultignore">LoggingRule Filters DefaultAction changed to FilterResult.Ignore</h3>
<p>Changed from <code class="language-plaintext highlighter-rouge">Neutral</code> default value:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><logger</span> <span class="na">name=</span><span class="s">"*"</span> <span class="na">minLevel=</span><span class="s">"Debug"</span> <span class="na">writo=</span><span class="s">"target"</span><span class="nt">></span>
<span class="nt"><filters</span> <span class="na">defaultAction=</span><span class="s">"Neutral"</span><span class="nt">></span>
<span class="nt"><when</span> <span class="na">condition=</span><span class="s">"'${exception:format=shorttype}' != ''"</span> <span class="na">action=</span><span class="s">"Log"</span> <span class="nt">/></span>
<span class="nt"></filters></span>
<span class="nt"></logger></span>
</code></pre></div></div>
<p>To <code class="language-plaintext highlighter-rouge">Ignore</code> as default value:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><logger</span> <span class="na">name=</span><span class="s">"*"</span> <span class="na">minLevel=</span><span class="s">"Debug"</span> <span class="na">writo=</span><span class="s">"target"</span><span class="nt">></span>
<span class="nt"><filters</span> <span class="na">defaultAction=</span><span class="s">"Ignore"</span><span class="nt">></span>
<span class="nt"><when</span> <span class="na">condition=</span><span class="s">"'${exception:format=shorttype}' != ''"</span> <span class="na">action=</span><span class="s">"Log"</span> <span class="nt">/></span>
<span class="nt"></filters></span>
<span class="nt"></logger></span>
</code></pre></div></div>
<ul>
<li>
<p><strong>Impact:</strong> This means NO output, if using dynamic filters and not already using <code class="language-plaintext highlighter-rouge">defaulAction="Ignore"</code>.</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience for new users when trying to use filters, as it will have effect right away.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit assign <code class="language-plaintext highlighter-rouge">defaultAction="Log"</code> on the <code class="language-plaintext highlighter-rouge"><filters></code>-element, or rewrite conditions to use <code class="language-plaintext highlighter-rouge">action="Log"</code>.</p>
</li>
</ul>
<h3 id="nlogextensionslogging-without-any-filter">NLog.Extensions.Logging without any filter</h3>
<p>NLog LoggingProvider no longer follows the Microsoft Logger filtering configuration.</p>
<ul>
<li>
<p><strong>Impact:</strong> This means LOTS of unexpected output. Because NLog will by default not react to Microsoft Logger filters defined in the Logging-section in appsettings.json.</p>
</li>
<li>
<p><strong>Reason:</strong> It is confusing to have two seperate systems for filtering logging output. New users might
think NLog is not working correctly after having configured NLog LoggingRules, because Microsoft LoggerFactory filters are interfering.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit specify <code class="language-plaintext highlighter-rouge">RemoveLoggerFactoryFilter = false</code> for NLogProviderOptions when calling <code class="language-plaintext highlighter-rouge">UseNLog()</code> to enable old behavior,
where Microsoft LoggerFactory filters specified in appsetting.json also applies to NLog.</p>
</li>
</ul>
<p>Alternatively the new <code class="language-plaintext highlighter-rouge">finalMinLevel</code>-option can be used to replicate the behavior of Microsoft Logging Filters:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><rules></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">"System.*"</span> <span class="na">finalMinLevel=</span><span class="s">"Warn"</span> <span class="nt">/></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">"Microsoft.*"</span> <span class="na">finalMinLevel=</span><span class="s">"Warn"</span> <span class="nt">/></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">"Microsoft.Hosting.Lifetime*"</span> <span class="na">finalMinLevel=</span><span class="s">"Info"</span> <span class="nt">/></span> <span class="c"><!-- Overrides previous rule --></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">"*"</span> <span class="na">minLevel=</span><span class="s">"Debug"</span> <span class="na">writeTo=</span><span class="s">"console"</span> <span class="nt">/></span>
<span class="nt"></rules></span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">finalMinLevel</code>-option has been introduced with NLog 5.0 to make it simpler to translate Micrsoft Logging Filters into NLog LoggingRules.
If one already knows about NLog LoggingRules, then <code class="language-plaintext highlighter-rouge">finalMinLevel</code> is similar to combination of <code class="language-plaintext highlighter-rouge">maxLevel="..."</code> and <code class="language-plaintext highlighter-rouge">final="true"</code>.
But <code class="language-plaintext highlighter-rouge">finalMinLevel</code> has the ability override previous <code class="language-plaintext highlighter-rouge">finalMinLevel</code>-rules, which is not possible with <code class="language-plaintext highlighter-rouge">final="true"</code>.
This makes it easier to customize LogLevels for different logger namespaces (Ex. <code class="language-plaintext highlighter-rouge">Microsoft.Hosting.Lifetime</code> within <code class="language-plaintext highlighter-rouge">Microsoft</code>-namspace).</p>
<p>Notice it is also possible to have <a href="https://github.com/NLog/NLog.Extensions.Logging/wiki/NLog-configuration-with-appsettings.json">NLog Configuration in appsetting.json</a>.</p>
<h3 id="nlogextensionslogging-changes-capture-of-eventid">NLog.Extensions.Logging changes capture of EventId</h3>
<p>NLog LoggingProvider will no longer capture <code class="language-plaintext highlighter-rouge">EventId</code>-struct + <code class="language-plaintext highlighter-rouge">EventId_Id</code>-number + <code class="language-plaintext highlighter-rouge">EventId_Name</code>, instead it will
by default capture the properties <code class="language-plaintext highlighter-rouge">EventId</code> (integer) and <code class="language-plaintext highlighter-rouge">EventName</code> (string).</p>
<ul>
<li>
<p><strong>Impact:</strong> <code class="language-plaintext highlighter-rouge">EventId_Id</code> and <code class="language-plaintext highlighter-rouge">EventId_Name</code> are no longer included by default. They have been replaced with the properties <code class="language-plaintext highlighter-rouge">EventId</code> and <code class="language-plaintext highlighter-rouge">EventName</code>.</p>
</li>
<li>
<p><strong>Reason:</strong> Avoid the overhead from capturing and boxing the EventId-struct. And provide more human readable names.</p>
</li>
<li>
<p><strong>Workaround:</strong> Adjust to the new property-names, or explicity specify NLogProviderOptions <code class="language-plaintext highlighter-rouge">CaptureEventId = Legacy</code> to enable old behavior.</p>
</li>
</ul>
<h3 id="nlogextensionslogging-makes-nlog-section-reserved-in-appsettingsjson">NLog.Extensions.Logging makes NLog-section reserved in appsettings.json</h3>
<p>NLog LoggingProvider will now by default check for <code class="language-plaintext highlighter-rouge">"NLog":</code>-section in appsettings.json, and will automatically
load the NLog configuration. This works together with JSON SchemaStore has been updated to provide basic intellisense
when editing <code class="language-plaintext highlighter-rouge">"NLog":</code>-section in appsetting.json.</p>
<ul>
<li>
<p><strong>Impact:</strong> Now <code class="language-plaintext highlighter-rouge">"NLog":</code>-section is reserved, and if already using this section for something else than NLog configuration, then it will cause NLog not to load its configuration.</p>
</li>
<li>
<p><strong>Reason:</strong> Making <a href="https://github.com/NLog/NLog.Extensions.Logging/wiki/NLog-configuration-with-appsettings.json">NLog Configuration in appsetting.json</a> closer to a first class citizen, that works out of the box.</p>
</li>
<li>
<p><strong>WorkAround:</strong> Assign <code class="language-plaintext highlighter-rouge">NLogProviderOptions.LoggingConfigurationSectionName = ""</code> (not recommended), or stop using the reserved <code class="language-plaintext highlighter-rouge">"NLog":</code>-section for other settings than NLog configuration.</p>
</li>
</ul>
<h3 id="nlog-extensions-assemblies-will-not-load-automatically">NLog Extensions assemblies will not load automatically</h3>
<ul>
<li>
<p><strong>Impact:</strong> NLog will no longer automatic scan and load assemblies where their filename starts with NLog.
This means one must remember to explicitly add extensions to <code class="language-plaintext highlighter-rouge"><extensions></code>-sections. NLog will now fail
to load unrecognized targets and layouts, that depends on unreferenced external NLog extension assemblies.</p>
</li>
<li>
<p><strong>Reason:</strong> NLog initialization becomes slower when having to scan for assembly files. When using NLog in
the cloud then the overhead from logging should be minimal. The automatic scanning also often failed on .NET Core
platforms because it would not see assemblies coming from nuget-packages.</p>
</li>
<li>
<p><strong>Workaround:</strong> NLog extensions assemblies can be specified explicitly in the NLog.config:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog></span>
<span class="nt"><extensions></span>
<span class="nt"><add</span> <span class="na">assembly=</span><span class="s">"NLog.MyAssembly"</span> <span class="nt">/></span>
<span class="nt"></extensions></span>
<span class="nt"></nlog></span>
</code></pre></div> </div>
<p>NLog 5.0 makes it possible to just specify the extension assembly-name directly in the type-alias:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><nlog></span>
<span class="nt"><targets></span>
<span class="nt"><target</span> <span class="na">type=</span><span class="s">"MyTarget, NLog.MyAssembly"</span> <span class="na">name=</span><span class="s">"hello"</span> <span class="nt">/></span>
<span class="nt"></targets></span>
<span class="nt"></nlog></span>
</code></pre></div> </div>
<p>NLog provides a method to force automatic loading of NLog extensions, before loading the NLog.config:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupExtensions</span><span class="p">(</span><span class="n">ext</span> <span class="p">=></span> <span class="n">ext</span><span class="p">.</span><span class="nf">AutoLoadExtensions</span><span class="p">());</span>
</code></pre></div> </div>
<p>Alternative one can update the NLog.config with the option <code class="language-plaintext highlighter-rouge">AutoLoadExtensions="true"</code>:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">autoloadExtensions=</span><span class="s">"true"</span><span class="nt">></span>
<span class="nt"></nlog></span>
</code></pre></div> </div>
</li>
</ul>
<h3 id="nlog-targets-extracted-into-their-own-nuget-packages">NLog Targets extracted into their own nuget-packages</h3>
<p>The following NLog targets has been extracted from the NLog-nuget-package to their own isolated nuget-packages:</p>
<ul>
<li>DatabaseTarget - <a href="https://www.nuget.org/packages/NLog.Database">NLog.Database</a>-package</li>
<li>OutputDebugStringTarget - <a href="https://www.nuget.org/packages/NLog.OutputDebugString">NLog.OutputDebugString</a>-package
<ul>
<li><a href="https://github.com/NLog/NLog/wiki/DebugSystem-target">DebugSystem</a>-target is available for <code class="language-plaintext highlighter-rouge">System.Diagnostics.Debug</code>-output.</li>
</ul>
</li>
<li>PerformanceCounterTarget - <a href="https://www.nuget.org/packages/NLog.PerformanceCounter">NLog.PerformanceCounter</a>-package</li>
<li>ImpersonatingTargetWrapper - <a href="https://www.nuget.org/packages/NLog.WindowsIdentity">NLog.WindowsIdentity</a>-package</li>
<li>LogReceiverWebServiceTarget - <a href="https://www.nuget.org/packages/NLog.Wcf">NLog.Wcf</a>-package</li>
</ul>
<p>The following NLog layoutrenderers has been extracted from the NLog-nuget-package to their own isolated nuget-packages:</p>
<ul>
<li>PerformanceCounterLayoutRenderer - <a href="https://www.nuget.org/packages/NLog.PerformanceCounter">NLog.PerformanceCounter</a>-package</li>
<li>RegistryLayoutRenderer - <a href="https://www.nuget.org/packages/NLog.WindowsRegistry">NLog.WindowsRegistry</a>-package</li>
<li>WindowsIdentityLayoutRenderer - <a href="https://www.nuget.org/packages/NLog.WindowsIdentity">NLog.WindowsIdentity</a>-package</li>
<li>
<p>QueryPerformanceCounterLayoutRenderer - Dropped into the ocean of dead code.</p>
</li>
<li>
<p><strong>Impact:</strong> The default NLog-nuget-package will no longer provide the same number of targets and layoutrenderers.
This means existing applications will have to be adjusted to reference the necessary nuget-packages and update
their NLog.config to load the now external NLog extensions.</p>
</li>
<li>
<p><strong>Reason:</strong> The default NLog-nuget-package introduces a lot of dependencies for small console applications that just wants to
write to the console. The DatabaseTarget also triggered alerts in static code analysis tools, since it allows execution
of arbitary SQL statements, thus NLog was falsely highlighted as a security risk.</p>
</li>
<li><strong>Workaround:</strong> Consider creating a meta nuget-package with your favorite collection of NLog-nuget-packages,
and change your projects to depend on this.</li>
</ul>
<h3 id="deprecated-nlogextended-nuget-package">Deprecated NLog.Extended nuget-package</h3>
<p>NLog.Extended nuget-package will no longer be released. The MSMQ-target has been extracted into its own nuget-package.</p>
<ul>
<li>
<p><strong>Impact:</strong> NLog.Extended-nuget-package will no longer be compatible with latest NLog and should be removed.</p>
</li>
<li>
<p><strong>Reason:</strong> NLog.Extended was intended as a swiss-army-knife of exotic targets and layouts. But it was discovered
that it introduced too many unwanted dependencies when just wanting to use a single target.</p>
</li>
<li>
<p><strong>Workaround:</strong> Change from NLog.Extended nuget-package to the specific NLog-nuget-package needed.</p>
</li>
</ul>
<h3 id="deprecated-nlogconfig-nuget-package">Deprecated NLog.Config nuget-package</h3>
<p>NLog.Config nuget-package will no longer be released.</p>
<ul>
<li>
<p><strong>Impact:</strong> NLog.Config-nuget-package will no longer be compatible with latest NLog and should be removed.</p>
</li>
<li>
<p><strong>Reason:</strong> NLog.Config-nuget-package stopped working properly when Microsoft refactored the nuget-package-system to
support <code class="language-plaintext highlighter-rouge"><packagereference></code>. Microsoft disabled the ability for a nuget-package to inject a default NLog.config into the
project directory when one didn’t exist. Instead it became overwrite always, so when deploying an application with dependency
on NLog.config-nuget-package, then it would unexpectedly reset the NLog.config.</p>
</li>
<li>
<p><strong>Workaround:</strong> Manually create the NLog.config file and add it to the application-project. Manually add NLog.Schema-package
for intellisense in NLog.config.</p>
</li>
</ul>
<h3 id="xamarin-windows-phone-and-silverlight-platforms-have-been-removed">Xamarin, Windows Phone and Silverlight platforms have been removed</h3>
<p>NLog have now removed Xamarin platform specific builds for iOS and Android. Instead they will rely on the .NET Standard-builds.
Windows Phone and Silverlight has also been removed together with the Xamarin-platforms as they shared a lot of the same
platform restrictions and are now obsolete.</p>
<ul>
<li>
<p><strong>Impact:</strong> Xamarin platforms will no longer have special restrictions, but will have all the features from the .NET Standard-build.
This also means it can access features like global mutex in the operating system (Now disabled by default), that will cause the
application to fail on the restricted mobile platforms. This also means the Android platform will no longer automatically load
NLog.config from assets-folder. This also mean that NLog 5 cannot be used in LOB Silverlight or Windows Phone applications.</p>
</li>
<li>
<p><strong>Reason:</strong> The Xamarin platforms have now embraced the .NET Standard-API, so it is no longer necessary with platform specific builds.
Removing platform specific logic reduces code complexity and code maintenance. Windows Phone and Silverlight are no longer supported
by Microsoft and have reached end of the line.</p>
</li>
<li>
<p><strong>Workaround:</strong> Because all features in the .NET Standard build are not supported on all platforms, then one should ensure not to
explicitly enable FileTarget ConcurrentWrites-option as it will enable use of operating system global mutex,
which is not available on Xamarin Mobile platforms and will make the application fail.</p>
<p>Instead of using assets-folder on Android, then change to Embedded Resource, and load NLog-config from application-assembly (Works for both iOS and Android):</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">LoadConfigurationFromAssemblyResource</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">App</span><span class="p">).</span><span class="nf">GetTypeInfo</span><span class="p">().</span><span class="n">Assembly</span><span class="p">);</span>
</code></pre></div> </div>
</li>
</ul>
<h3 id="net-framework-v40-platform-replaced-by-net-framework-v35">.NET Framework v4.0 platform replaced by .NET Framework v3.5</h3>
<p>NLog have removed direct support for .NET Framework v4.0, instead it will fallback to .NET Framework v3.5.</p>
<ul>
<li>
<p><strong>Impact:</strong> There is very little difference between NLog for .NET Framework v3.5 and NLog for .NET Framework v4.</p>
</li>
<li>
<p><strong>Reason:</strong> Removing platforms that are no longer supported by Microsoft reduces code complexity and code maintenance.
There is suddenly also one less platform to execute continuous integration builds with unit-tests.</p>
</li>
<li>
<p><strong>Workaround:</strong> Application rebuild will automatically fallback to NLog for .NET Framework 3.5 that will work just fine.
Alternative update the application from .NET Framework v4.0 to something newer.</p>
</li>
</ul>
<h3 id="automatic-loading-of-nlogconfig-now-first-check-for-exenlog">Automatic loading of NLog.config now first check for exe.nlog</h3>
<p>NLog will now first check for <code class="language-plaintext highlighter-rouge">Application.exe.nlog</code> at startup, before using <code class="language-plaintext highlighter-rouge">NLog.config</code></p>
<ul>
<li>
<p><strong>Impact:</strong> <code class="language-plaintext highlighter-rouge">NLog.config</code> will be ignored if application specific <code class="language-plaintext highlighter-rouge">.exe.nlog</code>-file is found.</p>
</li>
<li>
<p><strong>Reason:</strong> Fixing bug that was introduced long time ago, but required major version bump to revert the behavior.</p>
</li>
<li>
<p><strong>Workaround:</strong> Decide on whether to use <code class="language-plaintext highlighter-rouge">Application.exe.nlog</code> or <code class="language-plaintext highlighter-rouge">NLog.config</code> and remove the other.</p>
</li>
</ul>
<h3 id="nlog-configuration-will-have-keepvariablesonreload-enabled-by-default">NLog Configuration will have KeepVariablesOnReload enabled by default</h3>
<p>NLog Configuration Variables assigned at runtime will now automatically survive when using <code class="language-plaintext highlighter-rouge">autoReload="true"</code>.</p>
<ul>
<li>
<p><strong>Impact:</strong> NLog Configuration Variables assigned from API will no longer be reset on reload <code class="language-plaintext highlighter-rouge">NLog.config</code>.</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience when using <code class="language-plaintext highlighter-rouge">autoReload="true"</code> and updating NLog Configuration Variables at runtime.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explictly configure <code class="language-plaintext highlighter-rouge">KeepVariablesOnReload="false"</code> in NLog.config</p>
</li>
</ul>
<h3 id="layout-and-layoutrenderer-are-now-threadsafe-by-default">Layout and LayoutRenderer are now threadsafe by default</h3>
<p>NLog now always expects Layout and LayoutRenderer to be threadsafe, and will no longer check the <code class="language-plaintext highlighter-rouge">[ThreadSafe]</code>-class-attribute.</p>
<ul>
<li>
<p><strong>Impact:</strong> NLog Targets will no longer attempt to protect against 3rd Party Layout-logic that might not be threadsafe.</p>
</li>
<li>
<p><strong>Reason:</strong> The <code class="language-plaintext highlighter-rouge">[ThreadSafe]</code>-class-attribute was intended as a temporary workaround, to avoid breaking stuff with NLog ver. 4.5.3
Having to apply special class-attributes to get the expected performance is not very user-friendly.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicitly configure the Target-option <code class="language-plaintext highlighter-rouge">LayoutWithLock="true"</code> if target is using 3rd Party Layout-logic
that is not threadsafe.</p>
</li>
</ul>
<h3 id="default-layout-for-nlog-targets-has-been-updated">Default Layout for NLog Targets has been updated</h3>
<p>Changed from this default value:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>${longdate}|${level:uppercase=true}|${logger}|${message}
</code></pre></div></div>
<p>To this new default value:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>${longdate}|${level:uppercase=true}|${logger}|${message:withexception=true}
</code></pre></div></div>
<ul>
<li>
<p><strong>Impact:</strong> NLog targets that have not explicit assigned default layout will now also include exception-details.</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience when using default configuration. When using NLog to diagnose problems then
exception information is often important.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit assign the Layout-property on the target if other output is wanted.</p>
</li>
</ul>
<h3 id="default-format-for-nlog-exception-layoutrenderer-has-been-updated">Default Format for NLog Exception layoutrenderer has been updated</h3>
<p>Change from this default value:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>${exception:format=message}
</code></pre></div></div>
<p>To this new default value:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>${exception:format=tostring,data}
</code></pre></div></div>
<ul>
<li>
<p><strong>Impact:</strong> Locations where <code class="language-plaintext highlighter-rouge">${exception}</code> is used without specifying format will now perform <code class="language-plaintext highlighter-rouge">Exception.ToString()</code>,
instead of just rendering Exception.Message</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience when using default configuration. When using NLog to diagnose problems then
all exception information is usually important.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit specify <code class="language-plaintext highlighter-rouge">${exception:format=message}</code> to only get the <code class="language-plaintext highlighter-rouge">Exception.Message</code>.</p>
</li>
</ul>
<h3 id="nlog-internallogger-will-not-initialize-itself-from-appconfig-or-environment-variables">NLog InternalLogger will not initialize itself from app.config or environment variables</h3>
<ul>
<li>
<p><strong>Impact:</strong> NLog InternalLogger will no longer activate itself based on appsettings or environment variables.</p>
</li>
<li>
<p><strong>Reason:</strong> NLog initialization becomes slower when having to check for environment variables or app.config.
When using NLog in the cloud then overhead from logging should be minimal.</p>
</li>
<li>
<p><strong>Workaround:</strong> NLog InternalLogger can be enabled from NLog.config as always:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">internalLogToConsole=</span><span class="s">"true"</span> <span class="na">internalLogLevel=</span><span class="s">"Debug"</span><span class="nt">></span>
<span class="nt"></nlog></span>
</code></pre></div> </div>
<p>NLog InternalLogger can be enabled from code as always:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">Common</span><span class="p">.</span><span class="n">InternalLogger</span><span class="p">.</span><span class="n">LogToConsole</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
<span class="n">NLog</span><span class="p">.</span><span class="n">Common</span><span class="p">.</span><span class="n">InternalLogger</span><span class="p">.</span><span class="n">LogLevel</span> <span class="p">=</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">;</span>
</code></pre></div> </div>
<p>NLog InternalLogger can be initialized from environment-variables from code:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupInternalLogger</span><span class="p">(</span><span class="n">log</span> <span class="p">=></span> <span class="n">log</span><span class="p">.</span><span class="nf">SetupFromEnvironmentVariables</span><span class="p">());</span>
</code></pre></div> </div>
</li>
</ul>
<h3 id="removed-obsolete-method-targetwriteasynclogeventinfo-and-optimizebufferreuse-is-always-true">Removed obsolete method Target.Write(AsyncLogEventInfo[]) and OptimizeBufferReuse is always true</h3>
<ul>
<li>
<p><strong>Impact:</strong> NLog extensions targets that depends on batch writing LogEvents using the method <code class="language-plaintext highlighter-rouge">Write(AsyncLogEventInfo[] logEvent)</code>
will no longer work. The <code class="language-plaintext highlighter-rouge">OptimizeBufferReuse</code> performance optimization will now always be enabled for all NLog extensions targets.
Custom NLog Targets that uses <code class="language-plaintext highlighter-rouge">Target.RenderLogEvent()</code> instead of <code class="language-plaintext highlighter-rouge">Layout.Render()</code> will experience a performance boost.</p>
</li>
<li>
<p><strong>Reason:</strong> NLog 4.4.2 introduced the ability to reuse the same array-buffer to reduce memory allocation along with better performance for FileTarget.
NLog 4.5 activated the optimization for all other targets, as it had proven itself stable. NLog 5.0 now removes the ability
to fallback to legacy mode reduces code complexity and code maintenance.</p>
</li>
<li>
<p><strong>Workaround:</strong> NLog extensions target that depends on the removed method <code class="language-plaintext highlighter-rouge">Target.Write(AsyncLogEventInfo[])</code> should instead override
this method: <code class="language-plaintext highlighter-rouge">Target.Write(IList<AsyncLogEventInfo>)</code></p>
</li>
</ul>
<h3 id="scopecontext-changes-mappeddiagnosticcontext-mdc-to-use-asynclocal">ScopeContext changes MappedDiagnosticContext (MDC) to use AsyncLocal</h3>
<p>NLog ScopeContext is a reimplementation of MappedDiagnosticContext (MDC) and MappedDiagnosticLogicalContext (MDLC), that reduces
the overhead from capturing context-state. NLog no longer creates a mapped-dictionary upfront, but just stores the
context-state on an async stack, until actual logging requires scope-property lookup.</p>
<ul>
<li>
<p><strong>Impact:</strong> NLog MappedDiagnosticContext (MDC) will change from <a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.allocatedataslot">AllocateDataSlot</a>
to <a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.asynclocal-1">AsyncLocal</a> when using .NET Core or .NET Framework v4.6.
When using older platforms like .NET Framework v4.5 or v3.5 then it will change to <a href="https://docs.microsoft.com/en-us/dotnet/api/system.runtime.remoting.messaging.callcontext">CallContext</a>.
NLog MappedDiagnosticLogicalContext (MDLC) will change from <a href="https://docs.microsoft.com/en-us/dotnet/api/system.runtime.remoting.messaging.callcontext">CallContext</a>
to <a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.asynclocal-1">AsyncLocal</a> when using .NET Framework v4.6 just like on .NET Core.</p>
</li>
<li>
<p><strong>Reason:</strong> NLog MappedDiagnosticContext (MDC) was implemented to capture context-state and correlate a series of logging events.
MappedDiagnosticLogicalContext (MDLC) extended the MDC feature to also support async Task-state. It has been a long standing wish
to merge MDC and MDLC into one, because having both caused confusion. This advanced logging feature was not used by many,
and there was an additional overhead from creating the context-state, especially when no relevant logging between context state changes.
The NLog Logging Provider for Microsoft Extension Logging (MEL) <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger.beginscope">ILogger.BeginScope</a>
used the NLog MDLC for storing context-state, and so the overhead from handling context-state was now hitting lots of users.
The expected behavior that logging had minimal overhead, was no longer true when using MDC / MLDC.</p>
</li>
<li>
<p><strong>Workaround:</strong> MappedDiagnosticContext (MDC) and MappedDiagnosticLogicalContext (MDLC) still exists with all their API-methods,
but they have been redirected to the new NLog ScopeContext. Many of the old API-methods introduces a huge overhead compared to using
the NLog ScopeContext directly. NLog Logger object now also provides the methods <code class="language-plaintext highlighter-rouge">Logger.PushScopeProperty</code> and <code class="language-plaintext highlighter-rouge">Logger.PushScopeNested</code>
for easier availability.</p>
</li>
</ul>
<h3 id="mappeddiagnosticcontext-mdc-mappeddiagnosticlogicalcontext-mdlc-globaldiagnosticcontext-gdc-now-case-insensitive">MappedDiagnosticContext (MDC), MappedDiagnosticLogicalContext (MDLC), GlobalDiagnosticContext (GDC) now case-insensitive</h3>
<p>NLog have changed the default dictionary comparer to StringComparer.OrdinalIgnoreCase.</p>
<ul>
<li>
<p><strong>Impact:</strong> Property lookup with key <code class="language-plaintext highlighter-rouge">RequestId</code> will now match item-key <code class="language-plaintext highlighter-rouge">requestid</code>. This also means it will also overwrite independent
of casing. Notice that LogEventInfo.Properties is still case-sensitive, but <code class="language-plaintext highlighter-rouge">${event-properties}</code> will now ignore casing on property lookup by default.</p>
</li>
<li>
<p><strong>Reason:</strong> Making it easier to lookup a single property without having to ensure all code-locations are using exact same casing.</p>
</li>
<li>
<p><strong>Workaround:</strong> Instead just add a prefix (or suffix) to make it easier to distinguish the properties, when needing to store
two different <code class="language-plaintext highlighter-rouge">requestid</code> values.</p>
</li>
</ul>
<h3 id="filetarget-keepfileopen--true-by-default">FileTarget KeepFileOpen = true by default</h3>
<p>FileTarget will now keep file handles open by default, and will not release file handle after each write.</p>
<ul>
<li>
<p><strong>Impact:</strong> External applications that tries to acquire exclusive file-locks for the log-file will now fail,
instead of possibly blocking the application. Ex. <code class="language-plaintext highlighter-rouge">File.OpenText</code> or <code class="language-plaintext highlighter-rouge">File.ReadAllText</code> will now fail with
<code class="language-plaintext highlighter-rouge">System.IO.IOException: The process cannot access the file</code>.</p>
</li>
<li>
<p><strong>Reason:</strong> Avoid unexpected behavior caused by external applications (ex. malware scanner) suddenly taking over file handles,
thus blocking the application from logging so log-events are lost. Keeping the file open also gives much
better performance, than to open/close the file handle for each write.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicitly specify <code class="language-plaintext highlighter-rouge">KeepFileOpen=false</code> to enforce old behavior similar to log4net/log4j MinimalLock.
This is mostly important when FileName points to network-path on remote network-host, to avoid undetected invalidation of FileStream-handle.
But if having issues with external application on the local machine, that is no longer being able to acquire exclusive file-lock,
then it is better to fix the external application to use <code class="language-plaintext highlighter-rouge">FileShare.ReadWrite</code>.</p>
</li>
</ul>
<h3 id="filetarget-concurrentwrites--false-by-default">FileTarget ConcurrentWrites = false by default</h3>
<p>FileTarget will now by default not attempt to use operating system global mutexes for synchronized file-access between multiple applications on the same machine.</p>
<ul>
<li>
<p><strong>Impact:</strong> If multiple application instances on the same machine uses the same NLog FileTarget file-path with KeepFileOpen=true,
then it will lead to failure if not having explictly configured ConcurrentWrites=true. This means IIS applications where multiple
AppDomain application instances can be used, should check that ConcurrentWrites=true is explictly enabled. If using
KeepFileOpen=false, then it will use the operating system file-locks for synchronization, and then ConcurrentWrites=true
is only needed if making use of static-filename-archive-logic.</p>
</li>
<li>
<p><strong>Reason:</strong> NLog FileTarget was initially built for Desktop applications, Windows Services and IIS running on the Windows platform,
where global mutex is available even for restricted users. This is not the case for Xamarin platforms and UWP, where use of
global mutex will cause application failure. Because Xamarin platforms now use .NET Standard-build by default, then this “dangerous” feature
has been disabled by default for better compatibility. ConcurrentWrites=true also introduces a performance overhead, which is unnecessary for most
applications.</p>
</li>
<li>
<p><strong>Workaround:</strong> For best performance one should use FileTarget KeepFileOpen=true and ensure each application-instance doesn’t share filepath
with other application instances. One should only configure FileTarget ConcurrentWrites=true when absolutely certain that
multiple application instances must write to the same file-path, which is the case for application running on IIS.</p>
</li>
</ul>
<h3 id="filetarget-encoding-default-value-changed-to-utf8">FileTarget Encoding default value changed to UTF8</h3>
<p>Instead of using Encoding.Default then FileTarget will now use Encoding.UTF8</p>
<ul>
<li>
<p><strong>Impact:</strong> FileTarget will now by default write using UTF8 encoding.</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience when using JsonLayout together with FileTarget. Also make it easier
to read files coming from different locations and environments like the cloud.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit assign <code class="language-plaintext highlighter-rouge">Encoding</code> on the FileTarget.</p>
</li>
</ul>
<h3 id="filetarget-will-include-bom-by-default-for-utf16-and-utf32-encoding">FileTarget will include BOM by default for UTF16 and UTF32 encoding</h3>
<p>When the encoding requires a BOM preamble for proper parsing, then FileTarget will now include it by default.</p>
<ul>
<li>
<p><strong>Impact:</strong> When not having configured FileTarget WriteBom-option, then it will automatically become
true for UTF16 and UTF32 encoding.</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience when using default configuration. Most file viewers will fail to handle these file encodings without correct BOM.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit assign <code class="language-plaintext highlighter-rouge">WriteBom</code> on the FileTarget.</p>
</li>
</ul>
<h3 id="networktarget-will-discard-by-default-on-overflow">NetworkTarget will Discard by default on overflow</h3>
<p>NetworkTarget behaves asynchronous and never had any throttle of network requests pending.
With <code class="language-plaintext highlighter-rouge">KeepConnection = true</code> then network requests would be put in a pending-queue without
any upper limit. With <code class="language-plaintext highlighter-rouge">KeepConnection=false</code> then network connections would be created
without any upper limit.</p>
<p>This could cause the application to experience out-of-memory issues, which is not wanted
from the logging framework by default. For <code class="language-plaintext highlighter-rouge">KeepConnection = true</code> there has been
introduced a new setting <code class="language-plaintext highlighter-rouge">OnQueueOverflow</code> with default value Discard. For <code class="language-plaintext highlighter-rouge">KeepConnection = false</code>
the existing setting <code class="language-plaintext highlighter-rouge">OnConnectionOverflow</code> is now by default Discard.</p>
<ul>
<li>
<p><strong>Impact:</strong> LogEvents might be lost during high loads, where network cannot keep up.</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience by not taking the application down during high loads.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit assign <code class="language-plaintext highlighter-rouge">OnQueueOverflow</code> and <code class="language-plaintext highlighter-rouge">OnConnectionOverflow</code> to use <code class="language-plaintext highlighter-rouge">Grow</code> or <code class="language-plaintext highlighter-rouge">Block</code>.</p>
</li>
</ul>
<h3 id="jsonlayout-maxrecursionlimit-default-value-changed-to-1">JsonLayout MaxRecursionLimit default value changed to 1</h3>
<p>JsonLayout will by default perform reflection of property-values and output direct object-properties.</p>
<ul>
<li>
<p><strong>Impact:</strong> When enabling <code class="language-plaintext highlighter-rouge">IncludeEventProperties</code> then it will automatically output first level object-properties.</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience when using default configuration. When using JSON for structured logging,
then one expects to see the object-properties.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit assign <code class="language-plaintext highlighter-rouge">MaxRecursionLimit="0"</code> on the JsonLayout.</p>
</li>
</ul>
<h3 id="jsonlayout-escapeforwardslash-default-value-changed-to-false">JsonLayout EscapeForwardSlash default value changed to false</h3>
<p>JsonLayout will now by default not escape URL-values when rendering JSON.</p>
<ul>
<li>
<p><strong>Impact:</strong> Forward slashes <code class="language-plaintext highlighter-rouge">/</code> will no longer be escaped by default</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience as it aligns the NLog JSON Serializer with the default behavior of others.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit assign <code class="language-plaintext highlighter-rouge">EscapeForwardSlash="true"</code> on the JsonLayout.</p>
</li>
</ul>
<h3 id="jsonlayout-always-includes-decimal-point-for-floating-point-types">JsonLayout always includes decimal point for floating-point types</h3>
<p>JsonLayout will now by default add decimal point for properties of the type <code class="language-plaintext highlighter-rouge">decimal</code>, <code class="language-plaintext highlighter-rouge">double</code> and <code class="language-plaintext highlighter-rouge">float</code>.</p>
<ul>
<li>
<p><strong>Impact:</strong> Instead of writing double default value as <code class="language-plaintext highlighter-rouge">0</code> then it will become <code class="language-plaintext highlighter-rouge">0.0</code></p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience as it aligns the NLog JSON Serializer with JSON.NET, and many JSON-parsers (ElasticSearch)
deduces the datatype from the format of the property-values.</p>
</li>
<li>
<p><strong>Workaround:</strong> Stop using decimal types for properties where you don’t want decimal point in JSON.</p>
</li>
</ul>
<h3 id="callsite-renderer-will-automatically-clean-async-callstacks">CallSite-renderer will automatically clean async callstacks</h3>
<p><code class="language-plaintext highlighter-rouge">${callsite}</code> will now enable CleanNamesOfAnonymousDelegates and CleanNamesOfAsyncContinuations by default.</p>
<ul>
<li>
<p><strong>Impact:</strong> <code class="language-plaintext highlighter-rouge">${callsite}</code> rendering will now attempt to extract and log the actual method, instead of the async-delegate.</p>
</li>
<li>
<p><strong>Reason:</strong> Better user experience when using default configuration, and doing logging in async-methods.</p>
</li>
<li>
<p><strong>Workaround:</strong> Explicit assign <code class="language-plaintext highlighter-rouge">CleanNamesOfAnonymousDelegates</code> and <code class="language-plaintext highlighter-rouge">CleanNamesOfAsyncContinuations</code> when using <code class="language-plaintext highlighter-rouge">${callsite}</code>.</p>
</li>
</ul>
<h3 id="the-simplelayouttostring-has-been-changed">The Simplelayout.ToString() has been changed</h3>
<p>The ToString won’t add aditional quotes.</p>
<p>For example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Layout l = "a";
l.ToString();
</code></pre></div></div>
<p>In NLog 4 this results in <code class="language-plaintext highlighter-rouge">'a'</code> and in NLog 5 this results in <code class="language-plaintext highlighter-rouge">a</code>.</p>
<ul>
<li>
<p><strong>Impact:</strong> There are maybe changes needed when parsing the ToString value of a <code class="language-plaintext highlighter-rouge">Layout</code></p>
</li>
<li>
<p><strong>Reason:</strong> The additional quotes won’t has any value, it could be confusing and also it’s a good practive that the ToString value could be parsed by the Layout again.</p>
</li>
<li>
<p><strong>Workaround:</strong> Add quotes manually when needed.</p>
</li>
</ul>
<h2 id="many-other-improvements">Many other improvements</h2>
<p>For full list of all changes: <a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+is%3Amerged+milestone:%225.0%22">NLog 5.0 Pull Requests</a></p>
<ul>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22breaking%20change%22+is%3Amerged+milestone:%225.0%22">Breaking Changes</a></li>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22breaking%20behavior%20change%22+is%3Amerged+milestone:%225.0%22">Breaking Behavior Changes</a></li>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22Feature%22+is%3Amerged+milestone:%225.0%22">Features</a></li>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22Enhancement%22+is%3Amerged+milestone:%225.0%22">Improvements</a></li>
<li><a href="https://github.com/NLog/NLog/pulls?q=is%3Apr+label%3A%22Performance%22+is%3Amerged+milestone:%225.0%22">Performance</a></li>
</ul>
NLog 4.7 has been released!2020-03-28T00:00:00+00:00https://nlog-project.org/2020/03/28/nlog-4-7-has-been-released<p>NLog 4.7 marks another year of new features and performance improvements.</p>
<h2 id="main-features">Main features</h2>
<h3 id="logfactory-setup">LogFactory Setup</h3>
<p>There has been introduced a new fluent api for setting up NLog before logging. Instead of having static methods on different NLog types, then all options are being gathered around <code class="language-plaintext highlighter-rouge">LogFactory.Setup()</code>. This will also prepare the road for improving the support for multiple isolated <code class="language-plaintext highlighter-rouge">LogFactory</code> instances in the same application.</p>
<h3 id="custom-object-serialization">Custom Object Serialization</h3>
<p>It is now possible to customize the serialization of different object types. One can exclude unwanted properties, or add new artificial properties.</p>
<h4 id="examples">Examples</h4>
<p>Ensures that object-reflection is skipped for all objects that implements <code class="language-plaintext highlighter-rouge">IDangerousObject</code>:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupSerialization</span><span class="p">(</span><span class="n">s</span> <span class="p">=></span>
<span class="n">s</span><span class="p">.</span><span class="n">RegisterObjectTransformation</span><span class="p"><</span><span class="n">IDangerousObject</span><span class="p">>(</span><span class="n">o</span> <span class="p">=></span> <span class="n">o</span><span class="p">.</span><span class="nf">ToString</span><span class="p">()));</span>
</code></pre></div></div>
<p>Ensures that only selected properties for objects of the type <code class="language-plaintext highlighter-rouge">System.Net.WebException</code>:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">NLog</span><span class="p">.</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupSerialization</span><span class="p">(</span><span class="n">s</span> <span class="p">=></span>
<span class="n">s</span><span class="p">.</span><span class="n">RegisterObjectTransformation</span><span class="p"><</span><span class="n">System</span><span class="p">.</span><span class="n">Net</span><span class="p">.</span><span class="n">WebException</span><span class="p">>(</span><span class="n">ex</span> <span class="p">=></span> <span class="k">new</span> <span class="p">{</span>
<span class="n">Type</span> <span class="p">=</span> <span class="n">ex</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="nf">ToString</span><span class="p">(),</span>
<span class="n">Message</span> <span class="p">=</span> <span class="n">ex</span><span class="p">.</span><span class="n">Message</span><span class="p">,</span>
<span class="n">StackTrace</span> <span class="p">=</span> <span class="n">ex</span><span class="p">.</span><span class="n">StackTrace</span><span class="p">,</span>
<span class="n">Source</span> <span class="p">=</span> <span class="n">ex</span><span class="p">.</span><span class="n">Source</span><span class="p">,</span>
<span class="n">InnerException</span> <span class="p">=</span> <span class="n">ex</span><span class="p">.</span><span class="n">InnerException</span><span class="p">,</span>
<span class="n">Status</span> <span class="p">=</span> <span class="n">ex</span><span class="p">.</span><span class="n">Status</span><span class="p">,</span>
<span class="n">Response</span> <span class="p">=</span> <span class="n">ex</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(),</span> <span class="c1">// Call your custom method to render stream as string</span>
<span class="p">}));</span>
</code></pre></div></div>
<p>This can be used together with <code class="language-plaintext highlighter-rouge">${exception:format=@}</code> or the Properties-Format-option <code class="language-plaintext highlighter-rouge">${exception:format=Properties}</code>.</p>
<h3 id="lambda-condition-methods">Lambda Condition Methods</h3>
<p>NLog already has two ways for adding own custom condition methods:</p>
<ul>
<li>Create static class with class-attribute <code class="language-plaintext highlighter-rouge">[ConditionMethods]</code> and add static methods with function-attribute <code class="language-plaintext highlighter-rouge">[ConditionMethod]</code>. Then add the assembly to be registered as an extension.</li>
<li>Explicit register a static method using <code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.Default.ConditionMethods.RegisterDefinition()</code>.</li>
</ul>
<p>Now it is also possible to register lamdba methods:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupExtensions</span><span class="p">(</span><span class="n">s</span> <span class="p">=></span>
<span class="n">s</span><span class="p">.</span><span class="nf">RegisterConditionMethod</span><span class="p">(</span><span class="s">"hasParameters"</span><span class="p">,</span> <span class="n">evt</span> <span class="p">=></span> <span class="n">evt</span><span class="p">.</span><span class="n">Parameters</span><span class="p">?.</span><span class="n">Length</span> <span class="p">></span> <span class="m">0</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<p>And of course standard static methods:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LogManager</span><span class="p">.</span><span class="nf">Setup</span><span class="p">().</span><span class="nf">SetupExtensions</span><span class="p">(</span><span class="n">s</span> <span class="p">=></span>
<span class="n">s</span><span class="p">.</span><span class="nf">RegisterConditionMethod</span><span class="p">(</span><span class="s">"hasPriority"</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">NLogConditionMethods</span><span class="p">).</span><span class="nf">GetMethod</span><span class="p">(</span><span class="s">"HasPriority"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Static</span><span class="p">))</span>
<span class="p">);</span>
</code></pre></div></div>
<h3 id="filetarget-maxarchivedays">FileTarget MaxArchiveDays</h3>
<p>FileTarget can now use the timestamp of the archived files to check if they should be deleted. This allows you to keep log files from the last 30 days, even if <code class="language-plaintext highlighter-rouge">ArchiveAboveSize</code> have produced several files for the same day. It can be used in combination with the existing setting <code class="language-plaintext highlighter-rouge">MaxArchiveFiles</code>, so one will not have more than ex. 60 files in total.</p>
<h3 id="databasetarget-custom-connection-properties">DatabaseTarget Custom Connection Properties</h3>
<p>DatabaseTarget is very generic and supports multiple DbProviders. Certain DbProviders might have additional connection properties. Like <code class="language-plaintext highlighter-rouge">SqlConnection.AccessToken</code> for Azure AD Access Token.</p>
<p>Now it is possible to configure additional connection properties:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">name=</span><span class="s">"db"</span> <span class="na">xsi:type=</span><span class="s">"Database"</span> <span class="na">connectionstring=</span><span class="s">"..."</span> <span class="nt">></span>
<span class="nt"><connectionProperty</span> <span class="na">name=</span><span class="s">"AccessToken"</span> <span class="na">layout=</span><span class="s">"${gdc:AccessToken}"</span> <span class="na">propertyType=</span><span class="s">"System.String"</span> <span class="nt">/></span>
<span class="nt"></target></span>
</code></pre></div></div>
<p>All configured connection properties will be applied before opening the connection. In the above example then one must handle expiry of the AccessToken in <code class="language-plaintext highlighter-rouge">${gdc:AccessToken}</code>, by creating a custom background timer that will refresh the Azure AccessToken in timely manner.</p>
<h3 id="databasetarget-transaction-isolationlevel">DatabaseTarget Transaction IsolationLevel</h3>
<p>DatabaseTarget now has the option to write logevents in batches by using transactions. DatabaseTarget writes a logevent by executing a DbCommand. Now one can configure <a href="https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel">Isolationlevel</a>, so it creates a batch transaction for all DbCommand objects. This means for the SqlClient that it will execute all DbCommands as a single operation. This gives less traffic back and forth and better performance, especially in the cloud with high latency.</p>
<p>Make sure to use the <code class="language-plaintext highlighter-rouge">AsyncWrapper</code> to write logevents in batches to the DatabaseTarget:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">name=</span><span class="s">"db_async"</span> <span class="na">xsi:type=</span><span class="s">"AsyncWrapper"</span><span class="nt">></span>
<span class="nt"><target</span> <span class="na">name=</span><span class="s">"db"</span> <span class="na">xsi:type=</span><span class="s">"Database"</span> <span class="na">connectionstring=</span><span class="s">"..."</span> <span class="na">isolationLevel=</span><span class="s">"ReadCommitted"</span> <span class="nt">></span>
<span class="nt"></target></span>
<span class="nt"></target></span>
</code></pre></div></div>
<p>By default DatabaseTarget will ensure that its own DbCommands are not enlisted in other ongoing database transactions. But to be completely sure then one can add <code class="language-plaintext highlighter-rouge">;ENLIST=FALSE</code> to the ConnectionString.</p>
<h3 id="internallogger-logmessagereceived">InternalLogger LogMessageReceived</h3>
<p>NLog InternalLogger now has support for raising events, instead of having to create a custom <code class="language-plaintext highlighter-rouge">ITextWriter</code> and assign it as to <code class="language-plaintext highlighter-rouge">InternalLogger.LogWriter</code>.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">InternalLogger</span><span class="p">.</span><span class="n">LogMessageReceived</span> <span class="p">+=</span> <span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span> <span class="p">=></span> <span class="nf">SomethingUseful</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
</code></pre></div></div>
<p>One should be careful with executing heavy operations in the custom event handler, as it will hurt NLog performance. And most important of all, then one should never use NLog Logger inside the custom event handler, as it will cause stackoverflow or deadlock.</p>
<h3 id="github-sourcelink">GitHub SourceLink</h3>
<p>The new releases will now be tagged by <a href="https://github.com/dotnet/sourcelink">Microsoft.SourceLink.GitHub</a>, that will allow easier debugging with NLog source code available from Github. See also the <a href="https://www.hanselman.com/blog/ExploringNETCoresSourceLinkSteppingIntoTheSourceCodeOfNuGetPackagesYouDontOwn.aspx">
Scott Hanselman blog</a></p>
<h3 id="net-core-single-file-publish">.NET Core Single File Publish</h3>
<p>.NET Core 3 introduced a new feature called Single File Publish, that builds the entire application (with dotnet) as a single executable file. Microsoft failed to complete the illusion, so if checking the <code class="language-plaintext highlighter-rouge">AppDomain.BaseDirectory</code>, then one will get a secret temporary folder, where the single executable file has been unzipped to.</p>
<p>NLog uses <code class="language-plaintext highlighter-rouge">AppDomain.BaseDirectory</code> as base directory for all relative paths. This means log files will not appear as expected, but are instead written to the secret temp folder. The current work-around is to explicitly specify <code class="language-plaintext highlighter-rouge">${basedir}</code> with this special option:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">type=</span><span class="s">"file"</span> <span class="na">fileName=</span><span class="s">"${basedir:fixtempdir=true}\App.txt"</span> <span class="nt">/></span>
</code></pre></div></div>
<p>If wanting to support override of the <code class="language-plaintext highlighter-rouge">NLog.config</code>, that has been packaged into the single file (Ex. <code class="language-plaintext highlighter-rouge">SingleApp.exe</code>). Then one must rename <code class="language-plaintext highlighter-rouge">NLog.config</code> to <code class="language-plaintext highlighter-rouge">SingleApp.exe.nlog</code>. Then NLog will prioritize the <code class="language-plaintext highlighter-rouge">SingleApp.exe.nlog</code> placed next to the actual <code class="language-plaintext highlighter-rouge">SingleApp.exe</code>, but will fallback to <code class="language-plaintext highlighter-rouge">SingleApp.exe.nlog</code> in the secret temp folder.</p>
<p>Single File Publish can also be combined with <code class="language-plaintext highlighter-rouge">PublishTrimmed</code> that trims the single executable to a minimum. See also the <a href="https://www.hanselman.com/blog/MakingATinyNETCore30EntirelySelfcontainedSingleExecutable.aspx">
Scott Hanselman blog</a></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><PublishSingleFile></span>true<span class="nt"></PublishSingleFile></span>
<span class="nt"><PublishTrimmed></span>true<span class="nt"></PublishTrimmed></span>
<span class="nt"><RuntimeIdentifier></span>win-x64<span class="nt"></RuntimeIdentifier></span>
</code></pre></div></div>
<h2 id="many-other-improvements">Many other improvements</h2>
<p>For a full list of all the enhancements and performance improvements: <a href="https://github.com/NLog/NLog/releases/tag/v4.7">NLog 4.7 Release Notes</a></p>
NLog 4.6 is live!2019-03-20T00:00:00+00:00https://nlog-project.org/2019/03/20/nlog-4-6-is-live<p>NLog 4.6 contains lots of new features and performance improvements.</p>
<h2 id="main-features">Main features</h2>
<h3 id="databasetarget-supports-parameter-types">DatabaseTarget supports parameter types</h3>
<p>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.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">name=</span><span class="s">"db"</span> <span class="na">xsi:type=</span><span class="s">"Database"</span> <span class="na">connectionstring=</span><span class="s">"..."</span> <span class="nt">></span>
<span class="nt"><commandtext></span>INSERT INTO FooBar VALUES(@ts, @lvl, @msg)<span class="nt"></commandtext></span>
<span class="nt"><parameter</span> <span class="na">name=</span><span class="s">"@ts"</span> <span class="na">layout=</span><span class="s">"${date}"</span> <span class="na">dbType=</span><span class="s">"SqlDbType.DateTime2"</span> <span class="nt">/></span>
<span class="nt"><parameter</span> <span class="na">name=</span><span class="s">"@lvl"</span> <span class="na">layout=</span><span class="s">"${level}"</span> <span class="na">dbType=</span><span class="s">"DbType.Int32"</span> <span class="nt">/></span>
<span class="nt"><parameter</span> <span class="na">name=</span><span class="s">"@msg"</span> <span class="na">layout=</span><span class="s">"${message}"</span> <span class="na">dbType=</span><span class="s">"SqlDbType.VarChar"</span> <span class="na">size=</span><span class="s">"-1"</span> <span class="na">parameterType=</span><span class="s">"String"</span> <span class="nt">/></span>
<span class="nt"></target></span>
</code></pre></div></div>
<p>When using a non-string DbType then it will attempt to convert the raw value directly to the expected type.</p>
<h3 id="networktarget-supports-ssl--tls">NetworkTarget supports SSL & TLS</h3>
<p>NetworkTarget can now perform SSL/TLS handshake for the TCP-protocol:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">name=</span><span class="s">"net"</span> <span class="na">type=</span><span class="s">"network"</span> <span class="na">address=</span><span class="s">"tcp://127.0.0.1"</span> <span class="na">sslProtocols=</span><span class="s">"Tls12"</span> <span class="nt">/></span>
</code></pre></div></div>
<p>NetworkTarget has also received a new TCP option for activating KeepAliveTime. <strong>keepAliveTimeSeconds=”30”</strong> can be used to keep TCP connection going when no traffic (with very little overhead).</p>
<h3 id="new-xmllayout">New XmlLayout</h3>
<p>XmlLayout is now available for creating XML files.</p>
<p>Just like with JsonLayout then XmlLayout supports object reflection, so it can be used in combination with structured logging.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><layout</span> <span class="na">xsi:type=</span><span class="s">"XmlLayout"</span> <span class="na">includeAllProperties=</span><span class="s">"True"</span> <span class="na">elementName=</span><span class="s">'logevent'</span><span class="nt">></span>
<span class="nt"><attribute</span> <span class="na">name=</span><span class="s">"time"</span> <span class="na">layout=</span><span class="s">"${longdate}"</span> <span class="nt">/></span>
<span class="nt"><attribute</span> <span class="na">name=</span><span class="s">"level"</span> <span class="na">layout=</span><span class="s">"${level:upperCase=true}"</span><span class="nt">/></span>
<span class="nt"><element</span> <span class="na">name=</span><span class="s">"message"</span> <span class="na">layout=</span><span class="s">"${message}"</span> <span class="nt">/></span>
<span class="nt"></layout></span>
</code></pre></div></div>
<p>Will write:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><logevent</span> <span class="na">time=</span><span class="s">"2010-01-01 12:34:56.0000"</span> <span class="na">level=</span><span class="s">"ERROR"</span><span class="nt">></span>
<span class="nt"><message></span>hello, world<span class="nt"></message></span>
<span class="nt"></logevent></span>
</code></pre></div></div>
<p>This can also be used together with the DatabaseTarget for writing XML to a database:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><parameter</span> <span class="na">name=</span><span class="s">"@props"</span> <span class="na">dbType=</span><span class="s">"SqlDbType.Xml"</span> <span class="na">size=</span><span class="s">"-1"</span><span class="nt">></span>
<span class="nt"><layout</span> <span class="na">type=</span><span class="s">"xmllayout"</span> <span class="na">includeAllProperties=</span><span class="s">"true"</span> <span class="nt">/></span>
<span class="nt"></parameter></span>
</code></pre></div></div>
<h3 id="variables-in-level-attributes">Variables in level attributes</h3>
<p>In the XML configuration you could now variables in the level attributes (minlevel, maxlevel, level and levels),</p>
<p>e.g.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog></span>
<span class="nt"><variable</span> <span class="na">name=</span><span class="s">'myLevel'</span> <span class="na">value=</span><span class="s">'debug'</span><span class="nt">/></span>
<span class="nt"><rules></span>
<span class="nt"><logger</span> <span class="na">minLevel=</span><span class="s">'${myLevel}'</span><span class="nt">/></span>
<span class="nt"></rules></span>
<span class="nt"></nlog></span>
</code></pre></div></div>
<p>NLog ver. 4.6.7 adds support for using <code class="language-plaintext highlighter-rouge">${var:myLevel}</code> or other layout renderers. Allowing one to update filters at runtime like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LogManager</span><span class="p">.</span><span class="n">Configuration</span><span class="p">.</span><span class="n">Variables</span><span class="p">[</span><span class="s">"myLevel"</span><span class="p">]</span> <span class="p">=</span> <span class="s">"Debug"</span><span class="p">;</span>
<span class="n">LogManager</span><span class="p">.</span><span class="nf">ReconfigExistingLoggers</span><span class="p">();</span>
</code></pre></div></div>
<h3 id="added-default-action-for-filtering">Added default action for filtering</h3>
<p>Currently the default action for filtering - when not matching any rule - is “neutral”.</p>
<p>This is a bit tricky. This could be now configured with the attribute defaultAction. Possible values: Neutral, Ignore, Log, LogFinal, IgnoreFinal</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><rules></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">'*'</span> <span class="na">level=</span><span class="s">'Warn'</span> <span class="na">writeTo=</span><span class="s">'myTarget'</span><span class="nt">></span>
<span class="nt"><filters</span> <span class="na">defaultAction=</span><span class="s">'Ignore'</span><span class="nt">></span>
<span class="nt"><when</span> <span class="na">condition=</span><span class="s">"starts-with(message, 't')"</span> <span class="na">action=</span><span class="s">'Log'</span> <span class="nt">/></span>
<span class="nt"></filters></span>
<span class="nt"></logger></span>
<span class="nt"></rules></span>
</code></pre></div></div>
<p>In NLog 5 the default will be probably changed to “ignore”</p>
<h3 id="substring-left-and-right">Substring, left and right</h3>
<p>New layout renders has been added:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>${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
</code></pre></div></div>
<h3 id="name-filter-support-for-multiple-wildcards-and-in-any-position">Name filter: support for multiple wildcards and in any position</h3>
<p>In NLog 4.5 and before, the wildcards in the name filter of the <rule> element was limited.</rule></p>
<ul>
<li><code class="language-plaintext highlighter-rouge">?</code> was not supported</li>
<li>Only one <code class="language-plaintext highlighter-rouge">*</code> was allowed the name filter.</li>
</ul>
<p>With a new implementation, those restrictions are now gone and <code class="language-plaintext highlighter-rouge">?</code> wildcard has been added.</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">*</code> - matches 0 or more characters</li>
<li><code class="language-plaintext highlighter-rouge">?</code> - matches exactly 1 character</li>
</ul>
<p>Examples</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><logger</span> <span class="na">name=</span><span class="s">"*.Library.*"</span> <span class="na">minlevel=</span><span class="s">"Warn"</span> <span class="na">writeTo=</span><span class="s">"f3"</span> <span class="nt">/></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">"*TcpTestServer[*].Connection[??].*"</span> <span class="na">writeTo=</span><span class="s">"logconsole"</span> <span class="nt">/></span>
</code></pre></div></div>
<h3 id="internallogfile-variables">InternalLogFile variables</h3>
<p>The internalLogFile attribute is for stability limited in features, no layout renderers where allowed.</p>
<p>In NLog 4.6 we added support for: ${currentdir}, ${basedir} & ${tempdir}, and for environment variables, like <code class="language-plaintext highlighter-rouge">%myPath%</code></p>
<p>example:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">internalLogFile=</span><span class="s">"${basedir}\log.txt"</span> <span class="na">internalLogLevel=</span><span class="s">"Trace"</span><span class="nt">></span>
<span class="nt"><targets></span>
<span class="c"><!-- target configuration here --></span>
<span class="nt"></targets></span>
<span class="nt"><rules></span>
<span class="c"><!-- log routing rules --></span>
<span class="nt"></rules></span>
<span class="nt"></nlog></span>
</code></pre></div></div>
<h3 id="asyncwrapper-uses-concurrentqueue">AsyncWrapper uses ConcurrentQueue</h3>
<p>ConcurrentQueue has been optimized with .NET Standard 2.0, so it provides high performance and little allocation.</p>
<p>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.</p>
<h3 id="asyncwrapper-with-faster-timer">AsyncWrapper with faster timer</h3>
<p>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.</p>
<p>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.</p>
<h3 id="coloredconsoletarget-supports-ansi-output">ColoredConsoleTarget supports Ansi output</h3>
<p>Console coloring now also works on VS Code or other console terminal using ANSI color escape sequences.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">name=</span><span class="s">"console"</span> <span class="na">xsi:type=</span><span class="s">"ColoredConsole"</span> <span class="na">enableAnsiOutput=</span><span class="s">"true"</span> <span class="nt">/></span>
</code></pre></div></div>
<h3 id="appsetting-without-nlogextended">AppSetting without NLog.Extended</h3>
<p>NLog.Extended was needed when wanting to use <code class="language-plaintext highlighter-rouge">${appsetting}</code> 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.</p>
<h3 id="snupkg">Snupkg</h3>
<p>The new releases will also publish a snupkg to nuget.org, for improved package debugging experience. See also the <a href="https://blog.nuget.org/20181116/Improved-debugging-experience-with-the-NuGet-org-symbol-server-and-snupkg.html">NuGet blog</a></p>
<h3 id="liblog-breaking-change">LibLog Breaking change</h3>
<p><a href="https://github.com/damianh/LibLog/pull/181">damianh/LibLog#181</a> - 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.</p>
<ul>
<li>Make sure to update NLog.config to match this change.</li>
<li>Make sure that all sub-components have upgraded to LibLog ver. 5.0.3 (or newer) if they make use of <code class="language-plaintext highlighter-rouge">OpenNestedContext</code> or <code class="language-plaintext highlighter-rouge">OpenMappedContext</code>.</li>
</ul>
<h2 id="many-other-improvements">Many other improvements</h2>
<p>For a full list of all the enhancements and performance improvements: <a href="https://github.com/NLog/NLog/blob/master/CHANGELOG.md">NLog 4.6 Release Notes</a></p>
<p>Happy logging!</p>
NLog 4.5 is live!2018-03-25T00:00:00+00:00https://nlog-project.org/2018/03/25/nlog-4-5-is-live<p>NLog 4.5 is now finally ready. NLog 5.0 beta has now been abandoned and all features has been moved to NLog 4.5.</p>
<h2 id="main-features">Main features</h2>
<h3 id="net-core-support">.NET Core Support</h3>
<p>NLog 4.5 provides official support for .NET Core without any breaking changes!</p>
<ul>
<li>.NET Standard 1.3 - Minimal dependencies for limited .NET Core 1 platforms (Ex. UWP1)</li>
<li>.NET Standard 1.5 - Normal dependencies for standard .NET Core 1 platforms</li>
<li>.NET Standard 2.0 - Normal dependencies for standard .NET Core 2 platforms</li>
</ul>
<h3 id="message-template-support">Message Template Support</h3>
<p>Structured Logging support in NLog has been extended to also handle <a href="https://messagetemplates.org/">message templates</a>.
Joining the wave started by Serilog and Microsoft Extension Logging:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"Order {orderid} created for {user}"</span><span class="p">,</span> <span class="m">42</span><span class="p">,</span> <span class="s">"Kenny"</span><span class="p">);</span>
</code></pre></div></div>
<p>See also <a href="https://github.com/NLog/NLog/wiki/How-to-use-structured-logging">How to use structured logging</a></p>
<h3 id="jsonlayout-object-reflection-support">JsonLayout Object Reflection Support</h3>
<p><a href="https://github.com/NLog/NLog/wiki/JsonLayout">JsonLayout</a> can now perform object reflection and navigate object-collections.
This allows one to use anonymous object properties together with structured logging:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"Item {shopitem} added to {orderid}"</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">123</span><span class="p">,</span> <span class="n">Name</span> <span class="p">=</span> <span class="s">"Jacket"</span><span class="p">,</span> <span class="n">Color</span> <span class="p">=</span> <span class="s">"Orange"</span> <span class="p">},</span> <span class="m">42</span><span class="p">);</span>
</code></pre></div></div>
<p>Enable object reflection by configuring <code class="language-plaintext highlighter-rouge">maxRecursionLimit</code>:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><layout</span> <span class="na">type=</span><span class="s">"JsonLayout"</span> <span class="na">includeAllProperties=</span><span class="s">"true"</span> <span class="na">maxRecursionLimit=</span><span class="s">"10"</span><span class="nt">/></span>
</code></pre></div></div>
<p>Will give the following output:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"shopitem"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"Id"</span><span class="p">:</span><span class="w"> </span><span class="mi">123</span><span class="p">,</span><span class="w">
</span><span class="nl">"Name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jacket"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Color"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Orange"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"orderid"</span><span class="p">:</span><span class="w"> </span><span class="mi">42</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>It is now also possible to toggle Json serialization in these selected layoutrenderers by specifying <code class="language-plaintext highlighter-rouge">format=@</code>:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">${event-properties:format=@}</code></li>
<li><code class="language-plaintext highlighter-rouge">${exception:format=@}</code></li>
<li><code class="language-plaintext highlighter-rouge">${gdc:format=@}</code> - Global Context</li>
<li><code class="language-plaintext highlighter-rouge">${mdc:format=@}</code> - Thread Context</li>
<li><code class="language-plaintext highlighter-rouge">${mdlc:format=@}</code> - Async Context</li>
</ul>
<p>It is also possible to introduce your own favorite Json-Serializer by creating you own
implementation of <code class="language-plaintext highlighter-rouge">IJsonConverter</code> and assign it to <code class="language-plaintext highlighter-rouge">NLog.Config.ConfigurationItemFactory.Default.JsonConverter</code>.</p>
<h3 id="easier-filetarget-archive-setup">Easier FileTarget Archive Setup</h3>
<p>Previous NLog versions had several restrictions for how to configure FileTarget archive logic. Example if not
specifying <code class="language-plaintext highlighter-rouge">archiveFileName</code> then it was very important to perform logging in an isolated folder to avoid
deleting all files.</p>
<p>This is no longer the case, and one can setup file archive with very few parameters:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">type=</span><span class="s">"file"</span> <span class="na">logfile=</span><span class="s">"hello.txt"</span> <span class="na">archiveAboveSize=</span><span class="s">"1000000"</span> <span class="na">maxArchiveFiles=</span><span class="s">"10"</span> <span class="nt">/></span>
</code></pre></div></div>
<h3 id="many-other-improvements">Many other improvements</h3>
<p>For a full list of all the enhancements and performance improvements: <a href="https://github.com/NLog/NLog/releases/tag/v4.5">NLog 4.5 Release Notes</a></p>
NLog 4.5 is near! (and no NLog 5 for now)2017-12-20T00:00:00+00:00https://nlog-project.org/2017/12/20/nlog-4-5-is-near<p>With the releases of NLog 4.5 RC, a RTM release is near!</p>
<p>NLog 4.5 adds support for various platforms (.NET Standard 1.5+, .NET Standard 2 and UWP - This also means .NET Core!) and adds
structured logging!</p>
<p>Summary of the most important changes in NLog 4.5:</p>
<p><strong>Features:</strong></p>
<ul>
<li>Support for .Net Standard 1.5 #2341</li>
<li>Support for .Net Standard 2.0 #2263 + #2402</li>
<li>Support for UWP #2441 (Remember to manually flush on app suspend).</li>
<li>Introduced Structured logging #2208 + #2262 + #2244</li>
<li>Default file archive logic is now easier to use #1993</li>
<li>Introduced InstallationContext.ThrowExceptions #2214</li>
<li>WebServiceTarget - Allow configuration of proxy address #2375</li>
<li>Json conversion also supports object properties #2179</li>
<li>event-properties layout-renderer can now render objects as json #2241</li>
<li>exception layout-renderer can now render exceptions as json #2357</li>
<li>${guid}, added GeneratedFromLogEvent #2226</li>
<li>TraceTarget RawWrite to always perform Trace.WriteLine independent of LogLevel #1968</li>
<li>Adding OverflowAction options to BufferingTargetWrapper #2276</li>
<li>WhenRepeatedFilter #2123 + #2297</li>
<li>${callsite} added CleanNamesOfAsyncContinuations option #2292</li>
<li>${ndlctiming} allows timing of ndlc-scopes #2377</li>
<li>NLogViewerTarget - Enable override of the Logger-name #2390</li>
<li>${sequenceid} added #2411</li>
<li>Added “regex-matches” for filtering #2437</li>
</ul>
<p><strong>BugFixes:</strong></p>
<ul>
<li>Improved archive stability during concurrent file access #1889</li>
<li>FallbackGroup could lose log events #2265</li>
<li>Exception separator should only be inserted for available items #2250</li>
<li>${exception} - only include separator when items are available #2257</li>
<li>LogFactory - Fixes broken EventArgs for ConfigurationChanged #1897</li>
<li>Do not report wrapped targets as unused targets #2290</li>
<li>Added IIncludeContext, implemented missing properties #2117</li>
<li>Improved logging of callsite linenumber for async-methods #2386</li>
<li>NLogTraceListener - DisableFlush is enabled by default when AutoFlush=true #2407</li>
<li>NLogViewer - Better defaults for connection limits #2404</li>
<li>LoggingConfiguration.LoggingRules is not thread safe #2393, #2418</li>
</ul>
<p><strong>Performance:</strong></p>
<ul>
<li>More targets has OptimizeBufferReuse enabled by default #1913 + #1923 + #1912 + #1911 + #1910 + #1909 + #1908 + #1907</li>
<li>StringBuilderPool - Improved Layout Render Performance by reusing StringBuilders #2208</li>
<li>JsonLayout - Improved Layout Performance, by optimizing use of StringBuilder #2208</li>
<li>FileTarget - Faster byte-encoding of log messsages, by using crude Encoding.GetMaxByteCount() instead of exact Encoding.GetByteCount() #2208</li>
<li>Target - Precalculate Layout should ignore sub-layouts for complex layout (Ex Json) #2378</li>
</ul>
<h2 id="what-happend-to-nlog-5">What happend to NLog 5?</h2>
<p>We started with NLog 5 almost two years ago, at the time of DNX and dotnet5.4.
Fast forward: the branch we were building on is heavily diverged and we were maintaining two versions of NLog! (NLog 4 and NLog 5).
Almost every file had been changed in NLog 5 and with multiple migrations (DNX, project.json, csproj) and it was clear that merging the NLog 5 branch into master was too tricky!</p>
<p>With the completion of .NET Standard 2, it was easier to move to the new platforms (including .NET standard 1) in smaller steps and we have ported the most important stuff to NLog 4.5</p>
<p>This means that NLog 4.5 will have the support for the platforms added in NLog 5, thus making NLog 5 obsolete!</p>
<p>The best part, there are no breaking changes between NLog 4.x and NLog 4.5! (we take semver very serious!)</p>
NLog 4.4 is live!2016-12-14T00:00:00+00:00https://nlog-project.org/2016/12/14/nlog-4-4-is-live<p>NLog 4.4 contains new features, performance improvements and makes it easier
to write custom components (e.g. targets, layout renderers) for NLog!</p>
<p>A lot of stuff has been contributed by the community! Thanks for making NLog great!</p>
<h2 id="main-features">Main features</h2>
<h3 id="webservicetarget-support-for-json--xml">WebServiceTarget support for JSON & XML</h3>
<p>The WebServiceTarget was always a bit odd as it was posting the data Form-encoded (application/x-www-form-urlencoded).
This has now been fixed with the support for JSON and XML, just pick one!</p>
<p>Example</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">type=</span><span class="s">'WebService'</span>
<span class="na">name=</span><span class="s">'ws'</span>
<span class="na">url=</span><span class="s">'http://localhost:1234/logme'</span>
<span class="na">protocol=</span><span class="s">'JsonPost'</span>
<span class="na">encoding=</span><span class="s">'UTF-8'</span> <span class="nt">></span>
<span class="nt"><parameter</span> <span class="na">name=</span><span class="s">'param1'</span> <span class="na">type=</span><span class="s">'System.String'</span> <span class="na">layout=</span><span class="s">'${message}'</span><span class="nt">/></span>
<span class="nt"><parameter</span> <span class="na">name=</span><span class="s">'param2'</span> <span class="na">type=</span><span class="s">'System.String'</span> <span class="na">layout=</span><span class="s">'${level}'</span><span class="nt">/></span>
<span class="nt"></target></span>
</code></pre></div></div>
<h3 id="injecting-json-serializer-into-nlog">Injecting JSON serializer into NLog</h3>
<p>With the support of JSON in the WebServiceTarget, it can be important to give the opportunity
to choose your JSON serializer implementation.
This implementation will be also used for all other JSON serialization in NLog, like the JsonLayout.</p>
<p>We really like JSON.NET, but we don’t like to depend on it! It’s a great library,
but it can lead to issues with strong names and other versions in your project.
See also <a href="https://groups.google.com/forum/#!msg/restsharp/yjGCtOnEYHk/XbKZi0yjN8cJ">the statement of RestSharp library</a> (which is also a great library)</p>
<p>So we now have our own implementation, which is sufficient for most cases.</p>
<p>Do you like to choose your implementation? Implement <code class="language-plaintext highlighter-rouge">SerializeObject(..)</code> in <code class="language-plaintext highlighter-rouge">IJsonSerializer</code> and set it to <code class="language-plaintext highlighter-rouge">ConfigurationItemFactory.JsonSerializer</code>.</p>
<h3 id="json-layout-support-for-all-event-properties">JSON layout support for all-event-properties</h3>
<p>The JsonLayout has two new properties which will help you creating better JSON documents:</p>
<ul>
<li>includeAllProperties: Include all events properties of a logevent? default: false. Introduced in NLog 4.4</li>
<li>excludeProperties: comma separated string with names which properties to exclude. Only used when includeAllProperties is true. Case sensitive. Default empty When a name contains a comma, single quote the value. E.g. ‘value,withquote’,value2. Introduced in NLog 4.4</li>
</ul>
<p>Example:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><layout</span> <span class="na">xsi:type=</span><span class="s">"JsonLayout"</span> <span class="na">includeAllProperties=</span><span class="s">"true"</span> <span class="na">excludeProperties=</span><span class="s">"BadPropertyName1, BadProperty2"</span><span class="nt">></span>
<span class="nt"><field</span> <span class="na">name=</span><span class="s">"message"</span> <span class="na">layout=</span><span class="s">"My message for you is this ${message}"</span> <span class="nt">/></span>
<span class="nt"></layout></span>
</code></pre></div></div>
<h3 id="dont-stop-logging-when-there-is-something-wrong-in-the-layout">Don’t stop logging when there is something wrong in the layout</h3>
<p>Previously, if you made an error in a layout, e.g. typos:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><target</span> <span class="na">name=</span><span class="s">"file"</span> <span class="na">xsi:type=</span><span class="s">"File"</span>
<span class="na">layout=</span><span class="s">"${message} ${oops-I-made-a-typo}"</span> <span class="nt">></span>
</code></pre></div></div>
<p>or just using a layout renderer from a non-included package, nothing got logged!</p>
<p>This is unneccesary and we are skipping the invalid parts now. The invalid parts are replaced with an empty string.</p>
<p>NB: If <code class="language-plaintext highlighter-rouge">throwExceptions</code> or <code class="language-plaintext highlighter-rouge">throwConfigExceptions</code> is <code class="language-plaintext highlighter-rouge">true</code>, there will be still an error thrown</p>
<h3 id="lamba-function-layout-renderers">Lamba Function layout renderers</h3>
<p>Layout renders (those things between <code class="language-plaintext highlighter-rouge">${}</code>) can help you writing context information.</p>
<p>Since NLog 4.4 there is a new way to create a custom layout renderer, which can be written on one line!</p>
<p>The new <code class="language-plaintext highlighter-rouge">LayoutRenderer.Register</code> accepts a lamba function,
which accepts 1 or 2 parameters and should return a <code class="language-plaintext highlighter-rouge">string</code>.</p>
<ul>
<li>1 parameter: the <code class="language-plaintext highlighter-rouge">logEventInfo</code>.</li>
<li>2 parameters: <code class="language-plaintext highlighter-rouge">logEventInfo</code> and the current NLog config.</li>
</ul>
<p>Examples</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//register ${text-fixed}</span>
<span class="n">LayoutRenderer</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="s">"test-fixed"</span><span class="p">,</span> <span class="p">(</span><span class="n">logEvent</span><span class="p">)</span> <span class="p">=></span> <span class="s">"2"</span><span class="p">);</span>
<span class="c1">//register ${trace-identifier}</span>
<span class="n">LayoutRenderer</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="s">"trace-identifier"</span><span class="p">,</span> <span class="p">(</span><span class="n">logEvent</span><span class="p">)</span> <span class="p">=></span> <span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">TraceIdentifier</span><span class="p">);</span>
<span class="c1">//Using logEventInfo, ${message-length}</span>
<span class="n">LayoutRenderer</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="s">"message-length"</span><span class="p">,</span> <span class="p">(</span><span class="n">logEvent</span><span class="p">)</span> <span class="p">=></span> <span class="n">logEvent</span><span class="p">.</span><span class="n">Message</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>
<span class="c1">//Using config, ${targetCount}</span>
<span class="n">LayoutRenderer</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="s">"targetCount"</span><span class="p">,(</span><span class="n">logEvent</span><span class="p">,</span> <span class="n">config</span><span class="p">)</span> <span class="p">=></span> <span class="n">config</span><span class="p">.</span><span class="n">AllTargets</span><span class="p">.</span><span class="n">Count</span><span class="p">);</span>
</code></pre></div></div>
<p>See <a href="https://github.com/NLog/NLog/wiki/How%20to%20write%20a%20custom%20layout%20renderer">the wiki</a></p>
<h3 id="make-it-easier-to-register-custom-layout--target--layoutrendeners">Make it easier to register custom layout / target / layoutrendeners</h3>
<p>There is a new syntax introduced so it’s easier to register your custom extensions:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//target</span>
<span class="n">Target</span><span class="p">.</span><span class="n">Register</span><span class="p"><</span><span class="n">MyNamespace</span><span class="p">.</span><span class="n">MyFirstTarget</span><span class="p">>(</span><span class="s">"MyFirst"</span><span class="p">);</span> <span class="c1">//generic</span>
<span class="n">Target</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="s">"MyFirst"</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">MyNamespace</span><span class="p">.</span><span class="n">MyFirstTarget</span><span class="p">));</span> <span class="c1">//OR, dynamic</span>
<span class="c1">//layout renderer</span>
<span class="n">LayoutRenderer</span><span class="p">.</span><span class="n">Register</span><span class="p"><</span><span class="n">MyNamespace</span><span class="p">.</span><span class="n">MyFirstLayoutRenderer</span><span class="p">>(</span><span class="s">"MyFirst"</span><span class="p">);</span> <span class="c1">//generic</span>
<span class="n">LayoutRenderer</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="s">"MyFirst"</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">MyNamespace</span><span class="p">.</span><span class="n">MyFirstLayoutRenderer</span><span class="p">));</span> <span class="c1">//dynamic</span>
<span class="c1">//layout</span>
<span class="n">Layout</span><span class="p">.</span><span class="n">Register</span><span class="p"><</span><span class="n">MyNamespace</span><span class="p">.</span><span class="n">CsvLayout</span><span class="p">>(</span><span class="s">"csv"</span><span class="p">);</span> <span class="c1">//generic</span>
<span class="n">Layout</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="s">"csv"</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">MyNamespace</span><span class="p">.</span><span class="n">CsvLayout</span><span class="p">));</span> <span class="c1">//dynamic</span>
</code></pre></div></div>
<p>For more info, see <a href="https://github.com/NLog/NLog/wiki/Register%20your%20custom%20component">the wiki</a></p>
<h3 id="collection-types-for-custom-extensions">Collection types for custom extensions</h3>
<p>Custom Targets, layout etc. can have properties. There are only limitations if you’d like to set them from the XML config.</p>
<p>The following types are supported:</p>
<h4 id="allowed-types">Allowed types</h4>
<p>Allowed types for Targets, Layouts and Layout renderers.</p>
<ul>
<li>C# types: e.g. bool, char, decimal, double, float, int, uint, etc.</li>
<li>Enums (use short name)</li>
<li><code class="language-plaintext highlighter-rouge">Encoding</code></li>
<li><code class="language-plaintext highlighter-rouge">CultureInfo</code></li>
<li><code class="language-plaintext highlighter-rouge">Type</code></li>
<li><code class="language-plaintext highlighter-rouge">LineEndingMode</code></li>
<li><code class="language-plaintext highlighter-rouge">Uri</code></li>
<li>NLog types: <code class="language-plaintext highlighter-rouge">Layout</code>, <code class="language-plaintext highlighter-rouge">SimpleLayout</code> & <code class="language-plaintext highlighter-rouge">ConditionExpression</code></li>
<li>Types which has an implicit conversion from <code class="language-plaintext highlighter-rouge">string</code></li>
<li>Types which are using <code class="language-plaintext highlighter-rouge">TypeDescriptor</code> from <code class="language-plaintext highlighter-rouge">string</code> (not Silverlight)</li>
<li>Collections, introduced in NLog 4.4. See section <a href="#user-content-collection-types]">Collection types</a></li>
</ul>
<h4 id="collection-types">Collection types</h4>
<p>Introduced in NLog 4.4, the following collection types can be used.</p>
<p>Usage in XML: comma separated string. If the value contains a comma, single quote the whole value.</p>
<p>Examples:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">value="one arg"</code></li>
<li><code class="language-plaintext highlighter-rouge">value="1,2"</code></li>
<li><code class="language-plaintext highlighter-rouge">value="value1,'value2, with comma'"</code></li>
</ul>
<p>Collections of type:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">IList<T></code> / <code class="language-plaintext highlighter-rouge">IList</code></li>
<li><code class="language-plaintext highlighter-rouge">IEnumerable<T></code> / <code class="language-plaintext highlighter-rouge">IEnumerable</code></li>
<li><code class="language-plaintext highlighter-rouge">ISet<T></code> / <code class="language-plaintext highlighter-rouge">HashSet<T></code></li>
</ul>
<p>with the following types:</p>
<ul>
<li>C# built in types (string, int, double, object)</li>
<li>enum (use short name)</li>
<li>culture, encoding, Type</li>
<li>not supported: Layout</li>
</ul>
<p>Not supported:</p>
<ul>
<li>Arrays</li>
<li>Non-generic <code class="language-plaintext highlighter-rouge">List</code></li>
<li>Non-gereric <code class="language-plaintext highlighter-rouge">IList</code></li>
<li>Custom class implementing/inheriting from the collection classes/interfaces. (because of performance)</li>
</ul>
<p>PS: .NET 3.5 has <code class="language-plaintext highlighter-rouge">HashSet</code> but no <code class="language-plaintext highlighter-rouge">ISet</code></p>
<h3 id="added-condition-to-autoflushwrappper">Added condition to AutoFlushWrappper</h3>
<p>Something you would like to flush in special cases only, e.g. sending a mail when there is an error.
Of course you would like to have the trace logs in your mail too, as that can help identifying the problem!</p>
<p>This is now possible by using the <code class="language-plaintext highlighter-rouge">Condition</code> property on <code class="language-plaintext highlighter-rouge">AutoFlushWrappper</code></p>
<p>Example:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">name=</span><span class="s">"file"</span> <span class="na">xsi:type=</span><span class="s">"AutoFlushWrapper"</span> <span class="na">condition=</span><span class="s">"level >= LogLevel.Error"</span><span class="nt">></span>
<span class="nt"><target</span> <span class="na">xsi:type=</span><span class="s">"BufferingWrapper"</span> <span class="err">..</span><span class="nt">></span>
<span class="nt"><target</span> <span class="na">name=</span><span class="s">"gmail"</span> <span class="na">xsi:type=</span><span class="s">"Mail"</span>
<span class="na">smtpServer=</span><span class="s">"smtp.gmail.com"</span>
<span class="na">smtpPort=</span><span class="s">"587"</span>
<span class="na">smtpAuthentication=</span><span class="s">"Basic"</span>
<span class="nt">/></span>
<span class="nt"></target></span>
<span class="nt"></target></span>
</code></pre></div></div>
<h3 id="limitingtargetwrapper">LimitingTargetWrapper</h3>
<p>Like sending mail but not every 10 seconds?
With the LimitingTargetWrapper you can control the maximum events per interval.</p>
<p>Example, max 5 messages per 10 minutes</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><target</span> <span class="na">name=</span><span class="s">'limiting'</span> <span class="na">type=</span><span class="s">'LimitingWrapper'</span> <span class="na">messagelimit=</span><span class="s">'5'</span> <span class="na">interval=</span><span class="s">'0:10:00'</span><span class="nt">></span>
<span class="nt"><target</span> <span class="na">name=</span><span class="s">"gmail"</span> <span class="na">xsi:type=</span><span class="s">"Mail"</span>
<span class="na">smtpServer=</span><span class="s">"smtp.gmail.com"</span>
<span class="na">smtpPort=</span><span class="s">"587"</span>
<span class="na">smtpAuthentication=</span><span class="s">"Basic"</span>
<span class="nt">/></span>
<span class="nt"></target></span>
</code></pre></div></div>
<h3 id="windowsmultiprocessfileappender">WindowsMultiProcessFileAppender</h3>
<p>In Windows there is a new file writing implementation. From tests we have 10-40% performance increase!</p>
<h3 id="webservicetarget--urlencode---added-standard-support-for-utf8-encoding-added-support-for-rfc2396--rfc3986">WebServiceTarget & ${UrlEncode} - Added standard support for UTF8 encoding, added support for RFC2396 & RFC3986</h3>
<p>The URL encoding for the WebServiceTarget was not behaving to any RFC as far as we know.
This has been changed!</p>
<p>For the WebServiceTarget & <code class="language-plaintext highlighter-rouge">${UrlEncode}</code>,
NLog will by default encode parameters as UTF8 and escape special characters according to Rfc2396.</p>
<p>Also the following properties have been added to WebServiceTarget & <code class="language-plaintext highlighter-rouge">${UrlEncode}</code></p>
<ul>
<li>escapeDataRfc3986 - To escape data according to standard Rc3986, set this option to <code class="language-plaintext highlighter-rouge">true</code></li>
<li>escapeDataNLogLegacy - To escape data according to the old non-standard NLog style, set this option to <code class="language-plaintext highlighter-rouge">true</code></li>
</ul>
<h2 id="other-additions-and-changes">Other additions and changes</h2>
<ul>
<li><code class="language-plaintext highlighter-rouge">${exception}</code> - Added support for <code class="language-plaintext highlighter-rouge">AggregateException</code></li>
<li>Keeping variables during configuration reload (optional)</li>
<li>Layout processinfo with support for custom Format-string</li>
<li>DetectConsoleAvailable on (colored)Console disabled by default</li>
<li>Callsite: added includeNamespace option</li>
</ul>
<h3 id="bugfixes">Bugfixes:</h3>
<ul>
<li>Writing to the same file from multiple processes does not function when archiving with <code class="language-plaintext highlighter-rouge">concurrentWrites="true"</code> and <code class="language-plaintext highlighter-rouge">keepFileOpen="true"</code></li>
<li>NLog throws ConfigurationErrorsException when appsettings has invalid XML.</li>
</ul>
<h3 id="other">Other:</h3>
<ul>
<li>Improved <code class="language-plaintext highlighter-rouge">[Obsolete]</code> warnings - include the Nlog version when it became obsolete</li>
<li>FileTarget - Close stale file handles outside archive mutex lock #1513</li>
</ul>
<h2 id="thanks">THANKS!</h2>
<p>Thanks for the contributions!</p>
<ul>
<li>@aireq</li>
<li>@AndreGleichner</li>
<li>@ie-zero</li>
<li>@Jeinhaus</li>
<li>@nazim9214</li>
<li>@snakefoot</li>
<li>@tetrodoxin</li>
</ul>
<h3 id="whats-up-next">What’s up Next?</h3>
<p>Structural logging!</p>
<p>We could use your help to introduce this feature soon!</p>
<p>Like to help with coding or testing? <a href="https://github.com/NLog/yamtp/issues/28">Please let us know!</a></p>
NLog roadmap - .NET Core, structural logging & performance2016-10-30T00:00:00+00:00https://nlog-project.org/2016/10/30/nlog-roadmap-netcore-structural-logging<p>We have the following releases planned for NLog:</p>
<h3 id="nlog-44">NLog 4.4</h3>
<h4 id="no-net-core-yet">no .NET Core, yet</h4>
<p>Originally NLog 4.4 would have .NET Core support. We have released multiple alpha and beta releases with support .NET Core (or to be precise .NET Standard).
Unfortunately, there is a show-stopper: the behavior of <code class="language-plaintext highlighter-rouge">GetCurrentClassLogger</code> is wrong and we can’t fix it as the StackTrace API is limited in .NET Core
(see <a href="https://github.com/dotnet/corefx/issues/1797">here</a>). You can read more about it <a href="https://github.com/NLog/NLog/issues/1379#issuecomment-235696767">here</a>.
We will postpone .NET Core support to NLog 5.</p>
<p>Will this delay a RTM with .NET Core support? Yes. As long as the StackTrace API is missing, we can’t fix it.
It seems that .NET Standard 2 (Q1 2017) will support the StackTrace API.</p>
<h4 id="better-handling-of-invalid-config">Better handling of invalid config</h4>
<p>Currently, some mistakes in the config could lead to no logging at all.
For example, if <code class="language-plaintext highlighter-rouge">${aspnet-item}</code> is used in the file target and NLog.Web was not included, no files are written.</p>
<p>We will fix this in NLog 4.4 and we will replace the wrong part with an empty string. See <a href="https://github.com/NLog/NLog/pull/1583">this PR</a>.</p>
<h4 id="easier-extending">Easier extending</h4>
<p>A lot of feature requests could be easily implemented by writing a custom target or layout renderer.
Currently it’s a bit difficult to register your custom code. We will improve that.
Also a custom layout renderer should be as easy as one line of code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LayoutRenderer.RegisterLayoutRenderer("trace-identifier", (logEvent) => HttpContext.Current.TraceIdentifier );
</code></pre></div></div>
<h4 id="steam-and-byte-pooling-performance">Steam and byte pooling (performance)</h4>
<p>Currently under development, thanks to @bjornbouetsmith and @snakefoot!</p>
<p>This change will decrease memory pressure and prevent (excessive) garbage collection.</p>
<p>For details, see <a href="https://github.com/NLog/NLog/pull/1397">PR 1397</a> and and <a href="https://github.com/NLog/NLog/pull/1663">PR 1663</a></p>
<h3 id="nlog-45">NLog 4.5</h3>
<h4 id="structural-logging">Structural logging</h4>
<p>We would like to support structural logging like Serilog. We are currently working on an own parser and renderer. More info <a href="https://github.com/NLog/NLog/issues/1376">here</a>.</p>
<h3 id="nlog-5">NLog 5</h3>
<p>NLog 5 will have .NET Core support and we will push some small breaking changes.</p>
<h3 id="nlog-6">NLog 6</h3>
<p>NLog 6 will split all the functionality to multiple packages. Why is this not the case in NLog 5?
Well the .NET Core support consists of more than 250 commits and almost 400 changed files.
If something is broken by those changes, it’s easier to find the previous code if we won’t move all the code around!</p>
NLog 4.3 has been released!2016-04-16T00:00:00+00:00https://nlog-project.org/2016/04/16/nlog-4-3-has-been-released<p>After three RC releases, NLog 4.3 has been released! With more than 150 issues closed, this is one of the largest release since years.
Main features: Xamarin support, Windows Phone 8 support, improved error handling and logging of NLog self and a lot of bug fixes!</p>
<p>The release can be downloaded from <a href="https://www.nuget.org/packages/NLog/4.3.0">NuGet</a>.</p>
<p>Check for all the details the <a href="https://github.com/NLog/NLog/issues?q=milestone%3A4.3+is%3Aclosed">GitHub 4.3 milestone</a>.</p>
<p>For those who have contributed to NLog, big thanks!</p>
<h2 id="features">Features</h2>
<p>This release contains the following features:</p>
<h3 id="support-windows-phone-8-xamarin-android-and-xamarin-ios-beta">Support Windows Phone 8, Xamarin Android and Xamarin iOS (beta)</h3>
<p>In NLog 4.3 support has been added for the following platforms:
Windows Phone 8, Xamarin Android and Xamarin iOS.
The support is still in beta as we didn’t get the unit tests running.</p>
<p>Not every feature is working on those platforms, for example auto reloading the
configuration is not supported in Xamarin. A full overview of what is supported
on each platform can be viewed <a href="https://github.com/NLog/NLog/wiki/platform-support">on the wiki</a>.</p>
<h3 id="consistent-handling-of-exceptions-behaviour-change">Consistent handling of exceptions (BEHAVIOUR CHANGE)</h3>
<p>The logging and throwing of exceptions was previously inconsistent.
Not all of it was logged to the internal logger and some times they got lost.
For example, the async wrapper (or async attribute) was catching all exceptions without a proper rethrow.</p>
<p>This is bad as it is sometimes unclear why NLog isn’t working (got it myself multiple times).
This has been fixed in NLog 4.3!</p>
<ul>
<li>All exceptions are logged to the internal logger</li>
<li>The “throwExceptions” option will be respected in all cases</li>
</ul>
<p>Advise: disable throwExceptions in production environments! (this the default)</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">throwExceptions=</span><span class="s">"false"</span><span class="nt">></span>
</code></pre></div></div>
<h3 id="control-of-exception-throwing-for-configuration-errors">Control of exception throwing for configuration errors</h3>
<p>The following is stated in multiple locations:</p>
<blockquote>
<p>By default exceptions are not thrown under any circumstances.</p>
</blockquote>
<p>This was not true for configuration errors - those were always rethrown in the past.
If you change the config at runtime, this could lead to exceptions to the users!</p>
<p>We now introduce the “throwConfigExceptions” option:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">throwConfigExceptions=</span><span class="s">"true|false|<empty>"</span><span class="nt">></span>
</code></pre></div></div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LogManager</span><span class="p">.</span><span class="n">ThrowConfigExceptions</span> <span class="p">=</span> <span class="k">true</span> <span class="p">|</span> <span class="k">false</span> <span class="p">|</span> <span class="k">null</span>
</code></pre></div></div>
<ul>
<li>If set to <code class="language-plaintext highlighter-rouge">true</code>, if will throw exceptions for configuration errors.
Set this to <code class="language-plaintext highlighter-rouge">true</code> if you like the behaviour from NLog 4.2 and ealier.</li>
<li>If set to empty (or <code class="language-plaintext highlighter-rouge">null</code> in the API), this option will follow the “throwExceptions” option (previous section)</li>
<li>If set to <code class="language-plaintext highlighter-rouge">false</code>, don’t throw exceptions for configuration errors.</li>
</ul>
<p>Also throwing exceptions for a configuration error<br />
could lead to <code class="language-plaintext highlighter-rouge">System.TypeInitializationException</code> which is bad and confusing as sending info with the exception is difficult or sometimes impossible</p>
<ul>
<li>see <a href="http://stackoverflow.com/questions/34994470/better-typeinitializationexception-innerexception-is-also-null">stackoverflow</a>.</li>
</ul>
<h3 id="api-improvements">API improvements</h3>
<p>There are some notable changes in the API, so it’s easier to create or edit the configuration in C#
(or other .Net language).
The existence of the <code class="language-plaintext highlighter-rouge">SimpleConfigurator</code> was a hint things weren’t simple enough ;)</p>
<p>Changes:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">LogManager</code> has now <code class="language-plaintext highlighter-rouge">AddRule</code> methods. See examples below.</li>
<li>Set the max log level in the <code class="language-plaintext highlighter-rouge">LoggingRule</code> constructor.</li>
<li>The name of the <code class="language-plaintext highlighter-rouge">TargetAttribute</code> is used as fallback for every target now.</li>
</ul>
<h4 id="logmanager-now-has-addrule-methods"><code class="language-plaintext highlighter-rouge">LogManager</code> now has <code class="language-plaintext highlighter-rouge">AddRule</code> methods</h4>
<p>Rules can now be created directly in the <code class="language-plaintext highlighter-rouge">LogManager</code>.
There are some overloads to keep things simple.</p>
<p>Before:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LoggingConfiguration</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">fileTarget</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FileTarget</span><span class="p">();</span>
<span class="n">config</span><span class="p">.</span><span class="nf">AddTarget</span><span class="p">(</span><span class="s">"f1"</span><span class="p">,</span> <span class="n">fileTarget</span><span class="p">);</span>
<span class="n">config</span><span class="p">.</span><span class="n">LoggingRules</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">LoggingRule</span><span class="p">(</span><span class="s">"*"</span><span class="p">,</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">,</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Error</span><span class="p">,</span> <span class="n">fileTarget</span><span class="p">));</span>
<span class="n">LogManager</span><span class="p">.</span><span class="n">Configuration</span> <span class="p">=</span> <span class="n">config</span><span class="p">;</span>
</code></pre></div></div>
<p>now also possible:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LoggingConfiguration</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">fileTarget</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FileTarget</span><span class="p">(</span><span class="s">"f1"</span><span class="p">);</span>
<span class="n">config</span><span class="p">.</span><span class="nf">AddTarget</span><span class="p">(</span><span class="n">fileTarget</span><span class="p">);</span>
<span class="n">config</span><span class="p">.</span><span class="nf">AddRule</span><span class="p">(</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">,</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Fatal</span><span class="p">,</span> <span class="s">"f1"</span><span class="p">);</span>
<span class="n">LogManager</span><span class="p">.</span><span class="n">Configuration</span> <span class="p">=</span> <span class="n">config</span><span class="p">;</span>
</code></pre></div></div>
<p>or</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LoggingConfiguration</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">fileTarget</span> <span class="p">=</span> <span class="k">new</span> <span class="n">FileTarget</span> <span class="p">{</span><span class="n">name</span><span class="p">:</span> <span class="s">"f1"</span><span class="p">};</span>
<span class="n">config</span><span class="p">.</span><span class="nf">AddRule</span><span class="p">(</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">,</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Fatal</span><span class="p">,</span> <span class="n">fileTarget</span><span class="p">);</span>
<span class="n">LogManager</span><span class="p">.</span><span class="n">Configuration</span> <span class="p">=</span> <span class="n">config</span><span class="p">;</span>
</code></pre></div></div>
<h3 id="relative-paths-for-filetarget">Relative paths for fileTarget</h3>
<p>FileTarget now supports relative paths. No need for <code class="language-plaintext highlighter-rouge">${basedir}</code> in the file target anymore!</p>
<h3 id="internallogger-write-to-systemdiagnosticstrace">InternalLogger: write to System.Diagnostics.Trace</h3>
<p>It’s now possible to write to let the internal logger write to <code class="language-plaintext highlighter-rouge">System.Diagnostics.Trace</code>.
The trace is easy to follow within Visual Studio.</p>
<p><img src="https://cloud.githubusercontent.com/assets/5808377/13997991/f76fd65a-f134-11e5-8e9d-bd3d532b248c.png" alt="image" /></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">internalLogToTrace=</span><span class="s">"true"</span>
</code></pre></div></div>
<p>or</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">InternalLogger</span><span class="p">.</span><span class="n">LogToTrace</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
</code></pre></div></div>
<h3 id="other-features">Other features</h3>
<p>Smaller improvements</p>
<h4 id="targets">Targets</h4>
<ul>
<li>Mail Target: allow virtual paths for SMTP pickup</li>
<li>EventTarget: option to set the maximum length of the message and action (discard, split, truncate)</li>
<li>MethodCallTarget: allow optional parameters in called methods.</li>
<li>ConsoleTarget: regex cache is instead of compiled regex, for better memory usage. This is configurable.</li>
<li>Database target: doesn’t require “ProviderName” attribute when using <code class="language-plaintext highlighter-rouge"><connectionStrings></code></li>
</ul>
<h4 id="layouts">Layouts</h4>
<ul>
<li>RegistryLayout: support for layouts, RegistryView (32, 64 bit) and all root key names (HKCU/HKLM etc)</li>
</ul>
<h4 id="api">API</h4>
<ul>
<li>Allow to free CallContext in <code class="language-plaintext highlighter-rouge">MappedDiagnosticsLogicalContext</code></li>
<li>LogFactory: add generic-type versions of <code class="language-plaintext highlighter-rouge">GetLogger()</code> and <code class="language-plaintext highlighter-rouge">GetCurrentClassLogger()</code></li>
<li>Added <code class="language-plaintext highlighter-rouge">Logger.Swallow(Task task)</code></li>
</ul>
<h4 id="other">Other</h4>
<ul>
<li>Unused targets will be logged to the internal logger</li>
<li>Config classes are now thread-safe.</li>
<li>InternalLogger: improved logging of exceptions (analogous to normal Logger)</li>
<li>More logging to the internal logger (e.g. Async wrapper and buffer wrapper)</li>
<li>Added timestamp options for the internal logger:
<ul>
<li>Added “internalLogIncludeTimestamp” option to <code class="language-plaintext highlighter-rouge"><NLog></code></li>
<li>Added “nlog.internalLogIncludeTimestamp” option <code class="language-plaintext highlighter-rouge"><appSettings></code></li>
<li>Added <code class="language-plaintext highlighter-rouge">NLOG_INTERNAL_INCLUDE_TIMESTAMP</code> environment setting</li>
</ul>
</li>
<li>NLog reads NLog.Config from Android Assets.</li>
</ul>
<h2 id="bug-fixes">Bug fixes</h2>
<p>Various bugs have been fixed in this version. The most noticeable:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">${callsite}</code> works now for async methods!</li>
<li>A <strong>lot of</strong> Filetarget bug fixes regarding with archiving, locking and concurrent writing.
See <a href="https://github.com/NLog/NLog/issues?q=milestone%3A4.3+is%3Aclosed+label%3Afile-target">GitHub issues</a> for all details.
Most noticeable:
<ul>
<li>Use last-write-time for archive file name. This is far more stable.
In the past there were some issues with unexpected archive filenames.</li>
<li>Fix: archiving won’t work when a there is a date in the filename</li>
<li>Fix: archiving not working properly with AsyncWrapper</li>
<li>Fix: footer for archiving</li>
<li>Fix: crashes with relative path without <code class="language-plaintext highlighter-rouge">${basedir}</code></li>
<li>Fix: archive files are never created when there are lot of writes in log file</li>
<li>Fix: writing file to root wasn’t working</li>
</ul>
</li>
<li>NetworkTarget: fix possible deadlock</li>
<li>Fix autoreload nlog.config with parent configs.</li>
<li>WebServiceTarget: fix HTTP GET protocol</li>
<li>Bugfix: Internallogger creates folder, even when turned off</li>
<li>Fix possible Nullref in <code class="language-plaintext highlighter-rouge">${variable}</code></li>
<li><code class="language-plaintext highlighter-rouge">${processtime}</code>: incorrect milliseconds formatting</li>
<li><code class="language-plaintext highlighter-rouge">${processtime}</code>: fix incorrect negative time (rounding issue)</li>
</ul>
<h2 id="thanks-to">Thanks to!!</h2>
<ul>
<li><a href="https://github.com/bhaeussermann">bhaeussermann</a></li>
<li><a href="https://github.com/breyed">breyed</a></li>
<li><a href="https://github.com/brutaldev">brutaldev</a></li>
<li><a href="https://github.com/bryjamus">bryjamus</a></li>
<li><a href="https://github.com/eduardorascon">eduardorascon</a></li>
<li><a href="https://github.com/epignosisx">epignosisx</a></li>
<li><a href="https://github.com/Kaykins">Kaykins</a></li>
<li><a href="https://github.com/kt1996">kt1996</a></li>
<li><a href="https://github.com/michaeljbaird">michaeljbaird</a></li>
<li><a href="https://github.com/MikeFH">MikeFH</a></li>
<li><a href="https://github.com/nathan-schubkegel">nathan-schubkegel</a></li>
<li><a href="https://github.com/neris">neris</a></li>
<li><a href="https://github.com/Niklas-Peter">Niklas-Peter</a></li>
<li><a href="https://github.com/Page-Not-Found">Page-Not-Found</a></li>
<li><a href="https://github.com/pysco68">pysco68</a></li>
<li><a href="https://github.com/rellis-of-rhindleton">rellis-of-rhindleton</a></li>
<li><a href="https://github.com/sorvis">sorvis</a></li>
<li><a href="https://github.com/UgurAldanmaz">UgurAldanmaz</a></li>
<li><a href="https://github.com/vincechan">vincechan</a></li>
</ul>
New NLog OWIN adapter has been released2016-03-24T00:00:00+00:00https://nlog-project.org/2016/03/24/New-NLog-OWIN-adapter-released<p>We’re proud to announce that the former community project <code class="language-plaintext highlighter-rouge">NLogAdapter</code> is now part of NLog as <code class="language-plaintext highlighter-rouge">NLog.Owin.Logging</code> to provide a <code class="language-plaintext highlighter-rouge">Microsoft.Owin.Logging.ILoggerFactory</code> implementation for your OWIN pipeline.</p>
<p>Usage is as simple as:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PM</span><span class="w"> </span><span class="err">></span><span class="w"> </span><span class="nx">Install-Package</span><span class="w"> </span><span class="nx">NLog.Owin.Logging</span><span class="w">
</span></code></pre></div></div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">NLog.Owin.Logging</span><span class="p">;</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Configuration</span><span class="p">(</span><span class="n">IAppBuilder</span> <span class="n">app</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">app</span><span class="p">.</span><span class="nf">UseNLog</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
NLog 4.3 RC is Now Available!2016-03-23T00:00:00+00:00https://nlog-project.org/2016/03/23/nlog-4-3-0-RC-is-now-available<p><strong>update</strong> 9 april: RC 3 is released with some small fixes. See <a href="https://www.nuget.org/packages/NLog/4.3.0-rc3/">NuGet</a>.</p>
<p><strong>update</strong> 27 march: RC 2 is now online which resolves a bug in finding the correct stackframe for <code class="language-plaintext highlighter-rouge">${callsite}</code> etc. This was broken since 4.3-beta 1.</p>
<hr />
<p>NLog 4.3 is almost ready. There are some changes in the core, so therefore a Release Candidate (RC) has been released.
Right now there are 132 closed issues in NLog 4.3, which makes NLog 4.3 the largest release since years.
We have had a lot of contributions from the community (thanks!)
and have you noticed that NLog has <a href="https://github.com/orgs/NLog/people">more main contributors than before</a>?</p>
<p>The release can be downloaded from <a href="https://www.nuget.org/packages/NLog/4.3.0-rc1">NuGet</a>.</p>
<p>Check for all the details the <a href="https://github.com/NLog/NLog/issues?q=milestone%3A4.3+is%3Aclosed">GitHub 4.3 milestone</a>.</p>
<p>Please note that currently not all the docs have been updated yet.</p>
<h2 id="features">Features</h2>
<p>This release contains the following features:</p>
<h3 id="support-windows-phone-8-xamarin-android-and-xamarin-ios-beta">Support Windows Phone 8, Xamarin Android and Xamarin iOS (beta)</h3>
<p>In NLog 4.3 support has been added for the following platforms:
Windows Phone 8, Xamarin Android and Xamarin iOS.
The support is still in beta as we didn’t get the unit tests running.</p>
<p>Not every feature is working on those platforms, for example auto reloading the
configuration is not supported in Xamarin. A full overview of what is supported
on each platform can be viewed <a href="https://github.com/NLog/NLog/wiki/platform-support">on the wiki</a>.</p>
<h3 id="consistent-handling-of-exceptions-behaviour-change">Consistent handling of exceptions (BEHAVIOUR CHANGE)</h3>
<p>The logging and throwing of exceptions was previously inconsistent.
Not all of it was logged to the internal logger and some times they got lost.
For example, the async wrapper (or async attribute) was catching all exceptions without a proper rethrow.</p>
<p>This is bad as it is sometimes unclear why NLog isn’t working (got it myself multiple times).
This has been fixed in NLog 4.3!</p>
<ul>
<li>All exceptions are logged to the internal logger</li>
<li>The “throwExceptions” option will be respected in all cases</li>
</ul>
<p>Advise: disable throwExceptions in production environments! (this the default)</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">throwExceptions=</span><span class="s">"false"</span><span class="nt">></span>
</code></pre></div></div>
<h3 id="control-of-exception-throwing-for-configuration-errors">Control of exception throwing for configuration errors</h3>
<p>The following is stated in multiple locations:</p>
<blockquote>
<p>By default exceptions are not thrown under any circumstances.</p>
</blockquote>
<p>This was not true for configuration errors - those were always rethrown in the past.
If you change the config at runtime, this could lead to exceptions to the users!</p>
<p>We now introduce the “throwConfigExceptions” option:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">throwConfigExceptions=</span><span class="s">"true|false|<empty>"</span><span class="nt">></span>
</code></pre></div></div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LogManager</span><span class="p">.</span><span class="n">ThrowConfigExceptions</span> <span class="p">=</span> <span class="k">true</span> <span class="p">|</span> <span class="k">false</span> <span class="p">|</span> <span class="k">null</span>
</code></pre></div></div>
<ul>
<li>If set to <code class="language-plaintext highlighter-rouge">true</code>, if will throw exceptions for configuration errors.
Set this to <code class="language-plaintext highlighter-rouge">true</code> if you like the behaviour from NLog 4.2 and ealier.</li>
<li>If set to empty (or <code class="language-plaintext highlighter-rouge">null</code> in the API), this option will follow the “throwExceptions” option (previous section)</li>
<li>If set to <code class="language-plaintext highlighter-rouge">false</code>, don’t throw exceptions for configuration errors.</li>
</ul>
<p>Also throwing exceptions for a configuration error<br />
could lead to <code class="language-plaintext highlighter-rouge">System.TypeInitializationException</code> which is bad and confusing as sending info with the exception is difficult or sometimes impossible</p>
<ul>
<li>see <a href="http://stackoverflow.com/questions/34994470/better-typeinitializationexception-innerexception-is-also-null">stackoverflow</a>.</li>
</ul>
<h3 id="api-improvements">API improvements</h3>
<p>There are some notable changes in the API, so it’s easier to create or edit the configuration in C#
(or other .Net language).
The existence of the <code class="language-plaintext highlighter-rouge">SimpleConfigurator</code> was a hint things weren’t simple enough ;)</p>
<p>Changes:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">LogManager</code> has now <code class="language-plaintext highlighter-rouge">AddRule</code> methods. See examples below.</li>
<li>Set the max log level in the <code class="language-plaintext highlighter-rouge">LoggingRule</code> constructor.</li>
<li>The name of the <code class="language-plaintext highlighter-rouge">TargetAttribute</code> is used as fallback for every target now.</li>
</ul>
<h4 id="logmanager-now-has-addrule-methods"><code class="language-plaintext highlighter-rouge">LogManager</code> now has <code class="language-plaintext highlighter-rouge">AddRule</code> methods</h4>
<p>Rules can now be created directly in the <code class="language-plaintext highlighter-rouge">LogManager</code>.
There are some overloads to keep things simple.</p>
<p>Before:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LoggingConfiguration</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">fileTarget</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FileTarget</span><span class="p">();</span>
<span class="n">config</span><span class="p">.</span><span class="nf">AddTarget</span><span class="p">(</span><span class="s">"f1"</span><span class="p">,</span> <span class="n">fileTarget</span><span class="p">);</span>
<span class="n">config</span><span class="p">.</span><span class="n">LoggingRules</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">LoggingRule</span><span class="p">(</span><span class="s">"*"</span><span class="p">,</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">,</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Error</span><span class="p">,</span> <span class="n">fileTarget</span><span class="p">));</span>
<span class="n">LogManager</span><span class="p">.</span><span class="n">Configuration</span> <span class="p">=</span> <span class="n">config</span><span class="p">;</span>
</code></pre></div></div>
<p>now also possible:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LoggingConfiguration</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">fileTarget</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FileTarget</span><span class="p">(</span><span class="s">"f1"</span><span class="p">);</span>
<span class="n">config</span><span class="p">.</span><span class="nf">AddTarget</span><span class="p">(</span><span class="n">fileTarget</span><span class="p">);</span>
<span class="n">config</span><span class="p">.</span><span class="nf">AddRule</span><span class="p">(</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">,</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Fatal</span><span class="p">,</span> <span class="s">"f1"</span><span class="p">);</span>
<span class="n">LogManager</span><span class="p">.</span><span class="n">Configuration</span> <span class="p">=</span> <span class="n">config</span><span class="p">;</span>
</code></pre></div></div>
<p>or</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LoggingConfiguration</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">fileTarget</span> <span class="p">=</span> <span class="k">new</span> <span class="n">FileTarget</span> <span class="p">{</span><span class="n">name</span><span class="p">:</span> <span class="s">"f1"</span><span class="p">};</span>
<span class="n">config</span><span class="p">.</span><span class="nf">AddRule</span><span class="p">(</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">,</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Fatal</span><span class="p">,</span> <span class="n">fileTarget</span><span class="p">);</span>
<span class="n">LogManager</span><span class="p">.</span><span class="n">Configuration</span> <span class="p">=</span> <span class="n">config</span><span class="p">;</span>
</code></pre></div></div>
<h3 id="relative-paths-for-filetarget">Relative paths for fileTarget</h3>
<p>FileTarget now supports relative paths. No need for <code class="language-plaintext highlighter-rouge">${basedir}</code> in the file target anymore!</p>
<h3 id="internallogger-write-to-systemdiagnosticstrace">InternalLogger: write to System.Diagnostics.Trace</h3>
<p>It’s now possible to write to let the internal logger write to <code class="language-plaintext highlighter-rouge">System.Diagnostics.Trace</code>.
The trace is easy to follow within Visual Studio.</p>
<p><img src="https://cloud.githubusercontent.com/assets/5808377/13997991/f76fd65a-f134-11e5-8e9d-bd3d532b248c.png" alt="image" /></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><nlog</span> <span class="na">internalLogToTrace=</span><span class="s">"true"</span>
</code></pre></div></div>
<p>or</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">InternalLogger</span><span class="p">.</span><span class="n">LogToTrace</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
</code></pre></div></div>
<h3 id="other-features">Other features</h3>
<p>Smaller improvements</p>
<h4 id="targets">Targets</h4>
<ul>
<li>Mail Target: allow virtual paths for SMTP pickup</li>
<li>EventTarget: option to set the maximum length of the message and action (discard, split, truncate)</li>
<li>MethodCallTarget: allow optional parameters in called methods.</li>
<li>ConsoleTarget: regex cache is instead of compiled regex, for better memory usage. This is configurable.</li>
<li>Database target: doesn’t require “ProviderName” attribute when using <code class="language-plaintext highlighter-rouge"><connectionStrings></code></li>
</ul>
<h4 id="layouts">Layouts</h4>
<ul>
<li>RegistryLayout: support for layouts, RegistryView (32, 64 bit) and all root key names (HKCU/HKLM etc)</li>
</ul>
<h4 id="api">API</h4>
<ul>
<li>Allow to free CallContext in <code class="language-plaintext highlighter-rouge">MappedDiagnosticsLogicalContext</code></li>
<li>LogFactory: add generic-type versions of <code class="language-plaintext highlighter-rouge">GetLogger()</code> and <code class="language-plaintext highlighter-rouge">GetCurrentClassLogger()</code></li>
<li>Added <code class="language-plaintext highlighter-rouge">Logger.Swallow(Task task)</code></li>
</ul>
<h4 id="other">Other</h4>
<ul>
<li>Unused targets will be logged to the internal logger</li>
<li>Config classes are now thread-safe.</li>
<li>InternalLogger: improved logging of exceptions (analogous to normal Logger)</li>
<li>More logging to the internal logger (e.g. Async wrapper and buffer wrapper)</li>
<li>Added timestamp options for the internal logger:
<ul>
<li>Added “internalLogIncludeTimestamp” option to <code class="language-plaintext highlighter-rouge"><NLog></code></li>
<li>Added “nlog.internalLogIncludeTimestamp” option <code class="language-plaintext highlighter-rouge"><appSettings></code></li>
<li>Added <code class="language-plaintext highlighter-rouge">NLOG_INTERNAL_INCLUDE_TIMESTAMP</code> environment setting</li>
</ul>
</li>
<li>Read nlog.config from Android assets:</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">LogManager</span><span class="p">.</span><span class="n">Configuration</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">XmlLoggingConfiguration</span><span class="p">(</span><span class="s">"assets/nlog.config"</span><span class="p">);</span>
</code></pre></div></div>
<h2 id="bug-fixes">Bug fixes</h2>
<p>Various bugs have been fixed in this version. The most noticeable:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">${callsite}</code> works now for async methods!</li>
<li>A <strong>lot of</strong> Filetarget bug fixes regarding with archiving, locking and concurrent writing.
See <a href="https://github.com/NLog/NLog/issues?q=milestone%3A4.3+is%3Aclosed+label%3Afile-target">GitHub issues</a> for all details.
Most noticeable:
<ul>
<li>Use last-write-time for archive file name. This is far more stable.
In the past there were some issues with unexpected archive filenames.</li>
<li>Fix: archiving won’t work when a there is a date in the filename</li>
<li>Fix: archiving not working properly with AsyncWrapper</li>
<li>Fix: footer for archiving</li>
<li>Fix: crashes with relative path without <code class="language-plaintext highlighter-rouge">${basedir}</code></li>
<li>Fix: archive files are never created when there are lot of writes in log file</li>
</ul>
</li>
<li>NetworkTarget: fix possible deadlock</li>
<li>Fix autoreload nlog.config with parent configs.</li>
<li>WebServiceTarget: fix HTTP GET protocol</li>
<li>Bugfix: Internallogger creates folder, even when turned off</li>
<li>Fix possible Nullref in <code class="language-plaintext highlighter-rouge">${variable}</code></li>
<li><code class="language-plaintext highlighter-rouge">${processtime}</code>: incorrect milliseconds formatting</li>
<li><code class="language-plaintext highlighter-rouge">${processtime}</code>: fix incorrect negative time (rounding issue)</li>
</ul>
<h2 id="thanks-to">Thanks to!!</h2>
<ul>
<li><a href="https://github.com/bhaeussermann">bhaeussermann</a></li>
<li><a href="https://github.com/breyed">breyed</a></li>
<li><a href="https://github.com/brutaldev">brutaldev</a></li>
<li><a href="https://github.com/bryjamus">bryjamus</a></li>
<li><a href="https://github.com/eduardorascon">eduardorascon</a></li>
<li><a href="https://github.com/epignosisx">epignosisx</a></li>
<li><a href="https://github.com/Kaykins">Kaykins</a></li>
<li><a href="https://github.com/kt1996">kt1996</a></li>
<li><a href="https://github.com/michaeljbaird">michaeljbaird</a></li>
<li><a href="https://github.com/MikeFH">MikeFH</a></li>
<li><a href="https://github.com/nathan-schubkegel">nathan-schubkegel</a></li>
<li><a href="https://github.com/neris">neris</a></li>
<li><a href="https://github.com/Niklas-Peter">Niklas-Peter</a></li>
<li><a href="https://github.com/Page-Not-Found">Page-Not-Found</a></li>
<li><a href="https://github.com/pysco68">pysco68</a></li>
<li><a href="https://github.com/rellis-of-rhindleton">rellis-of-rhindleton</a></li>
<li><a href="https://github.com/sorvis">sorvis</a></li>
<li><a href="https://github.com/UgurAldanmaz">UgurAldanmaz</a></li>
<li><a href="https://github.com/vincechan">vincechan</a></li>
</ul>
NLog.Windows.Forms 4.2 has been released!2015-12-28T00:00:00+00:00https://nlog-project.org/2015/12/28/nlog-windows-forms-4-2-has-been-released<p>NLog.Windows.Forms 4.2 has been released including a new feature for the <a href="https://github.com/NLog/NLog.Windows.Forms/wiki/RichTextBoxTarget">RichTextBoxTarget</a> — it is now possible to add clickable links to log messages.</p>
<h2 id="features">Features</h2>
<p>This release contains the following features:</p>
<h3 id="richtextbox-links">RichTextBox links</h3>
<p>It is now possible to add clickable links to messages show in in the RichTextBox control and receive whole event info in the link click handler.
To do this, set target’s newly introduced <code class="language-plaintext highlighter-rouge">supportLink</code> parameter to <code class="language-plaintext highlighter-rouge">true</code> and use new <a href="https://github.com/NLog/NLog.Windows.Forms/wiki/RTB-Link-Layout-Renderer"><code class="language-plaintext highlighter-rouge">${rtb-link}</code></a> layout renderer to specify link part of the layout.
To receive link click events, add a handler to <code class="language-plaintext highlighter-rouge">RichTextBoxTarget.LinkClicked</code> event. Use <code class="language-plaintext highlighter-rouge">RichTextBoxTarget.GetTargetByControl(RichTextBox control)</code> static method to access the target attached to a specific RichTextBox control.</p>
<p>Not sure how to use it? Here are few examples.</p>
<h4 id="exception-details-example">Exception details example</h4>
<p>When logging exceptions to RichTextBoxTarget you have to find a compromise between flooding the control with huge stacktraces and missing important information. Not anymore! Now you may long only a short description into textbox, and show whole details when user clicks a link:</p>
<p><img src="/images/posts/2015/12/link_exception_details_click.png" /></p>
<p>Just setup a proper layout (don’t forget to enable <code class="language-plaintext highlighter-rouge">supportLinks</code>)</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><target</span> <span class="na">xsi:type=</span><span class="s">"RichTextBox"</span>
<span class="na">layout=</span><span class="s">"${message}${onexception:inner= ${exception:format=Message} ${rtb-link:details}}"</span>
<span class="err">....</span>
<span class="na">supportLinks=</span><span class="s">"true"</span>
<span class="err">....</span>
<span class="nt">/></span></code></pre></figure>
<p>And add a link click handler:</p>
<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="nf">Form1</span><span class="p">()</span>
<span class="p">{</span>
<span class="nf">InitializeComponent</span><span class="p">();</span>
<span class="n">RichTextBoxTarget</span><span class="p">.</span><span class="nf">ReInitializeAllTextboxes</span><span class="p">(</span><span class="k">this</span><span class="p">);</span> <span class="c1">//more on this later</span>
<span class="n">RichTextBoxTarget</span><span class="p">.</span><span class="nf">GetTargetByControl</span><span class="p">(</span><span class="n">richTextBox1</span><span class="p">).</span><span class="n">LinkClicked</span> <span class="p">+=</span> <span class="n">Form1_LinkClicked</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">Form1_LinkClicked</span><span class="p">(</span><span class="n">RichTextBoxTarget</span> <span class="n">sender</span><span class="p">,</span> <span class="kt">string</span> <span class="n">linkText</span><span class="p">,</span> <span class="n">LogEventInfo</span> <span class="k">event</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">MessageBox</span><span class="p">.</span><span class="nf">Show</span><span class="p">(</span><span class="k">event</span><span class="p">.</span><span class="n">Exception</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(),</span> <span class="s">"Exception details"</span><span class="p">,</span> <span class="n">MessageBoxButtons</span><span class="p">.</span><span class="n">OK</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h4 id="focusing-at-specific-item-example">Focusing at specific item example</h4>
<p>Sometimes you may need to not only notify user of some problem (like validation failing), but also help him navigate to the problematic item (for example when the list is huge). In this case you may store item’s id of some sort in the <a href="https://github.com/NLog/NLog/wiki/EventProperties-Layout-Renderer"><code class="language-plaintext highlighter-rouge">LogEventInfo.Property</code></a>, turn it into a link and navigate to the item in link click handler:</p>
<p><img src="/images/posts/2015/12/event_properties_link_click.png" /></p>
<p>The layout:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><target</span> <span class="na">xsi:type=</span><span class="s">"RichTextBox"</span>
<span class="na">layout=</span><span class="s">"${message} ${rtb-link:${event-properties:item=Index}}"</span>
<span class="err">....</span>
<span class="na">supportLinks=</span><span class="s">"true"</span>
<span class="err">....</span>
<span class="nt">/></span></code></pre></figure>
<p>Validation code:</p>
<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">private</span> <span class="k">void</span> <span class="nf">validateButton_Click</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">EventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"Validation started"</span><span class="p">);</span>
<span class="k">foreach</span> <span class="p">(</span><span class="n">ListViewItem</span> <span class="n">item</span> <span class="k">in</span> <span class="n">listView1</span><span class="p">.</span><span class="n">Items</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">SubItems</span><span class="p">[</span><span class="m">1</span><span class="p">].</span><span class="n">Text</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"bad"</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">()</span>
<span class="p">.</span><span class="nf">Message</span><span class="p">(</span><span class="s">"Validation failed on line"</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Property</span><span class="p">(</span><span class="s">"Index"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">item</span><span class="p">.</span><span class="n">Tag</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Write</span><span class="p">();</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"Validation succeeded"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Event handling code:</p>
<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="nf">Form2</span><span class="p">()</span>
<span class="p">{</span>
<span class="nf">InitializeComponent</span><span class="p">();</span>
<span class="n">RichTextBoxTarget</span><span class="p">.</span><span class="nf">ReInitializeAllTextboxes</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="n">RichTextBoxTarget</span><span class="p">.</span><span class="nf">GetTargetByControl</span><span class="p">(</span><span class="n">richTextBox1</span><span class="p">).</span><span class="n">LinkClicked</span> <span class="p">+=</span> <span class="n">Form2_LinkClicked</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">Form2_LinkClicked</span><span class="p">(</span><span class="n">RichTextBoxTarget</span> <span class="n">sender</span><span class="p">,</span> <span class="kt">string</span> <span class="n">linkText</span><span class="p">,</span> <span class="n">LogEventInfo</span> <span class="k">event</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">lineIndex</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="k">event</span><span class="p">.</span><span class="n">Properties</span><span class="p">[</span><span class="s">"Index"</span><span class="p">];</span>
<span class="n">listView1</span><span class="p">.</span><span class="nf">EnsureVisible</span><span class="p">(</span><span class="n">lineIndex</span><span class="p">);</span>
<span class="n">listView1</span><span class="p">.</span><span class="n">SelectedIndices</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">lineIndex</span><span class="p">);</span>
<span class="n">listView1</span><span class="p">.</span><span class="nf">Select</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>
<p>Hope you could find more useful applications of this new feature!</p>
<h3 id="a-note-on-41-release">A note on 4.1 release</h3>
<p><em>In case you are not sure what</em> <code class="language-plaintext highlighter-rouge">RichTextBoxTarget.ReInitializeAllTextboxes(this)</code> <em>call does, then you might have missed a feature added in 4.1 release. It improves the RichTextBoxTarget functional by allowing it to be configured and initialized before the actual control is created. Check</em> <code class="language-plaintext highlighter-rouge">allowAccessoryFormCreation</code> <em>and</em> <code class="language-plaintext highlighter-rouge">messageRetention</code> <em>options description in the <a href="https://github.com/NLog/NLog.Windows.Forms/wiki/RichTextBoxTarget">target’s documentation</a></em></p>
NLog 4.2.1 has been released!2015-11-21T00:00:00+00:00https://nlog-project.org/2015/11/21/nlog-4-2-1-has-been-released<p>Release notes:</p>
<ul>
<li>Show warning for Databasetarget.UseTransactions instead of exception.</li>
<li>NetworkTarget: improved performance, allow configuring of max connections. See <a href="https://github.com/NLog/NLog/wiki/Network-target">wiki</a>.</li>
<li>Filetarget: Max archives settings sometimes removes to many files.</li>
<li>Prevent Collection was modified (ObjectGraphScanner.ScanProperties)</li>
<li>General memory pressure improvements.</li>
<li>LogReceiverWebServiceTarget.CreateLogReceiver() should be virtual</li>
<li>VariableLayoutRenderer does not work with Custom LogManagers.</li>
</ul>
NLog 4.2 is here!2015-10-24T00:00:00+00:00https://nlog-project.org/2015/10/24/nlog-4-2-is-here<p>NLog 4.2 has been released. This release contains some small features and (important) bug fixes.</p>
<p>We take <a href="http://semver.org/">semver</a> serious, so all changes are backwards-compatible.</p>
<h2 id="features">Features</h2>
<ul>
<li>Performance Counter Target: it’s now possible to configure the step size for the counter target. Before the step size was always one.</li>
<li>Mail Target: <code class="language-plaintext highlighter-rouge">pickupDirectoryLocation</code> and <code class="language-plaintext highlighter-rouge">deliveryMethod</code> are configurable from the NLog config.</li>
<li>Cached Layout Renderer: a <code class="language-plaintext highlighter-rouge">clearCache</code> option has been added for more control over clearing the cache. See <a href="https://github.com/NLog/NLog/wiki/Cached-Layout-Renderer">wiki</a>.</li>
<li>File target: auto add <code class="language-plaintext highlighter-rouge">.zip</code> to compressed archive when <code class="language-plaintext highlighter-rouge">archiveName</code> isn’t specified.</li>
</ul>
<h2 id="bug-fixes">Bug fixes</h2>
<h3 id="inner-layout-can-now-contain-colons">Inner layout can now contain colons</h3>
<p>An inner layout can now contain colons, but it needs an escape.</p>
<p>It is required to escape <code class="language-plaintext highlighter-rouge">:</code> and <code class="language-plaintext highlighter-rouge">}</code> in an inner layout because:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">:</code> because it’s a value separator. <code class="language-plaintext highlighter-rouge">${when:when=1 == 1:Inner=Test\: Hello}</code></li>
<li><code class="language-plaintext highlighter-rouge">}</code> because it can be the end of another layout renderer when double nested. <code class="language-plaintext highlighter-rouge">${rot13:inner=${rot13:inner=${when:when=1 == 1:Inner=Test \} Hello}}}</code></li>
</ul>
<h3 id="other-bugfixes">Other bugfixes</h3>
<ul>
<li>Colored Console Target: highlight whole words was broken.</li>
<li>Mail Target: when <code class="language-plaintext highlighter-rouge">useSystemNetMailSettings</code> was <code class="language-plaintext highlighter-rouge">false</code>, some settings were still used from the <code class="language-plaintext highlighter-rouge"><mailSettings></code> of the .Net config.</li>
<li>Removed unnecessary System.Drawing references for Xamarin.</li>
<li>File Target: sometimes an exception was thrown when archiving was enabled.</li>
<li>File Target: file archiving DateAndSequence & FileArchivePeriod.Day won’t always work.</li>
<li>GetTargetsByLevelForLogger could throw a “Collection was modified” exception.</li>
</ul>
<h2 id="no-bug-nor-feature">No bug nor feature</h2>
<p>Improved document and error messages regarding the ‘type’ argument of <code class="language-plaintext highlighter-rouge">Getcurrentclasslogger</code> and <code class="language-plaintext highlighter-rouge">GetLogger</code>.
Please keep in mind:</p>
<blockquote>
<ul>
<li>It should inherit from <code class="language-plaintext highlighter-rouge">Logger</code>.</li>
<li>Instead of creating an instance of <code class="language-plaintext highlighter-rouge">Logger</code>, it will create an instance of <code class="language-plaintext highlighter-rouge">loggerType</code>.</li>
<li><code class="language-plaintext highlighter-rouge">type</code> argument necessary when using custom Loggers. Most of the time it isn’t required to pass a type to those methods.</li>
</ul>
</blockquote>
<p>We improved other docs and internal logging in the code. Our code coverage has also been increased.</p>
<h2 id="thanks">Thanks</h2>
<p>The NLog team has expanded greatly! We’d like to thank all the collaborators who have made this release possible:</p>
<ul>
<li><a href="https://github.com/bhaeussermann">Bernhard Häussermann</a></li>
<li><a href="https://github.com/dnlgmzddr">Daniel Gómez Didier</a></li>
<li><a href="https://github.com/ie-zero">Iraklis E.</a></li>
<li><a href="https://github.com/kevindaub">Kevin</a></li>
<li><a href="https://github.com/Xharze">Kim Christensen</a></li>
<li><a href="https://github.com/Page-Not-Found">Sreenath</a></li>
<li><a href="https://github.com/UgurAldanmaz">Uğur Aldanmaz</a></li>
</ul>
<p>Happy coding!</p>
<p>Julian <a href="https://github.com/304NotModified">(@304NotModified)</a></p>
How can we improve NLog? We have now UserEcho!2015-10-22T00:00:00+00:00https://nlog-project.org/2015/10/22/vote-and-add-feature-request<p>Do you have a feature request or another idea how we can improve NLog?</p>
<p>We are now also on <a href="http://nlog.userecho.com/">UserEcho</a>, so vote or add ideas!</p>
<p>Happy coding,
Julian</p>
<p>PS: if you like to have more status updates, just follow us <a href="https://twitter.com/nlogofficial">on Twitter</a>.</p>
NLog 4.1.1 has been released!2015-09-12T00:00:00+00:00https://nlog-project.org/2015/09/12/nlog-4-1-1-has-been-released<p>We just released a new version of NLog which fixes a few issues in NLog 4.1.0.</p>
<h2 id="features">Features</h2>
<ul>
<li>MDLC now also supports objects, such as MDC, GDC and NDC (those were added in 4.1.0)</li>
</ul>
<h2 id="bug-fixes">Bug fixes:</h2>
<ul>
<li>NLog won’t crash if there are binaries starting with “nlog” that we can’t load (those were loaded by the auto load feature)</li>
<li>Directory was required with the internal logger</li>
<li>Fixed assembly name issue with strong name. With the release of NLog 4.1.0 we made a mistake with the full name.
We changed the version in it to 4.1.0.0, but because of the strong naming, we should keep it 4.0.0.0.
This the curse of strong naming, and at least in NLog 4 we should just accept it.</li>
</ul>
<p>In the NLog 4.1.1, the full name is the same as NLog 4.0.0 and 4.0.1.</p>
<p>If nuget is adding the following to your (main) .config:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><dependentAssembly></span>
<span class="nt"><assemblyIdentity</span> <span class="na">name=</span><span class="s">"NLog"</span> <span class="na">publicKeyToken=</span><span class="s">"5120e14c03d0593c"</span> <span class="na">culture=</span><span class="s">"neutral"</span> <span class="nt">/></span>
<span class="nt"><bindingRedirect</span> <span class="na">oldVersion=</span><span class="s">"0.0.0.0-4.1.0.0"</span> <span class="na">newVersion=</span><span class="s">"4.1.0.0"</span> <span class="nt">/></span>
<span class="nt"></dependentAssembly></span></code></pre></figure>
<p>You should remove it, or change it to:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><dependentAssembly></span>
<span class="nt"><assemblyIdentity</span> <span class="na">name=</span><span class="s">"NLog"</span> <span class="na">publicKeyToken=</span><span class="s">"5120e14c03d0593c"</span> <span class="na">culture=</span><span class="s">"neutral"</span> <span class="nt">/></span>
<span class="nt"><bindingRedirect</span> <span class="na">oldVersion=</span><span class="s">"0.0.0.0-4.1.0.0"</span> <span class="na">newVersion=</span><span class="s">"4.0.0.0"</span> <span class="nt">/></span>
<span class="nt"></dependentAssembly></span></code></pre></figure>
<ul>
<li>If you use other libraries built on NLog 3, 4.1.0 or before: change it</li>
<li>If you don’t use other libraries built on NLog, or those which are built on NLog 4.x (expected 4.1.0), remove it</li>
</ul>
<p>We are sorry if the upgrade to 4.1.0 caused any issues.
We are aware that the strong naming sometimes gives more issues than solving things and
that versioning issues with strong naming are common.
But some users need the strong name, and therefore we will keep it for at least version 4.</p>
<h2 id="other">Other:</h2>
<ul>
<li>Obsolete text fixed</li>
<li>Removed some unused classes (moved to NLog.Windows.Forms before)</li>
</ul>
<p>Download it from <a href="https://www.nuget.org/packages/NLog/">nuget</a>!</p>
NLog 4.1 is Now Available!2015-08-31T00:00:00+00:00https://nlog-project.org/2015/08/31/nlog-4-1-0-is-now-available<p>A new version of NLog has been released!</p>
<p>We fixed around 25 bugs, added some new features and made the migration of NLog 3 to 4 easier.
The release can be downloaded from <a href="https://www.nuget.org/packages/NLog/4.1.0">NuGet</a>.</p>
<p>Check for all the details the <a href="https://github.com/NLog/NLog/issues?q=milestone%3A4.1+is%3Aclosed">GitHub 4.1 milestone</a>.</p>
<h2 id="features">Features</h2>
<p>This release contains the following features:</p>
<h3 id="overhaul-variables">Overhaul variables</h3>
<p>Since 4.0 you can read the variables defined in the configuration file. We also claimed you could change the values, but we were wrong…
The variables where implemented like a kind of macros and changing them would not give the expected results.</p>
<p>In NLog 4.1, we created a new method to render the variables, which fits a lot better in the NLog library:
we created a layout renderer for the variables! With the same syntax you can define the variables, but rendering is a bit different.</p>
<p>In NLog 4.0 you would define:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><nlog></span>
<span class="nt"><variable</span> <span class="na">name=</span><span class="s">'user'</span> <span class="na">value=</span><span class="s">'admin'</span> <span class="nt">/></span>
<span class="nt"><variable</span> <span class="na">name=</span><span class="s">'password'</span> <span class="na">value=</span><span class="s">'realgoodpassword'</span> <span class="nt">/></span>
<span class="nt"><targets></span>
<span class="nt"><target</span> <span class="na">name=</span><span class="s">'debug'</span> <span class="na">type=</span><span class="s">'Debug'</span> <span class="na">layout=</span><span class="s">'${message} and ${user}=${password}'</span> <span class="nt">/></span>
<span class="nt"></targets></span>
<span class="nt"><rules></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">'*'</span> <span class="na">minlevel=</span><span class="s">'Debug'</span> <span class="na">writeTo=</span><span class="s">'debug'</span> <span class="nt">/></span>
<span class="nt"></rules></span>
<span class="nt"></nlog></span></code></pre></figure>
<p>In 4.1 you can use the <code class="language-plaintext highlighter-rouge">$var{}</code> layout renderer:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><nlog></span>
<span class="nt"><variable</span> <span class="na">name=</span><span class="s">'user'</span> <span class="na">value=</span><span class="s">'admin'</span> <span class="nt">/></span>
<span class="nt"><variable</span> <span class="na">name=</span><span class="s">'password'</span> <span class="na">value=</span><span class="s">'realgoodpassword'</span> <span class="nt">/></span>
<span class="nt"><targets></span>
<span class="nt"><target</span> <span class="na">name=</span><span class="s">'debug'</span> <span class="na">type=</span><span class="s">'Debug'</span> <span class="na">layout=</span><span class="s">'${message} and ${var:user}=${var:password}'</span> <span class="nt">/></span>
<span class="nt"></targets></span>
<span class="nt"><rules></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">'*'</span> <span class="na">minlevel=</span><span class="s">'Debug'</span> <span class="na">writeTo=</span><span class="s">'debug'</span> <span class="nt">/></span>
<span class="nt"></rules></span>
<span class="nt"></nlog></span></code></pre></figure>
<p>What’s the real advantage here?</p>
<ul>
<li>It is in line with NLog’s current code</li>
<li>Variables can be changed, deleted and created from the API</li>
<li>A default value can be configured for a variable, e.g. <code class="language-plaintext highlighter-rouge">${var:password:default=unknown}</code></li>
<li>The old variables can still be used and so this is completely backwards-compatible.</li>
</ul>
<p>You might wonder: why has the old method not been replaced? The answer is simple: the new method only works on <code class="language-plaintext highlighter-rouge">Layout</code> types and not on plain <code class="language-plaintext highlighter-rouge">strings</code>.</p>
<h3 id="object-values-for-gdc-mdc-and-ndc-contexts">Object values for GDC, MDC and NDC contexts</h3>
<p>The context classes, GCD, MCD and NDC, now support using <code class="language-plaintext highlighter-rouge">object</code> values instead of <code class="language-plaintext highlighter-rouge">strings</code>. This is mostly beneficial from the API perspective.</p>
<p>The <code class="language-plaintext highlighter-rouge">get</code> method still returns a <code class="language-plaintext highlighter-rouge">string</code> - for backwards-compatibility reasons. We created a new method: <code class="language-plaintext highlighter-rouge">getObject</code>.</p>
<p>When writing to the logs, the <code class="language-plaintext highlighter-rouge">object</code> is converted to a <code class="language-plaintext highlighter-rouge">string</code></p>
<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">GlobalDiagnosticsContext</span><span class="p">.</span><span class="nf">Set</span><span class="p">(</span><span class="s">"myDataBase"</span><span class="p">,</span><span class="s">"someValue"</span><span class="p">);</span> <span class="c1">//already possible</span>
<span class="n">GlobalDiagnosticsContext</span><span class="p">.</span><span class="nf">Set</span><span class="p">(</span><span class="s">"myDataBaseNumber"</span><span class="p">,</span><span class="m">2</span><span class="p">);</span> <span class="c1">//4.1+</span>
</code></pre></figure>
<h3 id="easier-upgrade-from-nlog-3-to-nlog-4">Easier upgrade from NLog 3 to NLog 4</h3>
<p>With <a href="http://nlog-project.org/2015/06/09/nlog-4-has-been-released.html">the release of NLog 4.0</a> we made some breaking changes. Those breaking changes made upgrading an issue: all the code has to be upgraded to NLog 4 at once.</p>
<p>The main cause was the change of behavior of <code class="language-plaintext highlighter-rouge">Log(string message, Exception ex)</code>. This call should be replaced by <code class="language-plaintext highlighter-rouge">Log(Exception ex, string message)</code> in NLog 4.0.</p>
<p>Changing all those calls can be difficult at once. So we have introduced the following option:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><nlog</span> <span class="na">exceptionLoggingOldStyle=</span><span class="s">'true'</span><span class="nt">></span>
</code></pre></figure>
<p>With this option enabled, you can still use <code class="language-plaintext highlighter-rouge">Log(string message, Exception ex)</code> in NLog 4.</p>
<p>So the upgrade path to NLog 4</p>
<ol>
<li>Enable “exceptionLoggingOldStyle” in the configuration</li>
<li>Upgrade to NLog 4.1+</li>
<li>(this can take some time): replace the calls to <code class="language-plaintext highlighter-rouge">Log(string message, Exception ex)</code> etc.</li>
<li>Disable “exceptionLoggingOldStyle” in the configuration</li>
</ol>
<p>Note: we will remove this feature in NLog 5.0</p>
<h3 id="new-json-options">New JSON options</h3>
<p>New options have been added for writing JSON output.</p>
<ul>
<li>More control over spaces: SuppressSpaces. Example:</li>
</ul>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><layout</span> <span class="na">xsi:type=</span><span class="s">"JsonLayout"</span> <span class="na">SuppressSpaces=</span><span class="s">"false"</span><span class="nt">></span>
<span class="nt"><attribute</span> <span class="na">name=</span><span class="s">"process_name"</span> <span class="na">layout=</span><span class="s">"${processname}"</span> <span class="nt">/></span>
<span class="nt"><attribute</span> <span class="na">name=</span><span class="s">"short_message"</span> <span class="na">layout=</span><span class="s">"${message}"</span> <span class="nt">/></span>
<span class="nt"></layout></span></code></pre></figure>
<ul>
<li>The JSON encoding can be disabled for properties.</li>
</ul>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><layout</span> <span class="na">xsi:type=</span><span class="s">"JsonLayout"</span><span class="nt">></span>
<span class="nt"><attribute</span> <span class="na">name=</span><span class="s">"Message"</span> <span class="na">layout=</span><span class="s">"${message}"</span> <span class="na">encode=</span><span class="s">"false"</span><span class="nt">/></span>
<span class="nt"></layout></span></code></pre></figure>
<p>Example call:</p>
<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"{ \"hello\" : \"world\" }"</span><span class="p">);</span></code></pre></figure>
<p>See <a href="https://github.com/NLog/NLog/wiki/JsonLayout">the wiki</a></p>
<h3 id="integrated-nlogcontrib-to-core">Integrated NLog.Contrib to core</h3>
<p>The NLog.Contrib code has been integrated with the core of NLog.
The following features are now available on the NLog package:</p>
<ul>
<li>Mapped Diagnostics Context (MDLC): Async version of Mapped Diagnostics Context Allows for maintaining state across
asynchronous tasks and call contexts.</li>
<li>The Mapped Diagnostics Context Layout renderer: <code class="language-plaintext highlighter-rouge">${mdlc}</code></li>
<li>Trace Activity Id Layout Renderer: <code class="language-plaintext highlighter-rouge">${activityid}</code> write the <code class="language-plaintext highlighter-rouge">System.Diagnostics</code> his trace correlation id.</li>
</ul>
<h3 id="all-events-layout-renderer-optional-writing-of-caller-information">All events layout renderer: optional writing of caller information</h3>
<p>The all events layout renderer introduced in NLog 4.0 was unexpectedly writing <a href="https://msdn.microsoft.com/en-us/library/hh534540.aspx">caller information</a>, like current method etc, to the targets. This is now an option and disabled by default.</p>
<p>For example:</p>
<ul>
<li>` ${all-event-properties}` writes “Test=InfoWrite, coolness=200%, a=not b”</li>
<li>` ${all-event-properties:includeCallerInformation=true}` writes “Test=InfoWrite, coolness=200%, a=not b, CallerMemberName=foo, CallerFilePath=c:/test/log.cs, CallerLineNumber=1001”</li>
</ul>
<h3 id="call-site-line-number-layout-renderer">Call site line number layout renderer</h3>
<p>Officially introduced in NLog 4.0, but was not available due to a merge fault. The <code class="language-plaintext highlighter-rouge">${callsite-linenumber}</code> writes the line number of the caller.</p>
<h3 id="easy-replacement-of-newlines">Easy replacement of newlines</h3>
<p>With the <code class="language-plaintext highlighter-rouge">${replace}</code> layout renderer it was already possible to replace the newlines, but it was a bit tricky to use - different systems, different newlines.</p>
<p>The <code class="language-plaintext highlighter-rouge">${replace-newlines}</code> layout renderer fixes this.</p>
<h3 id="wcf-log-receiver-changes">WCF Log Receiver Changes</h3>
<p>4.0.0 introduced an unattended breaking changing that replaced the <code class="language-plaintext highlighter-rouge">WcfLogReceiverClient</code> with the <code class="language-plaintext highlighter-rouge">WcfLogReceiverClientFacade</code> (NLog/NLog#783). It was not only a naming issue, but also some functionality was lost and there was a lot of code duplication.</p>
<p>Unfortunately, there was not an easy fix, so the following was done to try to make it <em>less</em> of a breaking change. The changes are still breaking, but minus a recompilation, the changes should be mostly transparent. See NLog/NLog#874 for all of the changes related to WCF Log Receiver.</p>
<h4 id="changes-from-321">Changes from 3.2.1</h4>
<p>Compared to 3.2.x, these the changes:</p>
<ul>
<li>Use <code class="language-plaintext highlighter-rouge">ILogReceiverTwoWayClient</code> instead of <code class="language-plaintext highlighter-rouge">ILogReceiverClient</code>. <code class="language-plaintext highlighter-rouge">ILogReceiverClient</code> is still in the code, but is marked obsolete.</li>
<li>If your code is dependent on <code class="language-plaintext highlighter-rouge">ClientBase</code>, then change it to <code class="language-plaintext highlighter-rouge">WcfLogReceiverClientBase</code></li>
</ul>
<h4 id="changes-from-400">Changes from 4.0.0</h4>
<p>Compared to 4.0.x, these the changes:</p>
<ul>
<li>The return type for the method <code class="language-plaintext highlighter-rouge">CreateWcfLogReceiverClient()</code> in <code class="language-plaintext highlighter-rouge">LogReceiverWebServiceTarget</code> is <code class="language-plaintext highlighter-rouge">WcfLogReceiverClient</code> again, but is marked obsolete.</li>
<li>Use <code class="language-plaintext highlighter-rouge">CreateLogReceiver()</code>, which returns <code class="language-plaintext highlighter-rouge">IWcfLogReceiverClient</code> to reduce breaking changes in the future.</li>
</ul>
<h2 id="event-properties---culture-and-format-options">Event properties - culture and format options</h2>
<p>The event properties are <code class="language-plaintext highlighter-rouge">object</code> values. When writing them with <code class="language-plaintext highlighter-rouge">${event-properties}</code> to the logs, the values are converted to <code class="language-plaintext highlighter-rouge">strings</code>. It’s now possible to control the culture and format.</p>
<p>Examples: <code class="language-plaintext highlighter-rouge">${event-properties:prop1:format=yyyy-M-dd}</code> and <code class="language-plaintext highlighter-rouge">${event-properties:aaa:culture=nl-NL}</code></p>
<h2 id="bugs">Bugs</h2>
<p>Various bugs are fixed in this version. The most notable ones:</p>
<h3 id="unc-path-issues">UNC path issues</h3>
<p>4.0.1 did gave issues with configuration files or binaries hosted on UNC locations.</p>
<h3 id="fixes-in-file-archiving">Fixes in file archiving</h3>
<p>Multiple bugs are fixed with file archiving:</p>
<ul>
<li>Archive files where sometimes deleted in the wrong order.</li>
<li><code class="language-plaintext highlighter-rouge">DeleteOldDateArchive</code> could delete files not being actual archives. <a href="https://github.com/NLog/NLog/issues/847">#847</a></li>
</ul>
<h3 id="fixed-mono-build">Fixed Mono build</h3>
<p>This release finally builds again on Mono! We are busy adding Travis CI integration to keep the Mono build working.</p>
<h3 id="exception-is-not-correctly-logged-when-calling-without-message">Exception is not correctly logged when calling without message</h3>
<p>Writing an exception as only argument to a logger, like <code class="language-plaintext highlighter-rouge">logger.Info(new Exception())</code> was not correctly registering the exception to the log messages.</p>
<h3 id="internal-logger-improvements">Internal logger improvements</h3>
<p>Some small improved has been made to the internal logger.</p>
NLog is Looking for Developers!2015-08-05T00:00:00+00:00https://nlog-project.org/2015/08/05/NLog-is-looking-for-developers<p>This year the NLog project has grown a lot:</p>
<ul>
<li>We have released more often (and NLog 4.1 is on its way)</li>
<li>We have redesigned and improved the website (nlog-project.org)</li>
<li>The process of giving support and handling issues has been improved</li>
<li>A lot of old issues are fixed/closed.</li>
<li>The website is fully up-to-date, the wiki has been expanded and old forums have been closed.</li>
<li>Twitter and Gitter have been set up.</li>
</ul>
<p>However, we want to grow even more. We’d like to:</p>
<ul>
<li>Release even more often</li>
<li>Fix more bugs</li>
<li>Add more features</li>
<li>Improve the support for other platforms like Mono, PCL, Xamarin</li>
<li>Improve the automatic release management</li>
<li>Measure, and improve, the code coverage of the unit tests.</li>
</ul>
<p>Currently the NLog team consists of two people. If we want to develop NLog further, we need more horsepower!
And so we are looking for developers!</p>
<p>If you are interested in contributing to one of the most popular .Net libraries –we are ranked in the <a href="https://www.nuget.org/stats/packages">top 100 of NuGet</a>, and when excluding the non-.Net and Microsoft packages, we rank in the top 10.– then get in touch with us on Gitter or Github :)</p>
<p>Get in touch with us on <a href="https://gitter.im/NLog/NLog">Gitter</a> or <a href="https://github.com/NLog/NLog/issues/828">Github</a> :)</p>
Extending NLog is... easy!2015-06-30T00:00:00+00:00https://nlog-project.org/2015/06/30/extending-nlog-is-easy<p>Not everyone knows NLog is easy to extend to your own wishes.
There can be various reasons for wanting to extend NLog.
For example when you want to write your log messages to a custom output or you would like to use your own <code class="language-plaintext highlighter-rouge">${}</code> macros.</p>
<p>With some attributes you can create your own custom target, layout or layout renderer with ease.
Also creating your own conditions for filter messages is possible!</p>
<p>I will describe creating your own layout renderer and custom target in this post.</p>
<h2 id="how-to-write-a-custom-layout-renderer">How to write a custom layout renderer?</h2>
<p>Create a class which inherits from <code class="language-plaintext highlighter-rouge">NLog.LayoutRenderers.LayoutRenderer</code>, set the <code class="language-plaintext highlighter-rouge">[LayoutRenderer("your-name"]</code> on the class and override the <code class="language-plaintext highlighter-rouge">Append(StringBuilder builder, LogEventInfo logEvent)</code> method.
Invoke in this method <code class="language-plaintext highlighter-rouge">builder.Append(..)</code> to render your custom layout renderer.</p>
<h3 id="example">Example</h3>
<p>We create a <code class="language-plaintext highlighter-rouge">${hello-universe}</code> layout renderer, which renders… “hello universe!”.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="nf">LayoutRenderer</span><span class="p">(</span><span class="s">"hello-universe"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">HelloUniverseLayoutRenderer</span> <span class="p">:</span> <span class="n">LayoutRenderer</span>
<span class="p">{</span>
<span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Append</span><span class="p">(</span><span class="n">StringBuilder</span> <span class="n">builder</span><span class="p">,</span> <span class="n">LogEventInfo</span> <span class="n">logEvent</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">builder</span><span class="p">.</span><span class="nf">Append</span><span class="p">(</span><span class="s">"hello universe!"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h3 id="how-to-pass-configuration-options-to-the-layout-render">How to pass configuration options to the layout render?</h3>
<p>Just create <strong>public</strong> properties on the layout renderer. The properties can be decorated with the <code class="language-plaintext highlighter-rouge">[RequiredParameter]</code> and <code class="language-plaintext highlighter-rouge">[DefaultParameter]</code> attributes.
With the <code class="language-plaintext highlighter-rouge">[RequiredParameter]</code> attribute, NLog checks if this property has a value and throws an exception when it hasn’t.
The property names are required in your config by default. The property name of the first value can be skipped, if the property is decorated with the <code class="language-plaintext highlighter-rouge">[DefaultParameter]</code> attribute - see the examples below.</p>
<p>It’s not required for the property to be a <code class="language-plaintext highlighter-rouge">string</code>.
NLog takes care of the appropriate conversions when necessary. You can use, inter alia, the following types for the properties: <code class="language-plaintext highlighter-rouge">integer</code>, <code class="language-plaintext highlighter-rouge">string</code>, <code class="language-plaintext highlighter-rouge">datetime</code> and <code class="language-plaintext highlighter-rouge">boolean</code>.</p>
<p>For example:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="nf">LayoutRenderer</span><span class="p">(</span><span class="s">"hello-universe"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">HelloUniverseLayoutRenderer</span> <span class="p">:</span> <span class="n">LayoutRenderer</span>
<span class="p">{</span>
<span class="c1">/// <summary></span>
<span class="c1">/// I'm not required</span>
<span class="c1">/// </summary></span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">Config1</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="c1">/// <summary></span>
<span class="c1">/// I'm required! </span>
<span class="c1">/// </summary></span>
<span class="p">[</span><span class="n">RequiredParameter</span><span class="p">]</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">Config2</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="c1">/// <summary></span>
<span class="c1">/// Hi! I'm the default parameter. You can also set me as required.</span>
<span class="c1">/// </summary></span>
<span class="p">[</span><span class="n">DefaultParameter</span><span class="p">]</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">Caps</span> <span class="p">{</span><span class="k">get</span><span class="p">;</span><span class="k">set</span><span class="p">;}</span></code></pre></figure>
<p>Example usages:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">${hello-universe}</code> - Raises exception: required parameter “Config2” isn’t set.</li>
<li><code class="language-plaintext highlighter-rouge">${hello-universe:Config2=abc}</code> - OK, “Config2” property set.</li>
<li><code class="language-plaintext highlighter-rouge">${hello-universe:true:config2=abc}</code> - Default parameter “Caps” set to <code class="language-plaintext highlighter-rouge">true</code>.</li>
<li><code class="language-plaintext highlighter-rouge">${hello-universe:true:config2=abc:config1=yes}</code> - All the three properties set.</li>
</ul>
<h2 id="how-to-write-a-custom-target">How to write a custom target?</h2>
<p>Creating a custom target is almost identical to creating a custom layout renderer.</p>
<p>The created class should now inherit from <code class="language-plaintext highlighter-rouge">NLog.Targets.TargetWithLayout</code> and override the <code class="language-plaintext highlighter-rouge">Write()</code> method. In the body of the method invoke <code class="language-plaintext highlighter-rouge">this.Layout.Render()</code> to render the message text.</p>
<h3 id="example-1">Example</h3>
<p>An example of a custom target:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="nf">Target</span><span class="p">(</span><span class="s">"MyFirst"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">MyFirstTarget</span><span class="p">:</span> <span class="n">TargetWithLayout</span>
<span class="p">{</span>
<span class="k">public</span> <span class="nf">MyFirstTarget</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Host</span> <span class="p">=</span> <span class="s">"localhost"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">[</span><span class="n">RequiredParameter</span><span class="p">]</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">Host</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Write</span><span class="p">(</span><span class="n">LogEventInfo</span> <span class="n">logEvent</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">string</span> <span class="n">logMessage</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="n">Layout</span><span class="p">.</span><span class="nf">Render</span><span class="p">(</span><span class="n">logEvent</span><span class="p">);</span>
<span class="nf">SendTheMessageToRemoteHost</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">Host</span><span class="p">,</span> <span class="n">logMessage</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">SendTheMessageToRemoteHost</span><span class="p">(</span><span class="kt">string</span> <span class="n">host</span><span class="p">,</span> <span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// TODO - write me </span>
<span class="p">}</span>
<span class="p">}</span> </code></pre></figure>
<h3 id="how-to-pass-configuration-options-to-the-target">How to pass configuration options to the target?</h3>
<p>The property “host” is a configurable option to this target. You can pass the value as attribute in the config: <code class="language-plaintext highlighter-rouge"><layout type="myFirst" host="test.com" /></code></p>
<h2 id="how-to-use-the-custom-target-or-layout-renderer">How to use the custom target or layout renderer</h2>
<p>First put your custom target or layout renderer in a separate assembly (.dll). Then you should register your assembly. Starting from NLog 4.0, assemblies with the name “NLog*.dll”, such as “NLog.CustomTarget.dll” are now registered automatically - they should be in the same folder as “NLog.dll”.</p>
<p>If that’s not the case you should register your assembly manually: reference your assembly from the the config file using the <code class="language-plaintext highlighter-rouge"><extensions /></code> clause. Only the assembly name is needed (without “.dll”).</p>
<p>Configuration file example:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><nlog></span>
<span class="nt"><extensions></span>
<span class="nt"><add</span> <span class="na">assembly=</span><span class="s">"MyAssembly"</span><span class="nt">/></span>
<span class="nt"></extensions></span>
<span class="nt"><targets></span>
<span class="nt"><target</span> <span class="na">name=</span><span class="s">"a1"</span> <span class="na">type=</span><span class="s">"MyFirst"</span> <span class="na">host=</span><span class="s">"localhost"</span><span class="nt">/></span>
<span class="nt"><target</span> <span class="na">name=</span><span class="s">"f1"</span> <span class="na">type=</span><span class="s">"file"</span> <span class="na">layout=</span><span class="s">"${longdate} ${hello-universe}"</span>
<span class="na">fileName=</span><span class="s">"${basedir}/logs/logfile.log"</span> <span class="nt">/></span>
<span class="nt"></targets></span>
<span class="nt"><rules></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">"*"</span> <span class="na">minLevel=</span><span class="s">"Info"</span> <span class="na">appendTo=</span><span class="s">"a1"</span><span class="nt">/></span>
<span class="nt"><logger</span> <span class="na">name=</span><span class="s">"*"</span> <span class="na">minLevel=</span><span class="s">"Info"</span> <span class="na">appendTo=</span><span class="s">"f1"</span><span class="nt">/></span>
<span class="nt"></rules></span>
<span class="nt"></nlog></span></code></pre></figure>
<h3 id="do-i-really-need-to-create-a-separate-assembly">Do I really need to create a separate assembly?</h3>
<p>Not really. You should then register your target programmatically. Just make sure to register your stuff at the very beginning of your program, before any log messages are written.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">//layout renderer</span>
<span class="n">ConfigurationItemFactory</span><span class="p">.</span><span class="n">Default</span><span class="p">.</span><span class="n">LayoutRenderers</span>
<span class="p">.</span><span class="nf">RegisterDefinition</span><span class="p">(</span><span class="s">"hello-universe"</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">MyNamespace</span><span class="p">.</span><span class="n">HelloUniverseLayoutRenderer</span> <span class="p">));</span>
<span class="c1">//target</span>
<span class="n">ConfigurationItemFactory</span><span class="p">.</span><span class="n">Default</span><span class="p">.</span><span class="n">Targets</span>
<span class="p">.</span><span class="nf">RegisterDefinition</span><span class="p">(</span><span class="s">"MyFirst"</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">MyNamespace</span><span class="p">.</span><span class="n">MyFirstTarget</span><span class="p">));</span>
<span class="c1">// start logging here </span>
<span class="p">}</span></code></pre></figure>