Click here to Skip to main content
15,860,859 members
Articles / Programming Languages / C#

An enhanced wrapper around the LOG4NET logging framework

Rate me:
Please Sign up or sign in to vote.
3.77/5 (15 votes)
26 Mar 2005CPOL7 min read 100.1K   1.1K   57   14
An article about an enhanced wrapper around the popular logging framework LOG4NET.

An example logging output inside a console window

Introduction

(For the latest changes, please see the History section below)

In this article, I'll show you a class that simplified my life in the last years when it comes to logging (error) messages from a .NET application, no matter whether it is a Windows GUI application, a Windows Service or a Windows web application.

By using the single class described in this article you should be able to provide meaningful logging information in every state of your application with a minimum of effort and a maximum of flexibility.

Background

Again (like in some of my other articles), I did not write the logging part itself from scratch but rather added my own code to the popular and well-tested superb logging framework LOG4NET.

The main class for logging is the class LogCentral. I tried to hide all the LOG4NET classes and interfaces inside my class so that the user of the LogCentral class never gets in direct contact with the LOG4NET services. The reason was to allow maximum flexibility in that if I ever want to change the underlying logging engine to another engine, no code changes other than inside the LogCentral class itself are necessary.

Please note: A possible negative effect of the hiding of the LOG4NET is the fact that not all of the extended LOG4NET features are available to the user of the LogCentral class. In practice this was never a problem inside my small- to mid-size projects, but could be if you try to do logging to the extreme. In such cases it would probably be better to directly use a logging framework like LOG4NET and do not use the LogCentral class.

Supported Features

The LogCentral class provides the following features:

Single entry point for logging

To log a message, you simply use the static property LogCentral.Current to access an always-available instance of the logging class.

Logging of different types of messages by simple function calls

The LogCentral class provides easy access to actually log a message by providing overloads for several logging types.

Example: The following call logs an informational message.

C#
...
 
LogCentral.Current.LogInfo( 
    "This is an informational message." );
 
...

The following functions are defined inside the LogCentral class (parameters are omitted for better readability):

  • public void LogInfo() - Logs an informational message.
  • public void LogError() - Logs an error message, e.g. inside a catch block.
  • public void LogDebug() - Logs a debug message that should not appear in release builds (it is up to you to properly configure the class through the configuration file so that the debug message really is not logged during release builds, though).
  • public void LogWarn() - Logs a warning message.
  • public void LogFatal() - Logs a fatal message.

Standard configuration through the known LOG4NET XML configuration schema

Although I said that the LogCentral class hides all the LOG4NET code from the user of the class, I did not provide my own configuration file syntax. Therefore, the configuration for the LogCentral class is exactly the same as for the LOG4NET itself. All documentation for configuring the LOG4NET framework applies to the LogCentral class as well.

An example configuration inside your standard application configuration file (namely "YourExeName.exe.config" for Windows executables or "Web.config" for Web Services and web applications) might look like following:

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section 
      name="log4net" 
      type="System.Configuration.IgnoreSectionHandler" />
  </configSections>
  
  <log4net>
    <appender 
      name="RollingLogFileAppender" 
      type="log4net.Appender.RollingFileAppender">
      <param name="File" value="Test.log" />
      <param name="AppendToFile" value="true" />
      <param name="MaxSizeRollBackups" value="9" />
      <param name="MaximumFileSize" value="10MB" />
      <param name="RollingStyle" value="Size" />
      <param name="StaticLogFileName" value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <param 
          name="Header" 
          value="\r\n\r\n---------------------------------------------\r\n" />
        <param 
          name="Footer" 
          value="\r\n---------------------------------------------\r\n\r\n" />
        <param name="ConversionPattern" value="%d [%t] %-5p - %m%n" />
      </layout>
    </appender>
  
    <appender 
      name="ColoredConsoleAppender" 
      type="log4net.Appender.ColoredConsoleAppender">
      <mapping>
        <level value="ERROR" />
        <foreColor value="White" />
        <backColor value="Red" />
      </mapping>
      <mapping>
        <level value="DEBUG" />
        <backColor value="Green" />
      </mapping>
      <mapping>
        <level value="INFO" />
        <foreColor value="White" />
      </mapping>
  
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%-5p: %m%n" />
      </layout>
    </appender>
  
    <root>
      <level value="ALL" />
      <appender-ref ref="RollingLogFileAppender" />
      <appender-ref ref="ColoredConsoleAppender" />
    </root>
  </log4net>
