Shiman’s Weblog

Collecting stones from the sea-shore.

How to Log in C# .NET with log4net : A Tutorial with Practical Example

While developing software, you will always have to keep it in your mind that your software is going to be crashed someday. And when you are about to fix the bugs, you have to have something in your hand, which will give you a hint from where to start. This is why you need the logging service to log the software’s functionalities. You can build your own library for this purpose. But, for the beginning, I will recommend you to use the assembly, ‘log4net ‘, a free assembly developed by Apache.

As the first step you need to download the log4net.dll file. You can download it either from my shared files on your right hand side bar, or from here.

Now, you need to follow the steps to develop a logging service.

·         Add the reference of log4net.dll.

·         Add a new class Named CLogger.cs in the project you want to add logging.

·         Add an Application Configuration File named App.config to your application if you do not have one.

·         Add the following code segment under <configuration>…</configuration> tag.

<?xml version=1.0 encoding=utf-8 ?>

<configuration>

       <configSections>

              <section name=log4net type=log4net.Config.Log4NetConfigurationSectionHandler, log4net />

       </configSections>

       <log4net>

              <appender name=LogFileAppender type=log4net.Appender.FileAppender>

                     <param name=File value=D:\Temp\ApplicationLog.log />

                     <param name=AppendToFile value=true />

                     <layout type=log4net.Layout.PatternLayout>

                           <param name=Header value=“” />

                           <param name=Footer value=“” />

                           <param name=ConversionPattern value=%d [%t] %-5p %m%n />

                     </layout>

              </appender>

              <appender name=ConsoleAppender type=log4net.Appender.ConsoleAppender >

                     <layout type=log4net.Layout.PatternLayout>

                           <param name=Header value=[Header]\r\n />

                           <param name=Footer value=[Footer]\r\n />

                           <param name=ConversionPattern value=%d [%t] %-5p %m%n />

                     </layout>

              </appender>

              <root>

                     <level value=DEBUG />

                     <appender-ref ref=LogFileAppender />

                     <appender-ref ref=ConsoleAppender />

              </root>

       </log4net>

</configuration>

The configuration file has included two appenders, i) Console Appender and ii) File Appender. You can use either or both. The <level> tag specify the log-level. By assigning its value to “DEBUG”, we enabled the logging service to write logs of all levels. Here is a little discussion on it.

In an earlier post, I said that utility classes should be static. Our CLogger is also a utility class. So, we are going to declare this class as a static class. But before that, we will make an enum. We can do without this enum, but it will make our program flawless.

·         Add a new class named ELogLevel.cs to your project.

·         Write the following code segment in ELogLevel.cs.

using System;

using System.Collections.Generic;

using System.Text;

 

namespace Utility

{

    namespace LoggingService

    {

        public enum ELogLevel

        {

            DEBUG = 1,

            ERROR,

            FATAL,

            INFO,

            WARN

        }

    }

}

Log4Net supports five levels of logs with five methods. In the CLogger class we are going to call those methods depending on the passed parameters from the application. It is so likely that you will make a spelling mistake and the logging service will not work. This is why we are giving our service a professional touch by having this enum.

·         Now, write the following code in CLogger.cs.

using System;

using System.Collections.Generic;

using System.Text;

using log4net;

using log4net.Config;

using System.Diagnostics;

using System.Reflection;

 

namespace Utility

{

    namespace LoggingService

    {

        public static class CLogger

        {

            #region Members

            private static readonly ILog logger = LogManager.GetLogger(typeof(CLogger));

           

            #endregion

 

            #region Constructors

            static CLogger()

            {

                XmlConfigurator.Configure();

            }

            #endregion

 

            #region Methods

 

            public static void WriteLog(ELogLevel logLevel, String log)

            {

                if (logLevel.Equals(ELogLevel.DEBUG))

                {

                    logger.Debug(log);

                }

                else if (logLevel.Equals(ELogLevel.ERROR))

                {

                    logger.Error(log);

                }

                else if (logLevel.Equals(ELogLevel.FATAL))

                {

                    logger.Fatal(log);

                }

                else if (logLevel.Equals(ELogLevel.INFO))

                {

                    logger.Info(log);

                }

                else if (logLevel.Equals(ELogLevel.WARN))

                {

                    logger.Warn(log);

                }

            }

            #endregion

        }       

    }

}

YO! Your logging service is ready to serve. Just write logs from your application as you need.

CLogger.WriteLog(ELogLevel.DEBUG, “This is a Debug log.”);

CLogger.WriteLog(ELogLevel.INFO, “This is a Information log.”);

CLogger.WriteLog(ELogLevel.WARN, “This is a Warning log.”);

CLogger.WriteLog(ELogLevel.ERROR, “This is a Error log.”);

CLogger.WriteLog(ELogLevel.FATAL, “This is a Fatal Error log.”);

Nice work! You have created a log file for your application.Find your log file in “D:\Temp” directory. You configured this location in your configuration file, remember? If not, take a close look. In later post I will discuss about the configuration file for Log4Net. So, stay tuned.

July 9, 2008 - Posted by shiman | C#.Net, Computer Science, OOP, Programming, S/W Engineering | , , , , , | 15 Comments

