Quantcast
Channel: NLog

NLog is Looking for Developers!

$
0
0

This year the NLog project has grown a lot:

  • We have released more often (and NLog 4.1 is on its way)
  • We have redesigned and improved the website (nlog-project.org)
  • The process of giving support and handling issues has been improved
  • A lot of old issues are fixed/closed.
  • The website is fully up-to-date, the wiki has been expanded and old forums have been closed.
  • Twitter and Gitter have been set up.

However, we want to grow even more. We’d like to:

  • Release even more often
  • Fix more bugs
  • Add more features
  • Improve the support for other platforms like Mono, PCL, Xamarin
  • Improve the automatic release management
  • Measure, and improve, the code coverage of the unit tests.

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!

If you are interested in contributing to one of the most popular .Net libraries –we are ranked in the top 100 of NuGet, 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 :)

Get in touch with us on Gitter or Github :)


NLog 4.1 is Now Available!

$
0
0

A new version of NLog has been released!

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 NuGet.

Check for all the details the GitHub 4.1 milestone.

Features

This release contains the following features:

Overhaul variables

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.

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.

In NLog 4.0 you would define:

<nlog><variablename='user'value='admin'/><variablename='password'value='realgoodpassword'/><targets><targetname='debug'type='Debug'layout='${message} and ${user}=${password}'/></targets><rules><loggername='*'minlevel='Debug'writeTo='debug'/></rules></nlog>

In 4.1 you can use the $var{} layout renderer:

<nlog><variablename='user'value='admin'/><variablename='password'value='realgoodpassword'/><targets><targetname='debug'type='Debug'layout='${message} and ${var:user}=${var:password}'/></targets><rules><loggername='*'minlevel='Debug'writeTo='debug'/></rules></nlog>

What’s the real advantage here?

  • It is in line with NLog’s current code
  • Variables can be changed, deleted and created from the API
  • A default value can be configured for a variable, e.g. ${var:password:default=unknown}
  • The old variables can still be used and so this is completely backwards-compatible.

You might wonder: why has the old method not been replaced? The answer is simple: the new method only works on Layout types and not on plain strings.

Object values for GDC, MDC and NDC contexts

The context classes, GCD, MCD and NDC, now support using object values instead of strings. This is mostly beneficial from the API perspective.

The get method still returns a string - for backwards-compatibility reasons. We created a new method: getObject.

When writing to the logs, the object is converted to a string

GlobalDiagnosticsContext.Set("myDataBase","someValue");//already possibleGlobalDiagnosticsContext.Set("myDataBaseNumber",2);//4.1+

Easier upgrade from NLog 3 to NLog 4

With the release of NLog 4.0 we made some breaking changes. Those breaking changes made upgrading an issue: all the code has to be upgraded to NLog 4 at once.

The main cause was the change of behavior of Log(string message, Exception ex). This call should be replaced by Log(Exception ex, string message) in NLog 4.0.

Changing all those calls can be difficult at once. So we have introduced the following option:

<nlogexceptionLoggingOldStyle='true'>

With this option enabled, you can still use Log(string message, Exception ex) in NLog 4.

So the upgrade path to NLog 4

  1. Enable “exceptionLoggingOldStyle” in the configuration
  2. Upgrade to NLog 4.1+
  3. (this can take some time): replace the calls to Log(string message, Exception ex) etc.
  4. Disable “exceptionLoggingOldStyle” in the configuration

Note: we will remove this feature in NLog 5.0

New JSON options

New options have been added for writing JSON output.

  • More control over spaces: SuppressSpaces. Example:
<layoutxsi:type="JsonLayout"SuppressSpaces="false"><attributename="process_name"layout="${processname}"/><attributename="short_message"layout="${message}"/></layout>
  • The JSON encoding can be disabled for properties.
<layoutxsi:type="JsonLayout"><attributename="Message"layout="${message}"encode="false"/></layout>

Example call:

logger.Info("{ \"hello\" : \"world\" }");

See the wiki

Integrated NLog.Contrib to core

The NLog.Contrib code has been integrated with the core of NLog. The following features are now available on the NLog package:

  • Mapped Diagnostics Context (MDLC): Async version of Mapped Diagnostics Context Allows for maintaining state across asynchronous tasks and call contexts.
  • The Mapped Diagnostics Context Layout renderer: ${mdlc}
  • Trace Activity Id Layout Renderer: ${activityid} write the System.Diagnostics his trace correlation id.

All events layout renderer: optional writing of caller information

The all events layout renderer introduced in NLog 4.0 was unexpectedly writing caller information, like current method etc, to the targets. This is now an option and disabled by default.

For example:

  • ${all-event-properties} writes “Test=InfoWrite, coolness=200%, a=not b”
  • ${all-event-properties:includeCallerInformation=true} writes “Test=InfoWrite, coolness=200%, a=not b, CallerMemberName=foo, CallerFilePath=c:/test/log.cs, CallerLineNumber=1001”

Call site line number layout renderer

Officially introduced in NLog 4.0, but was not available due to a merge fault. The ${callsite-linenumber} writes the line number of the caller.

Easy replacement of newlines

With the ${replace} layout renderer it was already possible to replace the newlines, but it was a bit tricky to use - different systems, different newlines.

The ${replace-newlines} layout renderer fixes this.

WCF Log Receiver Changes

4.0.0 introduced an unattended breaking changing that replaced the WcfLogReceiverClient with the WcfLogReceiverClientFacade (NLog/NLog#783). It was not only a naming issue, but also some functionality was lost and there was a lot of code duplication.

Unfortunately, there was not an easy fix, so the following was done to try to make it less 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.

Changes from 3.2.1

Compared to 3.2.x, these the changes:

  • Use ILogReceiverTwoWayClient instead of ILogReceiverClient. ILogReceiverClient is still in the code, but is marked obsolete.
  • If your code is dependent on ClientBase, then change it to WcfLogReceiverClientBase

Changes from 4.0.0

Compared to 4.0.x, these the changes:

  • The return type for the method CreateWcfLogReceiverClient() in LogReceiverWebServiceTarget is WcfLogReceiverClient again, but is marked obsolete.
  • Use CreateLogReceiver(), which returns IWcfLogReceiverClient to reduce breaking changes in the future.

Event properties - culture and format options

The event properties are object values. When writing them with ${event-properties} to the logs, the values are converted to strings. It’s now possible to control the culture and format.

Examples: ${event-properties:prop1:format=yyyy-M-dd} and ${event-properties:aaa:culture=nl-NL}

Bugs

Various bugs are fixed in this version. The most notable ones:

UNC path issues

4.0.1 did gave issues with configuration files or binaries hosted on UNC locations.

Fixes in file archiving

Multiple bugs are fixed with file archiving:

  • Archive files where sometimes deleted in the wrong order.
  • DeleteOldDateArchive could delete files not being actual archives. #847

Fixed Mono build

This release finally builds again on Mono! We are busy adding Travis CI integration to keep the Mono build working.

Exception is not correctly logged when calling without message

Writing an exception as only argument to a logger, like logger.Info(new Exception()) was not correctly registering the exception to the log messages.

Internal logger improvements

Some small improved has been made to the internal logger.

NLog 4.1.1 has been released!

$
0
0

We just released a new version of NLog which fixes a few issues in NLog 4.1.0.

Features

  • MDLC now also supports objects, such as MDC, GDC and NDC (those were added in 4.1.0)

Bug fixes:

  • NLog won’t crash if there are binaries starting with “nlog” that we can’t load (those were loaded by the auto load feature)
  • Directory was required with the internal logger
  • 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.

In the NLog 4.1.1, the full name is the same as NLog 4.0.0 and 4.0.1.

If nuget is adding the following to your (main) .config:

<dependentAssembly><assemblyIdentityname="NLog"publicKeyToken="5120e14c03d0593c"culture="neutral"/><bindingRedirectoldVersion="0.0.0.0-4.1.0.0"newVersion="4.1.0.0"/></dependentAssembly>

You should remove it, or change it to:

<dependentAssembly><assemblyIdentityname="NLog"publicKeyToken="5120e14c03d0593c"culture="neutral"/><bindingRedirectoldVersion="0.0.0.0-4.1.0.0"newVersion="4.0.0.0"/></dependentAssembly>
  • If you use other libraries built on NLog 3, 4.1.0 or before: change it
  • 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

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.

Other:

  • Obsolete text fixed
  • Removed some unused classes (moved to NLog.Windows.Forms before)

Download it from nuget!

How can we improve NLog? We have now UserEcho!

$
0
0

Do you have a feature request or another idea how we can improve NLog?

We are now also on UserEcho, so vote or add ideas!

Happy coding, Julian

PS: if you like to have more status updates, just follow us on Twitter.

NLog 4.2 is here!

$
0
0

NLog 4.2 has been released. This release contains some small features and (important) bug fixes.

We take semver serious, so all changes are backwards-compatible.

Features

  • Performance Counter Target: it’s now possible to configure the step size for the counter target. Before the step size was always one.
  • Mail Target: pickupDirectoryLocation and deliveryMethod are configurable from the NLog config.
  • Cached Layout Renderer: a clearCache option has been added for more control over clearing the cache. See wiki.
  • File target: auto add .zip to compressed archive when archiveName isn’t specified.

Bug fixes

Inner layout can now contain colons

An inner layout can now contain colons, but it needs an escape.

It is required to escape : and } in an inner layout because:

  • : because it’s a value separator. ${when:when=1 == 1:Inner=Test\: Hello}
  • } because it can be the end of another layout renderer when double nested. ${rot13:inner=${rot13:inner=${when:when=1 == 1:Inner=Test \} Hello}}}

