You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

静态类映射端点与Mediatr处理器中Serilog日志Enrichment异常问题

Serilog Enrichment 失效问题分析与解决方案

原因分析

  1. 请求上下文范围不匹配:UseSerilogRequestLogging的Enrich属性依赖异步本地存储(AsyncLocal)的LogContext,仅在请求管道的特定阶段生效。Mediatr处理器、静态端点映射中的代码如果脱离了请求的异步执行流,就无法访问这些上下文属性。
  2. 静态类端点执行时机问题:若静态类的端点映射逻辑在应用启动阶段执行,此时无请求上下文,自然无法获取请求级Enrich属性;即使在请求时执行,若未正确继承请求的LogContext,也会丢失属性。
  3. 手动传参的属性冲突:手动传入与Enricher同名的属性时,Serilog的属性合并逻辑可能覆盖LogContext中的原有属性,导致Username这类值丢失。
  4. Mediatr上下文传递缺失:Mediatr默认不会自动传递LogContext到处理器,异步执行时上下文断裂,导致处理器无法获取请求级Enrich属性。

解决方案

1. 全局包裹请求的LogContext范围

自定义中间件,将整个请求处理流程包裹在LogContext范围内,确保所有后续代码都能访问请求级属性:

app.Use(async (context, next) =>
{
    // 推送请求级属性到LogContext
    using (LogContext.PushProperty("Username", context.User.Identity?.Name ?? "Anonymous"))
    using (LogContext.PushProperty("HttpRequestClientHostIP", context.Connection.RemoteIpAddress?.ToString()))
    {
        await next();
    }
});

注意:这个中间件要放在UseRouting之前,保证所有请求处理逻辑(包括端点映射、Mediatr处理器)都在LogContext范围内执行。

2. 给Mediatr添加LogContext传递行为

实现Mediatr管道行为,确保LogContext能传递到处理器中:

public class LogContextPropagationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : notnull
{
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        // 捕获当前请求的LogContext上下文
        var capturedContext = LogContext.Capture();
        using (capturedContext)
        {
            return await next();
        }
    }
}

然后在DI容器中注册该行为:

builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LogContextPropagationBehavior<,>));

3. 调整静态端点映射逻辑

  • 如果静态类的端点映射是应用启动时执行(比如静态配置路由):这类日志属于应用启动日志,本身无请求上下文,不要期望获取请求级属性。
  • 如果是请求处理时动态执行:确保代码在请求的LogContext范围内,不要脱离当前请求的异步执行流。

4. 避免手动传参与Enrich属性冲突

不要手动传入与LogContext中同名的属性,依赖LogContext自动注入即可:

// 错误写法:同名属性会覆盖LogContext中的值
Log.Information("User {Username} from {HttpRequestClientHostIP}", username, ip);

// 正确写法:仅传递业务参数,请求级属性由LogContext自动补充
Log.Information("User action completed for {UserId}", userId);

5. 检查Serilog配置的Enrich顺序

确保Enrich.FromLogContext()在Serilog配置中正确配置,且放在自定义Enricher之后:

builder.Host.UseSerilog((context, config) =>
{
    config
        .WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
        .Enrich.WithUsername() // 自定义Enricher或其他全局Enricher
        .Enrich.WithClientIp()
        .Enrich.FromLogContext(); // 必须添加,才能读取LogContext中的属性
});

内容的提问来源于stack exchange,提问作者DerHaifisch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 02:23:12