log4net tutorial– Great library for logging 27

log4net

facebooktwittergoogle_pluslinkedinmail

A lot of applications use logging as a way to store information about performed operations. Such data is very useful when you have to diagnose an issue. Logging could be done on many ways, but sometimes it’s just easier to use an existing solution. I’d like to introduce one of many libraries for logging, but quite powerful – log4net.

Get log4net

Let’s create a console application – log4netTutorial. Next you have to reference log4net library. The easiest way is to install NuGet package:

  • Right click your project
  • Click Manage NuGet Packages…
  • Click Online on the left hand panel
  • Type log4net in search box on the right side
  • Select log4net package and click Install

log4net NuGet pkg

How to use log4net

Now, let’s open Program.cs and add following field.

private static readonly log4net.ILog log =
    log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

The filed is initialized with log4net logger witch takes the type in which the filed is declared – this way it will be quite easy to identify what logged a message. So let’s try to log something.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace log4netTutorial
{
    class Program
    {
        private static readonly log4net.ILog log =
            log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        static void Main(string[] args)
        {
            log.Info("Application is working");
        }
    }
}

Run the program and… see nothing. Don’t worry, that’s expected.

Basic log4net configuration

You need to let log4net know where to put the data. First open AssemblyInfo.cs

AssemblyInfo

Add following line.

[assembly: log4net.Config.XmlConfigurator(Watch=true)]

This way log4net will know that it can look for configuration in the default application config file. Next, let’s open the config (App.config) and add following.

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

This time log4net will know that the real configuration is stored in XML node called log4net. So let’s add it.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
  </log4net>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

log4net message levels

Now, let’s think a bit how log4net works. There are 5 log message levels:

  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG

In the Program.cs file we used log.Info  method which logs INFO level message. You can use different method if you want to log different level messages.

There are also logging levels:

  1. OFF – no logging
  2. FATAL
  3. ERROR
  4. WARN
  5. INFO
  6. DEBUG
  7. ALL – everything is logged

You can specify what is the highest logging level in the config. For example, if you specify:

  • OFF – no message will be logged
  • FATAL – only FATAL messages will be logged
  • WARN – FATAL, ERROR and WARN messages will be logged
  • ALL – every message will be logged

To specify the logging level you have to add root node, then inside level node with value attribute.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <root>
      <level value="ALL" />
    </root>
  </log4net>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

log4net appenders

Console appender

Finally, you have to define where to put messages. In log4net there is a concept of appenders to which messages are appended. In the root node you can add appender-ref node with ref attribute which contains the name of appender to use. For example MyAppender.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="MyAppender" />
    </root>
  </log4net>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

Next, let’s define the appender. The simplest one is ConsoleAppender which logs messages to the application console.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="MyAppender" />
    </root>
    <appender name="MyAppender" type="log4net.Appender.ConsoleAppender">
    </appender>
  </log4net>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

Inside the appender XML node you have to define the message format. There is PatternLayout type which is commonly used.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="MyAppender" />
    </root>
    <appender name="MyAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level %logger - %message%newline" />
      </layout>
    </appender>
  </log4net>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

When you run the application you will see similar output:

2015-06-12 20:50:13,256 INFO log4netTutorial.Program - Application works
Press any key to continue . . .

