// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 using FluentAssertions; using FluentAssertions.Execution; using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.Exporter; using Xunit; namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations; // use collection to indicate that tests should not be run // in parallel // see https://xunit.net/docs/running-tests-in-parallel [Collection("EventEmittingTests")] public class SettingsTests : IDisposable { public SettingsTests() { ClearEnvVars(); } public void Dispose() { ClearEnvVars(); } [Fact] internal void GeneralSettings_DefaultValues() { var settings = Settings.FromDefaultSources(false); using (new AssertionScope()) { settings.Plugins.Should().BeEmpty(); settings.EnabledResourceDetectors.Should().NotBeEmpty(); settings.FlushOnUnhandledException.Should().BeFalse(); settings.OtlpExportProtocol.Should().Be(OtlpExportProtocol.HttpProtobuf); } } [Fact] internal void TracerSettings_DefaultValues() { var settings = Settings.FromDefaultSources(false); using (new AssertionScope()) { settings.TracesEnabled.Should().BeTrue(); settings.TracesExporter.Should().Be(TracesExporter.Otlp); settings.OtlpExportProtocol.Should().Be(OtlpExportProtocol.HttpProtobuf); settings.ConsoleExporterEnabled.Should().BeFalse(); settings.EnabledInstrumentations.Should().NotBeEmpty(); settings.ActivitySources.Should().BeEquivalentTo(new List { "OpenTelemetry.AutoInstrumentation.*" }); settings.AdditionalLegacySources.Should().BeEmpty(); settings.TracesSampler.Should().BeNull(); settings.TracesSamplerArguments.Should().BeNull(); // Instrumentation options tests settings.InstrumentationOptions.GraphQLSetDocument.Should().BeFalse(); settings.InstrumentationOptions.SqlClientSetDbStatementForText.Should().BeFalse(); #if NET6_0_OR_GREATER settings.InstrumentationOptions.EntityFrameworkCoreSetDbStatementForText.Should().BeFalse(); #endif } } [Fact] internal void MeterSettings_DefaultValues() { var settings = Settings.FromDefaultSources(false); using (new AssertionScope()) { settings.MetricsEnabled.Should().BeTrue(); settings.MetricExporter.Should().Be(MetricsExporter.Otlp); settings.OtlpExportProtocol.Should().Be(OtlpExportProtocol.HttpProtobuf); settings.ConsoleExporterEnabled.Should().BeFalse(); settings.EnabledInstrumentations.Should().NotBeEmpty(); settings.Meters.Should().BeEmpty(); } } [Fact] internal void LogSettings_DefaultValues() { var settings = Settings.FromDefaultSources(false); using (new AssertionScope()) { settings.LogsEnabled.Should().BeTrue(); settings.LogExporter.Should().Be(LogExporter.Otlp); settings.OtlpExportProtocol.Should().Be(OtlpExportProtocol.HttpProtobuf); settings.ConsoleExporterEnabled.Should().BeFalse(); settings.EnabledInstrumentations.Should().NotBeEmpty(); settings.IncludeFormattedMessage.Should().BeFalse(); } } [Fact] internal void SdkSettings_DefaultValues() { var settings = Settings.FromDefaultSources(false); using (new AssertionScope()) { settings.Propagators.Should().BeEmpty(); } } [Theory] [InlineData("none", TracesExporter.None)] [InlineData("non-supported", TracesExporter.Otlp)] [InlineData("otlp", TracesExporter.Otlp)] [InlineData("zipkin", TracesExporter.Zipkin)] internal void TracesExporter_SupportedValues(string tracesExporter, TracesExporter expectedTracesExporter) { Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.Exporter, tracesExporter); var settings = Settings.FromDefaultSources(false); settings.TracesExporter.Should().Be(expectedTracesExporter); } [Fact] internal void TracesExporter_FailFast() { Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.Exporter, "not-supported"); var action = () => Settings.FromDefaultSources(true); action.Should().Throw(); } [Theory] [InlineData("none", MetricsExporter.None)] [InlineData("non-supported", MetricsExporter.Otlp)] [InlineData("otlp", MetricsExporter.Otlp)] [InlineData("prometheus", MetricsExporter.Prometheus)] internal void MetricExporter_SupportedValues(string metricExporter, MetricsExporter expectedMetricsExporter) { Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Exporter, metricExporter); var settings = Settings.FromDefaultSources(false); settings.MetricExporter.Should().Be(expectedMetricsExporter); } [Fact] internal void MetricExporter_FailFast() { Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Exporter, "not-supported"); var action = () => Settings.FromDefaultSources(true); action.Should().Throw(); } [Theory] [InlineData("none", LogExporter.None)] [InlineData("non-supported", LogExporter.Otlp)] [InlineData("otlp", LogExporter.Otlp)] internal void LogExporter_SupportedValues(string logExporter, LogExporter expectedLogExporter) { Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.Exporter, logExporter); var settings = Settings.FromDefaultSources(false); settings.LogExporter.Should().Be(expectedLogExporter); } [Fact] internal void LogExporter_FailFast() { Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.Exporter, "not-supported"); var action = () => Settings.FromDefaultSources(true); action.Should().Throw(); } [Theory] [InlineData(null, new Propagator[] { })] [InlineData("not-supported", new Propagator[] { })] [InlineData("not-supported1,not-supported2", new Propagator[] { })] [InlineData("tracecontext", new[] { Propagator.W3CTraceContext })] [InlineData("baggage", new[] { Propagator.W3CBaggage })] [InlineData("b3multi", new[] { Propagator.B3Multi })] [InlineData("b3", new[] { Propagator.B3Single })] [InlineData("not-supported,b3", new Propagator[] { Propagator.B3Single })] [InlineData("tracecontext,baggage,b3multi,b3", new[] { Propagator.W3CTraceContext, Propagator.W3CBaggage, Propagator.B3Multi, Propagator.B3Single })] internal void Propagators_SupportedValues(string? propagators, Propagator[] expectedPropagators) { Environment.SetEnvironmentVariable(ConfigurationKeys.Sdk.Propagators, propagators); var settings = Settings.FromDefaultSources(false); settings.Propagators.Should().BeEquivalentTo(expectedPropagators); } [Fact] internal void Propagators_FailFast() { Environment.SetEnvironmentVariable(ConfigurationKeys.Sdk.Propagators, "not-supported"); var action = () => Settings.FromDefaultSources(true); action.Should().Throw(); } [Theory] #if NETFRAMEWORK [InlineData("ASPNET", TracerInstrumentation.AspNet)] #endif #if NET6_0_OR_GREATER [InlineData("GRAPHQL", TracerInstrumentation.GraphQL)] #endif [InlineData("HTTPCLIENT", TracerInstrumentation.HttpClient)] [InlineData("MONGODB", TracerInstrumentation.MongoDB)] #if NET6_0_OR_GREATER [InlineData("MYSQLDATA", TracerInstrumentation.MySqlData)] [InlineData("STACKEXCHANGEREDIS", TracerInstrumentation.StackExchangeRedis)] #endif [InlineData("NPGSQL", TracerInstrumentation.Npgsql)] [InlineData("SQLCLIENT", TracerInstrumentation.SqlClient)] [InlineData("GRPCNETCLIENT", TracerInstrumentation.GrpcNetClient)] #if NETFRAMEWORK [InlineData("WCFSERVICE", TracerInstrumentation.WcfService)] #endif #if NET6_0_OR_GREATER [InlineData("MASSTRANSIT", TracerInstrumentation.MassTransit)] #endif [InlineData("NSERVICEBUS", TracerInstrumentation.NServiceBus)] [InlineData("ELASTICSEARCH", TracerInstrumentation.Elasticsearch)] [InlineData("QUARTZ", TracerInstrumentation.Quartz)] #if NET6_0_OR_GREATER [InlineData("ENTITYFRAMEWORKCORE", TracerInstrumentation.EntityFrameworkCore)] [InlineData("ASPNETCORE", TracerInstrumentation.AspNetCore)] #endif [InlineData("WCFCLIENT", TracerInstrumentation.WcfClient)] [InlineData("MYSQLCONNECTOR", TracerInstrumentation.MySqlConnector)] [InlineData("AZURE", TracerInstrumentation.Azure)] [InlineData("ELASTICTRANSPORT", TracerInstrumentation.ElasticTransport)] [InlineData("KAFKA", TracerInstrumentation.Kafka)] internal void TracerSettings_Instrumentations_SupportedValues(string tracerInstrumentation, TracerInstrumentation expectedTracerInstrumentation) { Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesInstrumentationEnabled, "false"); Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Traces.EnabledTracesInstrumentationTemplate, tracerInstrumentation), "true"); var settings = Settings.FromDefaultSources(false); settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { expectedTracerInstrumentation }); } [Fact] internal void TracerSettings_TracerSampler() { const string expectedTracesSampler = nameof(expectedTracesSampler); const string expectedTracesSamplerArguments = nameof(expectedTracesSamplerArguments); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesSampler, expectedTracesSampler); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesSamplerArguments, expectedTracesSamplerArguments); var settings = Settings.FromDefaultSources(false); settings.TracesSampler.Should().Be(expectedTracesSampler); settings.TracesSamplerArguments.Should().Be(expectedTracesSamplerArguments); } [Theory] #if NETFRAMEWORK [InlineData("ASPNET", MetricInstrumentation.AspNet)] #endif [InlineData("NETRUNTIME", MetricInstrumentation.NetRuntime)] [InlineData("HTTPCLIENT", MetricInstrumentation.HttpClient)] [InlineData("PROCESS", MetricInstrumentation.Process)] [InlineData("NSERVICEBUS", MetricInstrumentation.NServiceBus)] #if NET6_0_OR_GREATER [InlineData("ASPNETCORE", MetricInstrumentation.AspNetCore)] #endif internal void MeterSettings_Instrumentations_SupportedValues(string meterInstrumentation, MetricInstrumentation expectedMetricInstrumentation) { Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.MetricsInstrumentationEnabled, "false"); Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Metrics.EnabledMetricsInstrumentationTemplate, meterInstrumentation), "true"); var settings = Settings.FromDefaultSources(false); settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { expectedMetricInstrumentation }); } [Theory] [InlineData("ILOGGER", LogInstrumentation.ILogger)] internal void LogSettings_Instrumentations_SupportedValues(string logInstrumentation, LogInstrumentation expectedLogInstrumentation) { Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.LogsInstrumentationEnabled, "false"); Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Logs.EnabledLogsInstrumentationTemplate, logInstrumentation), "true"); var settings = Settings.FromDefaultSources(false); settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { expectedLogInstrumentation }); } [Theory] [InlineData("true", true)] [InlineData("false", false)] internal void IncludeFormattedMessage_DependsOnCorrespondingEnvVariable(string includeFormattedMessage, bool expectedValue) { Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.IncludeFormattedMessage, includeFormattedMessage); var settings = Settings.FromDefaultSources(false); settings.IncludeFormattedMessage.Should().Be(expectedValue); } [Theory] [InlineData("", OtlpExportProtocol.HttpProtobuf)] [InlineData(null, OtlpExportProtocol.HttpProtobuf)] [InlineData("http/protobuf", null)] [InlineData("grpc", null)] [InlineData("nonExistingProtocol", null)] internal void OtlpExportProtocol_DependsOnCorrespondingEnvVariable(string? otlpProtocol, OtlpExportProtocol? expectedOtlpExportProtocol) { Environment.SetEnvironmentVariable(ConfigurationKeys.ExporterOtlpProtocol, otlpProtocol); var settings = Settings.FromDefaultSources(false); // null values for expected data will be handled by OTel .NET SDK settings.OtlpExportProtocol.Should().Be(expectedOtlpExportProtocol); } [Theory] [InlineData("true", true)] [InlineData("false", false)] [InlineData(null, false)] internal void FlushOnUnhandledException_DependsOnCorrespondingEnvVariable(string? flushOnUnhandledException, bool expectedValue) { Environment.SetEnvironmentVariable(ConfigurationKeys.FlushOnUnhandledException, flushOnUnhandledException); var settings = Settings.FromDefaultSources(false); settings.FlushOnUnhandledException.Should().Be(expectedValue); } [Theory] #if NET6_0_OR_GREATER [InlineData("CONTAINER", ResourceDetector.Container)] #endif [InlineData("AZUREAPPSERVICE", ResourceDetector.AzureAppService)] [InlineData("PROCESSRUNTIME", ResourceDetector.ProcessRuntime)] [InlineData("PROCESS", ResourceDetector.Process)] [InlineData("HOST", ResourceDetector.Host)] internal void GeneralSettings_Instrumentations_SupportedValues(string resourceDetector, ResourceDetector expectedResourceDetector) { Environment.SetEnvironmentVariable(ConfigurationKeys.ResourceDetectorEnabled, "false"); Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.EnabledResourceDetectorTemplate, resourceDetector), "true"); var settings = Settings.FromDefaultSources(false); settings.EnabledResourceDetectors.Should().BeEquivalentTo(new List { expectedResourceDetector }); } private static void ClearEnvVars() { Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.LogsInstrumentationEnabled, null); foreach (var logInstrumentation in Enum.GetValues(typeof(LogInstrumentation)).Cast()) { Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Logs.EnabledLogsInstrumentationTemplate, logInstrumentation.ToString().ToUpperInvariant()), null); } Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.Exporter, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.IncludeFormattedMessage, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.MetricsInstrumentationEnabled, null); foreach (var metricInstrumentation in Enum.GetValues(typeof(MetricInstrumentation)).Cast()) { Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Metrics.EnabledMetricsInstrumentationTemplate, metricInstrumentation.ToString().ToUpperInvariant()), null); } Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Exporter, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesInstrumentationEnabled, null); foreach (var tracerInstrumentation in Enum.GetValues(typeof(TracerInstrumentation)).Cast()) { Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Traces.EnabledTracesInstrumentationTemplate, tracerInstrumentation.ToString().ToUpperInvariant()), null); } Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.Exporter, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesSampler, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesSamplerArguments, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.GraphQLSetDocument, null); Environment.SetEnvironmentVariable(ConfigurationKeys.ExporterOtlpProtocol, null); Environment.SetEnvironmentVariable(ConfigurationKeys.FlushOnUnhandledException, null); Environment.SetEnvironmentVariable(ConfigurationKeys.ResourceDetectorEnabled, null); Environment.SetEnvironmentVariable(ConfigurationKeys.ResourceDetectorEnabled, null); foreach (var resourceDetector in Enum.GetValues(typeof(ResourceDetector)).Cast()) { Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.EnabledResourceDetectorTemplate, resourceDetector.ToString().ToUpperInvariant()), null); } Environment.SetEnvironmentVariable(ConfigurationKeys.Sdk.Propagators, null); } }