Ads by Lake Quincy Media
Gibraltar - Learn about the best analysis tool for NLog

Archive for September, 2010

NLog 2.0 Beta 1 has been released

It is my pleasure to announce that NLog 2.0 Beta 1 has been released.

NLog 2.0 release is focused on adding support for new platforms (Silverlight, .NET Framework 4), improving logging architecture and manageability and addressing most frequently reported user issues.

The following platforms are supported in this release:

  • .NET Framework 2.0 SP1 and above, 3.5 (Client and Extended profiles), 4.0 (Client and Extended profiles)
  • Silverlight 2.0, 3.0, 4.0
  • .NET Compact Framework 2.0, 3.5
  • Mono 2.x profile

Read full release notes:
http://nlog-project.org/nlog2-beta1-release-notes

Download Beta 1 bits on CodePlex:
http://nlog.codeplex.com/releases/view/52957

Source code is available on GitHub:
http://github.com/jkowalski/NLog/

Bugs can be reported on CodePlex:
http://nlog.codeplex.com/workitem/list/basic

Discuss on forum:
http://nlog-project.org/forum

Subscribe to NLog RSS feed:
http://nlog-project.org/feed

Follow @JarekKowalski on Twitter:
http://twitter.com/JarekKowalski

Ads by Lake Quincy Media

Deploying NLog configuration files

Some of the targets supported by NLog require installation to be performed on the machine before the target can be used. For example, when logging to a database, a DBA needs to create the necessary tables, when logging to event log or performance counter, administrator of the machine must create them before the application can write to them.

NLog 2.0 comes with a new tool and APIs that lets you manage installation and uninstallation of objects which support logging.

