Monday, October 31, 2011

Logging in MVC Part 4 – Log4Net

Introduction

In this article we will quickly add Log4Net into the website so that later on we can decide whether to use Log4Net or NLog to log our custom messages.
Log4Net is a very widely used logger and it is quite likely that you have 3rd party dependencies in your website that already use Log4Net so it can be a good idea to track any messages that it logs.

Log4Net

The steps we need to follow are:
1. Download Log4Net
2. Add a reference to Log4Net
3. Add a table in our database to store the Log4Net logs
4. Modify the web.config file for Log4Net
5. Implement a Log4NetLogger that implements our ILogger interface.


Setting up the database

Run the following script to create the table that Log4Net will log message to:
01SET ANSI_NULLS ON
02GO
03
04SET QUOTED_IDENTIFIER ON
05GO
06
07SET ANSI_PADDING ON
08GO
09
10CREATE TABLE [dbo].[Log4Net_Error](
11    [Id] [int] IDENTITY(1,1) NOT NULL,
12    [Date] [datetime] NOT NULL,
13    [Thread] [varchar](255) NOT NULL,
14    [Level] [varchar](50) NOT NULL,
15    [Logger] [varchar](255) NOT NULL,
16    [Message] [varchar](4000) NOT NULL,
17    [Exception] [varchar](2000) NULL
18) ON [PRIMARY]
19
20GO
21
22SET ANSI_PADDING OFF
23GO

Web.config configuration

Add the following to the top of your web.config file:
1<configuration>
2  <configSections>
3   ...
4  <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
5  ...
6  </configSections>
7</configuration>
Add the following underneath the configuration element in your web.config file:
01<log4net>
02    <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
03      <bufferSize value="100" />
04      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
05      <connectionString value="data source=[Machine]/[Instance];Initial Catalog=[DatabaseName];Integrated Security=True" />
06      <commandText value="INSERT INTO Log4Net_Error ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
07      <parameter>
08        <parameterName value="@log_date" />
09        <dbType value="DateTime" />
10        <layout type="log4net.Layout.RawTimeStampLayout" />
11      </parameter>
12      <parameter>
13        <parameterName value="@thread" />
14        <dbType value="String" />
15        <size value="255" />
16        <layout type="log4net.Layout.PatternLayout">
17          <conversionPattern value="%thread" />
18        </layout>
19      </parameter>
20      <parameter>
21        <parameterName value="@log_level" />
22        <dbType value="String" />
23        <size value="50" />
24        <layout type="log4net.Layout.PatternLayout">
25          <conversionPattern value="%level" />
26        </layout>
27      </parameter>
28      <parameter>
29        <parameterName value="@logger" />
30        <dbType value="String" />
31        <size value="255" />
32        <layout type="log4net.Layout.PatternLayout">
33          <conversionPattern value="%logger" />
34        </layout>
35      </parameter>
36      <parameter>
37        <parameterName value="@message" />
38        <dbType value="String" />
39        <size value="4000" />
40        <layout type="log4net.Layout.PatternLayout">
41          <conversionPattern value="%message" />
42        </layout>
43      </parameter>
44      <parameter>
45        <parameterName value="@exception" />
46        <dbType value="String" />
47        <size value="2000" />
48        <layout type="log4net.Layout.ExceptionLayout" />
49      </parameter>
50    </appender>
51
52    <!-- Set root logger level to DEBUG and its only appender to A1 -->
53    <root>
54      <level value="DEBUG" />
55      <appender-ref ref="AdoNetAppender" />
56    </root>
57  </log4net>

Implement a Log4NetLogger

Now let’s create a logger class for Log4Net that implements our ILogger interface (discussed in part 3).1. Create a new folder underneath the Services folder. Our folder structure will be like this:
Services -> Logging -> Log4Net
2. Create a new class file in the new folder and name it ‘Log4NetLogger.cs’.
3. Add the following code to the class:
01using System;
02using System.Collections.Generic;
03using System.Linq;
04using System.Web;
05
06using log4net;
07
08namespace MvcLoggingDemo.Services.Logging.Log4Net
09{
10 public class Log4NetLogger : ILogger
11 {
12
13 private ILog _logger;
14
15 public Log4NetLogger()
16 {
17 _logger = LogManager.GetLogger(this.GetType());
18 }
19
20 public void Info(string message)
21 {
22 _logger.Info(message);
23 }
24
25 public void Warn(string message)
26 {
27 _logger.Warn(message);
28 }
29
30 public void Debug(string message)
31 {
32 _logger.Debug(message);
33 }
34
35 public void Error(string message)
36 {
37 _logger.Error(message);
38 }
39
40 public void Error(Exception x)
41 {
42 Error(LogUtility.BuildExceptionMessage(x));
43 }
44
45 public void Error(string message, Exception x)
46 {
47 _logger.Error(message, x);
48 }
49
50 public void Fatal(string message)
51 {
52 _logger.Fatal(message);
53 }
54
55 public void Fatal(Exception x)
56 {
57 Fatal(LogUtility.BuildExceptionMessage(x));
58 }
59 }
60}
You will notice that the code above is almost identical to the one we created for NLog. The only difference is the line in the constructor that instantiates the Log4Net logger.

Testing the Log4Net logger

The last step is to write some code that uses our new debugger. Update the Index method of our Activity controller like this:
(You will also need to add a refernce to the namespace, “MvcLoggingDemo.Services.Logging.Log4Net” at the top of your file)
01public ActionResult Index()
02 {
03 IEnumerable list = activityRepository.GetAll();
04
05 NLogLogger logger = new NLogLogger();
06 logger.Info("Test message for NLog");
07
08 Log4NetLogger logger2 = new Log4NetLogger();
09 logger2.Info("Test message for Log4Net");
10
11 try
12 {
13 throw new Exception("A test exception");
14 }
15 catch(Exception ex)
16 {
17 Console.WriteLine("ERROR - An error has occurred");
18 }
19
20 return View(list);
21 }
Now go to the Index page for Activities and inspect the Log4Net_Error table to ensure that the message has been logged.

Conclusion

We now have Elmah, NLog, Log4Net and Health monitoring setup and working on our website. The next few articles will focus on building a log reporting viewer so that we can tie all of these things together so that we can see a consolidated and consistent view of everything that is getting logged on our website.

No comments:

Twitter Bird Gadget