allBlogsList

Sitecore Custom Log4net Filter

Recently, I was researching an issue with a health check to check the availability of Salesforce web service. The health check was set up to aggressively check the salesforce API every 50 ms. The job was running about 72,000 in an hour and would output a single logging statement to the log4net logs. The database was growing 14GB a day from the health check.

The challenge was that I wanted to record the job executed, but I did not care that the job ran 100 times in the past minute. To handle this use case, I needed to customize the Log4net filter. The custom filter would exclude the duplicate message in the log file.

To customize the Log4net I needed to create a new class named DuplicateFilter and extend from the FilterSkeleton class.

using log4net.Core;
using log4net.Filter;

namespace TestProject.Log
{
public class DuplicateFilter : FilterSkeleton
{
}
}


The FilterSkelton request requires us to override the function named decide. The decide function has the logging event as an argument and this allows us to view what is being requested to log. The code can evaluate the logging event and decide if the logging event is saved to the log. If the decide function accepts the request then the log event is saved otherwise the logging event is discarded.

The function to decide if we keep the logging event will compare the current message against the last message saved. If the current logging message is the same value as the last message we filter the message. The logging message will only be saved if the message is different. Below is the full code for the DuplicateFilter class.

using log4net.Core;
using log4net.Filter;

namespace TestProject.Log
{
public class DuplicateFilter : FilterSkeleton
{
private string lastMessage = null;

public override FilterDecision Decide(LoggingEvent loggingEvent)
{
if (lastMessage == loggingEvent.RenderedMessage)
{
return FilterDecision.Deny;
}
else
{
lastMessage = loggingEvent.RenderedMessage;
return FilterDecision.Accept;
}
}
}
}


Now we have created a new class called DuplicateFilter. The duplicate filter extends the FilterSkelton and contains logic to decide what message to filter in Log4net. Next, we need to update the Log4Net configuration to use the new DuplicateFilter. Below is a example log4net configuration file. The below standard configuration for Log4net saved all the logging event to a log file.

<?xml version="1.0"?>
<log4net>
<appender name="file" type="log4net.Appender.RollingFileAppender">
<file value="App_Log\logfile.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="10MB"/>
<countDirection value="1"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"/>
</layout>
</appender>
<root>
<!-- Options are "ALL", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" and "OFF". -->
<level value="ALL"/>
<appender-ref ref="file"/>
</root>
</log4net>

The final step we need is to update the appender and add a child node referencing the Duplicate filter.

<appender name="file" type="log4net.Appender.RollingFileAppender">
<filter type="TestProject.Log.DuplicateFilter" />
</appender>

Below is the full Log4net configuration file.

<?xml version="1.0"?>
<log4net>
<appender name="file" type="log4net.Appender.RollingFileAppender">
<file value="App_Log\logfile.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="10MB"/>
<countDirection value="1"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"/>
</layout>
<filter type="TestProject.Log.DuplicateFilter" />
</appender>
<root>
<!-- Options are "ALL", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" and "OFF". -->
<level value="ALL"/>
<appender-ref ref="file"/>
</root>
</log4net>

The above code and configuration show how to customize the Log4net filter. Customizing the Log4net filter is all a Sitecore developer needs to do to apply custom business rules to meet the business specific requirements.