tags:

views:

673

answers:

2

I have written a simple log4net wrapper. I was wondering whether this wrapper code could be improved.

I am little bit worried about the reflection code thrown in into each Logging Function (Info, Warn etc) to get the Calling function name. Whether there could be any possible performance problems in due to this?

namespace Acqueon.Pacer.Core.Helpers
{
    #region Imports

    using System;
    using System.Diagnostics;
    using System.Reflection;

    using log4net;

    #endregion

    /// <summary>
    /// log4net Log helper
    /// </summary>
    public sealed class Logger
    {
        #region Constants and Fields

        /// <summary>
        /// Determines whether the DEBUG Mode is enabled.
        /// </summary>
        private readonly bool isDebugEnabled;

        /// <summary>
        /// The is error enabled.
        /// </summary>
        private readonly bool isErrorEnabled;

        /// <summary>
        /// Determines whether the FATAL Mode is enabled.
        /// </summary>
        private readonly bool isFatalEnabled;

        /// <summary>
        /// Determines whether the INFO Mode is enabled.
        /// </summary>
        private readonly bool isInfoEnabled;

        /// <summary>
        /// Determines whether the WARN Mode is enabled.
        /// </summary>
        private readonly bool isWarnEnabled;

        /// <summary>
        /// The logger object
        /// </summary>
        private readonly ILog log;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the Logger class.
        /// </summary>
        public Logger()
            : this(new StackTrace().GetFrame(1).GetMethod().DeclaringType)
        {
        }

        /// <summary>
        /// Initializes a new instance of the Logger class.
        /// </summary>
        /// <param name="type">
        /// The type of logger.
        /// </param>
        public Logger(Type type)
        {
            this.log = LogManager.GetLogger(type);

            this.isDebugEnabled = this.log.IsDebugEnabled;
            this.isErrorEnabled = this.log.IsErrorEnabled;
            this.isInfoEnabled = this.log.IsInfoEnabled;
            this.isFatalEnabled = this.log.IsFatalEnabled;
            this.isWarnEnabled = this.log.IsWarnEnabled;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Logs the debug message.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        public void Debug(string message)
        {
            if (this.isDebugEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Debug(methodBase.Name + " : " + message);
            }
        }

        /// <summary>
        /// Logs the debug message and the exception.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        /// <param name="exception">
        /// The exception.
        /// </param>
        public void Debug(string message, Exception exception)
        {
            if (this.isDebugEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Debug(methodBase.Name + " : " + message, exception);
            }
        }

        /// <summary>
        /// Logs the error message.
        /// </summary>
        /// <param name="errorMessage">
        /// The error message.
        /// </param>
        public void Error(string errorMessage)
        {
            if (this.isErrorEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Error(methodBase.Name + " : " + errorMessage);
            }
        }

        /// <summary>
        /// Logs the error message and the exception.
        /// </summary>
        /// <param name="errorMessage">
        /// The error message.
        /// </param>
        /// <param name="exception">
        /// The exception.
        /// </param>
        public void Error(string errorMessage, Exception exception)
        {
            if (this.isErrorEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Error(methodBase.Name + " : " + errorMessage, exception);
            }
        }

        /// <summary>
        /// Logs the fatal error message.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        public void Fatal(string message)
        {
            if (this.isFatalEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Fatal(methodBase.Name + " : " + message);
            }
        }

        /// <summary>
        /// Logs the fatal error message and the exception.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        /// <param name="exception">
        /// The exception.
        /// </param>
        public void Fatal(string message, Exception exception)
        {
            if (this.isFatalEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Fatal(methodBase.Name + " : " + message, exception);
            }
        }

        /// <summary>
        /// Logs the info message.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        public void Info(string message)
        {
            if (this.isInfoEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Info(methodBase.Name + " : " + message);
            }
        }

        /// <summary>
        /// Logs the info message and the exception.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        /// <param name="exception">
        /// The exception.
        /// </param>
        public void Info(string message, Exception exception)
        {
            if (this.isInfoEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Info(methodBase.Name + " : " + message, exception);
            }
        }

        /// <summary>
        /// Logs the warning message.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        public void Warn(string message)
        {
            if (this.isWarnEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Warn(methodBase.Name + " : " + message);
            }
        }

        /// <summary>
        /// Logs the warning message and the exception.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        /// <param name="exception">
        /// The exception.
        /// </param>
        public void Warn(string message, Exception exception)
        {
            if (this.isWarnEnabled)
            {
                MethodBase methodBase = new StackTrace().GetFrame(1).GetMethod();
                this.log.Warn(methodBase.Name + " : " + message, exception);
            }
        }

        #endregion
    }
}
+3  A: 

Why can't you just use this:

The following PatternLayout patterns extract location information:

%F Used to output the file name where the logging request was issued

%L Used to output the line number from where the logging request was issued

%M Used to output the method name where the logging request was issued

%C Used to output the fully qualified class name of the caller issuing the logging request.

Please note that in both cases stack walk is required, which is expensive.

<appender name="DebugOut"
         type="log4net.Appender.OutputDebugStringAppender">
 <layout type="log4net.Layout.PatternLayout">
   <conversionPattern value="%-5p [%t] %C{1}.%M - %m%n" />
 </layout>

Alex Reitbort
%M will give the helper function name .. if I use a Wrapper for log4net
Zuhaib
Thank you .. I will remove the reflection part from the helper
Zuhaib
@ZuhaibZ - I think the point is that the entire class is unnecessary. As Grzenio mentioned, Log4Net will do all of this for you.
TrueWill
+1  A: 

There will eventually be a performance hit from the reflection code, obviously depending on how many log messages you are logging throughout your application.

You can also already output line number, a basic call stack and method information using the correct conversion pattern. This functionality is present in log4net by default - and the docs warn you that there is a performance hit.

Lastly, I would implement your wrapper class as extension methods on Exception.

sgrassie
Thanks for the Extension methods tip .. dono why I didn't think of that :)
Zuhaib
"Lastly, I would implement your wrapper class as extension methods on Exception" - why? Log4Net isn't only used to log exceptions.
Joe
@Joe - Well, of course not, obviously you are going to have a lot of debug/info statements peppered around your code at interesting places logging stuff that you expect.I always find that any time I want to output stacktrace information or anything like that, it's when something unexpected happens, which is always in an Exception of some kind. Also, having all this encapsulated in a single class enables you to change exactly what stacktrace information you collect across your entire codebase. Read more here: http://elegantcode.com/2009/07/31/exception-logging-with-entlib-made-simple/
sgrassie
Anyways I dropped the idea of using a helper .. you made your point
Zuhaib