Other bugfixes

  • Colored Console Target: highlight whole words was broken.
  • Mail Target: when useSystemNetMailSettings was false, some settings were still used from the <mailSettings> of the .Net config.
  • Removed unnecessary System.Drawing references for Xamarin.
  • File Target: sometimes an exception was thrown when archiving was enabled.
  • File Target: file archiving DateAndSequence & FileArchivePeriod.Day won’t always work.
  • GetTargetsByLevelForLogger could throw a “Collection was modified” exception.

No bug nor feature

Improved document and error messages regarding the ‘type’ argument of Getcurrentclasslogger and GetLogger. Please keep in mind:

  • It should inherit from Logger.
  • Instead of creating an instance of Logger, it will create an instance of loggerType.
  • type argument necessary when using custom Loggers. Most of the time it isn’t required to pass a type to those methods.

We improved other docs and internal logging in the code. Our code coverage has also been increased.

Thanks

The NLog team has expanded greatly! We’d like to thank all the collaborators who have made this release possible:

Happy coding!

Julian (@304NotModified)

NLog 4.2.1 has been released!

$
0
0

Release notes:

  • Show warning for Databasetarget.UseTransactions instead of exception.
  • NetworkTarget: improved performance, allow configuring of max connections. See wiki.
  • Filetarget: Max archives settings sometimes removes to many files.
  • Prevent Collection was modified (ObjectGraphScanner.ScanProperties)
  • General memory pressure improvements.
  • LogReceiverWebServiceTarget.CreateLogReceiver() should be virtual
  • VariableLayoutRenderer does not work with Custom LogManagers.

NLog.Windows.Forms 4.2 has been released!

$
0
0

NLog.Windows.Forms 4.2 has been released including a new feature for the RichTextBoxTarget— it is now possible to add clickable links to log messages.

Features

This release contains the following features:

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 supportLink parameter to true and use new ${rtb-link} layout renderer to specify link part of the layout. To receive link click events, add a handler to RichTextBoxTarget.LinkClicked event. Use RichTextBoxTarget.GetTargetByControl(RichTextBox control) static method to access the target attached to a specific RichTextBox control.

Not sure how to use it? Here are few examples.

Exception details example

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:

Just setup a proper layout (don’t forget to enable supportLinks)

<targetxsi:type="RichTextBox"layout="${message}${onexception:inner= ${exception:format=Message} ${rtb-link:details}}"....supportLinks="true"..../>

And add a link click handler:

publicForm1(){InitializeComponent();RichTextBoxTarget.ReInitializeAllTextboxes(this);//more on this laterRichTextBoxTarget.GetTargetByControl(richTextBox1).LinkClicked+=Form1_LinkClicked;}privatevoidForm1_LinkClicked(RichTextBoxTargetsender,stringlinkText,LogEventInfoevent){MessageBox.Show(event.Exception.ToString(),"Exception details",MessageBoxButtons.OK);}

Focusing at specific item example

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 LogEventInfo.Property, turn it into a link and navigate to the item in link click handler:

The layout:

<targetxsi:type="RichTextBox"layout="${message} ${rtb-link:${event-properties:item=Index}}"....supportLinks="true"..../>

Validation code:

privatevoidvalidateButton_Click(objectsender,EventArgse){logger.Info("Validation started");foreach(ListViewItemiteminlistView1.Items){if(item.SubItems[1].Text.Contains("bad")){logger.Info().Message("Validation failed on line").Property("Index",(int)item.Tag).Write();return;}}logger.Info("Validation succeeded");}

Event handling code:

publicForm2(){InitializeComponent();RichTextBoxTarget.ReInitializeAllTextboxes(this);RichTextBoxTarget.GetTargetByControl(richTextBox1).LinkClicked+=Form2_LinkClicked;}privatevoidForm2_LinkClicked(RichTextBoxTargetsender,stringlinkText,LogEventInfoevent){intlineIndex=(int)event.Properties["Index"];listView1.EnsureVisible(lineIndex);listView1.SelectedIndices.Add(lineIndex);listView1.Select();}

Hope you could find more useful applications of this new feature!

A note on 4.1 release

In case you are not sure whatRichTextBoxTarget.ReInitializeAllTextboxes(this)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. CheckallowAccessoryFormCreationandmessageRetentionoptions description in the target’s documentation

NLog 4.3 RC is Now Available!

$
0
0

update 27 march: RC 2 is now online which resolves a bug in finding the correct stackframe in for ${callsite} etc. This was broken since 4.3-beta 1.


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 more main contributors than before?

The release can be downloaded from NuGet.

Check for all the details the GitHub 4.3 milestone.

Please note that currently not all the docs have been updated yet.

Features

This release contains the following features:

Support Windows Phone 8, Xamarin Android and Xamarin iOS (beta)

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.

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 on the wiki.

Consistent handling of exceptions (BEHAVIOUR CHANGE)

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.

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!

  • All exceptions are logged to the internal logger
  • The “throwExceptions” option will be respected in all cases

Advise: disable throwExceptions in production environments! (this the default)

<nlogthrowConfigExceptions="false">

Control of exception throwing for configuration errors

The following is stated in multiple locations: > By default exceptions are not thrown under any circumstances.

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!

We now introduce the “throwConfigExceptions” option:

<nlogthrowConfigExceptions="true|false|<empty>">
LogManager.ThrowConfigExceptions=true|false|null
  • If set to true, if will throw exceptions for configuration errors. Set this to true if you like the behaviour from NLog 4.2 and ealier.
  • If set to empty (or null in the API), this option will follow the “throwExceptions” option (previous section)
  • If set to false, don’t throw exceptions for configuration errors.

Also throwing exceptions for a configuration error
could lead to System.TypeInitializationException which is bad and confusing as sending info with the exception is difficult or sometimes impossible - see stackoverflow.

API improvements

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 SimpleConfigurator was a hint things weren’t simple enough ;)

Changes:

  • LogManager has now AddRule methods. See examples below.
  • Set the max log level in the LoggingRule constructor.
  • The name of the TargetAttribute is used as fallback for every target now.

LogManager now has AddRule methods

Rules can now be created directly in the LogManager. There are some overloads to keep things simple.

Before:

varconfig=newLoggingConfiguration();varfileTarget=newFileTarget();config.AddTarget("f1",fileTarget);config.LoggingRules.Add(newLoggingRule("*",LogLevel.Debug,LogLevel.Error,fileTarget));LogManager.Configuration=config;

now also possible:

varconfig=newLoggingConfiguration();varfileTarget=newFileTarget("f1");config.AddTarget(fileTarget);config.AddRule(LogLevel.Debug,LogLevel.Fatal,"f1");LogManager.Configuration=config;

or

varconfig=newLoggingConfiguration();varfileTarget=newFileTarget{name:"f1"};config.AddRule(LogLevel.Debug,LogLevel.Fatal,fileTarget);LogManager.Configuration=config;

Relative paths for fileTarget

FileTarget now supports relative paths. No need for ${basedir} in the file target anymore!

InternalLogger: write to System.Diagnostics.Trace

It’s now possible to write to let the internal logger write to System.Diagnostics.Trace. The trace is easy to follow within Visual Studio.

image

<nloginternalLogToTrace="true"

or c# InternalLogger.LogToTrace = true;

Other features

Smaller improvements

Targets

  • Mail Target: allow virtual paths for SMTP pickup
  • EventTarget: option to set the maximum length of the message and action (discard, split, truncate)
  • MethodCallTarget: allow optional parameters in called methods.
  • ConsoleTarget: regex cache is instead of compiled regex, for better memory usage. This is configurable.
  • Database target: doesn’t require “ProviderName” attribute when using <connectionStrings>

Layouts

  • RegistryLayout: support for layouts, RegistryView (32, 64 bit) and all root key names (HKCU/HKLM etc)

API

  • Allow to free CallContext in MappedDiagnosticsLogicalContext
  • LogFactory: add generic-type versions of GetLogger() and GetCurrentClassLogger()
  • Added Logger.Swallow(Task task)

Other

  • Unused targets will be logged to the internal logger
  • Config classes are now thread-safe.
  • InternalLogger: improved logging of exceptions (analogous to normal Logger)
  • More logging to the internal logger (e.g. Async wrapper and buffer wrapper)
  • Added timestamp options for the internal logger:
    • Added “internalLogIncludeTimestamp” option to <NLog>
    • Added “nlog.internalLogIncludeTimestamp” option <appSettings>
    • Added NLOG_INTERNAL_INCLUDE_TIMESTAMP environment setting
  • Read nlog.config from Android assets:
LogManager.Configuration=newXmlLoggingConfiguration("assets/nlog.config");

Bug fixes

