logging - 如何在没有重复日志条目的情况下使用开发人员异常页面自定义未处理的异常日志记录中间件?
问题描述
这是一个 X/Y 问题:
- 我的 ASP.NET Core MVC + Web API 应用程序使用其他中间件层,例如 IdentityServer4,用于
Microsoft.Extensions.Logging
编写事件(例如身份验证失败事件)。 - 这些事件目前是用最少的额外数据编写的,这使得故障排除变得困难。我想添加诸如 HTTP 请求标头和路径之类的信息,以帮助确定错误事件的原因。
- 我的研究使我
ILogger<T>.BeginScope
创建了一个“作用域记录器”中间件,该中间件在 ASP.NET Core HTTP 请求的整个生命周期内都可以使用。此using( logger.BeginScope( ... ) )
调用将存在于中间件中(通过影响ILogger
瞬态服务的 DI 起作用)。 我的中间件本身不会捕获异常,只会添加到日志记录范围,如下所示:
class LoggingScopeMiddleware { private readonly ILoggerFactory loggerFactory; // DI private readonly RequestDelegate next; public async Task Invoke( HttpContext context ) { Dictionary<String,Object> values = CreateDict( context.Request... ); using( this.loggerFactory.CreateLogger().BeginScope( values ) ) { this.next( context ); } } }
但是,如果内部抛出异常,
next
那么当它被记录时(由链中更高或更低的另一个中间件层),它将丢失添加到BeginScope
. 我以为这不应该发生,但它确实发生了。- 我还希望开发人员异常页面继续工作
- 如果我确实在我的
LoggingScopeMiddleware.Invoke
方法中捕获并记录异常,那么开发人员异常页面将不会捕获异常,我只会在浏览器中显示一个空白页面。 - 如果我在中间件链中将开发人员异常页面向上移动,我注意到异常被记录时没有任何范围属性。
如果我在我的内部捕获异常,
LoggingScopeMiddleware
那么我可以使用额外的属性记录它:class ExceptionCatchingLoggingScopeMiddleware { private readonly ILoggerFactory loggerFactory; // DI private readonly RequestDelegate next; private readonly Boolean rethrow = true; public async Task Invoke( HttpContext context ) { Dictionary<String,Object> values = CreateDict( context.Request... ); using( this.loggerFactory.CreateLogger().BeginScope( values ) ) { try { this.next( context ); } catch( Exception ex ) { LogException( ex ); if( this.rethrow ) throw; } } } }
- 但是如果我重新抛出它,那么异常会在我控制之外的中间件链的其他地方记录两次(并且这个重复的日志条目不包括额外的属性)。如果我使用
when( LogException( ex ) /* == false */ )
C# 6.0 中的技巧,也会发生这种情况。 - 如果我吞下异常并且不重新抛出它,则不会调用开发人员异常页面并且我得到空白输出。
- 但是如果我重新抛出它,那么异常会在我控制之外的中间件链的其他地方记录两次(并且这个重复的日志条目不包括额外的属性)。如果我使用
总之:
场景一:
- 中间件:
--> DeveloperExceptionPage --> LoggingScopeMiddleware -->
- 开发者页面:显示。(好的)
- 未处理的异常:在没有范围属性的情况下记录。(坏的)
- 中间件:
场景二:
- 中间件:
--> LoggingScopeMiddleware --> DeveloperExceptionPage -->
- 开发者页面:显示。(好的)
- 未处理的异常:在没有范围属性的情况下记录。(坏的)
- 中间件:
场景 3:
- 中间件:
--> ExceptionCatchingLoggingScopeMiddleware --> DeveloperExceptionPage -->
- 开发者页面:显示。(好的)
- 未处理的异常:在没有范围属性的情况下记录。(坏的)
- 中间件:
场景四:
- 中间件:
--> DeveloperExceptionPage --> ExceptionCatchingLoggingScopeMiddleware( rethrow: true ) -->
- 开发者页面:显示。(好的)
- 未处理的异常:记录两次,一次使用范围属性(好),另一次没有范围属性(坏)
- 中间件:
场景 5:
- 中间件:
--> DeveloperExceptionPage --> ExceptionCatchingLoggingScopeMiddleware( rethrow: false ) -->
- 开发者页面:不显示。(坏的)
- 未处理的异常:使用范围属性记录一次(好)
- 中间件:
解决方案
推荐阅读
- pandas - 从镶木地板读取熊猫数据帧比从泡菜文件读取慢
- node.js - Firebase 部署找不到 serviceAccountKey
- javascript - 尝试将生成的 PDF 发送到谷歌云功能以使用 nodemailer 发送电子邮件
- spring - 有没有办法在 Spring 属性值中转义 SpEL 字符“#{”
- c - valgrind:条件跳转或移动取决于使用 strlen() strncat() 的未初始化值
- java - 获取报告不必要的强制转换表达式 MainActivity.onCreate
- python - Numpy.matmul 将数组视为整数
- python - pandas.Series.where 不适用于字典
- react-native - Redux & React Native 组件连接:this.props 未定义
- python - 如何在python中解析来自gRPC响应的数据?