Skip to content

Redis Tracing Dependency Injection Improvements #3650

@CodingFlow

Description

@CodingFlow

When using a dependency injection framework, I found it took quite a bit of effort to figure out the best approach that can be implemented with the current Redis tracing API. I've discovered a good solution and have idea proposals to improve it even further.

Best Current Solution

The best way I've found to register the Redis connection with it's current API is to use a factory class that returns the connection either lazily when accessed or via a method call in the startup class (in my case, it was in the hosted service). As for tracing instrumentation, the concrete instance is registered with DI and can be called to set the connection in the factory class:

using Microsoft.Extensions.Options;
using OpenTelemetry.Instrumentation.StackExchangeRedis;
using Service.Abstractions;
using StackExchange.Redis;

namespace Service.Libraries.Redis;

internal class RedisConnection(IOptions<RedisOptions> redisOptions, StackExchangeRedisInstrumentation instrumentation) : IStartupService, IRedisConnection
{
    private readonly RedisOptions redisSettings = redisOptions.Value;
    public IDatabase Database { get; private set; }
    public IServer Server { get; private set; }

    public async Task Startup()
    {
        var muxer = await ConnectionMultiplexer.ConnectAsync($"{redisSettings.Host}:{redisSettings.Port}");

        Database = muxer.GetDatabase();
        Server = muxer.GetServer(muxer.GetEndPoints().First());

        instrumentation.AddConnection(muxer);
    }
}

Tracing DI Registration:

services.AddOpenTelemetry()
    .WithTracing(tracing => tracing.AddRedisInstrumentation());

Solution Proposal 1: Short Term, Quick Win

  • Add interface to StackExchangeRedisInstrumentation and use it in DI instead of the concrete type.
  • Document this recommended solution when using DI.

This will make onboarding of new users of the Redis tracing library a lot easier and enable easier unit testing by being able to mock the interface for the injected instrumentation. This should also resolve the root issue of #2656

Solution Proposal 2: Long Term, But Even Better

I'm not sure exactly how they do it, but Npgsql.OpenTelemetry works magically without having the user of the library get a reference to a connection object:

public static void RegisterTelemetry(IOpenTelemetryBuilder telemetry)
{
    telemetry.WithTracing(tracing => tracing.AddNpgsql());
}

And that's all that needs to be done. 😕

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions