NLog Best Practices, Resources & Tips

Ultimate NLog Tutorial for .NET Logging – 19 Best Practices, Resources and Tips

Matt Watson Developer Tips, Tricks & Resources Leave a Comment

NLog is a very popular logging framework for .NET. It is second only to log4net in popularity but is much newer and has a few unique features. I recently also wrote a similar tutorial for log4net and after looking at them side by side, NLog has a lot of great features and advantages.

 

1. What is NLog? Why Should You Use It, or Any C# Logging Framework?

Logging is one of the most basic things that every application needs to have to help troubleshoot application problems.

Logging frameworks are important because they make it easy to send your logs to different places by simply changing your configuration. You can write your logs to a text file on disk, a database, a log management system or potentially dozens of other places, all without changing your code.

 

2. How to Install NLog via Nuget and Getting Started

Starting with NLog is as easy as installing an NLog Nuget package. You will also want to pick some logging targets to direct where your log messages should go, including the console and a text file.

If you are new to NLog, check out this article: NLog Tutorial.

 

3. Logging Targets: What They Are and Common Targets You Need to Know

Targets are how you direct where you want your logs sent. The most popular of the standard targets are most likely the File and Console targets. I would also try the Debugger target if you want to see your log statements in the Visual Studio Debug window so you don’t have to open a log file.

 

If you are using a Console, check out the ColoredConsole target:

NLog colored console target

NLog colored console target

 

4. How to Enable NLog’s Own Internal Debug Logging

If you are having any problems with NLog, you should enable the internal logging to help figure out the root cause.

<nlog internalLogFile="c:\log.txt" internalLogLevel="Trace">
   <targets>
      <!-- target configuration here -->
   </targets>
   <rules>
      <!-- log routing rules -->
   </rules>
</nlog>

5. Make Good Use of Multiple NLog Levels and Filter by Them

Be sure to use Debug, Info, Warning, Error, and Fatal logging levels as appropriate. This is really valuable if you want to specify only certain levels to be logged to a specific logging target or to reduce logging in production.

 

6. Always define a Logger object as static

Declaring any variable in your code has overhead. During some past profiling sessions to optimize code, I have noticed that the constructors on the LogManager object can use a lot of CPU.

 

7. Warning: Saving Logs to a Database Doesn’t Scale

Trying to query logs in SQL is very slow if you log any real volume of data if you don’t have full-text indexing. You are much better off sending your logs to Elasticsearch or a log management service that can provide full-text indexing and more functionality with your logs.

 

8. Do Not Send Emails on Every Exception

The last thing you want to do is send an email on every new exception. They either get ignored because they send so many emails, or something starts throwing a lot of exceptions and then your app starts sending thousands of errors. Although, there is a Mail target if you really want to do this.

 

9. How to Send Alerts for Exceptions

If you want to send alerts when exceptions occur, send your exceptions to an error reporting product, like Retrace, that is designed for this. They can also de-duplicate your errors so you can figure out when an error is truly new or regressed, track its history, and track error rates.

 

10. How to Search Logs Across Servers

Capturing logs and logging them to a file on disk is great but does not scale. If you want to search your logs across multiple servers and applications, you need to send all of your logs to a central repository. There are a lot of log management solutions that can help you with this or you can even set up your own Elasticsearch cluster for it.

If you want to query all the files on disk, consider using VisualLogParser.

 

11. Use Filters to Suppress Certain Logging Statements

NLog has the ability to configure filtering and routing to send specific logs to specific targets or suppress all log messages.

<logger name="*" writeTo="file">
   <filters>
    <when condition="lengthundefined'${message}') > 100" action="Ignore" />
  </filters>
</logger> 

12. You Can Make Your Own Custom NLog Targets

If you want to do something that the standard NLog targets do not support, you can search online for one or write your own.

One example could be a target for writing to Azure Storage.

As an example of a custom target, you can review the source code for our NLog target for sending logs to Retrace.

 

13. Customize Your Layout in Your Logs

NLog can support multiple targets which represent where your log data is to be written to. For each target, you can customize what fields are logged and how they are displayed.

The default layout looks like this:

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