</configuration>

Automatically logging to additional destinations

In addition to the logging destinations ("appenders") defined in your configuration file, the LogCentral class tries to log each message to the following destinations as well:

Event handler for adding additional text before a message gets logged

A common requirement in my applications was to provide additional information to the messages that actually get logged, depending on the current context of the application. E.g. when an SQL query failed, I wanted to log the actual SQL query too, not just the exception that was raised during the execution of the SQL query.

For such scenarios, I added support to provide event handlers by the application to the LogCentral class that get called just before a message is actually being logged. The handler can add additional information to the message being logged.

Example

The following code adds a handler for the event. Usually you do that at the start of the application:

C#
...
  
// Add handler.
LogCentral.Current.RequestMoreInformation += 
    new LogCentralRequestMoreInformationEventHandler(
    Current_RequestMoreInformation );  
...

The actual handler Current_RequestMoreInformation could be defined as following. In this example, the variable this.counter is some class member that gets modified by certain methods and is logged whenever a severe message is being logged.

C#
/// <summary>
/// This handler is called before a message is actually
/// being logged. Use this handler to provide more detailed 
/// information to the message being logged.
/// </summary>
private static void Current_RequestMoreInformation(
    object sender, 
    LogCentralRequestMoreInformationEventArgs e )
{
    // Only add for certain types.
    if ( e.Type==LogCentralRequestMoreInformationEventArgs.LogType.Error ||
    e.Type==LogCentralRequestMoreInformationEventArgs.LogType.Fatal ||
    e.Type==LogCentralRequestMoreInformationEventArgs.LogType.Warn )
    {
        // Add information that would otherwise not be visible
        // to the logging class.
        e.MoreInformationMessage += 
            string.Format(
            "The current counter value is '{0}'.",
            this.counter );
    }
}

Now whenever a message is logged, the Current_RequestMoreInformation handler is being called by the logging class.

Default handlers provided

The LogCentral class itself uses this event internally to provide context information for the following items:

  • HTTP information

    When running inside a web context, several information like requested URI, referer URI, user host name, session information etc. is being logged.

  • Assembly information

    Information about the assemblies of the running application are being logged. These information include assembly path, assembly date, assembly version, etc.

  • Environmental information

    Information about the local Windows environment is being logged. These information include current logged in user, user domain, machine name, CLR version, current working directory, etc.

  • Network information

    Information about the host name and the IP addresses of the computer running the application are being logged.

Please note: The default handlers only add the context information if the logged message is of type "warn", "error" or "fatal".

Event handler after a message got logged

For completeness, there also exists an event that gets raised after a log occurred. You can add your own handler to that event to perform miscellaneous tasks after a message got logged, e.g. cleaning up resources or something similar.

Example

The following code adds a handler for the event. Usually you do that at the start of the application:

C#
...
  
// Add handler.
LogCentral.Current.Log += 
    new LogCentralLogEventHandler(
    Current_Log );
  
...

The actual handler Current_Log could be defined as following. In this example it simply writes a notify message to the Debug output.

C#
/// <summary>
/// This handler is called after each call to one of the 
/// LogError, LogDebug, etc. function.
/// </summary>
private static void Current_Log(
    object sender, 
    LogCentralLogEventArgs e )
{
    System.Diagnostics.Debug.Write( "Log occured." );
}

Other features in brief

  • Protecting of passwords

    Every message that gets logged is being checked for potentially security related keyword like "password" or similar. If such a keyword is detected, a warning message ("...illegal words contained...") is actually being logged instead of the message itself.

  • Provide access to the path of the configuration file

    By using the ConfigurationFilePath property, you can read the full path of the current configuration property, e.g. "C:\Inetpub\WwwRoot\MyWebApplication\Web.config". Sometimes this can be useful when you, for example, want to read other files from exactly the same folder where the configuration file is stored.

