使用UseSerilogRequestLogging时Serilog过滤HTTP方法日志不生效
问题根因
- 字段取值错误:代码中给诊断上下文赋值的
Protocol字段取自request.Protocol,这个属性存储的是HTTP协议版本(值为HTTP/1.1、HTTP/2、HTTP/3这类),并非GET/POST/OPTIONS这类HTTP请求方法,HTTP请求方法对应的属性是request.Method,从根源上取错了匹配字段。 - 过滤器执行时机不匹配:appsettings.json中配置的是全局Serilog过滤器,这类过滤器在日志写入管道的最早期执行,而
UseSerilogRequestLogging中间件的Enrich操作是在请求处理完成、即将生成请求日志的节点才执行,全局过滤器运行时自定义的上下文字段还没被注入,自然匹配不到规则。 - 异步方法签名错误:
EnrichFromRequest方法写成了async void,这类签名会导致异步执行上下文丢失,Enrich赋值操作可能还没完成日志就已经写入,进一步加剧属性缺失问题。
修复方案
- 修正LogHelper代码,替换错误的字段取值,修正异步方法签名:
public static class LogHelper { // 修正返回值为Task,移除async void签名 public static Task EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext) { var request = httpContext.Request; // 正确读取HTTP请求方法存入上下文 diagnosticContext.Set("RequestMethod", request.Method); diagnosticContext.Set("Protocol", request.Protocol); return Task.CompletedTask; } }
- 移除appsettings.json中无效的全局过滤配置,直接在
UseSerilogRequestLogging中间件配置中添加过滤规则,该过滤时机和Enrich操作完全匹配,是官方推荐的请求日志过滤方式:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { // ...其他中间件配置 app.UseSerilogRequestLogging(opt => { opt.EnrichDiagnosticContext = LogHelper.EnrichFromRequest; // 配置过滤规则,仅保留GET/POST/PUT/DELETE方法的请求日志 opt.ShouldLog = (ctx) => { var method = ctx.Request.Method.ToUpperInvariant(); return method is HttpMethods.Get or HttpMethods.Post or HttpMethods.Put or HttpMethods.Delete; }; }); // ...其他中间件配置 }
如果确实需要通过Serilog.Expressions配置过滤而非内联代码,可将过滤规则配置在请求日志对应的子日志级别覆写节点,不要放在全局Filter节点,同时注意匹配字段名要改为实际注入的RequestMethod。从性能角度考虑,直接使用中间件自带的ShouldLog委托效率更高,不需要额外依赖表达式解析。
内容的提问来源于stack exchange,提问作者Citizen-Dror
相关产品推荐
相关产品推荐

