Search code examples
asp.net-mvcdatabase-connectionc#-3.0azure-application-insightsstackexchange.redis

Track Redis dependency calls and send details to Application insights


My application consists of few API that would call Redis db and some API dont. So, I created a middleware to intercept and track the Redis dependency calls and send info to app insights. But, it appears, it sends or shows redis dependency for all requests. I've checked this on end-to-end transaction in application insights.

       `var stopwatch = Stopwatch.StartNew();
        var database = connectionMultiplexer.GetDatabase();

        try
        {
            await next(httpContext).ConfigureAwait(false); // calling next middleware
        }
        finally
        {
            stopwatch.Stop();

            // Track Redis dependency using Application Insights SDK
            var dependency = new DependencyTelemetry
            {
                Name = "Redis",
                Type = "Redis",
                Target = connectionMultiplexer.Configuration,
                Data = httpContext.Request.Path,
                Duration = stopwatch.Elapsed,
                Success = true
            };

            telemetryClient.TrackDependency(dependency);`

The code I've used in the middleware.

I need to send the telemetry data of only those API requests which uses Redis db for its execution. Let me know if this is how it behaves or provide me with solution for this scenario. I would love your effort. Thank You!


Solution

  • Middleware within the .Net pipeline has no context about the action being invoced. There is no way it can possibly know whether a call to Redis Cache will be made somewhere in the pipeline unless you start using some advanced reflection to determine that. But even then, I would not rely on the reported dependency of the telemetry since a lot more can happen in the pipeline than just the call to Redis Cache.

    My suggestion is to create a helper that you can use to wrap call to Redis Cache into. Now, I think it would be best to use that helper inside the distributedCache calls since it looks like it is a self created abstraction over the Redis Cache client that contains all possible calls to Redis Cache your application can perform.

    Here is a sample implementation

    public class RedisCacheDependencyTracker
    {
        private readonly TelemetryClient telemetryClient;
    
        public RedisCacheDependencyTracker(TelemetryConfiguration telemetryConfiguration)
        {
            telemetryClient = new TelemetryClient(telemetryConfiguration);
        }
    
        public async Task<T> ExecuteAndLogAsync<T>(Func<Task<T>> redisMethod, string opName)
        {
            using var operation = telemetryClient.StartOperation<DependencyTelemetry>(opName);
            operation.Telemetry.Name = "Redis";
            operation.Telemetry.Type = "Redis";
    
            try
            {
                return await redisMethod.Invoke();
            }
            catch
            {
                operation.Telemetry.Success = false;
                throw;
            }
        }
    
        public async Task ExecuteAndLogAsync(Func<Task> redisMethod, string opName)
        {
            using var operation = telemetryClient.StartOperation<DependencyTelemetry>(opName);
            operation.Telemetry.Name = "Redis";
            operation.Telemetry.Type = "Redis";
    
            try
            {
                await redisMethod.Invoke();
            }
            catch
            {
                operation.Telemetry.Success = false;
                throw;
            }
        }
    }
    

    You can then call it like this:

    var cacheKey = "myCacheKey";
    var cacheValue = await redisCacheDependencyTracker.ExecuteAndLogAsync(() => GetStringAsync(cacheKey), "GetStringAsync");