Getting Started with Log4Net

Back in the day when I was far less experienced I can remember creating websites and applications that didn’t have any error logging. Without error logging you are essentially blind to what's going on with your application.

For a modern application, Error logging is absolutely critical for visibility of errors, indicators for code that needs refactoring and to understand how users are using your app and what is happening during the times when you are not able to monitor it, i.e. the middle of the night.

Error logging is also invaluable to catch frustrating intermittent issues that may arise due to performance bottlenecks or infrastructure issues.

Thankfully the Apache Software foundation have created Log4Net, a dedicate logging system designed for use with the Microsoft .NET Framework. The developers at Apache took the well-established Log4J (Log for Java) and ported it for other frameworks such as .NET, PHP and others. For more details of Log4Net and the apache software foundation please view there website -> http://logging.apache.org/

Getting Started

To begin you first need to install Log4Net into your project. The easiest way to do this is to use Nuget and install the package to your main application or website project.

To install Log4Net follow these steps.

  1. open the Package Manager Console in Visual Studio click View -> Other Windows -> Package Manager Console.
  2. in the package manager console select the project in the dropdown you wish to install Log4Net to. If you are unsure, install it to your web or app project, not a class library.
  3. In the window type Install-Package log4net and press enter to execute.

Saving your Error Logs to SQL Server

Log4Net allows you to save your error logs to a number of different formats. These include, XML, via Email and stored in a Database. From my experience it’s much better to store logs in SQL server and if necessary setup a Log4Net email appender to trigger emails for serious and fatal errors. You can use any version of SQL Server or DBMS to store your logs. To begin lets create the Log table. Run the following SQL against your database in SSMS to create the table

CREATE TABLE [dbo].[Log] (
    [Id] [int] IDENTITY (1, 1) NOT NULL,
    [Date] [datetime] NOT NULL,
    [Thread] [varchar] (255) NOT NULL,
    [Level] [varchar] (50) NOT NULL,
    [Logger] [varchar] (255) NOT NULL,
    [Message] [varchar] (4000) NOT NULL,
    [Exception] [varchar] (2000) NULL
)

Now we have the table, the next thing we need to do is configure the Web.config or App.config with our Log4Net setup.

Unfortunately, the documentation on the Log4Net website is not overly intuitive and ive spend many hours in the past playing around with the config to get it working. What I find is the most reliable way of installing Log4Net in new projects is to copy the log4net config from an existing project and update the database connections string.

To make things more complicated, if you have a config issue, Log4Net simply will not log anything, nothing happens. This is necessary to ensure that an application cannot fail due to issues with the logging system, but I can be tricky to work out what’s gone wrong.

To make it easy for you, I have posted the Web.config areas for Log4Net from intermittentBug.com below. All you need to so it copy it and update the areas I have added hashes.

1 – add the Log4Net section – this goes in as a child of <configSections>

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

2 – add in the log4net section updating the areas that are hashed. This goes under your connection strings section

  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="ADONetAppender" />
      <appender-ref ref="DebugAppender" />
    </root>
    <logger name="NHibernate" additivity="false" />
    <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
      <bufferSize value="1" />
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <connectionString value="data source=####;User ID=####;Password=####;initial catalog=####;" />
      <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
      <parameter>
        <parameterName value="@log_date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@thread" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%thread" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@log_level" />
        <dbType value="String" />
        <size value="50" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%level" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@logger" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%logger" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@message" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%message" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@exception" />
        <dbType value="String" />
        <size value="2000" />
        <layout type="log4net.Layout.ExceptionLayout" />
      </parameter>
    </appender>
    <appender name="DebugAppender" type="log4net.Appender.DebugAppender">
      <immediateFlush value="true" />
      <layout type="log4net.Layout.SimpleLayout" />
    </appender>
  </log4net>

Setting up the XmlConfigurator

To enable us to use Log4Net within our .NET code we need to return the ILog object which provides access to the logging methods. To make life easy, I have created a class I have used in many different apps that works great. It makes sense if your project has a DAL (Data Access Library) to create this class in that so it can be called everywhere within your application.

    public class Log4Net
    {
        public static ILog GetLog4Net(Type ClassType)
        {
            log4net.Config.XmlConfigurator.Configure();
            return log4net.LogManager.GetLogger(ClassType);
        }
    }

Testing Log4Net

Ok so now you have setup the Database, the web.config and we have our GetLog4Net Class lets write some code to test to see if Log4Net is working and if we are getting any logs to the database.

For this example, I will install Log4Net into my unit test project. To do this I simply repeat the steps above for use my unit test project.

    [TestClass]
    public class TestLog4Net
    {
        private static ILog _log = Log4Net.GetLog4Net(typeof(TestLog4Net));

        [TestMethod]
        public void Log4NetTest()
        {
            var ex = new Exception("tester");

            _log.Info("unit test", ex);
            _log.Error("unit test", ex);
            _log.Fatal("unit test", ex);
            _log.Warn("unit test", ex);            
        }
    }

For every class in which you plan to use Log4Net you need to create the private static field _log passing the type of the current class.

When you run this class it should run successfully and in the database you will have 4 logs.

Real world example

If you have got Log4Net saving to your database, then you’re ready to start Error logging your application. Below is a real world example of how you can use Log4Net in a typical MVC controller method using a try catch.

    public class HomeController : Controller
    {
        private static ILog _log = Log4Net.GetLog4Net(typeof(HomeController));

        public ActionResult Index()
        {
            try
            {
                HomeModel Model = new HomeModel();
                return View(Model);
            }
            catch(Exception ex)
            {
                _log.Error("Error on HomeController - Action Index() " + ex.Message, ex);
                throw;
            }            
        }
    }

If any exceptions were triggered on the home page you will have full visibility of the exception in the database, and you can use SQL to filter down to see exactly the errors you’re interested in.

So there we have it, your now setup with Log4Net and have full visibility of any exceptions your users experience.


JGilmartin Profile Image

JGilmartin

Technical Architect at Pinewood Technologies

Rating: 2890

C# Expert

Offline


Tutorial Statistics
  • Views: 1318
  • Comments: 0
  • Author: JGilmartin (2890)
  • Date: 19/4/2017 22:16
Tags
C# .NET Visual Sudio

© 2016 - 2018 - IntermittentBug