如何仅追踪调用Redis的API请求并上报至Application Insights
问题分析与解决方案
现象原因
这不是异常现象,完全是当前中间件代码逻辑导致的结果。你的代码在进入中间件后,无论后续业务逻辑是否真的调用了Redis命令,只要执行到finally块就会无条件上报Redis依赖。哪怕只是获取了IDatabase实例但没执行任何Redis操作,也会触发上报。
解决方案
要实现仅上报实际执行过Redis命令的请求,需要追踪Redis命令的真实执行情况,而非仅依赖中间件的生命周期。以下提供两种可行方案:
方案一:自定义Redis数据库包装类
通过封装IDatabase接口,记录是否有实际命令执行:
- 创建追踪用的Redis数据库包装类
public class TrackedRedisDatabase : IDatabase { private readonly IDatabase _innerDb; public bool HasExecutedCommands { get; private set; } public TrackedRedisDatabase(IDatabase innerDb) { _innerDb = innerDb; } // 实现IDatabase所有方法,每个方法执行后标记命令已执行 public RedisValue StringGet(RedisKey key, CommandFlags flags = CommandFlags.None) { HasExecutedCommands = true; return _innerDb.StringGet(key, flags); } // 此处需补充实现IDatabase的其他所有方法(如StringSet、HashGet等),每个方法都要设置HasExecutedCommands = true }
- 修改中间件代码
var stopwatch = Stopwatch.StartNew(); var originalDb = connectionMultiplexer.GetDatabase(); var trackedDb = new TrackedRedisDatabase(originalDb); // 将追踪实例存入HttpContext,供后续业务逻辑使用 httpContext.Items["TrackedRedisDatabase"] = trackedDb; try { await next(httpContext).ConfigureAwait(false); } finally { stopwatch.Stop(); // 仅当有实际Redis命令执行时才上报依赖 if (trackedDb.HasExecutedCommands) { var dependency = new DependencyTelemetry { Name = "Redis", Type = "Redis", Target = connectionMultiplexer.Configuration, Data = httpContext.Request.Path, Duration = stopwatch.Elapsed, Success = true }; telemetryClient.TrackDependency(dependency); } }
- 业务逻辑中使用追踪实例
// 从HttpContext获取追踪用的Redis数据库实例 var trackedDb = (TrackedRedisDatabase)HttpContext.Items["TrackedRedisDatabase"]; var value = trackedDb.StringGet("your-key");
方案二:利用StackExchange.Redis的事件回调
通过订阅ConnectionMultiplexer的CommandExecuted事件,监听Redis命令执行:
var stopwatch = Stopwatch.StartNew(); bool hasRedisCall = false; // 订阅命令执行完成事件 void OnCommandExecuted(object sender, CommandExecutedEventArgs e) { hasRedisCall = true; } connectionMultiplexer.CommandExecuted += OnCommandExecuted; try { await next(httpContext).ConfigureAwait(false); } finally { stopwatch.Stop(); // 必须取消订阅,避免内存泄漏和跨请求干扰 connectionMultiplexer.CommandExecuted -= OnCommandExecuted; if (hasRedisCall) { var dependency = new DependencyTelemetry { Name = "Redis", Type = "Redis", Target = connectionMultiplexer.Configuration, Data = httpContext.Request.Path, Duration = stopwatch.Elapsed, Success = true }; telemetryClient.TrackDependency(dependency); } }
注意:
ConnectionMultiplexer通常是单例实例,因此每个请求必须在finally块中取消事件订阅,防止多个请求的状态互相干扰。
内容的提问来源于stack exchange,提问作者Vikram R
相关产品推荐
相关产品推荐

