参数到 LogManager.GetLogger

为什么大多数 log4net 示例通过以下方法获得类的日志记录器:

private static ILog logger =
LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

而不是仅仅传递 typeof (MyClass) :

private static ILog logger = LogManager.GetLogger(typeof(MyClass));

除了第一个选项不要求您键入特定的类名之外,还有其他原因吗?

86169 次浏览

As you say - its convenient as you can create a logger in a method without knowing the name of the class (trivial I know) but allows you to cut and paste methods between classes without having to rename the call.

I think you've got the reason. I do it that way so I don't have to worry about the class name and can just copy and paste boiler plate code in a new class.

For the official answer, see: How do I get the fully-qualified name of a class in a static block? at the log4net faq

I think the reason is, that you get the type of the runtime type using the .DeclaringType() method. You can use the logger in a base class and still see the actual type of your object in the loggers output. That makes investigations much more convinient.

I'm an NLog user, and usually this boils down to :

var _logger = LogManager.GetCurrentClassLogger();

It seemed a bit strange that you need to go through reflection in Log4Net, so I had a look in the NLog source code, and lo and behold, this is what they do for you:

[MethodImpl(MethodImplOptions.NoInlining)]
public static Logger GetCurrentClassLogger()
{
string loggerName;
Type declaringType;
int framesToSkip = 1;
do
{
#if SILVERLIGHT
StackFrame frame = new StackTrace().GetFrame(framesToSkip);
#else
StackFrame frame = new StackFrame(framesToSkip, false);
#endif
var method = frame.GetMethod();
declaringType = method.DeclaringType;
if (declaringType == null)
{
loggerName = method.Name;
break;
}
framesToSkip++;
loggerName = declaringType.FullName;
} while (declaringType.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase));
return globalFactory.GetLogger(loggerName);
}

I guess I would write something similar for Log4Net as an extension or static method instead of pasting the reflection as part of my boiler code :)

It also makes it easier to create Codesmith templates for code generation purposes.

The following portable solution worked for me in .NET Core 6:

private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType);