Asp.net web api 使用ExceptionLogger在WebApi 2.1上运行log4net

Asp.net web api 使用ExceptionLogger在WebApi 2.1上运行log4net,asp.net-web-api,log4net,asp.net-web-api2,exception-logging,Asp.net Web Api,Log4net,Asp.net Web Api2,Exception Logging,如何正确实现WebApi 2.1的ExceptionLogger,以便log4net记录方法、位置和行的正确值 我试图实现的是一个全局异常记录器,用于在运行.NET 4.5.1的WebAPI 2.1 v5.1.2应用程序中记录所有未处理的异常。我已经阅读了很多文章,包括下面链接的一篇,其中解释了如何实现ExceptionLogger,它非常有效,只是我无法让log4net输出我真正想要记录的值 例如,如果我记录了一个控制器的异常,那么一切都是正确的。当我从ExceptionLogger记录时,我

如何正确实现WebApi 2.1的ExceptionLogger,以便log4net记录方法、位置和行的正确值

我试图实现的是一个全局异常记录器,用于在运行.NET 4.5.1的WebAPI 2.1 v5.1.2应用程序中记录所有未处理的异常。我已经阅读了很多文章,包括下面链接的一篇,其中解释了如何实现ExceptionLogger,它非常有效,只是我无法让log4net输出我真正想要记录的值

例如,如果我记录了一个控制器的异常,那么一切都是正确的。当我从ExceptionLogger记录时,我从记录器本身获取值,而不是从启动异常的方法获取值。我尝试了下面代码中列出的一些方法,但它们并不完全正确。这是我得到的

我知道文本很小,但表中显示了log4net写入的不同值。第一个日志来自控制器,一切都很好。第二个条目来自代码段中的log.Logger.log。最后一项来自代码段中的log.Error

代码段中的最后一个方法尝试使用限制类型,正如我从其他log4net包装器实现中读到的那样,但它只是抛出了一个错误,如代码段中所述

那么,当使用全局异常记录器时,如何获得从控制器调用时接收到的值呢

public class GlobalExceptionLogger: ExceptionLogger
{
    //private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    public override void Log(ExceptionLoggerContext context)
    {
        StackTrace stackTrace = new StackTrace(context.Exception);
        Type methodDeclaringType = stackTrace.GetFrame(2).GetMethod().DeclaringType;

        ILog log = LogManager.GetLogger(methodDeclaringType);
        string message = context.ExceptionContext.Exception.Message;

        //this methods works but writes the location, method name and line from this method, not the caller
        //location: System.Web.Http.ExceptionHandling.ExceptionLogger.LogAsync(:0)
        //method: LogAsync
        //line: 0
        log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, log4net.Core.Level.Error, message, context.ExceptionContext.Exception);


        //this methods works but writes the location, method name and line from this method, not the caller
        //location: Company.AppName.Api.GlobalExceptionLogger.Log(c:\TFS\AppName\AppName.Api\GlobalExceptionLogger.cs:38)
        //method: Log
        //line: 38
        log.Error(message, context.ExceptionContext.Exception);

        //this method throws an error in the log4net debug: log4net:ERROR loggingEvent.LocationInformation.StackFrames was null or empty.
        log.Logger.Log(methodDeclaringType, log4net.Core.Level.Error, message, context.ExceptionContext.Exception);
    }

}

不建议使用获取stacktrace的方法,因为代码在调试/发布或precessor架构上的行为会有所不同。方法stackTrace.GetFrame(2).GetMethod()将为您提供实际堆栈上的方法,同时考虑到处理器体系结构、linq重写等的运行时优化

获取成员名称的另一种方法:

public static string LogError(Exception ex, [CallerMemberName] string callerName = "")
你应该看看这个问题:


不建议使用获取stacktrace的方法,因为代码在调试/发布或precessor架构上的行为会有所不同。方法stackTrace.GetFrame(2).GetMethod()将为您提供实际堆栈上的方法,同时考虑到处理器体系结构、linq重写等的运行时优化

获取成员名称的另一种方法:

public static string LogError(Exception ex, [CallerMemberName] string callerName = "")
你应该看看这个问题:


有趣的注释。如果我使用类型methodDeclaringType=new StackTrace().GetFrame(2.GetMethod().DeclaringType,这将防止最后一个方法出错。但是,此stacktrace与创建stacktrace(context.Exception)时不同。这让我相信Logger.Log并没有使用作为传入异常一部分的stacktrace,而是来自其他来源。有趣的注意。如果我使用类型methodDeclaringType=new StackTrace().GetFrame(2.GetMethod().DeclaringType,这将防止最后一个方法出错。但是,此stacktrace与创建stacktrace(context.Exception)时不同。这让我相信Logger.Log使用的不是作为传入异常一部分的stacktrace,而是来自其他来源。了解stacktrace,但这来自解释如何在包装器内操作log4net的其他帖子。不幸的是,您的替代方案无法工作,因为在重写IEExceptionLogger的Log方法时无法添加新参数。我越来越清楚,尝试使用log4net进行全局错误记录不是一个好主意。我已经开始使用Elmah进行错误日志记录,不过如果我的通用日志记录器和错误日志记录器可以记录到同一个数据库,这样我就可以查看历史记录,而不仅仅是错误。了解stacktrace,但这来自解释如何在包装器内操作log4net的其他帖子。不幸的是,您的替代方案无法工作,因为在重写IEExceptionLogger的Log方法时无法添加新参数。我越来越清楚,尝试使用log4net进行全局错误记录不是一个好主意。我已经开始使用Elmah来记录错误,不过如果我的通用记录器和错误记录器可以记录到同一个数据库中,这样我就可以查看历史记录,而不仅仅是错误记录,那就太好了。