When I wanted to use the different logging levels available with log4net, I found out that I needed to use the method ILogger.Log, which looks like this:
void Log(Type callerStackBoundaryDeclaringType, Level level, object message, Exception exception);
We can get an ILogger reference from our usual ILog reference to call this method and it is usually suggested to wrap this call in an extension method. What we get is the following:
//typical log4net ILog reference
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//suggested extension method
public static void Trace(this ILog logger, object message, Exception e)
{
logger.Logger.Log(MethodBase.GetCurrentMethod().DeclaringType, log4net.Core.Level.Trace, message, e);
}
I have noticed how the reflection call to get the declaring type looks redundant. We have already passed the declaring type to GetLogger when we retrieved our ILog reference. Why did we need to pass another type reference to the method Log, which we are invoking on an ILogger reference which we have retrieved from our ILog reference. More importantly, the declaring type in the extension method would be the class that contains the extension method. Logging all your Trace logs with a class name like Log4NetExtensions would make no sense. Finally, reflection is supposed to be expensive, even though reflecting on the current method might be cheaper, calling reflection code every time we log does not sound right. So I decided to make a test:
//I just created a logger
var logger = logManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//and then I called Log with different type parameters
logger.Logger.Log(MethodBase.GetCurrentMethod().DeclaringType, log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(logger.GetType(), log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(null, log4net.Core.Level.Info, "hello!", null);
logger.Logger.Log(typeof(System.Console), log4net.Core.Level.Info, "hello!", null);
And the resulting logs looked like the following:
INFO 2015-05-29 11:06:57,200 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
INFO 2015-05-29 11:06:57,207 [9] Foo.Program - hello!
So, it seems that the type parameter to this method is ignored. This is very puzzling. Can anyone confirm or deny these results? Does anyone know why this works the way it does? I intend to create my extension method with null for this parameter. Would you suggest the same? Am I missing something?
The following are questions whose answers suggest using the declaring type in the extension method:
Log4net creating custom levels