There are dozens of other fields available to customize your layout with.

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <extensions>
    <add assembly="NLog.Targets.Stackify"/>
  </extensions>
  <targets>
    <target name="logfile" xsi:type="File" fileName="nlogfile.txt" layout="${machinename} ${message}" />
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="logfile" />
  </rules>
</nlog>

14. Use the Diagnostic Contexts to Log Additional Fields – GDC & MDC

With NLog you can create a dictionary of data that can be used as properties within your logging. This is really useful if you wanted to set a customer’s name on the context and then include that in every logging statement. Since the customer’s name would be different per transaction, you would not want to set it at a global scope. To do this, you would use the Mapped Diagnostics Context (MDC).

For global variables, you can use the Global Diagnostics Context (GDC). Anything properties stored will be shared across all threads in your application and available to be included in your logs. I could see using this for global configuration type data that is important to be aware of in the logs.

Using GDC, MDC, and MDLC is virtually all the same.

You set the dictionary values on the context like this:

GlobalDiagnosticsContext.Set("myDataBase","someValue");
MappedDiagnosticsLogicalContext.Set("PropertyName", "PropertyValue");
MappedDiagnosticsContext.Set("Property2", new { Part1 = 2.0m, Part2 = "Two parts" });

You can them modify your logging configuration to include these fields as needed in your layouts.

${gdc:item=myDatabase}
${mdlc:item=PropertyName}
${mdc:item=Property2}

Note: If your application is using async await, then you will want to use the MDLC, instead of MDC.

 

15. You Might Need NLog Extensions Packages

NLog has several extension packages that add additional features.

The following packages are available

  • NLog.Web – package contains targets and layout-renders specific to ASP.NET 4 and IIS.
  • NLog.Web.AspNetCore – package contains targets and layout-renders specific to ASP.NET Core and IIS.
  • NLog.Extensions.Logging – .NET Core support
  • NLog.Windows.Forms – package contains targets specific for Windows.Forms
  • NLog.Extended – MSMQ target, AppSetting layout renderer
  • NLog.Config – NLog Configuration example/starter – not supported in .NET Core
  • NLog.Schema – XSD Schema for the NLog config xml – for, among other, Intellisense in Visual Studio – not supported in .NET Core

 

16. How to Correlate Log Messages by Web Request Transaction

Starting with v4.1, NLog has built in support for the layout field ${activityid} which maps to the CorrelationManager.ActivityId. You just need to make sure that your app sets the activityId at the start of each request. This page on GitHub covers this layout renderer and the details.

 

17. How to Log ASP.NET Request Details

The NLog extensions package NLog.Web adds support for logging ASP.NET request fields to your logs. It will let you log the URL, user logged in, session id, or several other fields.

 

18. How to Do Structured Logging, or Log an Object or Properties with a Message

NLog has built-in support for writing your entire log in JSON. You can set the layout on your target to the type of JsonLayout.

<target name="jsonFile" xsi:type="File" fileName="${logFileNamePrefix}.json" includeAllProperties="Boolean" excludeProperties="Comma-separated list undefinedstring)"   >
      <layout xsi:type="JsonLayout">
              <attribute name="time" layout="${longdate}" />
              <attribute name="level" layout="${level:upperCase=true}"/>
              <attribute name="message" layout="${message}" />
       </layout>
</target>

If you want to really get the value of structured logging, you will want to send your logs to a log management tool that can index all the fields and enable powerful searching and analytics capabilities.

Learn more: What is structured logging and why developers need it.

 

19. How to View NLog logs by ASP.NET Web Request

Log files can quickly become a spaghetti mess of log messages. Especially with web apps that have lots of AJAX requests going on that all do logging.

I highly recommend using Prefix, Stackify’s FREE .NET Profiler to view your logs per web request along with SQL queries, HTTP calls and much more.

transaction trace annotated

 

20. What Tips and Best Practices Do You Have?!?!

Have anything we should add to the list? Let us know in the comments below!

 




About Matt Watson

Matt is the Founder & CEO of Stackify. He has been a developer/hacker for over 15 years and loves solving hard problems with code. While working in IT management he realized how much of his time was wasted trying to put out production fires without the right tools. He founded Stackify in 2012 to create an easy to use set of tools for developers.