Let’s say we have an application and we’ve implemented logging so we can keep an eye on performance, errors,… There are several strategies on how to configure your logging to ensure you that you not only get the right information, but also the right amount of information.
While developing an application (whether it’s a Windows Forms or Web application), usually you development environment provides you with a set of tools that help you debug your solution. .NET has the System.Diagnostics namespace which, next to the EventLog (interact with the Windows event logs), Process (interact with local and remote processes and start/stop local system processes) and PerformanceCounter classes, contains the Trace and Debug classes. As with log4net, the Trace class provides the ability to define the output target. You can do this by adding instances of the TraceListener to the Listeners collection. The TraceListener is also defined and configured in the applications configuration file, but the output is not as extensive as Log4Net and does not provide as many appenders. The PerformanceCounterCategory class allows you to define new counters and categories but doesn’t allow you to turn on/off logging per category. There is also no possibility to provide several output targets. This is logical since these tools shouldn’t be used as logging-mechanisms in production environments. Nonetheless, they are very helpful and efficient when using them while developing your applications.
Does this mean that log4net isn’t of any use while developing your application? Of course not! The logging functionalities should be embedded in your application’s architecture. Like this it becomes very normal for you to interpret log-files and you immediately have an idea of possible performance impact. During development you can also play with the log4net settings to optimize the amount of data that is stored in files/database.
In production environments, you can’t depend on the .net tools you used during the development of your solution. Here is where log-files come in handy. Of course, the amount of data we can keep in our logs isn’t infinite. The amount and size of log-files you wish to keep can be approached in several ways:
- archival logging
- circular logging
- rolling logging
Archival logging means that you will create log files of a certain size and each time the size is reached, a new file is started. A good way to distinguish between these files is to add the date to the filename, that way you have a chronically correct view of your log files. This can keep going until your hard drive is full. This type of logging can be interesting during development (keeping in mind you watch your available disk space). When your application is running in a production environment, circular logging becomes more interesting.
Circular logging will overwrite the oldest log-entry with a new log-entry. Here you will need to specify for how long you wish to keep a log-entry. For example, let’ say you want to keep all the logs for the past month, so every day the log entries older than today minus one month will be deleted and of course, the log-entries for today are added. The advantage here is that you have a defined set of logs which is interesting concerning disk space, of course, if you generate gigabytes of logs every day, this may still be a problem. This problem can be addressed by defining the boundaries of your log not in time but in size (of course, there is always data-loss) You can solve this by adapting the strategy to (compress and) move your log files on a daily/weekly/monthly basis to a storage server (generally slower, but with enough disk space so you can keep the files for the timeframe you want).
Rolling logging means that you define the size of a log and the number of repetitions the log can have. Let me clarify this with an example: Let’s say we write our logging-events to a file. I will define the maximum size of a log (let’s say 5MB) and the maximum amount of repetitions this file can have (let’s say 10). Now, the maximum size of your log is 50 MB, divided into 10 files of 5MB each. This can be very interesting for actually reading a log file in a text editor. These usually don’t do so well with big text-files. When the maximum number of files is reached the oldest log messages in the oldest file will be deleted and the new messages are added to the most recent file. Like this your logs represent a rolling window on the last 50MB of log-information.
In the previous methods, there is always a loss of data at some point. It can be interesting (especially for production environments) to keep a Log Digest. This is where a digest is generated of log-content that is to be deleted or overwritten. This can be a statistical summary of the events and you may include the most severe log-entries for future use. This digest can be used to have some statistics about your application over a long period of time. It will let you see the evolution in error/warning/informational logging-statements.
Using email
Often, there is a development team somewhere and the end users are some place else. And of course, you don’t have developers looking at the log-files all day to see that something has happened. Here notifications via email become crucial. Of course you want to keep spam-mail to a minimum, so make sure that the log-level for the SMTP-appender is set to ERROR. You can do this using the <evaluator> tag in the appender’s configuration. Apart from that the SMTPAppender has more, but expected, fields in it’s configuration such as sender (from), recipient(to), subject, smtpHost and buffersize (how many messages per email):
<to value="to@domain.com" />
<from value="from@domain.com" />
<subject value="test logging message" />
<smtpHost value="SMTPServer.domain.com" />
<bufferSize value="512" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="WARN"/>
</evaluator>
Using XML
When using the XmlLayout-class, you can, as the name would suggest, output your log messages in XML-format. As far as readability goes, the XmlLayout won’t do you any good, but it makes your log output structured. This can be essential when you want to automatically interpret log files for let’s say to filter out specific error-patterns, messages from a certain user or even when you want to write your own log-interpreter. Every attribute you use in your PatternLayout will be a tag in the XML-output.
Note: log4net does not add the root-node. So if you are opening the log file with an XML-reader you might need to add this yourself.