继承TelemetryInitializerBase的自定义遥测初始化器无法接收SignalR Hub日志
问题分析与解决方案
原因
你猜的没错,核心问题就是TelemetryInitializerBase的触发逻辑依赖当前活跃的HttpContext:
- 基类的
Initialize方法会先检查IHttpContextAccessor是否能拿到有效的HttpContext,只有存在时才会调用OnInitializeTelemetry。 - SignalR的Hub方法调用分为两个阶段:握手阶段(有HttpContext)和后续的持久连接调用(无活跃HttpContext)。当Hub方法执行日志时,
HttpContextAccessor的HttpContext为空,导致基类跳过了OnInitializeTelemetry的执行。 - 而直接实现
ITelemetryInitializer时,所有遥测都会触发Initialize方法,不受HttpContext存在与否的限制,所以能捕获Hub的日志。
解决方案
要让继承自TelemetryInitializerBase的初始化器支持SignalR场景,可以重写基类的Initialize方法,手动处理SignalR的Hub上下文:
修改后的遥测初始化器代码
private class DerivedTelemetryInitializer : TelemetryInitializerBase { private readonly IHttpContextAccessor _httpContextAccessor; public DerivedTelemetryInitializer(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } // 重写Initialize,覆盖基类的逻辑,同时处理SignalR场景 public override void Initialize(ITelemetry telemetry) { // 先执行基类的HTTP请求场景处理 base.Initialize(telemetry); // 尝试获取SignalR的HubCallerContext var hubCallerContext = _httpContextAccessor.HttpContext?.Features.Get<HubCallerContext>(); if (hubCallerContext != null && telemetry is ISupportProperties propTelemetry) { // 在这里添加用户数据或其他SignalR相关属性 propTelemetry.Properties["SignalR_UserID"] = hubCallerContext.User?.Identity?.Name ?? "Anonymous"; propTelemetry.Properties["SignalR_HubMethod"] = hubCallerContext.MethodName; } } protected override void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry) { // 原有的HTTP请求下的初始化逻辑保持不变 if (telemetry is ISupportProperties propTelemetry) { propTelemetry.Properties["HTTP_UserID"] = platformContext.User?.Identity?.Name ?? "Anonymous"; } } }
补充说明
HubCallerContext可以通过HttpContext.Features.Get<HubCallerContext>()获取,即使在持久连接阶段,这个Feature依然存在。- 如果你需要更直接地关联SignalR的请求遥测,可以结合
RequestTelemetry的上下文,比如将Hub方法标记为独立的请求段。
内容的提问来源于stack exchange,提问作者Linas
相关产品推荐
相关产品推荐