Using the Code in your Projects

The code download for this article contains a small example project as well as precompiled versions (.NET version 1.1, debug and release) of the library. To use it in your own projects you have (at least) two possibilities:

  1. Simply copy the content of the "Release" folder (namely the files "log4net.dll" and "ZetaLogger.dll") to a folder of your choice and add a reference to it by using the Add reference command in Visual Studio .NET 2003.
  2. Copy and add the source file "LogCentral.cs" to your project so that it gets compiled with your project. Please note that you still need to add a reference to the "log4net.dll" library.

I recommend that you first take a look at the example application and then use the library inside your own projects.

Conclusion

In this article, I've shown you a class for adding logging capabilities to your application. I'm using the class since more than two years, slightly enhancing the functionality from time to time. Hopefully you'll find this class useful, too.

For questions, comments and remarks, please use the commenting section at the bottom of this article.

References

  1. The LOG4NET framework homepage.

History

  • 2005-03-26

    Created first version of article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Zeta Software GmbH
Germany Germany
Uwe does programming since 1989 with experiences in Assembler, C++, MFC and lots of web- and database stuff and now uses ASP.NET and C# extensively, too. He has also teached programming to students at the local university.

➡️ Give me a tip 🙂

In his free time, he does climbing, running and mountain biking. In 2012 he became a father of a cute boy and in 2014 of an awesome girl.

Some cool, free software from us:

Windows 10 Ereignisanzeige  
German Developer Community  
Free Test Management Software - Intuitive, competitive, Test Plans.  
Homepage erstellen - Intuitive, very easy to use.  
Offline-Homepage-Baukasten

Comments and Discussions

 
Questionlog4Net Archieval Pin
jyotink3-Apr-08 4:35
jyotink3-Apr-08 4:35 
QuestionHow to get errors from log4net??? Pin
rajabha22-Nov-07 18:05
rajabha22-Nov-07 18:05 
AnswerRe: How to get errors from log4net??? Pin
Uwe Keim22-Nov-07 18:32
sitebuilderUwe Keim22-Nov-07 18:32 
GeneralRe: How to get errors from log4net??? Pin
rajabha22-Nov-07 18:46
rajabha22-Nov-07 18:46 
Questionloggin from web site on oracle database Pin
Mohamed Saeed Mohamed5-May-07 12:32
Mohamed Saeed Mohamed5-May-07 12:32 
AnswerRe: loggin from web site on oracle database Pin
Uwe Keim5-May-07 19:20
sitebuilderUwe Keim5-May-07 19:20 
NewsNewest version Pin
Uwe Keim7-Apr-06 5:58
sitebuilderUwe Keim7-Apr-06 5:58 
QuestionHow to combine the output from a second process Pin
smidha9-Jun-05 2:25
susssmidha9-Jun-05 2:25 
GeneralConfig file Pin
al_todd16-May-05 4:58
al_todd16-May-05 4:58 
GeneralPerformance differences Pin
Sean McCormack28-Mar-05 9:50
Sean McCormack28-Mar-05 9:50 
Great article! Just wondering if you did any performance benchmarking between using log4net vs log4net with your wrapper on top? I think most people will want to know that before rolling it into their projects...

Sean McCormack
http://www.adapdev.com
Open Source for .NET
GeneralRe: Performance differences Pin
Uwe Keim28-Mar-05 17:19
sitebuilderUwe Keim28-Mar-05 17:19 
GeneralRe: Performance differences Pin
tafkat29-Mar-05 7:54
tafkat29-Mar-05 7:54 
GeneralRe: Performance differences Pin
Anonymous31-Mar-05 2:20
Anonymous31-Mar-05 2:20 
GeneralRe: Performance differences Pin
Wcohen27-Dec-06 5:27
Wcohen27-Dec-06 5:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.