.NET 6下ASP.NET Core WebApi中Serilog失败时记录POST请求体及分Sink问题
针对Serilog请求日志的两个问题解决方案
1. POST请求失败时记录请求体:无现成配置,需自定义扩展
Serilog的UseSerilogRequestLogging中间件默认不提供仅在POST请求失败时记录请求体的现成配置,需要通过自定义逻辑实现,核心思路是允许请求体重读+在请求结束后判断状态并读取请求体:
实现步骤
- 第一步:确保请求体可重读
在Program.cs的管道配置中,先添加启用请求体重读的中间件(必须放在其他处理请求的中间件之前):app.Use(async (context, next) => { context.Request.EnableBuffering(); await next(); }); - 第二步:扩展请求日志逻辑
修改UseSerilogRequestLogging的配置,通过EnrichDiagnosticContext委托在请求结束后判断条件并读取请求体:app.UseSerilogRequestLogging(options => { options.EnrichDiagnosticContext = (diagnosticContext, httpContext) => { // 仅处理POST请求且响应状态码>299的情况 if (httpContext.Request.Method.Equals("POST", StringComparison.OrdinalIgnoreCase) && httpContext.Response.StatusCode > 299) { // 重置请求体读取位置 httpContext.Request.Body.Position = 0; // 读取请求体(可根据实际编码调整) using var reader = new StreamReader(httpContext.Request.Body, Encoding.UTF8, leaveOpen: true); var requestBody = reader.ReadToEnd(); // 将请求体添加到诊断上下文,后续日志会包含该属性 diagnosticContext.Set("RequestBody", requestBody); // 再次重置位置,避免后续中间件读取异常 httpContext.Request.Body.Position = 0; } }; }); - 注意事项:
- 需过滤敏感字段(如密码、令牌),避免日志泄露敏感数据
- 若请求体过大,需考虑性能问题,可添加大小限制逻辑
2. 将请求体写入独立Sink:通过日志过滤实现
要把包含请求体的日志单独发送到指定Sink,可利用Serilog的日志过滤+子日志器功能,结合环境区分虚拟机/容器的Sink类型:
实现步骤
- 第一步:在Serilog配置中添加带过滤的独立Sink
在Program.cs配置Serilog时,通过WriteTo.Logger()创建子日志器,仅将包含RequestBody属性的日志路由到独立Sink,同时保留原有日志的Sink配置:var builder = WebApplication.CreateBuilder(args); var env = builder.Environment; builder.Host.UseSerilog((context, config) => { // 基础日志配置(原有虚拟机/容器的日志Sink) config.ReadFrom.Configuration(context.Configuration) .Enrich.FromLogContext(); // 添加独立Sink:仅记录包含RequestBody的日志 config.WriteTo.Logger(lc => { lc.Filter.ByIncludingOnly(evt => evt.Properties.ContainsKey("RequestBody")); // 根据环境选择Sink:虚拟机用文件,容器用控制台 if (env.IsEnvironment("VM")) // 需自定义环境标识,或用env.IsProduction()等区分 { lc.WriteTo.File("logs/request-bodies-.txt", rollingInterval: RollingInterval.Day); } else { lc.WriteTo.Console(); } }); }); - 第二步:(可选)排除原有Sink中的请求体日志
如果不想让请求体日志出现在原有文件/控制台日志中,可给原有Sink添加排除过滤:// 原有文件Sink示例(添加排除逻辑) config.WriteTo.File("logs/app-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Information, filter: evt => !evt.Properties.ContainsKey("RequestBody")); - 注意事项:
- 确保环境标识准确,可通过环境变量
ASPNETCORE_ENVIRONMENT设置虚拟机/容器的环境值 - 独立Sink的配置(如文件路径、滚动策略)可根据实际需求调整
- 确保环境标识准确,可通过环境变量
内容的提问来源于stack exchange,提问作者askids
相关产品推荐
相关产品推荐

