NLOG New Utility For Smart Logging

NLog is a free logging platform for .NET, Silverlight, and Windows Phone with rich log routing and management capabilities. It makes it easy to produce and manage high-quality logs for your applications regardless of their size or complexity. When you don't want to care about the archiving, and log formats then NLog is your friend. Using just a few configuration settings will enable everything for you. So let's get started.

First, download the appropriate version of Nlog that you'll be using in your application. Now when you have the desired library of Nlog just add the reference to your project. The next thing you need to do is put some configuration lines in the config file.

Register the NLog section in config.

<configuration>
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
  </configSections>
</configuration>

Note. keep in mind you're putting the config sections tag at the top of the Configuration file otherwise, you'll get an exception "Can not have more than one config section in the configuration" or something like that.

Next, you need to specify the Nlog section to be defined. The following is the sample code configuration of Nlog required to enable logging in your application.

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwExceptions="true" internalLogFile="c:\temp\nLog_internal_log_file.txt" internalLogLevel="Trace" internalLogToConsole="true">
    <targets async="true">
        <target name="file" xsi:type="File" keepFileOpen="false" fileName="C:\\Temp\\Test_Log.MyApplication.${shortdate}.txt" layout="${newline}${newline}${level}: ${message} ${exception:format=Message,StackTrace}" archiveFileName="C:\\Temp\\archives\Log.FaultDetectionSitePoller.{#####}.txt" lineEnding="Default" archiveAboveSize="1024000" archiveNumbering="Sequence" concurrentWrites="true" />
        <target xsi:type="Database" name="database">
            <connectionString>
                data source=LABPC02;initial catalog=SampleDatabase;Integrated Security=SSPI;
            </connectionString>
            <commandText>
                INSERT INTO Diagnostics
                (Severity
                ,Message
                ,StackTrace
                ,User
                ,MachineName
                )
                VALUES ( @severity
                , @message
                , @stacktrace
                , @User
                , @machinename
                )
            </commandText>
            <parameter name="@severity" layout="${level}" />
            <parameter name="@message" layout="${message}" />
            <parameter name="@machinename" layout="${machinename}" />
            <parameter name="@User" layout="${windows-identity:domain=true}" />
            <parameter name="@stacktrace" layout="${stacktrace}" />
        </target>
    </targets>
    <rules>
        <logger name="*" writeTo="file" />
        <logger name="*" minLevel="OFF" appendTo="database" />
    </rules>
</nlog>

In this section, we have a couple of things that I need to explain.

InternalLogFile

This is the file that Nlog will use for its own logging. It'll help you troubleshoot any issue with the NLog configuration of your project. It's optional and not required if you don't want to log the status of Nlog's internal stuff.

InternalLogToConsole

You can turn it on/off if your application can run as a console application.

Targets

This is the section where you define the targets i.e. your logging will be done in a file or database etc. The attribute is async='true' will define the behavior of Nlog to be async when writing logs. So you don't need to consider the cost of logging statements if you're using the async write behavior. This is a great feature that I liked most cause I've seen the application consuming enough time/space for logging statements. In the given sample configuration we have file and database logging enabled in the targets table.

Renderlayouts

Whatever is written under the target tag in the Curley braces is called render layouts. Whatever I used are the internally defined templates by Nlog. You can also create your own templates. These templates are known as RenderLayouts. So Nlog is already providing a very good list of RenderLayouts; check them out here.

That's pretty much what is required to be done in the configuration area. Now you need to write a wrapper class that you'll be using in your project.

Here's the complete code for the wrapper.

using System;
using NLog;

namespace MyLogger {
    public static class Logger {
        private static readonly NLog.Logger _logger; // NLog logger
        private const string _DEFAULTLOGGER = "CustomLogger";

        static Logger() {
            _logger = LogManager.GetLogger(_DEFAULTLOGGER) ?? LogManager.GetCurrentClassLogger();
        }

        #region Public Methods
        /// <summary>
        /// This method writes the Debug information to trace file
        /// </summary>
        /// <param name="message">The message.</param>
        public static void Debug(String message) {
            if (!_logger.IsDebugEnabled) return;
            _logger.Debug(message);
        }

        /// <summary>
        /// This method writes the Information to trace file
        /// </summary>
        /// <param name="message">The message.</param>
        public static void Info(String message) {
            if (!_logger.IsInfoEnabled) return;
            _logger.Info(message);
        }

        /// <summary>
        /// This method writes the Warning information to trace file
        /// </summary>
        /// <param name="message">The message.</param>
        public static void Warn(String message) {
            if (!_logger.IsWarnEnabled) return;
            _logger.Warn(message);
        }

        /// <summary>
        /// This method writes the Error Information to trace file
        /// </summary>
        /// <param name="error">The error.</param>
        /// <param name="exception">The exception.</param>
        public static void Error(String error, Exception exception = null) {
            if (!_logger.IsErrorEnabled) return;
            _logger.ErrorException(error, exception);
        }

        /// <summary>
        /// This method writes the Fatal exception information to trace target
        /// </summary>
        /// <param name="message">The message.</param>
        public static void Fatal(String message) {
            if (!_logger.IsFatalEnabled) return;
            _logger.Warn(message);
        }

        /// <summary>
        /// This method writes the trace information to trace target
        /// </summary>
        /// <param name="message">The message.</param>
        public static void Trace(String message) {
            if (!_logger.IsTraceEnabled) return;
            _logger.Trace(message);
        }
        #endregion
    }
}

So the usage of this wrapper should be very simple as you will only need to write lines in the middle of your code.

Logger.Debug("Time elapsed: " + timeElapsed);

And you're done with setting up the new generation logger with your application. If you need to turn off the logging for any target then you can use minLevel="OFF" for that target.

For example

<logger name="*" minLevel="OFF" appendTo="database"/>