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!

Comments (2)

  1. Kamarey says:

    Looks interesting, but just some words why do we need all this?

  2. The main reason for this post was to explain the StreamInsightLog class that I'll refer to in future posts; it's not directly necessary, but a lot of my example code uses it for tracing.