log4net is a tool to help us easily add logging
capability to .NET applications.
Here are some instructions for how to set this up on your project. There's tons that
log4net
can do, but here is a basic setup to get it going on a project using SQL Server as your log store.
- Get log4net
If you're in the building, we have it on the network, and if not, you can
download it from sourceforge. Unzip it
and you should have a log4net folder with all the source, samples, documentation, and binaries.
- Include log4net in your project.
Here's the easy way:
- Open up your project in visual studio.
- Add a "/lib" folder
- "Add Existing Item..." on your new lib folder, browse to where you unzipped log4net, and choose
the \bin\net\1.1\release\log4net.dll file
- Go to "Add Reference", and browse to your lib folder and select the log4net.dll you just added.
Having the DLL as part of the project keeps it all in source control, so we don't need to bother with installing log4net
on all the workstations before we can work with it.
Alternatively, you could include the log4net source as another project in your solution, but all that means is you'll be compiling that much more code.
I had it set up that way originally, and then changed it to the method described above because I was never editing the log4net source
or debugging through it at all. I had expected to have to change it to meet a picky want of mine, but it just met all my needs with no
modification.
- Create the logging table in the database
This is a suitable create table statement:
if not exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Log]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
CREATE TABLE [Log] (
[Id] [int] IDENTITY (1, 1) NOT NULL ,
[Date] [datetime] NOT NULL ,
[Thread] [varchar] (32) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Context] [varchar] (512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Level] [varchar] (512) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Logger] [varchar] (512) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Message] [varchar] (4000) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Exception] [varchar] (2000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
END
GO
- Configure
log4net in your config file
I've tested this with web.config, haven't done so with an app.config yet, but its probably similiar enough.
- Add these lines to the very top of your config file, right after the
<configuration> node:
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"
/>
</configSections>
- Add these lines anywhere in the file, as a child of the
<configuration> node:
<log4net>
<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="server=SERVER; uid=USER; pwd=PASS; database=DATABASE" />
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception],[Context]) VALUES
(@log_date, @thread, @log_level, @logger, @message, @exception, @context)" />
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="32" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%t" />
</layout>
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="512" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%p" />
</layout>
</parameter>
<parameter>
<parameterName value="@context" />
<dbType value="String" />
<size value="512" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%x" />
</layout>
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="512" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%c" />
</layout>
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%m" />
</layout>
</parameter>
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ADONetAppender" />
</root>
</log4net>
That's basically building the query used to insert the log entry into the table you made in the previous step, and formatting
the data before it goes to the database. You'll need to change the connectionstring, which is underlined. Also, when you
actually deploy this, you should probably change the bufferSize to something higher, so it doesn't hit the database
for every single call to the log.
- Initialize the logger
Somewhere in the initialization of your application, add the following line:
log4net.Config.DOMConfigurator.Configure();
That will configure the logger with the stuff you specified in the config file. For web apps, put this in the
Application_Start function in Global.asax.cs.
- Use the logger in your code
There are a couple of steps to take when you want to log something.
- Create a logger for your class by adding this line at the top in the member declarations:
protected static readonly ILog log = LogManager.GetLogger(typeof(CLASS));
You'll have to change CLASS to name of the class you are in.
- Use the log, some examples:
log.Debug("The program got here with i = " + i.ToString());
log.Info("Some extended information, which is more important than the crap you put in a Debug() call");
log.Warn("Some unexpected but recoverable situation occurred, and you might want to see why this happen");
log.Error("Some outright error occured, an exception was thrown, or is about to be thrown", ex);
log.Fatal("Oh shit.", ex);
For web apps, add the following line to to the Application_Error function in Global.asax.cs:
log.Fatal("An uncaught exception occurred", this.Server.GetLastError());
- Add log contexts
log4net has a mechanism where you can easily add contextual information to the log, allowing you to
mark log entries as coming from a certain user, for example. Here's an example:
using(NDC.push(this.User.Email)){
log.Debug("this log entry will be tagged with the current user's email");
}
NDC stands for "Nested Dynamic Context". As the name implies, you can nest these, but I haven't messed with that yet.
So, thats the basics. There's a tremendous depth to that piece of software, things like having it send emails for some log entries,
changing the logging level, so only the more serious log entries are actually recorded, and just a ton of other options. Check the
log4net features page for more information, and look at the
log4net config examples if you want to do more complicated
things.
UPDATE: Please check out my
other post on log4net, there are a few other things you might want to do.