【问题标题】:How to add HttpContext to enrich un-handled exception logs?如何添加 HttpContext 来丰富未处理的异常日志?
【发布时间】:2018-07-26 20:53:06
【问题描述】:

我已设置 Serilog 以使用以下方式登录到 MSSql:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
    .MinimumLevel.Override("System", LogEventLevel.Information)
    .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information)
    .Enrich.FromLogContext()
    .WriteTo.Async(x => x.MSSqlServer(logConntectionString, tableName, LogEventLevel.Warning, autoCreateSqlTable: false, columnOptions: columnOptions))
    .CreateLogger();

此外,我在管道中添加了一个 SerilogMiddleware,它成功地从HttpContext 添加了LogContext

在测试控制器中,我有以下两种测试方法:

public class TestController : ControllerBase
{
    [HttpGet, Route("test")]
    public IActionResult Get() {
        try
        {
            string[] sar = new string[0];                
            var errorgenerator = sar[2]; // Trigger exception
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Caught Exception");
            return StatusCode(500, "Custom 500 Error");
        }
        return Ok();
    }

    [HttpGet, Route("test2")]
    public IActionResult Get2() {

        string[] sar = new string[0];
        var errorgenerator = sar[2];// Trigger exception

        return Ok();
    }
}

第一种方法不是 DRY,所以我想处理全局/未捕获的异常,例如方法 2。

我所拥有的from here 是:

public class GloablExceptionFilter : ActionFilterAttribute, IExceptionFilter
{    
    public void OnException(ExceptionContext context)
    {
        var httpContext = context.HttpContext;  //  This does not appear to have the actual HttpContext

        Log.Error(context.Exception, "Unhandled Exception");
    }
}

问题是,我原本可以正常工作的中间件不再起作用。它不会编辑响应正文等。此外,当我访问 ExceptionContext 的 context.HttpContext 时,它不包含从内部触发时的实际 HttpContext控制器方法如上。

  1. 如何使用此过滤器注入或共享 HttpContext 和/或 LogContext?
  2. 如果那不可能,我如何在 DRY、 有上下文可用的情况下完成日志记录异常?

更新 1:当前的中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddSerilog();            

    app.UseAuthentication();

    // Logging Middleware is just after Authentication, to have access to 
    // user IsAuthorized, claims, etc..
    app.UseMiddleware<SerilogMiddleware>();

    app.UseCors("CORSPolicy");

    app.UseMvc();
}

在中间件本身:

public class SerilogMiddleware
{
    readonly RequestDelegate _next;

    public SerilogMiddleware(RequestDelegate next)
    {
        if (next == null) throw new ArgumentNullException(nameof(next));
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
      // Do logging stuff with Request..
       await _next(httpContext);
      // Do logging stuff with Response but..
      // This point is never reached, when exception is unhandled.
    }
}

【问题讨论】:

  • 您可以考虑使用放置在管道早期的实际中间件,该中间件可以直接访问 htttp 上下文,与稍后进入管道的文件管理器相对。
  • 在我给stackoverflow.com/a/44791487/5233410的答案中找到了一个示例
  • @Nkosi - 我添加了中间件代码及其注入顺序以进行演示。我不希望这个问题过于宽泛,或者过于狭隘以至于我无法使用。
  • 基于代码 sn-p 当您将上下文传递到管道中时,您不会捕获异常。如果你没有捕捉到异常,那么它就不会到达你的代码。
  • 你尝试/捕获中间件中的await _next(httpContext) - 我明白了;谢谢!做一个答案,如果你愿意,我会标记它:)

标签: asp.net-core exception-handling asp.net-core-2.0 error-logging serilog


【解决方案1】:

根据代码 sn-p,当您将上下文传递到管道中时,您不会捕获异常。

如果您没有在中间件中捕获/处理异常,那么它在调用下游后不会到达您的代码。

public class SerilogMiddleware {
    readonly RequestDelegate _next;

    public SerilogMiddleware(RequestDelegate next) {
        if (next == null) throw new ArgumentNullException(nameof(next));
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext) {
        // Do logging stuff with Request..
        try {
            await _next(httpContext);
        } catch(Exception ex) {
            try {
                //Do exception specific logging

                // if you don't want to rethrow the original exception
                // then call return:
                // return;
            } catch (Exception loggingException) {
                //custom
            }

            // Otherwise re -throw the original exception
            throw;
        }
        // Do logging stuff with Response      
    }
}

上面将在记录后重新抛出原始错误,以便管道中的其他处理程序将捕获它并进行开箱即用的处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-14
    • 2014-10-28
    • 1970-01-01
    • 2019-03-30
    • 2011-03-01
    • 1970-01-01
    相关资源
    最近更新 更多