Creating a basic logging wrapper for StreamInsight adapters/applications using log4net

There are many different ways of implementing logging on the Microsoft .NET platform (Trace, ETW, etc).  To provide for a range of flexibility (not necessary for this post.. just setting the stage) let’s go ahead and put together a generic logging interface that we’ll use throughout various applications (all of the code samples I post on this blog will use this approach).  Behind this interface we’ll deliver implementations that can target various logging frameworks such as Tracing, ETW, and in this case log4net.

  • Download the log4net binary package, and unpack the zip file onto your local hard drive.  The critical file is the log4net-1.2.10\bin\net\2.0\release\log4net.dll assembly.
  • From a Visual Studio 2010 command window (with Run as Administrator), navigate to the log4net directory and install the log4net.dll assembly into the GAC (gacutil /i log4net.dll).
  • Add the log4net.dll assembly into the project references.
  • Create a StreamInsightLog class based on the following code:
    1:  using System;
    2:  using System.Collections.Generic;
    3:  using System.Linq;
    4:  using System.Text;
    5:  using System.Diagnostics;
    6:  using log4net.Config;
    7:  using System.IO;
    8:   
    9:  namespace IntroHost
   10:  {
   11:      /// <summary>
   12:      /// StreamInsight log implementation leveraging log4net.
   13:      /// </summary>
   14:      public class StreamInsightLog
   15:      {
   16:          /// <summary>
   17:          /// Reference to the log4net logging object
   18:          /// </summary>
   19:          private readonly log4net.ILog log;
   20:   
   21:          /// <summary>
   22:          /// The category under which this object will log messages
   23:          /// </summary>
   24:          private string category;
   25:   
   26:          /// <summary>
   27:          /// Default initialization of the log4net library based on
   28:          /// entries in the app.config file.
   29:          /// </summary>
   30:          public static void Init()
   31:          {
   32:              XmlConfigurator.Configure();
   33:          }
   34:   
   35:          /// <summary>
   36:          /// Initialization of the log4net library based on a separate
   37:          /// configuration file.
   38:          /// </summary>
   39:          /// <param name="configFile"></param>
   40:          public static void Init(string configFile)
   41:          {
   42:              XmlConfigurator.ConfigureAndWatch(
   43:                  new FileInfo(configFile));
   44:          }
   45:   
   46:          /// <summary>
   47:          /// Initialize a StreamInsightLog object with the stated category
   48:          /// </summary>
   49:          /// <param name="category"></param>
   50:          public StreamInsightLog(string category)
   51:          {
   52:              this.log = log4net.LogManager.GetLogger(category);
   53:              this.category = category;
   54:          }
   55:   
   56:          /// <summary>
   57:          /// Log an exception to the ERROR log with the specified message
   58:          /// </summary>
   59:          public void LogException(Exception ex0, string fmt, params object[] vars)
   60:          {
   61:              log.Error(string.Format(fmt, vars), ex0);
   62:          }
   63:   
   64:          /// <summary>
   65:          /// Log a message of the specific log level
   66:          /// </summary>
   67:          public void LogMsg(TraceEventType type, string fmt, params object[] vars)
   68:          {
   69:              string message;
   70:   
   71:              if (vars.Any())
   72:                  message = String.Format(fmt, vars);
   73:              else
   74:                  message = fmt;
   75:   
   76:              switch (type)
   77:              {
   78:                  case TraceEventType.Verbose:
   79:                      log.Debug(message);
   80:                      break;
   81:   
   82:                  case TraceEventType.Information:
   83:                      log.Info(message);
   84:                      break;
   85:   
   86:                  case TraceEventType.Warning:
   87:                      log.Warn(message);
   88:                      break;
   89:   
   90:                  case TraceEventType.Error:
   91:                      log.Error(message);
   92:                      break;
   93:   
   94:                  case TraceEventType.Critical:
   95:                      log.Fatal(message);
   96:                      break;
   97:              }
   98:          }
   99:   
  100:          public void LogInfo(string fmt, params object[] vars)
  101:          {
  102:              log.InfoFormat(fmt, vars);
  103:          }
  104:   
  105:          public bool ShouldLog(TraceEventType type)
  106:          {
  107:              switch (type)
  108:              {
  109:                  case TraceEventType.Verbose:
  110:                      return log.IsDebugEnabled;
  111:   
  112:                  case TraceEventType.Information:
  113:                      return log.IsInfoEnabled;
  114:   
  115:                  case TraceEventType.Warning:
  116:                      return log.IsWarnEnabled;
  117:   
  118:                  case TraceEventType.Error:
  119:                      return log.IsErrorEnabled;
  120:   
  121:                  case TraceEventType.Critical:
  122:                      return log.IsFatalEnabled;
  123:   
  124:                  default:
  125:                      return false;
  126:              }
  127:          }
  128:      }
  129:  }

The logging interface is up and ready to go; in order to configure log4net (the underlying logging library), let’s create an appropriate app.config with this content, defining a:

  • Console appender (write out log records to the console)
  • File appender (write out log records to a file, commented out by default)
  • Two log categories (General and Adapter)
    1:  <?xml version="1.0" encoding="utf-8"?>
    2:  <configuration>
    3:    <configSections>
    4:      <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
    5:    </configSections>
    6:    <log4net>
    7:      <!-- Uncomment this block to log to files 
    8:      <appender name="ServiceLog" type="log4net.Appender.RollingFileAppender">
    9:        <file value="logs\StreamInsightHost.log" />
   10:        <appendToFile value="true" />
   11:        <maxSizeRollBackups value="10" />
   12:        <maximumFileSize value="50MB" />
   13:        <rollingStyle value="Size" />
   14:        <staticLogFileName value="true" />
   15:        <layout type="log4net.Layout.PatternLayout">
   16:          <header value="[Header]&#13;&#10;" />
   17:          <footer value="[Footer]&#13;&#10;" />
   18:          <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
   19:        </layout>
   20:      </appender>
   21:      -->
   22:      <!-- Log to the console -->
   23:      <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
   24:        <layout type="log4net.Layout.PatternLayout">
   25:          <conversionPattern value="%date %-5level - %message%newline" />
   26:        </layout>
   27:      </appender>
   28:      <root>
   29:        <!-- The master logging level; change to update all logging categories -->
   30:        <level value="INFO" />
   31:        <!-- Log to the console -->
   32:        <appender-ref ref="ConsoleAppender" />
   33:        <!-- Uncomment to log to file 
   34:        <appender-ref ref="ServiceLog" />      
   35:        -->
   36:      </root>
   37:      <!-- Levels are DEBUG, INFO, WARNING, ERROR and FATAL -->
   38:      <logger name="General">
   39:        <level value="INFO" />
   40:      </logger>
   41:      <logger name="Adapter">
   42:        <level value="DEBUG" />
   43:      </logger>    
   44:    </log4net>
   45:  </configuration>

 

  • In the Main.cs file, initialize the logging interface:
    1:  static void Main(string[] args)
    2:  {
    3:      StreamInsightLog.Init();
    4:  }

 We’re now set up for some logging and tracing.  On to actually building an adapter!