The %name elements in the pattern are special tags that are replaced with values. Here is a short list of the most useful:

  • %date – date in local time zone
  • %utcdate – the same as %date, but in universal time
  • %level – message level
  • %logger – the logger declaring type (passed to GetLogger method; example in first C# code from the top of this post)
  • %message – the message
  • %newline – new line entry based on the platform on which it’s used

File appender

You can also define an appender that will add messages to a file.

    <appender name="MyFileAppender" type="log4net.Appender.FileAppender">
      <file value="application.log" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level %logger - %message%newline" />
      </layout>
    </appender>

More, you can use few appenders at the same time.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="MyAppender" />
      <appender-ref ref="MyFileAppender" />
    </root>
    <appender name="MyAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level %logger - %message%newline" />
      </layout>
    </appender>
    <appender name="MyFileAppender" type="log4net.Appender.FileAppender">
      <file value="application.log" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level %logger - %message%newline" />
      </layout>
    </appender>
  </log4net>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

Rolling file appender

There is one last very useful appender that I can recommend. Let’s assume that your application has to log a lot of messages, maybe 10’s of MB a day, maybe more. After few weeks of using your application might consume few GBs. This might be a case that you don’t want to have. Maybe it would be better if you could keep only a piece of that – the most recent one? log4net can help with that as well – there is a concept of rolling log. Rolling file has a maximum size defined. When the size is reached the file is backed up and new one is created. There is also defined a number of backups to keep.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="MyAppender" />
      <appender-ref ref="RollingFileAppender" />
    </root>
    <appender name="MyAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level %logger - %message%newline" />
      </layout>
    </appender>
    <appender name="MyFileAppender" type="log4net.Appender.FileAppender">
      <file value="application.log" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level %logger - %message%newline" />
      </layout>
    </appender>
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="rolling.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="5" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
      </layout>
    </appender>
  </log4net>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

log4net summary

This is just overview of log4net capabilities. I just wanted to present a quick start and basic configuration. If you need more details there is a good log4net tutorial on codeproject. Here is also log4net manual available.

 

facebooktwittergoogle_pluslinkedinmail

Leave a comment

Your email address will not be published. Required fields are marked *

27 thoughts on “log4net tutorial– Great library for logging

  • Perry Tew

    Excellent tutorial. I had stumbled across most of what I needed. I was missing the line

    [assembly: log4net.Config.XmlConfigurator(Watch=true)]

    As a new C# developer, this little step totally escaped me. Appreciate the time you spent with this article.

  • Andrew Polar

    Nice post but useless. It works when copy/paste example and stop working as soon as you pass code to web application. The whole purpose of elegant logging is to have them in web application and there the file just not created without any visible indication to a reason.

    • Mariusz Bojkowski Post author

      I focused on desktop application logging in this article. I believe that ‘elegant logging’ is not only reserved to web applications.

      I’m pretty sure that log4net can be used with web applications. I’ve seen working example. If I find some spare time, I will prepare a short post.

  • Ams1

    Hey,
    Very nice Article, thanks!
    Is there a way to configure a path where the log file should be placed in?
    Regards,
    Ams1

    • Mariusz Bojkowski Post author

      The ‘value’ attribute in ‘file’ node can contain path. You can use absolute path or relative. Example:
      <file value="C:\logs\application.log" />

  • Josh Ciardelli

    Just thought I should mention this here.

    Want to start by saying this is a great tutorial, Thanks!

    Followed this tutorial exactly and was not getting a log file created. Permissions were fine, everything else was fine but could not figure it out. Turned out having the configuration information in app.config without specifying in AssemblyInfo.cs was the issue.

    If you are using app.config for your log4net configuration please look below:

    Instead of this:
    [assembly: log4net.Config.XmlConfigurator(Watch=true)]

    do this:
    [assembly: log4net.Config.XmlConfigurator(ConfigFile=”app.config”, Watch=true)]

  • Daniele

    instead of
    [assembly: log4net.Config.XmlConfigurator(Watch = true)]

    you can use

    log4net.Config.XmlConfigurator.Configure();
    in the main starting class

    • Dilhan

      I am using Log4Net in my ASP.NET API Controller project. Is it good practise to use ILog directly or should I create a wrapper class and use for Dependancy Injection. Or just use a static reference to log4net logger instance.

  • Avi Ken

    I observed one thing with this implementation, each time I run the code, logs are getting generated under `bin\debug\application.log` and not under `applicationroot\application.log` or `applicationroot\Logs\application.log` file.