Various bugs have been fixed in this version. The most noticeable:

  • ${callsite} works now for async methods!
  • A lot of Filetarget bug fixes regarding with archiving, locking and concurrent writing. See GitHub issues for all details. Most noticeable:
    • Use last-write-time for archive file name. This is far more stable. In the past there were some issues with unexpected archive filenames.
    • Fix: archiving won’t work when a there is a date in the filename
    • Fix: archiving not working properly with AsyncWrapper
    • Fix: footer for archiving
    • Fix: crashes with relative path without ${basedir}
    • Fix: archive files are never created when there are lot of writes in log file
  • NetworkTarget: fix possible deadlock
  • Fix autoreload nlog.config with parent configs.
  • WebServiceTarget: fix HTTP GET protocol
  • Bugfix: Internallogger creates folder, even when turned off
  • Fix possible Nullref in ${variable}
  • ${processtime}: incorrect milliseconds formatting
  • ${processtime}: fix incorrect negative time (rounding issue)

Thanks to!!


New NLog OWIN adapter has been released

$
0
0

We’re proud to announce that the former community project NLogAdapter is now part of NLog as NLog.Owin.Logging to provide a Microsoft.Owin.Logging.ILoggerFactory implementation for your OWIN pipeline.

Usage is as simple as:

PM > Install-Package NLog.Owin.Logging
usingNLog.Owin.Logging;publicclassStartup{publicvoidConfiguration(IAppBuilderapp){app.UseNLog();}}

NLog 4.3 has been released!

$
0
0

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!

The release can be downloaded from NuGet.

Check for all the details the GitHub 4.3 milestone.

For those who have contributed to NLog, big thanks!

Features

This release contains the following features:

Support Windows Phone 8, Xamarin Android and Xamarin iOS (beta)

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.

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 on the wiki.

Consistent handling of exceptions (BEHAVIOUR CHANGE)

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.

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!

  • All exceptions are logged to the internal logger
  • The “throwExceptions” option will be respected in all cases

Advise: disable throwExceptions in production environments! (this the default)

<nlogthrowExceptions="false">

Control of exception throwing for configuration errors

The following is stated in multiple locations: > By default exceptions are not thrown under any circumstances.

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!

We now introduce the “throwConfigExceptions” option:

<nlogthrowConfigExceptions="true|false|<empty>">
LogManager.ThrowConfigExceptions=true|false|null
  • If set to true, if will throw exceptions for configuration errors. Set this to true if you like the behaviour from NLog 4.2 and ealier.
  • If set to empty (or null in the API), this option will follow the “throwExceptions” option (previous section)
  • If set to false, don’t throw exceptions for configuration errors.

Also throwing exceptions for a configuration error
could lead to System.TypeInitializationException which is bad and confusing as sending info with the exception is difficult or sometimes impossible - see stackoverflow.

API improvements

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 SimpleConfigurator was a hint things weren’t simple enough ;)

Changes:

  • LogManager has now AddRule methods. See examples below.
  • Set the max log level in the LoggingRule constructor.
  • The name of the TargetAttribute is used as fallback for every target now.

LogManager now has AddRule methods

Rules can now be created directly in the LogManager. There are some overloads to keep things simple.

Before:

varconfig=newLoggingConfiguration();varfileTarget=newFileTarget();config.AddTarget("f1",fileTarget);config.LoggingRules.Add(newLoggingRule("*",LogLevel.Debug,LogLevel.Error,fileTarget));LogManager.Configuration=config;

now also possible:

varconfig=newLoggingConfiguration();varfileTarget=newFileTarget("f1");config.AddTarget(fileTarget);config.AddRule(LogLevel.Debug,LogLevel.Fatal,"f1");LogManager.Configuration=config;

or

varconfig=newLoggingConfiguration();varfileTarget=newFileTarget{name:"f1"};config.AddRule(LogLevel.Debug,LogLevel.Fatal,fileTarget);LogManager.Configuration=config;

Relative paths for fileTarget

FileTarget now supports relative paths. No need for ${basedir} in the file target anymore!

InternalLogger: write to System.Diagnostics.Trace

It’s now possible to write to let the internal logger write to System.Diagnostics.Trace. The trace is easy to follow within Visual Studio.

image

<nloginternalLogToTrace="true"

or c# InternalLogger.LogToTrace = true;

Other features

Smaller improvements

Targets

  • Mail Target: allow virtual paths for SMTP pickup
  • EventTarget: option to set the maximum length of the message and action (discard, split, truncate)
  • MethodCallTarget: allow optional parameters in called methods.
  • ConsoleTarget: regex cache is instead of compiled regex, for better memory usage. This is configurable.
  • Database target: doesn’t require “ProviderName” attribute when using <connectionStrings>

Layouts

  • RegistryLayout: support for layouts, RegistryView (32, 64 bit) and all root key names (HKCU/HKLM etc)

API

  • Allow to free CallContext in MappedDiagnosticsLogicalContext
  • LogFactory: add generic-type versions of GetLogger() and GetCurrentClassLogger()
  • Added Logger.Swallow(Task task)

Other

  • Unused targets will be logged to the internal logger
  • Config classes are now thread-safe.
  • InternalLogger: improved logging of exceptions (analogous to normal Logger)
  • More logging to the internal logger (e.g. Async wrapper and buffer wrapper)
  • Added timestamp options for the internal logger:
    • Added “internalLogIncludeTimestamp” option to <NLog>
    • Added “nlog.internalLogIncludeTimestamp” option <appSettings>
    • Added NLOG_INTERNAL_INCLUDE_TIMESTAMP environment setting
  • NLog reads NLog.Config from Android Assets.

Bug fixes

Various bugs have been fixed in this version. The most noticeable:

  • ${callsite} works now for async methods!
  • A lot of Filetarget bug fixes regarding with archiving, locking and concurrent writing. See GitHub issues for all details. Most noticeable:
    • Use last-write-time for archive file name. This is far more stable. In the past there were some issues with unexpected archive filenames.
    • Fix: archiving won’t work when a there is a date in the filename
    • Fix: archiving not working properly with AsyncWrapper
    • Fix: footer for archiving
    • Fix: crashes with relative path without ${basedir}
    • Fix: archive files are never created when there are lot of writes in log file
    • Fix: writing file to root wasn’t working
  • NetworkTarget: fix possible deadlock
  • Fix autoreload nlog.config with parent configs.
  • WebServiceTarget: fix HTTP GET protocol
  • Bugfix: Internallogger creates folder, even when turned off
  • Fix possible Nullref in ${variable}
  • ${processtime}: incorrect milliseconds formatting
  • ${processtime}: fix incorrect negative time (rounding issue)

Thanks to!!

NLog roadmap - .NET Core, structural logging & performance

$
0
0

We have the following releases planned for NLog:

NLog 4.4

no .NET Core, yet

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 GetCurrentClassLogger is wrong and we can’t fix it as the StackTrace API is limited in .NET Core (see here). You can read more about it here. We will postpone .NET Core support to NLog 5.

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.

Better handling of invalid config

Currently, some mistakes in the config could lead to no logging at all. For example, if ${aspnet-item} is used in the file target and NLog.Web was not included, no files are written.

We will fix this in NLog 4.4 and we will replace the wrong part with an empty string. See this PR.

Easier extending

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:

LayoutRenderer.RegisterLayoutRenderer("trace-identifier", (logEvent) =>  HttpContext.Current.TraceIdentifier );

Steam and byte pooling (performance)

Currently under development, thanks to @bjornbouetsmith and @snakefoot!

This change will decrease memory pressure and prevent (excessive) garbage collection.

For details, see PR 1397 and and PR 1663

NLog 4.5

Structural logging

We would like to support structural logging like Serilog. We are currently working on an own parser and renderer. More info here.

NLog 5

NLog 5 will have .NET Core support and we will push some small breaking changes.

NLog 6

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!

NLog 4.4 is live!

$
0
0

NLog 4.4 contains new features, performance improvements and makes it easier to write custom components (e.g. targets, layout renderers) for NLog!

A lot of stuff has been contributed by the community! Thanks for making NLog great!

Main features

WebServiceTarget support for JSON & XML

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!

Example

<targettype='WebService'name='ws'url='http://localhost:1234/logme'protocol='JsonPost'encoding='UTF-8'><parametername='param1'type='System.String'layout='${message}'/><parametername='param2'type='System.String'layout='${level}'/></target>

Injecting JSON serializer into NLog

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.

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 the statement of RestSharp library (which is also a great library)

So we now have our own implementation, which is sufficient for most cases.

Do you like to choose your implementation? Implement SerializeObject(..) in IJsonSerializer and set it to ConfigurationItemFactory.JsonSerializer.

JSON layout support for all-event-properties

The JsonLayout has two new properties which will help you creating better JSON documents:

  • includeAllProperties: Include all events properties of a logevent? default: false. Introduced in NLog 4.4
  • 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

Example:

<layoutxsi:type="JsonLayout"includeAllProperties="true"excludeProperties="BadPropertyName1, BadProperty2"><fieldname="message"layout="My message for you is this ${message}"/></layout>

Don’t stop logging when there is something wrong in the layout

Previously, if you made an error in a layout, e.g. typos:

<targetname="file"xsi:type="File"layout="${message} ${oops-I-made-a-typo}">

or just using a layout renderer from a non-included package, nothing got logged!

This is unneccesary and we are skipping the invalid parts now. The invalid parts are replaced with an empty string.

NB: If throwExceptions or throwConfigExceptions is true, there will be still an error thrown

Lamba Function layout renderers

Layout renders (those things between ${}) can help you writing context information.

Since NLog 4.4 there is a new way to create a custom layout renderer, which can be written on one line!

