January 17, 2008

Logging .Net

This is my foray into building .net systems. My boss says, "Lets build our new enterprise system in pure .NET. Lets do it in 6 days." Obviously this upset me quite a bit. Rebuild our VB6 middleware in .NET in 6 days? That's going to be tough. "Don't forget to use best-practices" he added.

Ok, our enterprise middleware engine consists of auditing, messaging and transmission (Databases), error handling and id generation. Query best practices in .net and one usually encounters Enterprise Library Blocks. Great half my work is done. We'll implement auditing in stored procedures, database access through the Enterprise library blocks - which leaves error handling and id generation to be built. ID Generation is nothing but a business object which calls stored procedures so that's basic. So I spend most of the 6 days learning ASP.NET and trying to get logging to work on .NET using best practices.

Enterprise Library Logging Block

This guy comes with the Enterprise Library and its configured through the app.config file. The most major problem dealing with this guy is where to put the app.config. Here is what you need to know:
1. ASP.NET - if you use logging directly from ASP.NET you app.config file is also your web.config file. Put all your configuration entries in there. Beware there is a hierarchy. I haven't really tried it myself, but after reading about this bugger for 2 days, I picked up some things.

2. .NET application - this is the easiest. In your application solution, add a configuration file called app.config. When you compile, this file will be renamed to "appname.exe.config" - replacing appname with your own application name.

3. COM+ application - This bugger is not documented in the Enterprise Library docs, but I suppose one needs to know a bit about .NET Enterprise Services to know about this. The app.config file for COM+ applications is called application.config and its located in a specified folder in the COM+ application property sheet. In COM+ Services MMC, go to the Activation Tab and set the application directory. Drop in the application.manifest and application.config file in that folder. It should work - but it hasn't for me. That's why I abandoned Enterprise Library logging and moved on to Log4Net.

So since I couldn't get Enterprise Library logging to work with COM+ applications, I tried Log4Net by Apache. If you want to persist with Enterprise Library Logging, you should know the following:

1. Use the Enterprise Library Configuration program to edit your app.config or web.config or application.config files.
2. In Enterprise Library Logging Block there are categories, formatters, and trace listeners. The default trace listener adds entries to the system event log. Its called Formatted Event Log Trace Listener. This is fine. But you want to add your own trace listener such as FlatFile Trace Listener. Not only that!
3. You need to Set the category for the TraceListener to listen to. Default category is General. You can add categories. Categories is also what you specify when you create your LogEvent object in code. If you try to add a LogEvent with a category which is not defined in your app.config file, you won't be able to see the event in your logs. This might cause you confusion when you try to run the sample code in the Enterprise Library help system against a default app.config file.
4. You should also set your TraceListener formatter and filename (if its a flat file trace listener).

Ok let's move on to log4net.

Log4NET

Using log4net, the documentation says you can programmatically set the parameters without the need of an XML configuration file. That's nice if there was sample code in the documentation to show you how to do this. The whole problem with Enterprise Library Logging Block was not being able to verify WHICH app.config file it was using - if it was using one at all. Presumably, if it used one, it would log properly. But seeing as the Logging object encapsulated the Enterprise Library Logging Block functionality to provide an additional layer of abstraction, and we considered whether this Logging object should be COM+, a .NET private assembly or a .NET shared assembly, figuring out where exactly the app.config file should be is no easy task. Luckily in log4net you can specify where to put the log4net.xml config file - except that now this location had to be hardcoded which is not good practice anyway. The code for that is:

XmlConfigurator.Configure(New System.IO.FileInfo("c:\log4net.xml"))

I found out, you can solve the hardcoding of the location by using the app.config settings which bring us back to the original Enterprise Library Logging Block problem.

To write to the log:

mlog As ILog = LogManager.GetLogger("Module")
mlog.Info("Message")


Most examples use LogManager.GetLogger(GetType(object)) but I don't think it matters. Also there are several predefined log types (INFO, DEBUG, ERROR and FATAL) so you have to use mlog.debug("Message") etc. The logs types are hierarchical so log level DEBUG - presumable is the lowest level meaning everything will be logged.

Comparisons

Technically, I don't think log4net is as flexible as Enterprise Library Logging Block but I'm forced to use it because I can't get Enterprise Library Logging Block to work for me. For my project I encapsulated both logging libraries in my Logging module and use the app.config settings to turn things on and off.

In case you're wondering, you can get values out of your app.config settings in the following way:

Dim strValue as String = System.Configuration.ConfigurationManager.AppSettings("MySetting")