File: src\Vendoring\OpenTelemetry.Instrumentation.StackExchangeRedis\StackExchangeRedisInstrumentation.cs
Web Access
Project: src\src\Components\Aspire.StackExchange.Redis\Aspire.StackExchange.Redis.csproj (Aspire.StackExchange.Redis)
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
 
using Microsoft.Extensions.Options;
using OpenTelemetry.Internal;
using StackExchange.Redis;
 
namespace OpenTelemetry.Instrumentation.StackExchangeRedis;
 
/// <summary>
/// StackExchange.Redis instrumentation.
/// </summary>
internal sealed class StackExchangeRedisInstrumentation : IDisposable
{
    private readonly IOptionsMonitor<StackExchangeRedisInstrumentationOptions> options;
 
    internal StackExchangeRedisInstrumentation(
        IOptionsMonitor<StackExchangeRedisInstrumentationOptions> options)
    {
        this.options = options;
    }
 
    internal List<StackExchangeRedisConnectionInstrumentation> InstrumentedConnections { get; } = new();
 
    /// <summary>
    /// Adds an <see cref="IConnectionMultiplexer"/> to the instrumentation.
    /// </summary>
    /// <param name="connection"><see cref="IConnectionMultiplexer"/>.</param>
    /// <returns><see cref="IDisposable"/> to cancel the registration.</returns>
    public IDisposable AddConnection(IConnectionMultiplexer connection)
        => this.AddConnection(Options.DefaultName, connection);
 
    /// <summary>
    /// Adds an <see cref="IConnectionMultiplexer"/> to the instrumentation.
    /// </summary>
    /// <param name="name">Name to use when retrieving options.</param>
    /// <param name="connection"><see cref="IConnectionMultiplexer"/>.</param>
    /// <returns><see cref="IDisposable"/> to cancel the registration.</returns>
    public IDisposable AddConnection(string name, IConnectionMultiplexer connection)
    {
        Guard.ThrowIfNull(name);
        Guard.ThrowIfNull(connection);
 
        var options = this.options.Get(name);
 
        lock (this.InstrumentedConnections)
        {
            var instrumentation = new StackExchangeRedisConnectionInstrumentation(connection, name, options);
 
            this.InstrumentedConnections.Add(instrumentation);
 
            return new StackExchangeRedisConnectionInstrumentationRegistration(() =>
            {
                lock (this.InstrumentedConnections)
                {
                    if (this.InstrumentedConnections.Remove(instrumentation))
                    {
                        instrumentation.Dispose();
                    }
                }
            });
        }
    }
 
    /// <inheritdoc/>
    public void Dispose()
    {
        lock (this.InstrumentedConnections)
        {
            foreach (var instrumentation in this.InstrumentedConnections)
            {
                instrumentation.Dispose();
            }
 
            this.InstrumentedConnections.Clear();
        }
    }
 
    private sealed class StackExchangeRedisConnectionInstrumentationRegistration : IDisposable
    {
        private readonly Action disposalAction;
 
        public StackExchangeRedisConnectionInstrumentationRegistration(
            Action disposalAction)
        {
            this.disposalAction = disposalAction;
        }
 
        public void Dispose()
        {
            this.disposalAction();
        }
    }
}