//Karthik Srinivasan

Product Engineer, CTO & a Beer Enthusiast
Experiments, thoughts and scripts documented for posterity.

Quirky Personal Projects

LinkedIn

Email me

NLog - Custom Target

May, 2013

Nlog similar to log4net is quite a powerful logging library. Though out of the box it provides logging to text files, windows event log, database, Sentinal etc but how about about custom logging? Extending NLog to write to your own custom target is as quite simple as follows:

Create the target class:
   using System.ComponentModel.DataAnnotations;
   using NLog;
   using NLog.Targets;
   using Dapper;

   [Target("RDSAuditLogger")] 
    public sealed class RDSAuditLogger : TargetWithLayout 
    {
        public RDSAuditLogger()
        {
            this.Host = "localhost";
        }
 
        [Required] 
        public string Host { get; set; }
 
        protected override void Write(LogEventInfo logEvent) 
        { 
            string logMessage = this.Layout.Render(logEvent); 

            if(logEvent.Parameters != null && logEvent.Parameters.Count() > 1)
                SendTheMessageToRemoteHost(logEvent.Parameters[0] as string, logEvent.Message, logEvent.Parameters[1] as string); 
        } 
 
        //Yours custom logging - Over here I am storing an Id, the message and a custom type 
        //that my logger is logging
        private void SendTheMessageToRemoteHost(string id, string body, string type) 
        {
   //Make the logging async
            Task.Factory.StartNew(() =>
            {
    //Dapper.NET - write to sql using a Stored procedure
    using (var connection = DataAccessManager.GetOpenConnection())
    {
     connection.Execute("AddToLog", new { Id = id, Type = type, Body = body},
      commandType: CommandType.StoredProcedure);
    }
             
            });
        } 
    }

Register the target class:
using NLog;
using NLog.Config;
using NLog.Targets;

public static class Log
{
 public static Logger Instance { get; private set; }
 static Log()
 {
  //Register the custom target
  ConfigurationItemFactory.Default.Targets.RegisterDefinition("RDSAuditLogger", 
    typeof(MyLibrary.RDSAuditLogger));

  LogManager.ReconfigExistingLoggers();
  Instance = LogManager.GetCurrentClassLogger();
 }
}

Add to nlog configuration to assign log level:
  <nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <extensions>
      <add assembly="MyLibrary"/>
    </extensions>
    <targets>
      <target name="eventlog" xsi:type="EventLog" layout="${message}" log="Application" source="SomeName" />
      <target name="rdsAuditLogger" type="RDSAuditLogger" host="localhost"/>
    </targets>
    <rules>
      <logger name="*" levels="Error,Fatal,Warn" writeTo="eventlog" />
      <logger name="*" levels="Info" writeTo="rdsAuditLogger" />
    </rules>
  </nlog>
                

Example:
Log.Instance.Info("This is a test log", "123", "AM-Start");
Note that the example above is specific to my custom logger.