The new LayoutRenderer.Register accepts a lamba function, which accepts 1 or 2 parameters and should return a string.

  • 1 parameter: the logEventInfo.
  • 2 parameters: logEventInfo and the current NLog config.

Examples

//register ${text-fixed}LayoutRenderer.Register("test-fixed",(logEvent)=>"2");//register ${trace-identifier}LayoutRenderer.Register("trace-identifier",(logEvent)=>HttpContext.Current.TraceIdentifier);//Using logEventInfo, ${message-length}LayoutRenderer.Register("message-length",(logEvent)=>logEvent.Message.Length);//Using config, ${targetCount}LayoutRenderer.Register("targetCount",(logEvent,config)=>config.AllTargets.Count);

See the wiki

Make it easier to register custom layout / target / layoutrendeners

There is a new syntax introduced so it’s easier to register your custom extensions:

//targetTarget.Register<MyNamespace.MyFirstTarget>("MyFirst");//genericTarget.Register("MyFirst",typeof(MyNamespace.MyFirstTarget));//OR, dynamic//layout rendererLayoutRenderer.Register<MyNamespace.MyFirstLayoutRenderer>("MyFirst");//genericLayoutRenderer.Register("MyFirst",typeof(MyNamespace.MyFirstLayoutRenderer));//dynamic//layoutLayout.Register<MyNamespace.CsvLayout>("csv");//genericLayout.Register("csv",typeof(MyNamespace.CsvLayout));//dynamic

For more info, see the wiki

Collection types for custom extensions

Custom Targets, layout etc. can have properties. There are only limitations if you’d like to set them from the XML config.

The following types are supported:

Allowed types

Allowed types for Targets, Layouts and Layout renderers.

  • C# types: e.g. bool, char, decimal, double, float, int, uint, etc.
  • Enums (use short name)
  • Encoding
  • CultureInfo
  • Type
  • LineEndingMode
  • Uri
  • NLog types: Layout, SimpleLayout& ConditionExpression
  • Types which has an implicit conversion from string
  • Types which are using TypeDescriptor from string (not Silverlight)
  • Collections, introduced in NLog 4.4. See section Collection types

Collection types

Introduced in NLog 4.4, the following collection types can be used.

Usage in XML: comma separated string. If the value contains a comma, single quote the whole value.

Examples:

  • value="one arg"
  • value="1,2"
  • value="value1,'value2, with comma'"

Collections of type:

  • IList<T> / IList
  • IEnumerable<T> / IEnumerable
  • ISet<T> / HashSet<T>

with the following types:

  • C# built in types (string, int, double, object)
  • enum (use short name)
  • culture, encoding, Type
  • not supported: Layout

Not supported:

  • Arrays
  • Non-generic List
  • Non-gereric IList
  • Custom class implementing/inheriting from the collection classes/interfaces. (because of performance)

PS: .NET 3.5 has HashSet but no ISet

Added condition to AutoFlushWrappper

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!

This is now possible by using the Condition property on AutoFlushWrappper

Example:

<targetname="file"xsi:type="AutoFlushWrapper"condition="level >= LogLevel.Error"><targetxsi:type="BufferingWrapper"..><targetname="gmail"xsi:type="Mail"smtpServer="smtp.gmail.com"smtpPort="587"smtpAuthentication="Basic"/></target></target>

LimitingTargetWrapper

Like sending mail but not every 10 seconds? With the LimitingTargetWrapper you can control the maximum events per interval.

Example, max 5 messages per 10 minutes

<targetname='limiting'type='LimitingWrapper'messagelimit='5'interval='0:10:00'><targetname="gmail"xsi:type="Mail"smtpServer="smtp.gmail.com"smtpPort="587"smtpAuthentication="Basic"/></target>

WindowsMultiProcessFileAppender

In Windows there is a new file writing implementation. From tests we have 10-40% performance increase!

WebServiceTarget & ${UrlEncode} - Added standard support for UTF8 encoding, added support for RFC2396 & RFC3986

The URL encoding for the WebServiceTarget was not behaving to any RFC as far as we know. This has been changed!

For the WebServiceTarget & ${UrlEncode}, NLog will by default encode parameters as UTF8 and escape special characters according to Rfc2396.

Also the following properties have been added to WebServiceTarget & ${UrlEncode}

  • escapeDataRfc3986 - To escape data according to standard Rc3986, set this option to true
  • escapeDataNLogLegacy - To escape data according to the old non-standard NLog style, set this option to true

Other additions and changes

  • ${exception} - Added support for AggregateException
  • Keeping variables during configuration reload (optional)
  • Layout processinfo with support for custom Format-string
  • DetectConsoleAvailable on (colored)Console disabled by default
  • Callsite: added includeNamespace option

Bugfixes:

  • Writing to the same file from multiple processes does not function when archiving with concurrentWrites="true" and keepFileOpen="true"
  • NLog throws ConfigurationErrorsException when appsettings has invalid XML.

Other:

  • Improved [Obsolete] warnings - include the Nlog version when it became obsolete
  • FileTarget - Close stale file handles outside archive mutex lock #1513

THANKS!

Thanks for the contributions!

  • @aireq
  • @AndreGleichner
  • @ie-zero
  • @Jeinhaus
  • @nazim9214
  • @snakefoot
  • @tetrodoxin

What’s up Next?

Structural logging!

We could use your help to introduce this feature soon!

Like to help with coding or testing? Please let us know!

NLog 4.5 is live!

$
0
0

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.

Main features

.NET Core Support

NLog 4.5 provides official support for .NET Core without any breaking changes!

  • .NET Standard 1.3 - Minimal dependencies for limited .NET Core 1 platforms (Ex. UWP1)
  • .NET Standard 1.5 - Normal dependencies for standard .NET Core 1 platforms
  • .NET Standard 2.0 - Normal dependencies for standard .NET Core 2 platforms

Message Template Support

Structured Logging support in NLog has been extended to also handle message templates. Joining the wave started by Serilog and Microsoft Extension Logging:

logger.Info("Order {orderid} created for {user}",42,"Kenny");

See also How to use structured logging

JsonLayout Object Reflection Support

JsonLayout can now perform object reflection and navigate object-collections. This allows one to use anonymous object properties together with structured logging:

logger.Info("Item {shopitem} added to {orderid}",new{Id=123,Name="Jacket",Color="Orange"},42);

Enable object reflection by configuring maxRecursionLimit:

<layouttype="JsonLayout"includeAllProperties="true"maxRecursionLimit="10"/>

Will give the following output:

{"shopitem":{"Id":123,"Name":"Jacket","Color":"Orange"},"orderid":42}

It is now also possible to toggle Json serialization in these selected layoutrenderers by specifying format=@:

  • ${event-properties:format=@}
  • ${exception:format=@}
  • ${gdc:format=@} - Global Context
  • ${mdc:format=@} - Thread Context
  • ${mdlc:format=@} - Async Context

It is also possible to introduce your own favorite Json-Serializer by creating you own implementation of IJsonConverter and assign it to NLog.Config.ConfigurationItemFactory.Default.JsonConverter.

Easier FileTarget Archive Setup

Previous NLog versions had several restrictions for how to configure FileTarget archive logic. Example if not specifying archiveFileName then it was very important to perform logging in an isolated folder to avoid deleting all files.

This is no longer the case, and one can setup file archive with very few parameters:

<targettype="file"logfile="hello.txt"archiveAboveSize="1000000"maxArchiveFiles="10"/>

Many other improvements

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

NLog 4.6 is live!

$
0
0

NLog 4.6 contains lots of new features and performance improvements.

Main features

DatabaseTarget supports parameter types

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

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

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

NetworkTarget supports SSL & TLS

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

<targetname="net"type="network"address="tcp://127.0.0.1"sslProtocols="Tls12"/>

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

New XmlLayout

XmlLayout is now available for creating XML files.

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

<layoutxsi:type="XmlLayout"includeAllProperties="True"elementName='logevent'><attributename="time"layout="${longdate}"/><attributename="level"layout="${level:upperCase=true}"/><elementname="message"layout="${message}"/></layout>

Will write:

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

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

<parametername="@props"dbType="SqlDbType.Xml"size="-1"><layouttype="xmllayout"includeAllProperties="true"/></parameter>

Variables in level attributes

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

e.g.

<nlog><variablename='myLevel'value='debug'/><rules><loggerminLevel='${myLevel}'/></rules></nlog>

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

Added default action for filtering

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

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

<rules><loggername='*'level='Warn'writeTo='myTarget'><filtersdefaultAction='Ignore'><whencondition="starts-with(message, 't')"action='Log'/></filters></logger></rules>

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

Substring, left and right

New layout renders has been added:

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

Name filter: support for multiple wildcards and in any position

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

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

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

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

Examples

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

InternalLogFile variables

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

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

example:

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

AsyncWrapper uses ConcurrentQueue

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

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

AsyncWrapper with faster timer

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

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

ColoredConsoleTarget supports Ansi output

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

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

AppSetting without NLog.Extended

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

Snupkg

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

LibLog Breaking change

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

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

Many other improvements

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

Happy logging!

NLog 4.5 is near! (and no NLog 5 for now)

$
0
0

With the releases of NLog 4.5 RC, a RTM release is near!

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!

Summary of the most important changes in NLog 4.5:

