One of the more exotic and advanced features of Log4net is lossy logging.
Actually the idea behind it is simply great, it supports the typical production scenario of: As long as everything is working, I don’t want my log filled up with debug (or info) messages, but when an error occurs, I would like to have all the messages that leads to this error situation.
And that’s what lossy logging is all about!
Implementing lossy logging is done through configuration, and as always in Log4net, configuration takes place in the configuration file, i.e. you don’t have to change your program.
To configure an appender to implement lossy logging, you need to write the following configuration statements in the config file:
<lossy value="true" />
<bufferSize value="10" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="ERROR"/>
evaluator>
Translated, this means: Log the last 10 messages every time an error (or fatal) message is encountered.
Lossy logging is supported by the appenders which are based on the BufferingAppenderSkeleton, currently that is AdoNetAppender, RemotingAppender, SmtpAppender, SmtpPickupDirAppender or BufferingForwardingAppender.
If you are using another appender, you need a detour to the BufferingForwardingAppender, and have the BufferingForwardingAppender deliver the log rows to your appender of choice.
I wrote a small test program enclosed below:
using System;
using System.Text;
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace L4NTest
{
class Program
{
private static readonly log4net.ILog log
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
static void Main(string[] args)
{
TestLossy();
}
static void TestLossy()
{
int logno = 0;
for (int i = 0; i < 20; i++)
log.Debug("Log message no: " + (++logno).ToString());
log.Error("Error message no: " + (++logno).ToString());
for (int i = 0; i < 10; i++)
log.Debug("Log message no: " + (++logno).ToString());
}
}
}
This test program writes 31 log rows, first 20 debug rows, one error row and then 10 debug rows.
To test this I used two appenders, one FileAppender and on AdoNetAppender. The FileAppender was not configured to be lossy (in fact the FileAppender does not support Lossy), the AdoNetAppender was configured to be lossy and to log 10 rows if an Error occurred.
The complete configuration file for my test program is listed below:
xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
</configSections>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
appSettings>
<log4net>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<connectionString value="Data Source=(Local); initial Catalog=Log4Net;Integrated Security=True;"/>
<commandText value="INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"/>
<lossy value="true" />
<bufferSize value="10" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="ERROR"/>
evaluator>
<parameter>
<parameterName value="@log_date"/>
<dbType value="DateTime"/>
<layout type="log4net.Layout.RawTimeStampLayout"/>
parameter>
<parameter>
<parameterName value="@thread"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread"/>
layout>
parameter>
<parameter>
<parameterName value="@log_level"/>
<dbType value="String"/>
<size value="50"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level"/>
layout>
parameter>
<parameter>
<parameterName value="@logger"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger"/>
layout>
parameter>
<parameter>
<parameterName value="@message"/>
<dbType value="String"/>
<size value="4000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message"/>
layout>
parameter>
<parameter>
<parameterName value="@exception"/>
<dbType value="String"/>
<size value="2000"/>
<layout type="log4net.Layout.ExceptionLayout"/>
parameter>
appender>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="L4NTest.Log.Txt"/>
<appendToFile value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline"/>
layout>
appender>
<root>
<level value="ALL"/>
<appender-ref ref="AdoNetAppender"/>
<appender-ref ref="FileAppender"/>
root>
log4net>
configuration>
When running the program, the FileAppender wrote these log rows to the log file:
2005-11-09 13:19:47,906 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 1
2005-11-09 13:19:48,000 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 2
2005-11-09 13:19:48,000 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 3
2005-11-09 13:19:48,000 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 4
2005-11-09 13:19:48,000 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 5
2005-11-09 13:19:48,000 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 6
2005-11-09 13:19:48,000 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 7
2005-11-09 13:19:48,015 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 8
2005-11-09 13:19:48,015 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 9
2005-11-09 13:19:48,015 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 10
2005-11-09 13:19:48,015 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 11
2005-11-09 13:19:48,015 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 12
2005-11-09 13:19:48,015 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 13
2005-11-09 13:19:48,031 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 14
2005-11-09 13:19:48,031 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 15
2005-11-09 13:19:48,031 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 16
2005-11-09 13:19:48,031 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 17
2005-11-09 13:19:48,031 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 18
2005-11-09 13:19:48,031 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 19
2005-11-09 13:19:48,031 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 20
2005-11-09 13:19:48,046 [4988] ERROR L4NTest.Program [(null)] - Error message no: 21
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 22
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 23
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 24
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 25
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 26
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 27
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 28
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 29
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 30
2005-11-09 13:19:48,093 [4988] DEBUG L4NTest.Program [(null)] - Log message no: 31
The AdoNetAppender wrote these log rows to the database:
|
Date
|
Level
|
Logger
|
Message
|
|
2005-11-09 13:19:48.017
|
DEBUG
|
L4NTest.Program
|
Log message no: 12
|
|
2005-11-09 13:19:48.017
|
DEBUG
|
L4NTest.Program
|
Log message no: 13
|
|
2005-11-09 13:19:48.030
|
DEBUG
|
L4NTest.Program
|
Log message no: 14
|
|
2005-11-09 13:19:48.030
|
DEBUG
|
L4NTest.Program
|
Log message no: 15
|
|
2005-11-09 13:19:48.030
|
DEBUG
|
L4NTest.Program
|
Log message no: 16
|
|
2005-11-09 13:19:48.030
|
DEBUG
|
L4NTest.Program
|
Log message no: 17
|
|
2005-11-09 13:19:48.030
|
DEBUG
|
L4NTest.Program
|
Log message no: 18
|
|
2005-11-09 13:19:48.030
|
DEBUG
|
L4NTest.Program
|
Log message no: 19
|
|
2005-11-09 13:19:48.030
|
DEBUG
|
L4NTest.Program
|
Log message no: 20
|
|
2005-11-09 13:19:48.047
|
ERROR
|
L4NTest.Program
|
Error message no: 21
|
As you can see, the AdoNetAppender has logged the errormessage, and the 9 rows before the error message, in contrast to the FileAppender which logs all messages.