10 Comments

UPDATE: The latest version of NLog breaks many of these tools by including NLog data by default. The code has been updated to correct this problem by excluding it for both Sentinel and Harvester applications.

The time has come where I needed to add some sophisticated logging to Directory Monitor. I know there are a couple of frameworks out there and this comparison chart lays it out quite nicely although it may be quite dated. So after some quick investigation on the free ones I decided to go with NLog.

  • ObjectGuy Framework was really appealing at only a 40KB dependency. It's really simple and actually quite powerful, I chose not to use it because as you can see in the chart, thread safety is questionable (not sure why or hasn’t been tested) and it doesn't have built in file rotation/archiving. - @Lorne set me straight, the  ObjectGuy Framework does indeed have these features, however, my decision still stands for reasons beyond this.
  • Log4Net is a good option but the license didn’t agree with me because I want to use it for closed source applications.
  • Enterprise Library is a monster with lots of other dependencies, really only for large scale applications and if you want to extend it to do crazy things. Use it at work almost exclusively but not ideal for my small app.
  • NLog is 372KB, works in Mono (enterprise library as well), and has a build for WP7, all versions of the framework, Silverlight etc. Because of this I didn't mind checking it out because it immediately allows me to take that learning anywhere, to almost any application I build. There is also a great monitoring tools you can use along with it such as Sentinel or Harvester.

 

Quick Setup

You can download and install it or just add it through NuGet in Visual Studio.

Configuration File

Just make a config called NLog.config in the root of your project.

When editing the configuration file, reference the XSD and you'll get intellisense and inline comments in Visual Studio: Right-click the config -> Properties -> Schemas -> "C:\Program Files (x86)\Microsoft Visual Studio 10.0\xml\Schemas\NLog.xsd"

If you have a separate config file, make sure you set the "Copy to Output Directory" is set to "Copy Always" to avoid many tears wondering why the logging doesn't work.

CopyToOutputDirectory

You get a lot of layout options to play with, this is my configuration file, it writes to the event log on error and fatal, creates a daily rolling log file (30 days max), everything is asynchronous and the configuration auto reloads on the fly if anything changes. It also writes to a location that you will have write access to in low privilege situations.

<?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"
      autoReload="true"
      throwExceptions="false">

  <variable name="appName" value="YourAppName" />
  
  <targets async="true">
    <target xsi:type="File"
            name="default"            
            layout="${longdate} - ${level:uppercase=true}: ${message}${onexception:${newline}EXCEPTION\: ${exception:format=ToString}}"
            fileName="${specialfolder:ApplicationData}\${appName}\Debug.log"
            keepFileOpen="false"
            archiveFileName="${specialfolder:ApplicationData}\${appName}\Debug_${shortdate}.{##}.log"
            archiveNumbering="Sequence"
            archiveEvery="Day"
            maxArchiveFiles="30"
            />
    
    <target xsi:type="EventLog"
            name="eventlog"
            source="${appName}"
            layout="${message}${newline}${exception:format=ToString}"/>
  </targets>
  <rules>
    <logger name="*" writeTo="default" minlevel="Info" />
    <logger name="*" writeTo="eventlog" minlevel="Error" />
  </rules>
</nlog>

 

Code

This is the singleton class that I use which also includes targets for Sentinel and Harvester when I'm running a debug build.

using NLog;
using NLog.Config;
using NLog.Targets;

namespace YourAppName.Logging
{
  internal static class Log
  {
    public static Logger Instance { get; private set; }
    static Log()
    {
#if DEBUG
      // Setup the logging view for Sentinel - http://sentinel.codeplex.com
      var sentinalTarget = new NLogViewerTarget()
      {
        Name = "sentinal",
        Address = "udp://127.0.0.1:9999",
        IncludeNLogData = false
      };
      var sentinalRule = new LoggingRule("*", LogLevel.Trace, sentinalTarget);
      LogManager.Configuration.AddTarget("sentinal", sentinalTarget);
      LogManager.Configuration.LoggingRules.Add(sentinalRule);

      // Setup the logging view for Harvester - http://harvester.codeplex.com
      var harvesterTarget = new OutputDebugStringTarget()
      { 
        Name = "harvester",
        Layout = "${log4jxmlevent:includeNLogData=false}"
      };
      var harvesterRule = new LoggingRule("*", LogLevel.Trace, harvesterTarget);
      LogManager.Configuration.AddTarget("harvester", harvesterTarget);
      LogManager.Configuration.LoggingRules.Add(harvesterRule);
#endif

      LogManager.ReconfigExistingLoggers();

      Instance = LogManager.GetCurrentClassLogger();
    }
  }
}

 