Features:

  • Support for .Net Standard 1.5 #2341
  • Support for .Net Standard 2.0 #2263 + #2402
  • Support for UWP #2441 (Remember to manually flush on app suspend).
  • Introduced Structured logging #2208 + #2262 + #2244
  • Default file archive logic is now easier to use #1993
  • Introduced InstallationContext.ThrowExceptions #2214
  • WebServiceTarget - Allow configuration of proxy address #2375
  • Json conversion also supports object properties #2179
  • event-properties layout-renderer can now render objects as json #2241
  • exception layout-renderer can now render exceptions as json #2357
  • ${guid}, added GeneratedFromLogEvent #2226
  • TraceTarget RawWrite to always perform Trace.WriteLine independent of LogLevel #1968
  • Adding OverflowAction options to BufferingTargetWrapper #2276
  • WhenRepeatedFilter #2123 + #2297
  • ${callsite} added CleanNamesOfAsyncContinuations option #2292
  • ${ndlctiming} allows timing of ndlc-scopes #2377
  • NLogViewerTarget - Enable override of the Logger-name #2390
  • ${sequenceid} added #2411
  • Added “regex-matches” for filtering #2437

BugFixes:

  • Improved archive stability during concurrent file access #1889
  • FallbackGroup could lose log events #2265
  • Exception separator should only be inserted for available items #2250
  • ${exception} - only include separator when items are available #2257
  • LogFactory - Fixes broken EventArgs for ConfigurationChanged #1897
  • Do not report wrapped targets as unused targets #2290
  • Added IIncludeContext, implemented missing properties #2117
  • Improved logging of callsite linenumber for async-methods #2386
  • NLogTraceListener - DisableFlush is enabled by default when AutoFlush=true #2407
  • NLogViewer - Better defaults for connection limits #2404
  • LoggingConfiguration.LoggingRules is not thread safe #2393, #2418

Performance:

  • More targets has OptimizeBufferReuse enabled by default #1913 + #1923 + #1912 + #1911 + #1910 + #1909 + #1908 + #1907
  • StringBuilderPool - Improved Layout Render Performance by reusing StringBuilders #2208
  • JsonLayout - Improved Layout Performance, by optimizing use of StringBuilder #2208
  • FileTarget - Faster byte-encoding of log messsages, by using crude Encoding.GetMaxByteCount() instead of exact Encoding.GetByteCount() #2208
  • Target - Precalculate Layout should ignore sub-layouts for complex layout (Ex Json) #2378

What happend to NLog 5?

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!

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

This means that NLog 4.5 will have the support for the platforms added in NLog 5, thus making NLog 5 obsolete!

The best part, there are no breaking changes between NLog 4.x and NLog 4.5! (we take semver very serious!)


NLog 4.7 has been released!

$
0
0

NLog 4.7 marks another year of new features and performance improvements.

Main features

LogFactory Setup

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 LogFactory.Setup(). This will also prepare the road for improving the support for multiple isolated LogFactory instances in the same application.

Custom Object Serialization

It is now possible to customize the serialization of different object types. One can exclude unwanted properties, or add new artificial properties.

Examples

Ensures that object-reflection is skipped for all objects that implements IDangerousObject:

NLog.LogManager.Setup().SetupSerialization(s=>s.RegisterObjectTransformation<IDangerousObject>(o=>o.ToString()));

Ensures that only selected properties for objects of the type System.Net.WebException:

