File: Sampling\SamplingLoggerBuilderExtensionsTests.cs
Web Access
Project: src\test\Libraries\Microsoft.Extensions.Telemetry.Tests\Microsoft.Extensions.Telemetry.Tests.csproj (Microsoft.Extensions.Telemetry.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.Sampling;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Xunit;
 
namespace Microsoft.Extensions.Telemetry.Sampling;
 
public class SamplingLoggerBuilderExtensionsTests
{
    [Fact]
    public void AddTraceBasedSampling_RegistersInDI()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddTraceBasedSampler();
        });
 
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        LoggingSampler? sampler = serviceProvider.GetService<LoggingSampler>();
 
        Assert.NotNull(sampler);
        Assert.IsType<TraceBasedSampler>(sampler);
    }
 
    [Fact]
    public void AddRandomProbabilisticSampler_RegistersInDI()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddRandomProbabilisticSampler(1.0);
        });
 
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        LoggingSampler? sampler = serviceProvider.GetService<LoggingSampler>();
 
        Assert.NotNull(sampler);
        Assert.IsType<RandomProbabilisticSampler>(sampler);
    }
 
    [Fact]
    public void AddRandomProbabilisticSamplerFromConfiguration_RegistersInDI()
    {
        List<RandomProbabilisticSamplerFilterRule> expectedData =
        [
            new RandomProbabilisticSamplerFilterRule (probability: 1.0, categoryName: "Program.MyLogger", logLevel: LogLevel.Information, eventId: 1, eventName: "number one"),
            new RandomProbabilisticSamplerFilterRule (probability : 0.01, logLevel : LogLevel.Information),
            new RandomProbabilisticSamplerFilterRule (probability : 0.1, logLevel : LogLevel.Warning)
        ];
        ConfigurationBuilder configBuilder = new ConfigurationBuilder();
        configBuilder.AddJsonFile("appsettings.json");
        IConfigurationRoot configuration = configBuilder.Build();
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddRandomProbabilisticSampler(configuration);
        });
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        IOptionsMonitor<RandomProbabilisticSamplerOptions>? options = serviceProvider.GetService<IOptionsMonitor<RandomProbabilisticSamplerOptions>>();
        Assert.NotNull(options);
        Assert.NotNull(options.CurrentValue);
        Assert.Equivalent(expectedData, options.CurrentValue.Rules);
    }
 
    [Fact]
    public void AddRandomProbabilisticSampler_WhenRulesIsNull_ValidationFails()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddRandomProbabilisticSampler(o => o.Rules = null!);
        });
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        IOptionsMonitor<RandomProbabilisticSamplerOptions>? options = serviceProvider.GetService<IOptionsMonitor<RandomProbabilisticSamplerOptions>>();
        Assert.Throws<OptionsValidationException>(() => options?.CurrentValue.Rules);
    }
 
    [Theory]
    [InlineData(1.1)]
    [InlineData(-0.1)]
    [InlineData(2)]
    [InlineData(100)]
    public void AddRandomProbabilisticSampler_WhenDelegateIsInvalid_ValidationFails(double invalidProbabilityValue)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddRandomProbabilisticSampler(o => o.Rules.Add(new RandomProbabilisticSamplerFilterRule(invalidProbabilityValue)));
        });
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        IOptionsMonitor<RandomProbabilisticSamplerOptions>? options = serviceProvider.GetService<IOptionsMonitor<RandomProbabilisticSamplerOptions>>();
        Assert.Throws<OptionsValidationException>(() => options?.CurrentValue.Rules);
    }
 
    [Theory]
    [InlineData(1.1)]
    [InlineData(-0.1)]
    [InlineData(2)]
    [InlineData(100)]
    public void AddRandomProbabilisticSampler_WhenConfigInvalid_ValidationFails(double invalidProbabilityValue)
    {
        ConfigurationBuilder configBuilder = new ConfigurationBuilder();
        configBuilder.AddInMemoryCollection(new List<KeyValuePair<string, string?>>
        {
            new KeyValuePair<string, string?>("RandomProbabilisticSampler:Rules:0:Probability", invalidProbabilityValue.ToString(CultureInfo.InvariantCulture))
        });
        IConfigurationRoot configuration = configBuilder.Build();
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddRandomProbabilisticSampler(configuration);
        });
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        IOptionsMonitor<RandomProbabilisticSamplerOptions>? options = serviceProvider.GetService<IOptionsMonitor<RandomProbabilisticSamplerOptions>>();
        Assert.Throws<OptionsValidationException>(() => options?.CurrentValue.Rules);
    }
 
    [Fact]
    public void AddRandomProbabilisticSamplerFromDelegate_RegistersInDI()
    {
        List<RandomProbabilisticSamplerFilterRule> expectedData =
        [
            new RandomProbabilisticSamplerFilterRule (probability: 1.0, categoryName: "Program.MyLogger", logLevel: LogLevel.Information, eventId: 1, eventName: "number one"),
            new RandomProbabilisticSamplerFilterRule (probability : 0.01, logLevel : LogLevel.Information),
            new RandomProbabilisticSamplerFilterRule (probability : 0.1, logLevel : LogLevel.Warning)
        ];
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddRandomProbabilisticSampler(opts =>
            {
                opts.Rules = expectedData;
            });
        });
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        IOptionsMonitor<RandomProbabilisticSamplerOptions>? options = serviceProvider.GetService<IOptionsMonitor<RandomProbabilisticSamplerOptions>>();
        Assert.NotNull(options);
        Assert.NotNull(options.CurrentValue);
        Assert.Equivalent(expectedData, options.CurrentValue.Rules);
    }
 
    [Fact]
    public void AddSampler_RegistersInDI()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddSampler<MySampler>();
        });
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        LoggingSampler? sampler = serviceProvider.GetService<LoggingSampler>();
 
        Assert.NotNull(sampler);
        Assert.IsType<MySampler>(sampler);
    }
 
    [Fact]
    public void AddSamplerInstance_RegistersInDI()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging(builder =>
        {
            builder.AddSampler(new MySampler());
        });
 
        ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
        LoggingSampler? sampler = serviceProvider.GetService<LoggingSampler>();
 
        Assert.NotNull(sampler);
        Assert.IsType<MySampler>(sampler);
    }
 
    [Fact]
    public void WhenArgumentIsNull_Throws()
    {
        var builder = null as ILoggingBuilder;
 
        Func<ILoggingBuilder> action = () => SamplingLoggerBuilderExtensions.AddTraceBasedSampler(builder!);
        Assert.Throws<ArgumentNullException>(action);
 
        Func<ILoggingBuilder> action2 = () => SamplingLoggerBuilderExtensions.AddRandomProbabilisticSampler(builder!, 1.0);
        Assert.Throws<ArgumentNullException>(action);
 
        Func<ILoggingBuilder> action3 = () => SamplingLoggerBuilderExtensions.AddSampler<MySampler>(builder!);
        Assert.Throws<ArgumentNullException>(action);
 
        Func<ILoggingBuilder> action4 = () => SamplingLoggerBuilderExtensions.AddSampler(builder!, new MySampler());
        Assert.Throws<ArgumentNullException>(action);
    }
 
    private class MySampler : LoggingSampler
    {
        public override bool ShouldSample<TState>(in LogEntry<TState> logEntry) => true;
    }
}