File: src\Vendoring\OpenTelemetry.Instrumentation.StackExchangeRedis\TracerProviderBuilderExtensions.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.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using OpenTelemetry.Instrumentation.StackExchangeRedis;
using OpenTelemetry.Internal;
using StackExchange.Redis;
 
namespace OpenTelemetry.Trace;
 
/// <summary>
/// Extension methods to simplify registering of dependency instrumentation.
/// </summary>
internal static class TracerProviderBuilderExtensions
{
    /// <summary>
    /// Enables automatic data collection of outgoing requests to Redis.
    /// </summary>
    /// <remarks>
    /// Note: A <see cref="IConnectionMultiplexer"/> will be resolved using the
    /// application <see cref="IServiceProvider"/>.
    /// </remarks>
    /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
    /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
    public static TracerProviderBuilder AddRedisInstrumentation(
        this TracerProviderBuilder builder)
        => AddRedisInstrumentation(builder, name: null, connection: null, configure: null);
 
    /// <summary>
    /// Enables automatic data collection of outgoing requests to Redis.
    /// </summary>
    /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
    /// <param name="connection"><see cref="IConnectionMultiplexer"/> to instrument.</param>
    /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
    public static TracerProviderBuilder AddRedisInstrumentation(
        this TracerProviderBuilder builder,
        IConnectionMultiplexer connection)
    {
        Guard.ThrowIfNull(connection);
 
        return AddRedisInstrumentation(builder, name: null, connection, configure: null);
    }
 
    /// <summary>
    /// Enables automatic data collection of outgoing requests to Redis.
    /// </summary>
    /// <remarks>
    /// Note: A <see cref="IConnectionMultiplexer"/> will be resolved using the
    /// application <see cref="IServiceProvider"/>.
    /// </remarks>
    /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
    /// <param name="configure">Callback to configure options.</param>
    /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
    public static TracerProviderBuilder AddRedisInstrumentation(
        this TracerProviderBuilder builder,
        Action<StackExchangeRedisInstrumentationOptions> configure)
    {
        Guard.ThrowIfNull(configure);
 
        return AddRedisInstrumentation(builder, name: null, connection: null, configure);
    }
 
    /// <summary>
    /// Enables automatic data collection of outgoing requests to Redis.
    /// </summary>
    /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
    /// <param name="connection"><see cref="IConnectionMultiplexer"/> to instrument.</param>
    /// <param name="configure">Callback to configure options.</param>
    /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
    public static TracerProviderBuilder AddRedisInstrumentation(
        this TracerProviderBuilder builder,
        IConnectionMultiplexer connection,
        Action<StackExchangeRedisInstrumentationOptions> configure)
    {
        Guard.ThrowIfNull(connection);
        Guard.ThrowIfNull(configure);
 
        return AddRedisInstrumentation(builder, name: null, connection, configure);
    }
 
    /// <summary>
    /// Enables automatic data collection of outgoing requests to Redis.
    /// </summary>
    /// <remarks>
    /// Note: If an <see cref="IConnectionMultiplexer"/> is not supplied
    /// using the <paramref name="connection"/> parameter it will be
    /// resolved using the application <see cref="IServiceProvider"/>.
    /// </remarks>
    /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
    /// <param name="name">Optional name which is used when retrieving options.</param>
    /// <param name="connection">Optional <see cref="IConnectionMultiplexer"/> to instrument.</param>
    /// <param name="configure">Optional callback to configure options.</param>
    /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
    public static TracerProviderBuilder AddRedisInstrumentation(
        this TracerProviderBuilder builder,
        string? name,
        IConnectionMultiplexer? connection,
        Action<StackExchangeRedisInstrumentationOptions>? configure)
    {
        Guard.ThrowIfNull(builder);
 
        name ??= Options.DefaultName;
 
        builder.AddRedisInstrumentationSharedServices();
 
        if (configure != null)
        {
            builder.ConfigureServices(services =>
            {
                services.Configure(name, configure);
            });
        }
 
        return builder
            .AddSource(StackExchangeRedisConnectionInstrumentation.ActivitySourceName)
            .AddInstrumentation(sp =>
            {
                var instrumentation = sp.GetRequiredService<StackExchangeRedisInstrumentation>();
 
                connection ??= sp.GetService<IConnectionMultiplexer>();
 
                if (connection != null)
                {
                    instrumentation.AddConnection(name, connection);
                }
 
                return instrumentation;
            });
    }
 
    /// <summary>
    /// Registers a callback for configuring Redis instrumentation.
    /// </summary>
    /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
    /// <param name="configure">Callback to configure instrumentation.</param>
    /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
    public static TracerProviderBuilder ConfigureRedisInstrumentation(
        this TracerProviderBuilder builder,
        Action<StackExchangeRedisInstrumentation> configure)
    {
        Guard.ThrowIfNull(configure);
 
        return ConfigureRedisInstrumentation(builder, (sp, instrumentation) => configure(instrumentation));
    }
 
    /// <summary>
    /// Registers a callback for configuring Redis instrumentation.
    /// </summary>
    /// <param name="builder"><see cref="TracerProviderBuilder"/> being configured.</param>
    /// <param name="configure">Callback to configure instrumentation.</param>
    /// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
    public static TracerProviderBuilder ConfigureRedisInstrumentation(
        this TracerProviderBuilder builder,
        Action<IServiceProvider, StackExchangeRedisInstrumentation> configure)
    {
        Guard.ThrowIfNull(configure);
 
        if (builder is not IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
        {
            throw new NotSupportedException("ConfigureRedisInstrumentation is not supported on the supplied builder type.");
        }
 
        builder.AddRedisInstrumentationSharedServices();
 
        deferredTracerProviderBuilder.Configure(
            (sp, builder) => configure(sp, sp.GetRequiredService<StackExchangeRedisInstrumentation>()));
 
        return builder;
    }
 
    private static TracerProviderBuilder AddRedisInstrumentationSharedServices(
        this TracerProviderBuilder builder)
    {
        Guard.ThrowIfNull(builder);
 
        return builder.ConfigureServices(services =>
        {
            services.TryAddSingleton(
                sp => new StackExchangeRedisInstrumentation(
                    sp.GetRequiredService<IOptionsMonitor<StackExchangeRedisInstrumentationOptions>>()));
        });
    }
}