I have explained before what the constraints I have when working with logging. I got several good comments about it, and several has hit the nail directly on the head.
Just to recap, here is the list of my requirements:
- The output from the logs should be deliverable by email by a layman. This basically means a file.
- The ouptut should allow me to slice / dice the data. The best way is if I could utilize existing SQL skills to do this.
- The system may run unattended for weeks at a time, so the log file can't reach huge proportions.
- I'm not really interested in historical data - something that happened long time ago is not important.
- Plug into my current logging infrastructure (log4net).
- Nice to have - Convention over configuration
After giving this much thought, I decided to implement a RollingSqliteAppender. This is based of the existing ADO.Net appender, but is focused on utilizing Sqlite only. Sqlite needs only a single file for its database, so it answers the first requirement, it also has a runtime (for .Net) of about less than 500Kb, so size / installation is not an issue. Despite writing to a file, it is a fully fledged database, meaning that I get to do all sorts of interesting things to it.
The third / forth requirements are what prompted the creation of this appender, rather than using the existing ADO.Net one. I took a look at RollingFileAppender and implemented similar functionality for my appender as well. Although I am checking rows, rather size/date, since this is a bit easier to check. What is basically does is save all the logs to a sqlite file, until the amount of rows in the database is filled, then it rename the file and create a new one. Another reason for the need to create my own appender is that when creating a new file, the database structure is created for you automatically.From the name, you can figure out that this is a log4net appender, so integrating it is not an issue.
The last part is about minimum configuration. I tend to use the pretty standard logging table fairly often. That means [date, thread, level, logger, message, exception], so the appender is setup to support this (90% scenario, I would guess) out of the box. Here is how you configure the loggerin:
<log4net>
<appender name="rolling-sqlite-appender"
type="Rhino.Commons.Logging.RollingSqlliteAppender, Rhino.Commons"/>
<root>
<appender-ref ref="rolling-sqlite-appender"/>
</root>
</log4net>
This is it.
Now, it does provide a set of options that you can override (because I need that functionality fairly often).
Here is a list of the ones unique for the RollingSqliteAppender:
- CreateScript - the script to generate the table(s) when creating a new database file. Default is to create the standard table (date, thread, level, logger, message, exception) named "logs".
- TableName - must match to the name of the table in CreateScript. Default: "logs"
- FileNameFormat - file format for the file. Default is {0}.log4net, where {0} is the current process name (which result is mostly correct results in most cases).
- Directory - where to save the files. Default: Current Directory
- MaxNumberOfRows - number of rows in the database that triggers rolling the file. Note that this is not a hard number, it depends on your BufferSize settings and flush options. It is close enough for my needs. Default: 50,000
- MaxNumberOfBackUps - number of backup files to save. Backup files are given a numeric prefix where lower is newer. Default: 3
In my tests, each file was about 5Mb - 10Mb in size, and they compressed nicely to a more emailable size.
By the way, I really like the log4net architecture.
The code is here