Author: Josh Twist
Continuing our recent logging theme, I want to talk about the different logging levels and some guidance on how to use them. Most logging frameworks (EntLib, log4net, nlog etc) support some kind of logging level or severity, where each individual log entry is marked at a certain level such as "Warning", "Error" or "Information". Not only is this great for ranking the importance of a particular entry, it can also be used to control the amount of logging making its way through to your log repository of choice.
If you've heard me talk about this in the past then you've probably heard the volume control analogy - if there's just too much noise at the "Information" level you can always turn the volume down to "Error". Maybe you want to write all entries at "Information" volume level to your database but for anything of "Error" or above, you'd also like an e-mail. All the logging frameworks listed support this scenario.
log4net and nlog share the same level structure with the following entries (in ascending priority): Debug, Information, Warn, Error and Fatal. Just five to worry about and easy to provide guidance for but perhaps not as granular as their little brother... Enterprise Library is built upon System.Diagnostics (part of the .NET Framework) and therefore uses the TraceEventType enumeration which has the following values: Transfer, Resume, Suspend, Stop, Start, Verbose, Information, Warning, Error and Critical.
In a previous post 'Unit testing a logging wrapper', we talked about wrapping your logging framework du jour and looked at two reasons for doing this: portability to a different framework and simplifying the API. For these reasons, I usually create my own log level enumeration to maintain ownership of the API surface and, in the past, I've followed log4net and nlog's lead with just five logging levels*. Here's how I use them:
Debug
This is the most
verbose logging level
(maximum volume setting). I usually consider Debug to be out-of-bounds for a production system and used it only for development and testing. I prefer to aim to get my logging levels just right so I have just enough information and endeavour to log this at the Information level or above.
Information
The Information level is typically used to output information that is useful to the running and management of your system. Information would also be the level used to log Entry and Exit points in key areas of your application. However, you may choose to add more entry and exit points at Debug level for more granularity during development and testing.
Warning is often used for handled 'exceptions' or other important log events. For example, if your application requires a configuration setting but has a default in case the setting is missing, then the Warning level should be used to log the missing configuration setting.
Error is used to log all unhandled exceptions. This is typically logged inside a catch block at the boundary of your application.
Fatal is reserved for special exceptions/conditions where it is imperative that you can quickly pick out these events. I normally wouldn't expect Fatal to be used early in an application's development. It's usually only with experience I can identify situations worthy of the FATAL moniker experience do specific events become worth of promotion to Fatal. After all, an error's an error.
So in summary, you'd mostly only use Information, Warning and Error which makes it pretty self explanatory what to do with each. Debug and Fatal are left in for outlying cases and give you some scope for movement.
Admittedly, worrying about portability may force you into a 'lowest common denominator' corner that you really shouldn't be in. But in this case I think the simplification of the API makes it worthwhile. If this doesn't work for you then don't worry. Go ahead and use as many values as you deem fit!