Introduction
In my previous article, I discussed the basics of the log4net logging package. I gave an overview of the 5 levels of logging that the library provides, and examples of the different type of appenders that can be used for outputting data to your logs. In this article, I'd like to give some information on how to use log4net effectively.
Specifying different logging levels for different modules
Sometimes within your application, you will want more logging information from some areas, and less from others. Log4net facilitates this by allowing different logging levels for different loggers. An example of this is shown in LogTest3 and LogTest4.
using log4net;
using log4net.Config;
public class LogTest3
{
private static readonly ILog logger =
LogManager.GetLogger(typeof(LogTest3));
static LogTest3()
{
DOMConfigurator.Configure();
}
static void Main(string[] args)
{
LogTest3 log3 = new LogTest3();
log3.DoLogging();
LogTest4 log4 = new LogTest4();
log4.DoLogging();
}
public void DoLogging()
{
logger.Debug("Here is a debug log from LogTest3.");
logger.Info("... and an Info log from LogTest3.");
}
}
public class LogTest4
{
private static readonly ILog logger =
LogManager.GetLogger(typeof(LogTest4));
static LogTest4()
{
DOMConfigurator.Configure();
}
public void DoLogging()
{
logger.Debug("Here is a debug log from LogTest4.");
logger.Info("... and an Info log from LogTest4.");
}
}
The configuration file for LogTest3 has the following lines of interest:
<root>
<level value="FATAL" />
<appender-ref ref="ConsoleAppender" />
</root>
<logger name="LogTest3">
<level value="DEBUG" />
</logger>
<logger name="LogTest4">
<level value="INFO" />
</logger>
</pre>
Within this XML fragment, we can see that the root logging level is set to "FATAL". That means that only FATAL error messages are logged. We can see however that this is overridden for LogTest3 and LogTest4 to the "DEBUG" and "INFO" levels accordingly. When we run this application, we will see then that LogTest3 logs everything from DEBUG level whereas LogTest4 logs everything from INFO level onwards.
2004-09-12 21:45:51,546 [1060] DEBUG LogTest3 - Here is a debug log from LogTest3.
2004-09-12 21:45:51,546 [1060] INFO LogTest3 - ... and an Info log from LogTest3.
2004-09-12 21:45:51,546 [1060] INFO LogTest4 - ... and an Info log from LogTest4.
Using this technique of specifying different log levels for different parts of your application gives you a great flexibility.
Should I log or not?
In general, the more logging you have, the greater flexibility you have and the easier it is to find out what's going wrong with your program. Don't get me wrong, logging is no substitute for debugging your program thoroughly, but there's always the case when you have deployed your application and you want to know exactly what's going on.
Sometimes, the cost of logging can be expensive, particularly when performance of your application is paramount (imagine logging every DEBUG statement to a database). Obviously, the first thing to do here, is turn down the logging level so that only the relevant information is produced (e.g., WARNINGs and above). This is a good start, but what if the cost of construction of the logging message is great (e.g., you have an expensive .ToString()
method)?
logger.Debug("Expensive object value="+ExpensiveObject.ToString());
The ILog
interface (of which all your loggers are implemented) provides a set of methods that enable you to check if a particular logging level is being used. These methods are shown below:
bool IsDebugEnabled();
bool IsInfoEnabled();
bool IsWarnEnabled();
bool IsErrorEnabled();
bool IsFatalEnabled();
Using these functions, we can now change our logging code for the expensive object to:
if (logger.IsDebugEnabled())
{
logger.Debug("Expensive object value="+ExpensiveObject.ToString());
}
Completely removing logging
If you are completely happy with your application and you want to turn off logging completely, you can do this by setting the logging threshold to "OFF" for any/all your appenders, as shown below:
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<threshold value="OFF" />
<layout type="log4net.Layout.PatternLayout">
<param name="Header" value="[Header]\r\n" />
<param name="Footer" value="[Footer]\r\n" />
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
The threshold can also be set to one of DEBUG, WARN, INFO etc. to set the threshold for the specified appender irrespective of the logger being used.
That's all
That's the end of the brief introduction to logging using log4net. I hope you've enjoyed these articles, and I hope I've convinced you that logging is worthwhile and fun!