Say you want to write logs to:

  • local SQLEXPRESS database
  • Event Log on the local machine
  • increase performance counter each time log message occurs.
  • With NLog 2.0, you can embed installation/uninstallations steps directly in the log configuration file, like in the following example:

    <?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">
      <targets>
        <target xsi:type="Database" name="db">
          <!-- SQL command to be executed for each entry -->
          <commandText>INSERT INTO [LogEntries](TimeStamp, Message, Level, Logger) VALUES(getutcdate(), @msg, @level, @logger)</commandText>
    
          <!-- parameters for the command -->
          <parameter name="@msg" layout="${message}" />
          <parameter name="@level" layout="${level}" />
          <parameter name="@logger" layout="${logger}" />
    
          <!-- connection string -->
          <dbProvider>System.Data.SqlClient</dbProvider>
          <connectionString>server=.\SQLEXPRESS;database=MyLogs;integrated security=sspi</connectionString>
    
          <!-- commands to install database -->
          <install-command>
            <text>CREATE DATABASE MyLogs</text>
            <connectionString>server=.\SQLEXPRESS;database=master;integrated security=sspi</connectionString>
            <ignoreFailures>true</ignoreFailures>
          </install-command>
    
          <install-command>
            <text>
              CREATE TABLE LogEntries(
              id int primary key not null identity(1,1),
              TimeStamp datetime2,
              Message nvarchar(max),
              level nvarchar(10),
              logger nvarchar(128))
            </text>
          </install-command>
    
          <!-- commands to uninstall database -->
          <uninstall-command>
            <text>DROP DATABASE MyLogs</text>
            <connectionString>server=.\SQLEXPRESS;database=master;integrated security=sspi</connectionString>
            <ignoreFailures>true</ignoreFailures>
          </uninstall-command>
        </target>
    
        <target xsi:type="EventLog" name="eventLog" source="NLog Demo"
                layout="${message}${newline}Call site: ${callsite:className=true:methodName=true}${newline}Logger: ${logger}">
        </target>
    
        <target xsi:type="PerfCounter" name="pc1" categoryName="My Log" counterName="My Counter">
        </target>
    
      <rules>
        <logger name="*" minlevel="Trace" writeTo="db,eventLog,pc1" />
      </rules>
    </nlog>

    In order to deploy the database, event log and performance counter, you can use simply use InstallNLogConfig.exe tool that comes with NLog. Open elevated command prompt and run the following command:

    > InstallNLogConfig.exe c:\path\to\NLog.config
    Installing 'Database Target[db]'
    Finished installing 'Database Target[db]'.
    Installing 'EventLog Target[eventLog]'
    Finished installing 'EventLog Target[eventLog]'.
    Installing 'PerfCounter Target[pc1]'
    Finished installing 'PerfCounter Target[pc1]'.

    Uninstalling is equally easy:

    > InstallNLogConfig.exe" -u c:\path\to\NLog.config 
    Uninstalling 'Database Target[db]'
    Finished uninstalling 'Database Target[db]'.
    Uninstalling 'EventLog Target[eventLog]'
    Finished uninstalling 'EventLog Target[eventLog]'.
    Uninstalling 'PerfCounter Target[pc1]'
    Finished uninstalling 'PerfCounter Target[pc1]'.

    Passing parameters to installation

    Sometimes there is a need to pass parameters to the installation routing, which should not be normally visible in the NLog.config file. One example might be DBA username and password for connecting to the database. You can pass parameters on the command line by using –p NAME=VALUE option:

    > InstallNLogConfig.exe" –p ADMIN_USER=sa –p ADMIN_PASSWORD=megaSecret1234 c:\path\to\NLog.config 

    The parameters are accessible using  ${install-context} layout renderer. For example, we can easily modify the above example to use SQL authentication where user name and password are passed from command line:

    <install-command>
      <text>CREATE DATABASE MyLogs</text>
        <connectionString>server=.\SQLEXPRESS;database=master;
                          user id=${install-context:ADMIN_USER};password=${install-context:PASSWORD}</connectionString>
        <ignoreFailures>true</ignoreFailures>
    </install-command>

    Installation API

    In order to install logging configuration, you can simply use Install() and Uninstall() methods on LoggingConfiguration object. They both take InstallationContext arguments, which can be used pass parameters and specify logging and other options:

    namespace NLog.Config
    {
        public sealed class InstallationContext : IDisposable
        {
            /// <summary>
            /// Gets or sets the installation log level.
            /// </summary>
            public LogLevel LogLevel { get; set; }
    
            /// <summary>
            /// Gets or sets a value indicating whether to ignore failures during installation.
            /// </summary>
            public bool IgnoreFailures { get; set; }
    
            /// <summary>
            /// Gets the installation parameters.
            /// </summary>
            public IDictionary<string, string> Parameters { get; private set; }
    
            /// <summary>
            /// Gets or sets the log output.
            /// </summary>
            public TextWriter LogOutput { get; set; }
        }
    }

    Typical installation code will look like this:

    using (var context = new InstallationContext())
    {
      var config = new XmlLoggingConfiguration("NLog.config");
    
      // output detailed installation logs
      context.LogLevel = LogLevel.Trace;
    
      context.Parameters["ADMIN_USER"] = "sa";
      context.Parameters["ADMIN_PASSWORD"] = "megaSecret1234";
    
      // write logs to a log file
      using (var logFile = File.CreateText("InstallLog.txt"))
      {
        context.LogOutput = logFile;
    
        config.Install(context);
      }
    }

    In order to support custom installation in your target or any other configuration item (such as layout, filter, etc.), you simply need to implement IIinstallable interface:

    public interface IInstallable
    {
      void Install(InstallationContext installationContext);
      void Uninstall(InstallationContext installationContext);
      bool? IsInstalled(InstallationContext installationContext);
    }

    See DatabaseTarget sources for example implementation.

    New exception handling rules in NLog 2.0

    NLog will introduce a change to logging exception handling and suppression. In NLog 1.0 all exceptions were disabled by default, but could be enabled by setting

    <nlog throwExceptions=”true>
    
    </nlog>

    or in code:

    LogManager.ThrowExceptions = true;

    This flag applied to configuration errors as well as runtime errors, which was problematic, because a simple configuration file typo could cause entire logging to be disabled silently.

    To address this, NLog 2.0 will treat configuration errors separately from runtime errors. There will be two kinds of exceptions:

    1. Configuration exceptions – raised during parsing of configuration file and wrapped in NLogConfigurationException. Such errors are fatal and will prevent your application from starting (this is the same as having malformed App.config or Web.config). The errors that cause this exception are:
      • syntax errors in NLog.config
      • invalid target names
      • invalid property names
      • invalid property values
    2. Runtime exceptions (such as permission issues, connection failures, etc.) – raised during logging and initialization and wrapped in NLogRuntimeException. They can be controlled by throwExceptions flag.

    I would love to hear your comments.

    Routing System.Diagnostics.Trace and System.Diagnostics.TraceSource logs through NLog

    I have recently added a trace listener class for NLog, which enables routing of System.Diagnostics.Trace and System.Diagnostics.TraceSource logs through your favorite log routing engine. This can be very useful for integrating components that don’t necessarily support logging through NLog as well as analyzing traces produced .NET Framework itself.

    By using NLog trace listener you can send those logs via email, save them to a database, file or to any other supported log target.

    Let’s create a simple example – application that makes network call. We will then enable network call tracing without touching a single line of code.

    namespace TraceDemo
    {
      using System.Net; 
    
      class Program
      {
        static void Main(string[] args)
        {
          var webClient = new WebClient();
          webClient.DownloadString("http://somehost/nosuchfile.txt");
        }
      }
    }

    As you can see the example is just using WebClient from System.Net namespace, and has no tracing-specific code. Internally WebClient is capable of outputting traces through System.Net trace source. To route those traces through NLog you need to assign a listener to each source in the application configuration file. It is convenient to define NLogTraceListener as a shared listener and reference by name in all sources that you need as in the following example:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.diagnostics>
        <sources>
          <source name="System.Net" switchValue="All">
            <listeners>
              <add name="nlog" />
            </listeners>
          </source>
          <source name="System.Net.Sockets" switchValue="All">
            <listeners>
              <add name="nlog" />
            </listeners>
          </source>
        </sources>
        <sharedListeners>
          <add name="nlog" type="NLog.NLogTraceListener, NLog" />
        </sharedListeners>
      </system.diagnostics>
    </configuration>

    Obviously you also need NLog.dll and NLog.config to be located in the application directory. For our purposes we’ll use simple configuration with single target:

    <nlog>
      <targets>
        <target name="console" type="ColoredConsole" layout="${longdate} ${windows-identity} ${message}" />
      </targets>
    
      <rules>
        <logger name="*" minlevel="Trace" writeTo="console" />
      </rules>
    </nlog>

    When you run this application, you will get nice color-coded trace that includes lots of diagnostics information straight from the guts of .NET Framework. Having access to detailed trace like this can be very helpful in diagnosing hard-to-reproduce problems that are often impossible to figure out with a debugger.

    image