如何添加HttpContext丰富未处理的异常日志?

How to add HttpContext to enrich un-handled exception logs?

我已设置 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,所以我想处理 global/uncaught 异常,例如方法 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.
    }
}

根据代码片段,当您将上下文传递到管道时,您没有捕捉到异常。

如果您不 catch/handle 中间件中的异常,那么在调用下游后它不会到达您的代码。

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      
    }
}

以上将 re-throw 原始错误记录下来,以便管道中的其他处理程序将捕获它并进行开箱即用的处理。