question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Redis instrumentation: allow IConnexionMultiplexer to be added *after* instrumentation creation

See original GitHub issue

Feature Request

Related: #624

We have a problem using the Redis instrumentation library, because in our app, IConnexionMultiplexer is not available on startup, and is instead created on first demand later in the app lifecycle.

We still want to use this library, because it handles perfectly how to profile the redis commands.

Observations

The current implementation of StackExchangeRedisCallsInstrumentation requires that the IConnexionMultiplexer is passed in the constructor despite only being used to call connection.RegisterProfiler(this.GetProfilerSessionsFactory());¸

An alternative ctor could be added without this connection and a public method RegisterConnection(IConnectionMultiplexer).

But then we need a way to call this Instrumentation instance from our code, to register the connection when created.

Because the instance is internal, everything is supposed to happen on the registration extension method.

Summary

We want to register a IConnexionMultiplexer later on StackExchangeRedisCallsInstrumentation.

  • There are cases where the IConnexionMultiplexer is not available at startup
  • There is no way to reuse the code of the Redis Instrumentation library because everything is internal

Proposed solution

I see two ways of allowing that, both of them requires that StackExchangeRedisCallsInstrumentation add public a void RegisterConnection(IConnectionMultiplexer connection) to register a connection later.

  • Make StackExchangeRedisCallsInstrumentation public, so we can create an instance before, store it somewhere to be able to call the RegisterConnection method, then pass directly this instance to AddInstrumentation().

  • Keeps StackExchangeRedisCallsInstrumentation internal, but provide a callback on AddRedisInstrumentation to allow capturing the instrumentation instance (hidden in an interface or a method signature) where we can register a IConnectionMultiplexer later.

Here is a naive example for solution 2:

public interface IRedisCallsInstrumentation
{
    void RegisterConnection(IConnectionMultiplexer connection);
}

/// <summary>
/// Redis calls instrumentation.
/// </summary>
internal class StackExchangeRedisCallsInstrumentation : IRedisCallsInstrumentation, IDisposable
{
    // ...
    public void RegisterConnection(IConnectionMultiplexer connection)
    {
        connection.RegisterProfiler(this.GetProfilerSessionsFactory());
    }
}


/// <summary>
/// Extension methods to simplify registering of dependency instrumentation.
/// </summary>
public static class TracerProviderBuilderExtensions
{
    /// <summary>
    /// Enables the outgoing requests automatic data collection for Redis.
    /// </summary>
    /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
    /// <param name="registration">Callback to receive the instrumentation for redis, allowing to register a connection after the instrumentation is started.</param>
    /// <param name="configureOptions">Redis configuration options.</param>
    /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
    public static TracerProviderBuilder AddRedisInstrumentation(
        this TracerProviderBuilder builder,
        Action<IRedisCallsInstrumentation> registration,
        Action<StackExchangeRedisCallsInstrumentationOptions> configureOptions = null)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

        StackExchangeRedisCallsInstrumentationOptions options = new StackExchangeRedisCallsInstrumentationOptions();
        configureOptions?.Invoke(options);

        var instrumentation = new StackExchangeRedisCallsInstrumentation(options);
        
        registration(instrumentation);

        return builder
            .AddInstrumentation(instrumentation)
            .AddSource(StackExchangeRedisCallsInstrumentation.ActivitySourceName);
    }
}

public static class Program
{
    private static IRedisCallsInstrumentation redisCallsIntrumentation;

    public static void Main()
    {
        using var telemetry = Sdk.CreateTracerProviderBuilder()
            .AddRedisInstrumentation(r => { redisCallsIntrumentation = r })
            .Build();

        // ...
        // now you can use redisCallsInstrumentation
    }
}

Other considerations

I understand and agree that it is easier when a library exposes as few public endpoint as possible. But I see extension methods as a shortcut, not the only way to use a library.

I think (but can understand that you don’t agree) that you should provide a way to register an instrumentation instance by yourself, by providing the instrumentation instance and adding the source yourself: StackExchangeRedisCallsInstrumentation should be public and the ActivitySourceName constant should be also public.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:11
  • Comments:10 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
Kielekcommented, Jul 25, 2023
1reaction
danatcofocommented, Jul 25, 2023

If this is still relevant, you can take a look at my implementation using reflection.

@Norbe3t did you by chance happen to make and publish a nuget package with this? Its exactly what we need with a multi tenant distributed caching solution (i.e. multiple lazy loaded connections). If not would you mind if I stole this solution and generated a public nuget package?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Redis Cache Calls In OpenTelemetry in DotNet
AddRedisInstrumentation (connection) .AddConsoleExporter());. Currently I tried OpenTelemetry.StackExchange.redis.Instrumentation configured as ...
Read more >
C#/.NET guide
Connect to your production Redis with TLS ; ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect(options); //Creation of the connection to the DB ...
Read more >
Getting started with OpenTelemetry and distributed tracing in ...
This means that users can instrument their applications/libraries to emit OpenTelemetry compatible traces by using just the .NET Runtime.
Read more >
Automatic Instrumentation of Containerized .NET ...
Learn how to automatically instrument your containerized .NET applications using OpenTelemetry and see how it integrates with Jaeger and ...
Read more >
OpenTelemetry Redis Instrumentation
Instrument redis to report Redis queries. There are two options for instrumenting code. The first option is to use the opentelemetry-instrument executable ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found