使用log4net记录日志并将日志级别作为参数传递

13

有没有一种方法可以使用log4net记录日志,并将LogLevel作为参数?

也就是说,不是写成这样

Log.Debug("Something went wrong");

我想写出这样的代码:

Log("Something went wrong", LogLevel.Debug);

你可以扩展这个类,但我怀疑你需要告诉我们为什么要进行这个更改。 - Tony Hopkinson
这主要是为了方便。我有一个应用程序,可以作为Windows服务或控制台应用程序运行。当作为控制台应用程序运行时,日志应该打印到屏幕上而不是文件中。由于已经实现了记录日志的方法,因此该方法将日志级别作为参数。我知道我可能可以使用log4net的控制台附加器,但我不知道在编译期间如何决定使用哪个附加器。 - olif
2个回答

14
根据log4net文档(在log4net.Core.ILogger下查看),您可以在ILogger接口上使用Log方法。
private static ILog logger = 
    LogManager.GetLogger(
    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

logger.Logger.Log(logger.GetType(),LogLevel.Debug,"Something went wrong", ex);

Type参数用于log4net来确定日志代码和应用程序代码之间的调用栈边界。如果启用了方法名称记录,log4net会沿着调用栈向上导航,直到栈上的MethodInfo的DeclaringType等于传入的Type(Log调用中的Type)为止。当它找到该DeclaringType时,调用栈中的下一个方法就是实际的调用方法(应用程序代码)。

您还可以使用接受LoggingEvent结构的重载版本。

文档还称Log方法旨在由包装器使用。我不知道这是否应该被视为“信息”消息或强烈建议不直接使用它。

如果希望通过Log方法进行所有日志记录调用,则可以更改获取记录器的代码,使其像这样(因此可以消除每个Log调用的Logger属性):

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

logger.Log(logger.GetType(),LogLevel.Debug,"Something went wrong", ex);

3
为什么log4net这么难用?要花费非常长的时间并且不得不参考15篇不同的Stack Overflow帖子才能完成基本的日志记录,这让人感到非常沮丧。/牢骚 - Andrew Keeton

9

在@wageoghe的答案基础上,我编写了以下扩展方法:

public static bool Log(this ILog log, Level level, string message, Exception exception = null)
{
    var logger = log.Logger;
    if (logger.IsEnabledFor(level))
    {
        logger.Log(logger.GetType(), level, message, exception);
        return true;
    }

    return false;
}

public static bool LogFormat(this ILog log, Level level, string messageFormat, params object[] messageArguments)
{
    var logger = log.Logger;
    if (logger.IsEnabledFor(level))
    {
        var message = string.Format(messageFormat, messageArguments);
        logger.Log(logger.GetType(), level, message, exception: null);

        return true;
    }

    return false;
}       

这些允许你进行如下调用:

Log.Log(Level.Debug, "Something went wrong", myException);

或格式化消息:
Log.Log(Level.Info, "Request took {0:0} seconds", duration.TotalSeconds);

这正是我所需要的,我需要定期记录一个级别,但有时需要覆盖该级别,以便可以按需将对象转储到日志文件中。 - Steve Hibbert
这很好,但为了更灵活性,第一个方法应该接受object message而不是string message - Miral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接