NLog.LogManager.Setup().SetupSerialization(s=>s.RegisterObjectTransformation<System.Net.WebException>(ex=>new{Type=ex.GetType().ToString(),Message=ex.Message,StackTrace=ex.StackTrace,Source=ex.Source,InnerException=ex.InnerException,Status=ex.Status,Response=ex.Response.ToString(),// Call your custom method to render stream as string}));

This can be used together with ${exception:format=@} or the Properties-Format-option ${exception:format=Properties}.

Lambda Condition Methods

NLog already has two ways for adding own custom condition methods:

  • Create static class with class-attribute [ConditionMethods] and add static methods with function-attribute [ConditionMethod]. Then add the assembly to be registered as an extension.
  • Explicit register a static method using ConfigurationItemFactory.Default.ConditionMethods.RegisterDefinition().

Now it is also possible to register lamdba methods:

LogManager.Setup().SetupExtensions(s=>s.RegisterConditionMethod("hasParameters",evt=>evt.Parameters?.Length>0));

And of course standard static methods:

LogManager.Setup().SetupExtensions(s=>s.RegisterConditionMethod("hasPriority",typeof(NLogConditionMethods).GetMethod("HasPriority",BindingFlags.Static)));

FileTarget MaxArchiveDays

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 ArchiveAboveSize have produced several files for the same day. It can be used in combination with the existing setting MaxArchiveFiles, so one will not have more than ex. 60 files in total.

DatabaseTarget Custom Connection Properties

DatabaseTarget is very generic and supports multiple DbProviders. Certain DbProviders might have additional connection properties. Like SqlConnection.AccessToken for Azure AD Access Token.

Now it is possible to configure additional connection properties:

<targetname="db"xsi:type="Database"connectionstring="..."><connectionPropertyname="AccessToken"layout="${gdc:AccessToken}"propertyType="System.String"/></target>

All configured connection properties will be applied before opening the connection. In the above example then one must handle expiry of the AccessToken in ${gdc:AccessToken}, by creating a custom background timer that will refresh the Azure AccessToken in timely manner.

DatabaseTarget Transaction IsolationLevel

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 Isolationlevel, 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.

Make sure to use the AsyncWrapper to write logevents in batches to the DatabaseTarget:

<targetname="db_async"xsi:type="AsyncWrapper"><targetname="db"xsi:type="Database"connectionstring="..."isolationLevel="ReadCommitted"></target></target>

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 ;ENLIST=FALSE to the ConnectionString.

InternalLogger LogMessageReceived

NLog InternalLogger now has support for raising events, instead of having to create a custom ITextWriter and assign it as to InternalLogger.LogWriter.

InternalLogger.LogMessageReceived+=(sender,e)=>SomethingUseful(e);

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.

The new releases will now be tagged by Microsoft.SourceLink.GitHub, that will allow easier debugging with NLog source code available from Github. See also the Scott Hanselman blog

.NET Core Single File Publish

.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 AppDomain.BaseDirectory, then one will get a secret temporary folder, where the single executable file has been unzipped to.

NLog uses AppDomain.BaseDirectory 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 ${basedir} with this special option:

<targettype="file"fileName="${basedir:fixtempdir=true}\App.txt"/>

If wanting to support override of the NLog.config, that has been packaged into the single file (Ex. SingleApp.exe). Then one must rename NLog.config to SingleApp.exe.nlog. Then NLog will prioritize the SingleApp.exe.nlog placed next to the actual SingleApp.exe, but will fallback to SingleApp.exe.nlog in the secret temp folder.

Single File Publish can also be combined with PublishTrimmed that trims the single executable to a minimum. See also the Scott Hanselman blog

<PublishSingleFile>true</PublishSingleFile><PublishTrimmed>true</PublishTrimmed><RuntimeIdentifier>win-x64</RuntimeIdentifier>

Many other improvements

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

NLog 5.0 - List of major changes

$
0
0

NLog 5.0 is a major version bump, and includes several breaking changes and lots of improvements.

New Features

NLog is now faster and lighter

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.

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 <add assembly="NLog.MyAssembly" />, or use the new ability to specify type with assembly-name: <target type="MyTarget, NLog.MyAssembly" name="hello" />.

NLog also skips initialization of NLog InternalLogger from environment variables and app.config. This also reduces the impact on initialization time.

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.

These references will no longer be added automatically, when wanting to use the NLog Logger in a .NET Framework-project:

  • <Reference Include="System.Data" />
  • <Reference Include="System.Runtime.Serialization" />
  • <Reference Include="System.ServiceModel" />
  • <Reference Include="System.Transactions" />

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.

NLog Layout for everything

NLog Layout logic is almost magical especially when creating string output, but less magical when handling simple output types.

This is the usual code when using Layout for an integer value:

inteventId=0;stringrenderEventId=EventIdLayout.Render(logEvent);if(string.IsNullOrEmpty(renderEventId)||!int.TryParse(renderEventId,outeventId)){eventId=42;// fallback default value}

This has now been improved with the introduction of Layout<T> that automatically handles parsing and fallback value, and at the same time provides better performance than normal Layout when handling static values.

inteventId=EventIdLayout.RenderValue(logEvent,defaultValue:42);

This makes it easier for NLog Target developers to use NLog Layout everywhere without having to worry about handling parsing and conversion issues.

NLog Targets that has been extracted from the default NLog-nuget-package has now also been updated to make use of the new Layout<T>-features.

NLog ScopeContext to replace MDC + MDLC + NDC + NDLC

NLog ScopeContext has been introduced to cater for Microsoft Extension Logging (MEL) ILogger.BeginScope. 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 ofILogger.BeginScope has been improved dramatically.

These are the performance numbers when just using ILogger.BeginScope but no logevents are written.

Test NameTime (ms)Calls/secGC2GC1GC0CPU (ms)Alloc (MB)
NLog v5.06.0261.659.339003936.1565.493,2
NLog v4.720.144496.41500118720.79616.479,5

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 ILogger.BeginScope way of pushing context-properties and nested context-state in a single call.

NLog Logger object also includes new methods Logger.PushScopeProperty and Logger.PushScopeNested to make it easy to update the NLog ScopeContext.

NLog Layout stored as NLog Configuration Variables

NLog Configuration Variables now has support for other types of Layouts than SimpleLayout. This means a NLog Configuration Variable can hold a JsonLayout, and it can be referenced by multiple targets.

<nlog><variablename="myJson"><layouttype="JsonLayout"><attributename="shortdate"layout="${shortdate}"/><attributename="message"layout="${message}"/></layout></variable><targets><targettype="console"layout="${myJson}"/><targettype="file"layout="${myJson}"/></targets><rules><loggerminLevel="Debug"writeTo="console,file"/></rules></nlog>

Fluent API for NLog LoggingConfiguration

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.

NLog has extended its NLog.LogManager.Setup() to make it easy to setup NLog Targets and filtering with NLog LoggingRules:

varlogger=LogManager.Setup().LoadConfiguration(c=>{c.ForLogger("*").FilterMinLevel(NLog.LogLevel.Info).WriteTo(newConsoleTarget("logconsole")).WithAsync();c.ForLogger().WriteTo(newFileTarget("logfile"){FileName="file.txt"}).WithAsync();}).GetCurrentClassLogger();

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:

varlogger=LogManager.Setup().LoadConfiguration(c=>{varconsoleTarget=c.ForTarget("console").WriteTo(newConsoleTarget()).WithAsync();varfileTarget=c.ForTarget("logfile").WriteTo(newFileTarget(){FileName="file.txt"}).WithAsync();// Suppress noise from Microsoft-classes, except from Microsoft.Hosting.Lifetime for startup detectionc.ForLogger("Microsoft.Hosting.Lifetime*").FilterMinLevel(NLog.LogLevel.Info).WriteTo(consoleTarget);c.ForLogger("System*").WriteToNil(NLog.LogLevel.Warn);c.ForLogger("Microsoft*").WriteToNil(NLog.LogLevel.Warn);c.ForLogger().FilterMinLevel(NLog.LogLevel.Info).WriteTo(consoleTarget);c.ForLogger().FilterMinLevel(NLog.LogLevel.Debug).WriteTo(fileTarget);}).GetCurrentClassLogger();

NLog Callsite from caller member attributes

NLog already had support for caller member attributes through the NLog.Fluent-API. But it saved the CallSite-information intoLogEventInfo.Properties. This has now changed so it will use the method LogEventInfo.SetCallerInfo, so it is no longer necessary to exclude the sometimes unwanted properties.

${callsite} no longer requires the capture of StackTrace to render the callsite, but can rely on the input fromLogEventInfo.SetCallerInfo. This means that ${callsite} will have much less overhead when using API that usesLogEventInfo.SetCallerInfo.

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 LogEventBuilder has been introduced in the standard NLog-namespace:

logger.ForErrorEvent().Message("This is a test fluent message.").Property("Test","TraceWrite").Log();

When using LogEventBuilder for logging, then it will automatically captures callsite details with very little overhead with help from C# caller member attributes.

LogFactory with Dependency Injection

NLog now includes better support for dependency injection, so instead of having a global object-factory-delegate that affects all instances of NLog LogFactory:

NLog.Config.ConfigurationItemFactory.Default.CreateInstance=(type)=>System.Activator.CreateInstance(type);

Then NLog LogFactory now has an isolated ServiceRepository, where one can register own custom interface-implementations or external System.IServiceProvider:

NLog.LogManager.Setup().SetupExtensions(ext=>ext.RegisterSingletonService<IMyInterface>(singletonInstance));NLog.LogManager.Setup().SetupExtensions(ext=>ext.RegisterServiceProvider((IServiceProvider)externalDependencyInjection));

External dependencies can now be resolved during Target- or Layout-initialization like this:

protectedoverridevoidInitializeTarget(){varwantedDependency=ResolveService<IMyInterface>();}

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 ResolveService() throw exception when wanted dependency is not yet available. When InitializeTarget() 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.

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.

Breaking Changes

Strong Version Changed

The major version has been bumped for the strong-version to v5.0.0.0 (from v4.0.0.0).

  • Impact: .NET framework applications will have to be recompiled to use NLog 5.0.

  • Reason: Major version must be bumped to protect application from runtime compile errors.

  • Workaround: Upgrade to .NET Core where assembly strong version doesn’t have the same meaning. Alternative one can make use of binding-redirects, as the NLog 5 API includes the NLog 4 API except for methods that has been deprecated for a long time.

Obsolete methods have been removed

Lots of obsolete methods and properties in the NLog API has now been removed.

  • Impact: Applications that depends on the deprecated NLog API will fail to compile and run.

  • Reason: Removing obsolete logic reduces code complexity and code maintenance.

  • Workaround: 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.

Xamarin, Windows Phone and Silverlight platforms have been removed

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.

  • Impact: 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.

  • Reason: 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.

  • Workaround: 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.

    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):

    NLog.LogManager.Setup().LoadConfigurationFromAssemblyResource(typeof(App).GetTypeInfo().Assembly);

.NET Framework v4.0 platform removed and replaced with .NET Framework v4.6

NLog have removed direct support for .NET Framework v4.0, instead it will fallback to .NET Framework v3.5.

  • Impact: There is very little difference between NLog for .NET Framework v3.5 and NLog for .NET Framework v4.

  • Reason: 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.

  • Workaround: 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.

NLog Extensions assemblies will not load automatically

  • Impact: 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 <extensions>-sections. NLog will now fail to load unrecognized targets and layouts, that depends on unreferenced external NLog extension assemblies.

  • Reason: 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.

  • Workaround: NLog extensions assemblies can be specified explicitly in the NLog.config:

    <nlog><extensions><addassembly="NLog.MyAssembly"/></extensions></nlog>

    NLog extensions assemblies can also be extracted from the type-name in the NLog.config:

    <nlog><targets><targettype="MyTarget, NLog.MyAssembly"name="hello"/></targets></nlog>

    NLog provides a method to force automatic loading of NLog extensions, before loading the NLog.config:

    NLog.LogManager.Setup().SetupExtensions(ext=>ext.AutoLoadExtensions());

    Alternative one can update the NLog.config with the option AutoLoadExtensions="true":

    <nlogautoloadExtensions="true"></nlog>

NLog Targets extracted into their own nuget-packages

The following NLog targets has been extracted from the NLog-nuget-package to their own isolated nuget-packages:

The following NLog layoutrenderers has been extracted from the NLog-nuget-package to their own isolated nuget-packages:

  • PerformanceCounterLayoutRenderer - NLog.PerformanceCounter-package
  • RegistryLayoutRenderer - NLog.WindowsRegistry-package
  • WindowsIdentityLayoutRenderer - NLog.WindowsIdentity-package
  • QueryPerformanceCounterLayoutRenderer - Dropped into the ocean of dead code.

  • Impact: 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.

  • Reason: 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.

  • Workaround: Consider creating a meta nuget-package with your favorite collection of NLog-nuget-packages, and change your projects to depend on this.

Deprecated NLog.Extended nuget-package

NLog.Extended nuget-package will no longer be released. The MSMQ-target has been extracted into its own nuget-package.

  • Impact: NLog.Extended-nuget-package will no longer be compatible with latest NLog and should be removed.

  • Reason: 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.

  • Workaround: Change from NLog.Extended nuget-package to the specific NLog-nuget-package needed.

Deprecated NLog.Config nuget-package

NLog.Config nuget-package will no longer be released.

  • Impact: NLog.Config-nuget-package will no longer be compatible with latest NLog and should be removed.

  • Reason: NLog.Config-nuget-package stopped working properly when Microsoft refactored the nuget-package-system to support <packagereference>. 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.

  • Workaround: Manually create the NLog.config file and add it to the application-project. Manually add NLog.Schema-package for intellisense in NLog.config.

Automatic loading of NLog.config now first check for exe.nlog

NLog will now first check for Application.exe.nlog at startup, before using NLog.config

  • Impact:NLog.config will be ignored if application specific .exe.nlog-file is found.

  • Reason: Fixing bug that was introduced long time ago, but required major version bump to revert the behavior.

  • Workaround: Decide on whether to use Application.exe.nlog or NLog.config and remove the other.

NLog Configuration will have KeepVariablesOnReload enabled by default

NLog Configuration Variables assigned at runtime will now automatically survive when using autoReload="true".

  • Impact: NLog Configuration Variables assigned from API will no longer be reset on reload NLog.config.

  • Reason: Better user experience when using autoReload="true" and updating NLog Configuration Variables at runtime.

  • Workaround: Explictly configure KeepVariablesOnReload="false" in NLog.config

Layout and LayoutRenderer are now threadsafe by default

NLog now always expects Layout and LayoutRenderer to be threadsafe, and will no longer check the [ThreadSafe]-class-attribute.

  • Impact: NLog Targets will no longer attempt to protect against 3rd Party Layout-logic that might not be threadsafe.

  • Reason: The [ThreadSafe]-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.

  • Workaround: Explicitly configure the Target-option LayoutWithLock="true" if target is using 3rd Party Layout-logic that is not threadsafe.

Default Layout for NLog Targets has been updated

Changed from this default value:

${longdate}|${level:uppercase=true}|${logger}|${message}

To this new default value:

${longdate}|${level:uppercase=true}|${logger}|${message:withexception=true}
  • Impact: NLog targets that have not explicit assigned default layout will now also include exception-details.

  • Reason: Better user experience when using default configuration. When using NLog to diagnose problems then exception information is often important.

  • Workaround: Explicit assign the Layout-property on the target if other output is wanted.

Default Format for NLog Exception layoutrenderer has been updated

Change from this default value:

${exception:format=message}

To this new default value:

${exception:format=tostring,data}
  • Impact: Locations where ${exception} is used without specifying format will now perform Exception.ToString(), instead of just rendering Exception.Message

  • Reason: Better user experience when using default configuration. When using NLog to diagnose problems then all exception information is usually important.

  • Workaround: Explicit specify ${exception:format=message} to only get the Exception.Message.

NLog InternalLogger will not initialize itself from app.config or environment variables

  • Impact: NLog InternalLogger will no longer activate itself based on appsettings or environment variables.

  • Reason: 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.

  • Workaround: NLog InternalLogger can be enabled from NLog.config as always:

    <nloginternalLogToConsole="true"internalLogLevel="Debug"></nlog>

    NLog InternalLogger can be enabled from code as always:

    NLog.Common.InternalLogger.LogToConsole=true;NLog.Common.InternalLogger.LogLevel=LogLevel.Debug;

    NLog InternalLogger can be initialized from environment-variables from code:

    NLog.LogManager.Setup().SetupInternalLogger(log=>log.SetupFromEnvironmentVariables());

Removed obsolete method Target.Write(AsyncLogEventInfo[]) and OptimizeBufferReuse is always true

  • Impact: NLog extensions targets that depends on batch writing LogEvents using the method Write(AsyncLogEventInfo[] logEvent) will no longer work. The OptimizeBufferReuse performance optimization will now always be enabled for all NLog extensions targets. Custom NLog Targets that uses Target.RenderLogEvent() instead of Layout.Render() will experience a performance boost.

  • Reason: 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.

  • Workaround: NLog extensions target that depends on the removed method Target.Write(AsyncLogEventInfo[]) should instead override this method: Target.Write(IList<AsyncLogEventInfo>)

ScopeContext changes MappedDiagnosticContext (MDC) to use AsyncLocal

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.

  • Impact: NLog MappedDiagnosticContext (MDC) will change from AllocateDataSlot to AsyncLocal 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 CallContext. NLog MappedDiagnosticLogicalContext (MDLC) will change from CallContext to AsyncLocal when using .NET Framework v4.6 just like on .NET Core.

  • Reason: 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) ILogger.BeginScope 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.

  • Workaround: 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 Logger.PushScopeProperty and Logger.PushScopeNested for easier availability.

MappedDiagnosticContext (MDC), MappedDiagnosticLogicalContext (MDLC), GlobalDiagnosticContext (GDC) now case-insensitive

NLog have changed the default dictionary comparer to StringComparer.OrdinalIgnoreCase.

  • Impact: Property lookup with key RequestId will now match item-key requestid. This also means it will also overwrite independent of casing. Notice that LogEventInfo.Properties is still case-sensitive, but ${event-properties} will now ignore casing on property lookup by default.

  • Reason: Making it easier to lookup a single property without having to ensure all code-locations are using exact same casing.

  • Workaround: Instead just add a prefix (or suffix) to make it easier to distinguish the properties, when needing to store two different requestid values.

FileTarget KeepFileOpen = true by default

FileTarget will now keep file handles open by default, and will not release file handle after each write.

  • Impact: External applications that tries to acquire exclusive file-locks for the log-file will now fail, instead of possibly blocking the application. Ex. File.OpenText or File.ReadAllText will now fail withSystem.IO.IOException: The process cannot access the file.

  • Reason: 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.

  • Workaround: Explicitly specify KeepFileOpen=false to enforce old behavior similar to log4net/log4j MinimalLock. But if the problem comes from external application no longer being able to acquire exclusive file-lock, then it is better to fix the external application to use FileShare.ReadWrite.

FileTarget ConcurrentWrites = false by default

FileTarget will now by default not attempt to use operating system global mutexes for synchronized file-access between multiple applications on the same machine.

  • Impact: 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.

  • Reason: 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.

  • Workaround: 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.

FileTarget Encoding default value changed to UTF8

Instead of using Encoding.Default then FileTarget will now use Encoding.UTF8

  • Impact: FileTarget will now by default write using UTF8 encoding.

  • Reason: 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.

  • Workaround: Explicit assign Encoding on the FileTarget.

FileTarget will include BOM by default for UTF16 and UTF32 encoding

When the encoding requires a BOM preamble for proper parsing, then FileTarget will now include it by default.

  • Impact: When not having configured FileTarget WriteBom-option, then it will automatically become true for UTF16 and UTF32 encoding.

  • Reason: Better user experience when using default configuration. Most file viewers will fail to handle these file encodings without correct BOM.

  • Workaround: Explicit assign WriteBom on the FileTarget.

NetworkTarget will Discard by default on overflow

NetworkTarget behaves asynchronous and never had any throttle of network requests pending. With KeepConnection = true then network requests would be put in a pending-queue without any upper limit. With KeepConnection=false then network connections would be created without any upper limit.

This could cause the application to experience out-of-memory issues, which is not wanted from the logging framework by default. For KeepConnection = true there has been introduced a new setting OnQueueOverflow with default value Discard. For KeepConnection = false the existing setting OnConnectionOverflow is now by default Discard.

  • Impact: LogEvents might be lost during high loads, where network cannot keep up.

  • Reason: Better user experience by not taking the application down during high loads.

  • Workaround: Explicit assign OnQueueOverflow and OnConnectionOverflow to use Grow or Block.

JsonLayout MaxRecursionLimit default value changed to 1

JsonLayout will by default perform reflection of property-values and output direct object-properties.

  • Impact: When enabling IncludeEventProperties then it will automatically output first level object-properties.

  • Reason: Better user experience when using default configuration. When using JSON for structured logging, then one expects to see the object-properties.

  • Workaround: Explicit assign MaxRecursionLimit="0" on the JsonLayout.

JsonLayout EscapeForwardSlash default value changed to false

JsonLayout will now by default not escape URL-values when rendering JSON.

  • Impact: Forward slashes / will no longer be escaped by default

  • Reason: Better user experience as it aligns the NLog JSON Serializer with the default behavior of others.

  • Workaround: Explicit assign EscapeForwardSlash="true" on the JsonLayout.

JsonLayout always includes decimal point for floating-point types

JsonLayout will now by default add decimal point for properties of the type decimal, double and float.

  • Impact: Instead of writing double default value as 0 then it will become 0.0

  • Reason: 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.

  • Workaround: Stop using decimal types for properties where you don’t want decimal point in JSON.

CallSite-renderer will automatically clean async callstacks

${callsite} will now enable CleanNamesOfAnonymousDelegates and CleanNamesOfAsyncContinuations by default.

  • Impact:${callsite} rendering will now attempt to extract and log the actual method, instead of the async-delegate.

  • Reason: Better user experience when using default configuration, and doing logging in async-methods.

  • Workaround: Explicit assign CleanNamesOfAnonymousDelegates and CleanNamesOfAsyncContinuations when using ${callsite}.

LoggingRule Filters DefaultAction changed to FilterResult.Ignore

Changed from Neutral default value:

<loggername="*"minLevel="Debug"writo="target"><filtersdefaultAction="Neutral"><whencondition="'${exception:format=shorttype}' != ''"action="Log"/></filters></logger>

To Ignore as default value:

<loggername="*"minLevel="Debug"writo="target"><filtersdefaultAction="Ignore"><whencondition="'${exception:format=shorttype}' != ''"action="Log"/></filters></logger>
  • Impact: Will give unexpected behavior for ALL users that are using action="Ignore", as it will lead to always ignore (no output)

  • Reason: Better user experience when trying to use filters, as it will have effect right away.

  • Workaround: Explicit assign defaultAction on the <filters>-element, or change to action="Log".

NLog.Extensions.Logging without any filter

NLog LoggingProvider no longer follows the Microsoft Logger filtering configuration.

  • Impact: Microsoft Logger filtering in appsettings.json will no longer have any effect.

  • Reason: 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.

  • Workaround: Explicit specify NLogProviderOptions RemoveLoggerFactoryFilter = false to enable old behavior, where Microsoft LoggerFactory filters specified in appsetting.json also applies to NLog.

Notice NLog LoggingRules now have the finalMinLevel-option that allows one to replicate behavior of Microsoft Logging Filters:

<rules><loggername="System*"finalMinLevel="Warn"/><loggername="Microsoft*"finalMinLevel="Warn"/><loggername="Microsoft.Hosting.Lifetime*"finalMinLevel="Info"/><loggername="*"minLevel="Debug"writeTo="console"/></rules>

Notice it is also possible to have NLog Configuration in appsetting.json.

NLog.Extensions.Logging changes capture of EventId

NLog LoggingProvider will no longer capture EventId-struct + EventId_Id-number + EventId_Name, instead it will by default capture the properties EventId (integer) and EventName (string).

  • Impact:EventId_Id and EventId_Name are no longer included by default. They have been replaced with the properties EventId and EventName.

  • Reason: Avoid the overhead from capturing and boxing the EventId-struct. And provide more human readable names.

  • Workaround: Adjust to the new property-names, or explicity specify NLogProviderOptions CaptureEventId = Legacy to enable old behavior.

Many other improvements

For a full list of all the enhancements and performance improvements: NLog 5.0 PullRequests

NLog 5.0 Finally Ready!

$
0
0

NLog 5.0 has completed preview testing, and is ready for release.

Major Changes

  • NLog ScopeContext replaces MDLC and MDC
  • NLog Configuration from code with fluent LogManager.Setup()
  • NLog DatabaseTarget extracted into its own NLog.Database nuget-package
  • NLog Extensions assemblies will not be loaded automatically, so extensions must be explicitly added.
  • .NET Standard takes over target-platforms Silverlight / WindowsPhone / Xamarin iOS / Xamarin Android
  • Updated default values for better out-of-the-box experience
  • Removed obsolete methods and properties

For more details see List of major changes in NLog 5.0

For full list of all changes: NLog 5.0 Pull Requests

Credits

Additional thanks to contributers:

  • @TalAloni
  • @njqdev
  • @menishmueli
  • @ErickJeffries
  • @AlanLiu90
  • @aled
  • @tetrodoxin
  • @noamyogev84
  • @simoneserra93
  • @sjafarianm
  • @Orace
  • @GitHubPang
  • @KurnakovMaksim

NLog 5.2 without trim warnings

$
0
0

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.

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.

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.

NLog v5.2 now recommends that one registers the individual NLog extension types like this:

NLog.LogManager.Setup().SetupExtensions(ext=>{ext.RegisterTarget<MyCustomTarget>();ext.RegisterLayout<MyCustomLayout>();ext.RegisterLayoutRenderer<MyCustomLayoutRenderer>();});

NLog.Web.AspNetCore and NLog.Extensions.Logging have been updated to automatically register their NLog extensions the recommended way when calling UseNLog() or AddNLog().

If one needs the NLog Logger in ASP.NET Core before the HostBuilder has been created, then LoadConfigurationFromAppSettings() will ensure to register NLog extensions before loading the NLog configuration:

var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();

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 <extensions>-section when NLog detects relevant types are already registered the recommended way.

When enabling NET trimming on application publish, then make sure that NLog-configuration file, doesn’t depend on <extensions>-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.

Obsoleted methods that conflicts with application trimming

NLog v5.2 marks several methods as obsolete, to move towards the following goals:

  • Move all dynamic assembly loading logic from ConfigurationItemFactory into Setup() extensions methods. Later moved into separate NLog-nuget-package with next major version.
  • Move all file loading logic from LogManager / LogFactory into Setup() extensions methods. Later moved into separate NLog-nuget-package with next major version.
  • Promote the Setup() extensions methods, instead of having many different static-methods.

The following methods has been marked obsolete on ConfigurationItemFactory, with redirection to Setup() extensions methods:

  • ConfigurationItemFactory(params Assembly[] assemblies)-Constructor
  • ConfigurationItemFactory.CreateInstance-Method for legacy dependency-injection replaced by Register-extension-methods with custom factory-method.
  • ConfigurationItemFactory.RegisterItemsFromAssembly-Method for explicit assembly loading replaced by extension methods.
  • ConfigurationItemFactory.AssemblyLoading-EventHandler together with AssemblyLoadingEventArgs
  • ConfigurationItemFactory.PreloadAssembly-Method for explicit assembly loading replaced by extension methods.
  • ConfigurationItemFactory.RegisterType-Method for explicit assembly loading replaced by extension methods.
  • ConfigurationItemFactory.RegisterType-Method for explicit assembly loading replaced by extension methods.
  • INamedItemFactory-Interface prevents correct trimming annotations.
  • INamedItemFactory ConfigurationItemFactory.Targets-Property prevents correct trimming annotations.
  • INamedItemFactory ConfigurationItemFactory.Layouts-Property prevents correct trimming annotations.
  • INamedItemFactory ConfigurationItemFactory.LayoutRenderers-Property prevents correct trimming annotations.
  • INamedItemFactory ConfigurationItemFactory.AmbientProperties-Property prevents correct trimming annotations.
  • INamedItemFactory ConfigurationItemFactory.TimeSources-Property prevents correct trimming annotations.
  • INamedItemFactory ConfigurationItemFactory.Filters-Property prevents correct trimming annotations.
  • INamedItemFactory ConfigurationItemFactory.ConditionMethods-Property prevents correct trimming annotations.

The following methods has been marked obsolete on LogManager / LogFactory, with redirection to Setup() extension methods:

  • LogManager.LoadConfiguration(string configFile)-Method replaced by LogManager.Setup().LoadConfigurationFromFile(...)
  • LogManager.ConfigurationReloaded-EventHandler replaced by ConfigurationChanged-EventHandler.
  • LogManager.GetCandidateConfigFilePaths()-Method replaced by just explicitly specifying file-path.
  • LogManager.SetCandidateConfigFilePaths()-Method replaced by just explicitly specifying file-path.
  • LogManager.ResetCandidateConfigFilePath()-Method replaced by just explicitly specifying file-path.

The following methods has been marked obsolete on SimpleConfigurator, with redirection to Setup() extension methods:

  • SimpleConfigurator.ConfigureForConsoleLogging-Method replaced by LogManager.Setup().LoadConfiguration(c => c.ForLogger().WriteToConsole())
  • SimpleConfigurator.ConfigureForFileLogging-Method replaced by LogManager.Setup().LoadConfiguration(c => c.ForLogger().WriteToFile(fileName))
  • SimpleConfigurator.ConfigureForTargetLogging-Method replaced by LogManager.Setup().LoadConfiguration(c => c.ForLogger().WriteTo(target))

The following methods has been marked obsolete on XmlLoggingConfiguration, with redirection to Setup() extension methods:

  • XmlLoggingConfiguration.GetCandidateConfigFilePaths()-Method replaced by just explicitly specifying file-path.
  • XmlLoggingConfiguration.SetCandidateConfigFilePaths()-Method replaced by just explicitly specifying file-path.
  • XmlLoggingConfiguration.ResetCandidateConfigFilePath()-Method replaced by just explicitly specifying file-path.

The following methods has been marked obsolete on LayoutRenderer, with redirection to Setup() extension methods:

  • Target.Register-Method replaced by RegisterTarget<T>-extension-method
  • Layout.Register-Method replaced by RegisterLayout<T>-extension-method
  • LayoutRenderer.Register-Method replaced by RegisterLayoutRenderer<T>-extension-method

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.

If having questions or problems about these changes, then one is wellcome to open GitHub Issue

Dependency Injection without CreateInstance

NLog ConfigurationItemFactory.CreateInstance has for a long time been the default way to handle dependency injection. It allows override of how to create instance of class-type, and parse input-dependencies as constructor parameters.

The CreateInstance-delegate has now been marked obsolete, as it doesn’t work well with annotations for application trimming.

NLog v5 introduced the ability to acquire dependencies during InitializeTarget-method with help from ResolveService<T>-method.

NLog v5.2 now also introduces the ability to register extensions together with a custom factory-method:

NLog.LogManager.Setup().SetupExtensions(ext=>ext.RegisterTarget<MyTarget>(()=>newMyTarget(someDependency));

NLog 6.0 goals

$
0
0

NLog v6.0 has the following goals:

  • Support Ahead-of-Time (AOT) builds without warnings
  • Support Nullable references
  • Remove old target platforms NetStandard1.3 + NetStandard1.5
  • Cleanup interfaces for Logger / ILogger to remove unnecessary boxing optimizations from .NET v1
  • Remove System.Text.RegularExpressions dependency since a heavy dependency for AOT
    • Need to implement a minimal syntax-support for NLog Logging Rules. Ex. ? and *
  • Remove System.Xml dependency since a heavy dependency for AOT
    • Need to implement a minimal XML reader to continue loading NLog.config XML files
  • Extract NLog.Targets.WebServiceTarget to its own nuget-package
  • Extract NLog.Targets.NetworkTarget to its own nuget-package
  • Extract NLog.Targets.MailTarget to its own nuget-package
  • Extract NLog.Targets.FileTarget to its own nuget-package NLog.Targets.ConcurrentFileTarget
    • NLog will instead have a simple FileTarget without ConcurrentWrites-support but only KeepFileOpen = false

The overall goal for NLog v6.0 is to continue being a fully working logging-library in a single nuget-package. The NLog-package will out of the box only handle file- and console-output, which will probably cover 90 pct. of the use cases. When needing other output targets or formats, then additional nuget-packages must be included.

The planned interface cleanup for Logger / ILogger will probably give a lot of headache, as it will require all dependencies to be upgraded before upgrading the main-application. Where NLog v5 was mostly an update of default values for the main-application to handle, then the upgrade to NLog v6 will affect the entire dependency- / project-tree.

Another goal is that all existing nuget-packages that depends on NLog v4, should continue to function with NLog v6. This means NLog v6 will continue to support obsolete API-methods, that are relevant for custom NLog targets.

.NET8 already have great support for AOT, but many Microsoft teams are still working on updating their nuget-packages to support AOT. Believe the goal for .NET9 is to ensure even more nuget-packages will fully support AOT, to allow more ASP.NET or MAUI applications to start using AOT. NLog should not become a blocker, when wanting to try out AOT builds.

This means NLog v5 will now go into maintenance mode (together with NLog v4), and focus will now be on getting NLog v6 preview build ready. If having suggestions for the future direction of the NLog v6 milestone then comments are wellcome.