15 Comments »

  1. Excellent!!! very helpful, indeed!

    One thing though, how do you provide email support?

    Cheers,

    Jimar

    Comment by Jimar | September 4, 2008 | Reply

  2. Thanks Jimar. I didn’t understand the question “how do you provide email support?” If the question is if I provide email support, then, yes, sometimes I provide email support, but most of the time it is no. But we can discuss any related thing here, like a discussion board. Coz, email make the things private. If things can be be helpful to others, its good to discuss it in public. May be you can get some better support than I can provide.
    If you are asking about “email service” using programs, then, you can search web for that, or stick with me. Hopefully, I will post that stuff within a few days.

    Comment by shiman | September 5, 2008 | Reply

  3. What was trying to know if log4net supports automatic emailing of log messages (say, actual email address will be taken from a database)…Apologies for not making myself clear about this one.

    Comment by Jimar | September 5, 2008 | Reply

  4. Enable email service for sending the log messages to a specific email address

    <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
    	<to value="to@domain.com" />
    	<from value="from@domain.com" />
    	<subject value="test logging message" />
    	<smtpHost value="SMTP SERVER ADDRESS" />
    	<bufferSize value="512" />
    	<lossy value="true" />
    	<evaluator type="log4net.Core.LevelEvaluator">
    		<threshold value="FATAL"/>
    	</evaluator>
    	<layout type="log4net.Layout.PatternLayout">
    		<conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" />
    	</layout>
    </appender>

    Add this appender to the App.config file under <log4net> node. Take care of the attributes. After that, add the following line under <root> node.

    <appender-ref ref="SmtpAppender" />

    But I think it’s not a good idea to use email log setting the threshold below ERROR.

    Comment by shiman | September 9, 2008 | Reply

  5. hello
    thanks for this page. it was really usefull.
    i’d like to configure which logs are written in the log file.
    is it possible to do that in the config file?

    Comment by Chris | November 12, 2008 | Reply

  6. Hi Chris,

    You reminded me about a something I had to do long ago. Thanks for your query. You will find the answer in the following link:

    http://shiman.wordpress.com/2008/11/13/log4net-cofiguration

    -Author

    Comment by shiman | November 13, 2008 | Reply

  7. I think that if you work in this way you then lose the benefit of log4net hierarchy mechanism !

    For best practice & perf. use also the Is… test before calling the logger. For instance..

    public static void LogFormat(LogLevels level, String log, params object[] args)
    {
    Log(level, string.Format(log, args));
    }

    public static void Log(LogLevels level, String log)
    {
    switch(level)
    {
    case LogLevels.INFO:
    if(logger.IsInfoEnabled) logger.Info(log);
    break;

    case LogLevels.WARN:
    if(logger.IsWarnEnabled) logger.Warn(log);
    break;

    case LogLevels.ERROR:
    if(logger.IsErrorEnabled) logger.Error(log);
    break;

    case LogLevels.FATAL:
    if(logger.IsFatalEnabled) logger.Fatal(log);
    break;

    case LogLevels.DEBUG:
    if(logger.IsDebugEnabled) logger.Debug(log);
    break;
    }
    }

    Comment by Semio | December 9, 2008 | Reply

  8. Yeah, that is so thoughtful of you. Switch is always faster, and Is… test is a legitmate check. It has to be done to gain the best performance. Thanks.

    -Author

    Comment by shiman | December 11, 2008 | Reply

  9. use switch in WriteLog function !

    public static void WriteLog(ELogLevel logLevel, String log)
    {
    switch (logLevel)
    {
    case ELogLevel.DEBUG:
    default:
    logger.Debug(log);
    break;
    case ELogLevel.ERROR:
    logger.Error(log);
    break;
    case ELogLevel.FATAL:
    logger.Fatal(log);
    break;
    case ELogLevel.INFO:
    logger.Info(log);
    break;
    case ELogLevel.WARN:
    logger.Warn(log);
    break;
    }
    }

    Comment by yair | February 4, 2009 | Reply

  10. This looks good for a single user application. What about a middle-tier app (COM+ or IIS)?

    How could file contention as well as performance be minimized?

    It would be nice if there was an easy way to log this information to memory only. Then if/when necessary use a different app/process to process the data.

    Any thoughts on how to approach a solution?

    Comment by Harold | March 26, 2009 | Reply

  11. Nice tutorial, although I a,m not sure if you really need to wrap log4net, because it should be wrapped enough right?

    Comment by MichaelL | July 17, 2009 | Reply

  12. Hi folks,

    I have configured log4net as described in this tutorial.
    Log file does not get created even when a statement executes fine.

    Any clue?

    Comment by Praveen | October 8, 2009 | Reply

  13. Got the solution!
    This needs to be added in AssemblyInfo.cs. Which triggers the program to look for App.config file by default.

    // Configure log4net using the .config file
    [assembly: log4net.Config.XmlConfigurator(Watch = true)]

    Comment by Praveen | October 8, 2009 | Reply

  14. Hi,

    I need to create a log file and this will be acessed to many treads.

    To this, I need to manager this access. How can I do this?

    Comment by Abdul Hade | November 4, 2009 | Reply

    • Hi Abdul,
      I am not so clear about your sayings. If you are to say about the permissions to access the log file, I must say it is out of this context.

      /Author

      Comment by shiman | November 5, 2009 | Reply


Leave a comment