Monitoring Tools

Let Sentinel or Harvester run all the time when you are debugging and it will pick up everything that your app is logging (screenshots from their respective project pages).

Sentinel

Harvester

 

Start Logging

Now to start log anything, anywhere in your app, just use the static log instance.

try
{
  Log.Instance.Debug("We're going to throw an exception now.");
  Log.Instance.Warn("It's gonna happen!!");
  throw new ApplicationException();
}
catch (ApplicationException ae)
{
  Log.Instance.ErrorException("Error doing something...", ae);
}

This is a really simple and effective setup but you can of course get really advanced from there, all in the configuration file.

The cool thing about having a separate log file is that you can send someone a modified log file that will write trace level logging or even ship the log to a web server or database for you to check out.

Logging is so important in any live application. This just makes it easy while still leaving it very powerful if you ever need to use that power. The logger itself is pretty easy to debug because of it's massive internal logging and setting to expose the internals of it.

 

Comments

Comment by Lorne Brinkman

The comparison chart to which you refer in your article is inaccurate. The author of that chart was informed a long time ago that it was in error and he has refused to make appropriate corrections. The Object Guy's Logging Framework is thread-safe. It also has file rotation. Watch this video for a multi-threaded example: http://youtu.be/jv9u6wmKiUU

Lorne Brinkman
Comment by Werner

[b]@Lorne[/b]: I have updated the article to strike out the assumption made against the framework based in the comparison chart. Admittedly, I was taking this at face value and never really did sufficient investigation on my own. This article was never intended to highlight the strengths or weaknesses of one option against another, NLog was just the option I went for at the time and upon request, made a 5 minute setup write about it. Although I really have nothing against any of the mentioned frameworks, they all serve their own purpose based on the type of application you intend to build, NLog ended up meeting my expectations in more ways than one for my particular needs which led to this article.

I still stick to my guns though for a couple of reasons.

[b]1.[/b] NLog may be bigger in file size, but in my particular case, it wasn't that much of a factor.
[b]2.[/b] Because NLog adopted a log4net compatible format, it creates an opportunity for logging utilities and management systems built against it to also work seamlessly with NLog.
[b]3.[/b] NLog can be integrated into your project via NuGet. Not major, but it's these little things...
[b]4.[/b] NLog has some other out-the-box integration options such as databases and third party monitoring and consolidation systems, no need to develop these plugins/extensions.

Don't get me wrong, I'm not settling on NLog as the answer to all my logging woes, it comes with issues of it's own as well. I advocate using the right tool for the job and NLog was the right tool for what I needed. When I get the opportunity to use the ObjectGuy's Framework for my next project, I'll be sure to write a 5 minute article on setting it up as well. I'm hoping people land here because they are looking for a quick guide on setting up NLog and not to argue the pros and cons of competing frameworks.

Werner
Comment by srikanth

How to log Business Access Layer and Data access layer exceptions using nLog ?
please provide us the any ref .

srikanth
Comment by Brady Kelly

@srikanth Exactly the same as you log any other exceptions with NLog. Just be aware that each executable needs its own copy of an NLog.config.

Comment by Petro

> Log4Net is a good option but the license didn’t agree with me because I want to use it for closed source applications.
Log4Net license does not contain such limitations.
It uses standard Apache 2.0 license http://logging.apache.org/log4net/license.html which allows you to use this library as soon as you linking library and attribute usage of log4net somehow.

Petro
Comment by Ali Sebt

Thanks. very useful. :)

Ali Sebt
Comment by JeromeA

"If you have a separate config file, make sure you set the "Copy to Output Directory" is set to "Copy Always" to avoid many tears wondering why the logging doesn't work." didn't save me for the first 20 mins of tears from forehead smacking... LOL. Good thing my Google Fu is strong and I found your article on my first search! Thank you!!

Comment by Gargavar

Nice article. It led me to Sentinel on GitHub, however I cannot get it to work like in your screenshots. Getting the Message Activity panel to appear is a mystery, nor can I find a way to make multiple provider tabs. I've tried both branches. There's no reply to this in Issues (others have the same problem). The version number displayed is 0.13.4.0. Any ideas?

Gargavar
Comment by Andrew Janke

"Copy to Output Directory"! Thank you! I indeed had many tears before I came across this article.

Post comment