Serilog Logcontext属性在异常处理程序之后消失了 [英] Serilog Logcontext properties are gone after exception handler

查看:282
本文介绍了Serilog Logcontext属性在异常处理程序之后消失了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的网站中,我正在集成Serilog以将错误记录到自定义接收器中。 LogContext丰富了日志,其中需要传递一些自定义属性。如果我使用Log.Information(),它将到达LogEvent中带有属性的接收器。

In my website I'm integrating Serilog to log my errors to a custom sink. The logging is enriched with a LogContext where some custom properties needs to be passed. If I use Log.Information() it arrives at my sink with the properties in the LogEvent. So this is working great.

主要目的是将日志记录系统与异常处理程序中间件结合起来。因此,在异常处理程序中捕获了错误,该错误是从控制器方法引发的。我将_logger.Log()放在异常处理程序中的任何位置,接收器中都没有自定义属性。调试时,它先经过LogContextFilter,然后再到达接收器,但未找到过滤器的属性。

The main purpose is to combine the logging system to a exception handler middleware. So in the exception handler the error is caught, which is thrown from a controller method. Anywhere I place the _logger.Log() in the exception handler, no custom properties are available in the Sink. While debugging it passes the LogContextFilter before it goes to the Sink, but no properties of the filter are found.

有人有任何想法吗?

启动

Log.Logger = new LoggerConfiguration()
            .WriteTo.PasSink(new SerLogServiceClient.SerLogServiceClient(new SerLogServiceClientOptions()))
            .Enrich.FromLogContext()
            .CreateLogger();

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddMvcOptions(mo =>
        {
            mo.Filters.Add(typeof(LogContextFilter));
        });

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseMiddleware<LogContextMiddleware>();
        app.UseErrorHandler(o =>
        {
            o.ExceptionHandlingPath = "/Home/Error";
            o.Context = ExceptionHandler.Context.MVC;
        });

        //app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseStaticFiles(new StaticFileOptions
        {
            FileProvider = new PhysicalFileProvider(
                Path.Combine(Directory.GetCurrentDirectory(), "Content")),
            RequestPath = "/Content"
        });

        app.UseAuthentication();

        app.UseSession();
        //app.UseCookiePolicy();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

LogContextFilter

public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        using (LogContext.Push(
            new PropertyEnricher("UserCode", context.HttpContext.User.Claims.FirstOrDefault(s => s.ToString().StartsWith("UserCode"))?.Value),
            new PropertyEnricher("Test", "Will this go through?")))
        {
            await next.Invoke();
        }
    }

ExceptionHandlerMiddleware

public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next.Invoke(context);
        }
        catch (HttpRequestException hex)
        {
            //check response naar reynaersexception??
            //deserialize naar re
            throw new NotSupportedException();  //als test
        }
        catch  (Exception ex)
        {

            if (context.Response.HasStarted)
            {
                throw ex;
            }

            _logger.LogError(ex.Message);

            var originalPath = context.Request.Path;
            try
            {
                if (_options.Context == Context.MVC)
                {
                    context.Response.Clear();
                    context.Response.StatusCode = 500;
                    context.Response.OnStarting(Callback, context.Response);

                    //set features
                    var exceptionHandlerFeature = new ReynaersExceptionHandlerFeature()
                    {
                        Error = ex,
                        Path = context.Request.Path.Value,
                    };
                    context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
                    context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);

                    //continue lifecycle with updated context
                    if (_options.ExceptionHandlingPath.HasValue)
                    {
                        context.Request.Path = _options.ExceptionHandlingPath;
                    }

                    await _next.Invoke(context);
                }
            }
            catch (Exception ex2)
            {
                // Suppress secondary exceptions, re-throw the original.
                Log.Error(ex2.Message);
                context.Request.Path = originalPath;
                throw ex;
            }
        }
    }


推荐答案

之所以会发生这种情况,是因为使用(LogContext.Push(..))将异常记录到在之外运行的处理程序中,因此自定义属性已经从上下文中删除了

This happens because the exception gets logged in a handler that runs outside of using (LogContext.Push(..)), therefore custom properties already have gone from context.

...

// in mvc's OnActionExecutionAsync()
        using (LogContext.Push(
            new PropertyEnricher("UserCode", ".."),
            new PropertyEnricher("Test", "Will this go through?")))
        {
            await next.Invoke(); // code that throws
        }

...

// later in ExceptionHandlerMiddleware, no custom properties
_logger.LogError(ex.Message);

前一段时间,我研究了这个问题并写了 ThrowContextEnricher

Some time ago I researched this problem and wrote ThrowContextEnricher.

此库从引发异常的位置捕获上下文。然后,可以使用ThrowContextEnricher来用原始上下文丰富异常日志。

This library captures context from a point where an exception was thrown. Then ThrowContextEnricher can be used to enrich the exception log with the original context.

Log.Logger = new LoggerConfiguration()
    .Enrich.With<ThrowContextEnricher>()  // Adds enricher globally
    .Enrich.FromLogContext()
    .WriteTo
    ...
    .CreateLogger();
...


// in mvc's OnActionExecutionAsync()
// push your properties as normal
        using (LogContext.Push(
            new PropertyEnricher("UserCode", ".."),
            new PropertyEnricher("Test", "Will this go through?")))
        {
            await next.Invoke(); // code that throws
        }

...

// in exception handler
// properties get logged now
// notice the exception is passed too, not just message
_logger.LogError(ex, ex.Message);

这篇关于Serilog Logcontext属性在异常处理程序之后消失了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