Performance-Analyzing of log4net regarding creation of new logger vs. taking an existing one
Motivation During playing with AOP framework PostSharp I thought about the technique to weave the logger instances inside the code by using the CompileTimeIn...
Motivation
During playing with AOP framework PostSharp I thought about the technique to weave the logger instances inside the code by using the CompileTimeInitialize–method. Unfortunately my logging-stuff must be serializable. This is not given. So I must use the other weaving point and access my Loggers.
Over an abstraction layer I use log4net in the background. So my question was: how expensive is access to loggers and log something.
Testing-Setup
My little testing project consists mostly of these lines:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using NUnit.Framework;
using log4net;
using log4net.Config;
namespace EsriDE.Commons.Logging.log4net.Analyzing
{
[TestFixture]
public class Fixture
{
IEnumerable<Guid> _guids = GetGuids();
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
var configFile = new FileInfo("log4net.config");
XmlConfigurator.Configure(configFile);
}
[Test]
public void testing_performance_of_a_bunch_of_individual_loggers()
{
var watch = Stopwatch.StartNew();
foreach (var guid in _guids)
{
var s = guid.ToString();
var log = LogManager.GetLogger(s);
log.Debug(s);
}
watch.Stop();
Debug.WriteLine("Ellapses time for individuals: " + watch.ElapsedMilliseconds);
}
[Test]
public void testing_one_definied_logger_with_recalculating()
{
var s = new Guid().ToString();
var watch = Stopwatch.StartNew();
foreach (var guid in _guids)
{
var log = LogManager.GetLogger(s);
log.Debug(s);
}
watch.Stop();
Debug.WriteLine("Ellapses time for definied recalculated logger: " + watch.ElapsedMilliseconds);
}
[Test]
public void testing_one_definied_logger_without_recalculating()
{
var s = new Guid().ToString();
var log = LogManager.GetLogger(s);
var watch = Stopwatch.StartNew();
foreach (var guid in _guids)
{
log.Debug(s);
}
watch.Stop();
Debug.WriteLine("Ellapses time for definied logger: " + watch.ElapsedMilliseconds);
}
private static IEnumerable<Guid> GetGuids()
{
for (int i = 0; i < 100000; i++)
{
var guid = Guid.NewGuid();
yield return guid;
}
}
}
}
with this log4net-configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<!-- Define some output appenders -->
<appender name="RollingLogFileAppenderDebug" type="log4net.Appender.RollingFileAppender">
<file value="${APPDATA}\ESRI Deutschland GmbH\EsriDE.Commons.Logging.log4net.Analyzing\Logs\DEBUG.log" />
<appendToFile value="true" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="500000" />
<rollingStyle value="Size" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<header value="------ [Log Header] ------ " />
<footer value="------ [Log Footer] ------ " />
<conversionPattern value="%date %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="DebugAppender" type="log4net.Appender.DebugAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%m%n" />
</layout>
</appender>
<!-- Setup the root category, add the appenders and set the default level -->
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppenderDebug" />
<!--<appender-ref ref="DebugAppender" />-->
</root>
</log4net>
</configuration>
Result
with DbgView I could catch the output:
[8176] Ellapses time for definied recalculated logger: 1895
[8176] Ellapses time for definied logger: 1023
[8176] Ellapses time for individuals: 3117
Conclusion
What I have learned?
Accessing a new logger and logging is three times slower that log to a known logger.
Acessing a known logger and logging is in the middle of this span.
All three variants are in the same order of magnitude and in my environement with 100.000 logs in a few seconds insignificant.
So I could relinquish to the compile time initializing and use the method boundary stuff with recalculating the right logger.