Serilog通过EnrichDiagnosticContext添加的属性未在SignalR Hub中被记录怎么办
问题原因
UseSerilogRequestLogging 仅作用于单次短生命周期的常规HTTP请求管道,而SignalR的核心交互基于长连接:只有初始握手请求会触发该中间件的属性注入,后续所有Hub方法调用、连接断开事件都运行在长连接专属上下文内,不会重新走常规HTTP请求管道,因此DiagnosticContext内的属性不会被自动携带到Hub的执行上下文。
前置配置确认
首先确保你的Serilog初始化配置中已经开启了日志上下文继承:
Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() // 必须配置,否则自定义属性不会随日志上下文传递 // 其余你的Elasticsearch Sink等配置 .CreateLogger();
方案1:全局Hub过滤器(推荐)
通过实现IHubFilter可以一次性为所有Hub的所有调用、连接/断开事件注入自定义属性,无需修改业务代码:
- 实现Hub过滤器
public class SerilogEnrichHubFilter : IHubFilter { // 处理Hub方法调用的日志属性注入 public async ValueTask<object> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next) { var httpContext = invocationContext.Context.GetHttpContext(); if (httpContext == null) return await next(invocationContext); using var scope = LogContext.PushProperty("HttpRequestClientIP", httpContext.Connection.RemoteIpAddress) .PushProperty("UserName", httpContext.User?.Identity?.Name ?? "(anonymous)"); return await next(invocationContext); } // 处理连接建立事件的日志属性注入 public async Task OnConnectedAsync(HubLifetimeContext context, Func<HubLifetimeContext, Task> next) { var httpContext = context.Context.GetHttpContext(); if (httpContext == null) { await next(context); return; } using var scope = LogContext.PushProperty("HttpRequestClientIP", httpContext.Connection.RemoteIpAddress) .PushProperty("UserName", httpContext.User?.Identity?.Name ?? "(anonymous)"); await next(context); } // 处理连接断开事件的日志属性注入 public async Task OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func<HubLifetimeContext, Exception, Task> next) { var httpContext = context.Context.GetHttpContext(); if (httpContext == null) { await next(context, exception); return; } using var scope = LogContext.PushProperty("HttpRequestClientIP", httpContext.Connection.RemoteIpAddress) .PushProperty("UserName", httpContext.User?.Identity?.Name ?? "(anonymous)"); await next(context, exception); } }
- 注册过滤器到SignalR配置
// Startup.cs ConfigureServices 或 Program.cs 服务注册位置 services.AddSignalR(options => { options.AddFilter<SerilogEnrichHubFilter>(); });
方案2:单Hub/单方法手动注入
如果只需要为部分Hub的特定方法加属性,可以直接在方法内手动获取上下文注入:
public class CustomHub : Hub { private readonly ILogger<CustomHub> _logger; public CustomHub(ILogger<CustomHub> logger) { _logger = logger; } public async Task CustomOperation() { var httpContext = Context.GetHttpContext(); using var scope = LogContext.PushProperty("HttpRequestClientIP", httpContext.Connection.RemoteIpAddress) .PushProperty("UserName", httpContext.User?.Identity?.Name ?? "(anonymous)"); // 这里输出的日志就会携带自定义属性 _logger.LogInformation("执行自定义操作"); // 其余业务逻辑 } }
内容的提问来源于stack exchange,提问作者kman
相关产品推荐
相关产品推荐

