在我的网站中,我正在集成Serilog,以将我的错误记录到自定义接收器中。 LogContext丰富了日志记录,其中需要传递一些自定义属性。如果使用Log.Information(),它将到达LogEvent中带有属性的接收器。所以这很好用。
主要目的是将日志记录系统与异常处理程序中间件相结合。因此,在异常处理程序中捕获了错误,该错误是从控制器方法引发的。我将_logger.Log()放在异常处理程序中的任何位置,接收器中都没有自定义属性。调试时,它先经过LogContextFilter,然后再到达接收器,但找不到过滤器的属性。
有人有什么主意吗?
启动
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;
}
}
}
答案 0 :(得分:2)
之所以发生这种情况,是因为该异常记录在运行在using (LogContext.Push(..))
之外的处理程序中,因此自定义属性已经脱离上下文了。
...
// 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。
此库从引发异常的位置捕获上下文。然后可以使用ThrowContextEnricher将异常日志添加到原始上下文中。
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);
答案 1 :(得分:0)
我也为此付出了努力,几个月前找到了答案(虽然现在找不到。寻找它,这就是我偶然发现您的问题的方式。)可以肯定的是,您现在已经找到了解决方案,但这可能会对某人有所帮助。
但是尝试这种变化:
catch (Exception ex2) when (LogUnexpectedError(ex2))
{
// Suppress secondary exceptions, re-throw the original.
context.Request.Path = originalPath;
throw ex;
}
private bool LogUnexpectedError(Exception ex)
{
Log.Error(ex.Message);
return true;
}
如果我没有记错的话,那么在LogExceptionFilter超出范围之前,when部分是唯一可以处理Exception的地方。希望对您有所帮助。
更新:找到了我最初发现它的位置: https://andrewlock.net/how-to-include-scopes-when-logging-exceptions-in-asp-net-core/#using-exception-filters-to-capture-scopes