diff --git a/CHANGELOG.md b/CHANGELOG.md index fa9ee5e05d..ad069eb046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,24 @@ This beta release is built on top of [OpenTelemetry .NET](https://github.com/ope to `linux-musl-x64` for Linux musl and `OpenTelemetry.AutoInstrumentation.Native.dylib` to `osx-x64` for MacOS. +- Change the way to manage enabled instrumentations. The following environmental + variables: + - `OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS`, + - `OTEL_DOTNET_AUTO_TRACES_DISABLED_INSTRUMENTATIONS`, + - `OTEL_DOTNET_AUTO_METRICS_ENABLED_INSTRUMENTATIONS`, + - `OTEL_DOTNET_AUTO_METRICS_DISABLED_INSTRUMENTATIONS`, + - `OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS`, + - `OTEL_DOTNET_AUTO_LOGS_DISABLED_INSTRUMENTATIONS` + + are replaced by: + + - `OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED`, + - `OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED`, + - `OTEL_DOTNET_AUTO_TRACES_{0}_INSTRUMENTATION_ENABLED`, + - `OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED`, + - `OTEL_DOTNET_AUTO_METRICS_{0}_INSTRUMENTATION_ENABLED`, + - `OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED`, + - `OTEL_DOTNET_AUTO_LOGS_{0}_INSTRUMENTATION_ENABLED`. ### Deprecated diff --git a/docs/config.md b/docs/config.md index c3ecf87770..2a10c151f5 100644 --- a/docs/config.md +++ b/docs/config.md @@ -62,15 +62,29 @@ for more details. ## Instrumentations -| Environment variable | Description | Default value | -|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------| -| `OTEL_DOTNET_AUTO_INTEGRATIONS_FILE` | List of bytecode instrumentations JSON configuration filepaths, delimited by the platform-specific path separator (`;` on Windows, `:` on Linux and macOS). For example: `%ProfilerDirectory%/integrations.json`. It is required for bytecode instrumentations. | | -| `OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS` | Comma-separated list of traces source instrumentations you want to enable. Set to `none` to disable all trace instrumentations. | all available instrumentations | -| `OTEL_DOTNET_AUTO_TRACES_DISABLED_INSTRUMENTATIONS` | Comma-separated list of traces source and bytecode instrumentations you want to disable. | | -| `OTEL_DOTNET_AUTO_METRICS_ENABLED_INSTRUMENTATIONS` | Comma-separated list of metrics source instrumentations you want to enable. Set to `none` to disable all metric instrumentations. | all available instrumentations | -| `OTEL_DOTNET_AUTO_METRICS_DISABLED_INSTRUMENTATIONS` | Comma-separated list of metrics source instrumentations you want to disable. | | -| `OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS` | Comma-separated list of logs source instrumentations you want to enable. Set to `none` to disable all metric instrumentations. | all available instrumentations | -| `OTEL_DOTNET_AUTO_LOGS_DISABLED_INSTRUMENTATIONS` | Comma-separated list of logs source instrumentations you want to disable. | | +All instrumentations are enabled by default for all signal types +(traces, metrics, and logs). + +You can disable all instrumentations for a specific signal type by setting +the `OTEL_DOTNET_AUTO_{SIGNAL}_INSTRUMENTATION_ENABLED` +environment variable to `false`. + +For a more granular approach, you can disable specific instrumentations +for a given signal type by setting +the `OTEL_DOTNET_AUTO_{SIGNAL}_{0}_INSTRUMENTATION_ENABLED` +environment variable to `false`, where `{SIGNAL}` is the type of signal, +for example `TRACES`, and `{0}` is the case-sensitive name of the instrumentation. + +| Environment variable | Description | Default value | +|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| +| `OTEL_DOTNET_AUTO_INTEGRATIONS_FILE` | List of bytecode instrumentations JSON configuration filepaths, delimited by the platform-specific path separator (`;` on Windows, `:` on Linux and macOS). For example: `%ProfilerDirectory%/integrations.json`. It is required for bytecode instrumentations. | | +| `OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED` | Disables all instrumentations. | `true` | +| `OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED` | Disables all trace instrumentations. Overrides `OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED`. | Inherited from the current value of `OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED` | +| `OTEL_DOTNET_AUTO_TRACES_{0}_INSTRUMENTATION_ENABLED` | Configuration pattern for enabling or disabling a specific trace instrumentation, where `{0}` is the case-sensitive name of the instrumentation you want to enable. Overrides `OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED`. | Inherited from the current value of `OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED` | +| `OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED` | Disables all metric instrumentations. Overrides `OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED`. | Inherited from the current value of `OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED` | +| `OTEL_DOTNET_AUTO_METRICS_{0}_INSTRUMENTATION_ENABLED` | Configuration pattern for enabling or disabling a specific metric instrumentation, where `{0}` is the case-sensitive name of the instrumentation you want to enable. Overrides `OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED`. | Inherited from the current value of `OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED` | +| `OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED` | Disables all log instrumentations. Overrides `OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED`. | Inherited from the current value of `OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED` | +| `OTEL_DOTNET_AUTO_LOGS_{0}_INSTRUMENTATION_ENABLED` | Configuration pattern for enabling or disabling a specific log instrumentation, where `{0}` is the case-sensitive name of the instrumentation you want to enable. Overrides `OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED`. | Inherited from the current value of `OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED` | ### Traces instrumentations diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/OpenTelemetry.AutoInstrumentation.Native.vcxproj b/src/OpenTelemetry.AutoInstrumentation.Native/OpenTelemetry.AutoInstrumentation.Native.vcxproj index 874bea799a..a3c025d710 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/OpenTelemetry.AutoInstrumentation.Native.vcxproj +++ b/src/OpenTelemetry.AutoInstrumentation.Native/OpenTelemetry.AutoInstrumentation.Native.vcxproj @@ -180,6 +180,7 @@ + @@ -199,6 +200,7 @@ + diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/bytecode_instrumentations.h b/src/OpenTelemetry.AutoInstrumentation.Native/bytecode_instrumentations.h new file mode 100644 index 0000000000..ff5763d167 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation.Native/bytecode_instrumentations.h @@ -0,0 +1,13 @@ +// Auto-generated file, do not change it - generated by the IntegrationsJsonGenerator +#ifndef BYTECODE_INSTRUMENTATIONS_H +#define BYTECODE_INSTRUMENTATIONS_H + +#include "string.h" + +namespace trace +{ +inline std::unordered_map trace_integration_names = {{WStr("StrongNamedValidation"), WStr("OTEL_DOTNET_AUTO_TRACES_StrongNamedValidation_INSTRUMENTATION_ENABLED")}, {WStr("StackExchangeRedis"), WStr("OTEL_DOTNET_AUTO_TRACES_StackExchangeRedis_INSTRUMENTATION_ENABLED")}, {WStr("NServiceBus"), WStr("OTEL_DOTNET_AUTO_TRACES_NServiceBus_INSTRUMENTATION_ENABLED")}, {WStr("MySqlData"), WStr("OTEL_DOTNET_AUTO_TRACES_MySqlData_INSTRUMENTATION_ENABLED")}, {WStr("MongoDB"), WStr("OTEL_DOTNET_AUTO_TRACES_MongoDB_INSTRUMENTATION_ENABLED")}, {WStr("GraphQL"), WStr("OTEL_DOTNET_AUTO_TRACES_GraphQL_INSTRUMENTATION_ENABLED")}}; +inline std::unordered_map metric_integration_names = {{WStr("NServiceBus"), WStr("OTEL_DOTNET_AUTO_METRICS_NServiceBus_INSTRUMENTATION_ENABLED")}}; +inline std::unordered_map log_integration_names = {{WStr("ILogger"), WStr("OTEL_DOTNET_AUTO_LOGS_ILogger_INSTRUMENTATION_ENABLED")}}; +} +#endif diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/cor_profiler.cpp b/src/OpenTelemetry.AutoInstrumentation.Native/cor_profiler.cpp index 7e6b8b596c..58814e46c4 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/cor_profiler.cpp +++ b/src/OpenTelemetry.AutoInstrumentation.Native/cor_profiler.cpp @@ -4,6 +4,7 @@ #include #include +#include "bytecode_instrumentations.h" #include "clr_helpers.h" #include "dllmain.h" #include "environment_variables.h" @@ -163,19 +164,16 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown* cor_profiler_info_un rejit_handler = new RejitHandler(this->info_, callback); - + const bool instrumentation_enabled_by_default = AreInstrumentationsEnabledByDefault(); // load all integrations from JSON files const LoadIntegrationConfiguration configuration( AreTracesEnabled(), - GetEnvironmentValues(environment::enabled_traces_integrations), - GetEnvironmentValues(environment::disabled_traces_integrations), + GetEnabledEnvironmentValues(AreTracesInstrumentationsEnabledByDefault(instrumentation_enabled_by_default), trace_integration_names), AreMetricsEnabled(), - GetEnvironmentValues(environment::enabled_metrics_integrations), - GetEnvironmentValues(environment::disabled_metrics_integrations), + GetEnabledEnvironmentValues(AreMetricsInstrumentationsEnabledByDefault(instrumentation_enabled_by_default), metric_integration_names), AreLogsEnabled(), - GetEnvironmentValues(environment::enabled_logs_integrations), - GetEnvironmentValues(environment::disabled_logs_integrations)); + GetEnabledEnvironmentValues(AreLogsInstrumentationsEnabledByDefault(instrumentation_enabled_by_default), log_integration_names)); LoadIntegrationsFromEnvironment(integration_methods_, configuration); Logger::Debug("Number of Integrations loaded: ", integration_methods_.size()); diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables.h b/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables.h index e2bc51ae17..b5fee2336f 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables.h @@ -24,60 +24,33 @@ const WSTRING profiler_home_path = WStr("OTEL_DOTNET_AUTO_HOME"); // "MyApp.exe,dotnet.exe" const WSTRING exclude_process_names = WStr("OTEL_DOTNET_AUTO_EXCLUDE_PROCESSES"); +// Whether instrumentations are enabled. If not set (default), all instrumentations are enabled. +const WSTRING instrumentation_enabled = + WStr("OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED"); + // Whether traces are enabled or not. If not set (default), traces are enabled. const WSTRING traces_enabled = WStr("OTEL_DOTNET_AUTO_TRACES_ENABLED"); -// Sets a list of integrations to enable. If not set (default), all integrations are enabled. -// Supports multiple values separated with comma, for example: -// "ElasticsearchNet,AspNetWebApi2" -const WSTRING enabled_traces_integrations = - WStr("OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS"); - -// Sets a list of integrations to disable. Status of other integrations will remain -// unchanged. Calculation order: OTEL_DOTNET_AUTO_TRACES_DISABLED_INSTRUMENTATIONS -// then if instrumentation is not explicitly disabled OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS is checked. -// Supports multiple values separated with comma, for example: -// "ElasticsearchNet,AspNetWebApi2" -const WSTRING disabled_traces_integrations = - WStr("OTEL_DOTNET_AUTO_TRACES_DISABLED_INSTRUMENTATIONS"); +// Whether traces instrumentations are enabled. If not set (default), value from OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED is used. +const WSTRING traces_instrumentation_enabled = + WStr("OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED"); // Whether metrics are enabled or not. If not set (default), traces are enabled. const WSTRING metrics_enabled = WStr("OTEL_DOTNET_AUTO_METRICS_ENABLED"); -// Sets a list of integrations to enable. If not set (default), all integrations are enabled. -// Supports multiple values separated with comma, for example: -// "ElasticsearchNet,AspNetWebApi2" -const WSTRING enabled_metrics_integrations = - WStr("OTEL_DOTNET_AUTO_METRICS_ENABLED_INSTRUMENTATIONS"); - -// Sets a list of integrations to disable. Status of other integrations will remain -// unchanged. Calculation order: OTEL_DOTNET_AUTO_METRICS_DISABLED_INSTRUMENTATIONS -// then if instrumentation is not explicitly disabled OTEL_DOTNET_AUTO_METRICS_ENABLED_INSTRUMENTATIONS is checked. -// Supports multiple values separated with comma, for example: -// "ElasticsearchNet,AspNetWebApi2" -const WSTRING disabled_metrics_integrations = - WStr("OTEL_DOTNET_AUTO_METRICS_DISABLED_INSTRUMENTATIONS"); +// Whether metrics instrumentations are enabled. If not set (default), value from OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED is used. +const WSTRING metrics_instrumentation_enabled = + WStr("OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED"); // Whether logs are enabled or not. If not set (default), logs are enabled. const WSTRING logs_enabled = WStr("OTEL_DOTNET_AUTO_LOGS_ENABLED"); -// Sets a list of integrations to enable. If not set (default), all integrations -// are enabled. Supports multiple values separated with comma, for example: -// "ElasticsearchNet,AspNetWebApi2" -const WSTRING enabled_logs_integrations = - WStr("OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS"); - -// Sets a list of integrations to disable. Status of other integrations will -// remain unchanged. Calculation order: -// OTEL_DOTNET_AUTO_LOGS_DISABLED_INSTRUMENTATIONS then if instrumentation is -// not explicitly disabled OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS is -// checked. Supports multiple values separated with comma, for example: -// "ElasticsearchNet,AspNetWebApi2" -const WSTRING disabled_logs_integrations = - WStr("OTEL_DOTNET_AUTO_LOGS_DISABLED_INSTRUMENTATIONS"); +// Whether logs instrumentations are enabled. If not set (default), value from OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED is used. +const WSTRING logs_instrumentation_enabled = + WStr("OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED"); // Sets the directory for the profiler's log file. // If not set, default is diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables_util.h b/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables_util.h index 1c12ac93cc..5549b036cc 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables_util.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables_util.h @@ -78,6 +78,22 @@ bool IsNetFxAssemblyRedirectionEnabled() { ToBooleanWithDefault(GetEnvironmentValue(environment::netfx_assembly_redirection_enabled), true); } +bool AreInstrumentationsEnabledByDefault() { + ToBooleanWithDefault(GetEnvironmentValue(environment::instrumentation_enabled), true); +} + +bool AreTracesInstrumentationsEnabledByDefault(const bool enabled_if_not_configured) { + ToBooleanWithDefault(GetEnvironmentValue(environment::traces_instrumentation_enabled), enabled_if_not_configured); +} + +bool AreMetricsInstrumentationsEnabledByDefault(const bool enabled_if_not_configured) { + ToBooleanWithDefault(GetEnvironmentValue(environment::metrics_instrumentation_enabled), enabled_if_not_configured); +} + +bool AreLogsInstrumentationsEnabledByDefault(const bool enabled_if_not_configured) { + ToBooleanWithDefault(GetEnvironmentValue(environment::logs_instrumentation_enabled), enabled_if_not_configured); +} + } // namespace trace -#endif // OTEL_CLR_PROFILER_ENVIRONMENT_VARIABLES_UTIL_H_ \ No newline at end of file +#endif // OTEL_CLR_PROFILER_ENVIRONMENT_VARIABLES_UTIL_H_ diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.cpp b/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.cpp index 3a5c857863..a7c4a1cdf7 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.cpp +++ b/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.cpp @@ -119,23 +119,8 @@ namespace { bool InstrumentationEnabled( const WSTRING name, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames) + const std::vector& enabledIntegrationNames) { - // check if the integration is disabled - for (const WSTRING& disabledName : disabledIntegrationNames) - { - if (name == disabledName) - { - return false; - } - } - - if (enabledIntegrationNames.empty()) - { - return true; - } - // check if the integration is enabled for (const WSTRING& enabledName : enabledIntegrationNames) { @@ -178,7 +163,7 @@ namespace return; } - if (!InstrumentationEnabled(name, configuration.enabledTraceIntegrationNames, configuration.disabledTraceIntegrationNames)) + if (!InstrumentationEnabled(name, configuration.enabledTraceIntegrationNames)) { return; } @@ -189,7 +174,7 @@ namespace { return; } - if (!InstrumentationEnabled(name, configuration.enabledMetricIntegrationNames, configuration.disabledMetricIntegrationNames)) + if (!InstrumentationEnabled(name, configuration.enabledMetricIntegrationNames)) { return; } @@ -200,7 +185,7 @@ namespace { return; } - if (!InstrumentationEnabled(name, configuration.enabledLogIntegrationNames, configuration.disabledLogIntegrationNames)) + if (!InstrumentationEnabled(name, configuration.enabledLogIntegrationNames)) { return; } diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.h b/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.h index fb67736635..22f8721851 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.h @@ -20,33 +20,24 @@ class LoadIntegrationConfiguration { public: LoadIntegrationConfiguration(bool traces_enabled, std::vector enabled_trace_integration_names, - std::vector disabled_trace_integration_names, bool metrics_enabled, std::vector enabled_metric_integration_names, - std::vector disabled_metric_integration_names, bool logs_enabled, - std::vector enabled_log_integration_names, - std::vector disabled_log_integration_names) + std::vector enabled_log_integration_names) : traces_enabled(traces_enabled), enabledTraceIntegrationNames(std::move(enabled_trace_integration_names)), - disabledTraceIntegrationNames(std::move(disabled_trace_integration_names)), metrics_enabled(metrics_enabled), enabledMetricIntegrationNames(std::move(enabled_metric_integration_names)), - disabledMetricIntegrationNames(std::move(disabled_metric_integration_names)), logs_enabled(logs_enabled), - enabledLogIntegrationNames(std::move(enabled_log_integration_names)), - disabledLogIntegrationNames(std::move(disabled_log_integration_names)) { + enabledLogIntegrationNames(std::move(enabled_log_integration_names)) { } const bool traces_enabled; const std::vector enabledTraceIntegrationNames; - const std::vector disabledTraceIntegrationNames; const bool metrics_enabled; const std::vector enabledMetricIntegrationNames; - const std::vector disabledMetricIntegrationNames; const bool logs_enabled; const std::vector enabledLogIntegrationNames; - const std::vector disabledLogIntegrationNames; }; // LoadIntegrationsFromEnvironment loads integrations from any files specified diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/util.cpp b/src/OpenTelemetry.AutoInstrumentation.Native/util.cpp index cde66bb293..4c6d164b48 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/util.cpp +++ b/src/OpenTelemetry.AutoInstrumentation.Native/util.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -102,6 +103,30 @@ std::vector GetEnvironmentValues(const WSTRING& name) return GetEnvironmentValues(name, L','); } +std::vector GetEnabledEnvironmentValues(const bool enabled_by_default, const std::unordered_map& values_map) +{ + std::vector values; + + for (const auto& value : values_map) + { + bool enabled = enabled_by_default; + const auto env_value = GetEnvironmentValue(value.second); + if (env_value == WStr("true")) + { + enabled = true; + } + else if (env_value == WStr("false")) + { + enabled = false; + } + if (enabled) + { + values.push_back(value.first); + } + } + + return values; +} std::vector GetEnvironmentVariables(const std::vector &prefixes) { diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/util.h b/src/OpenTelemetry.AutoInstrumentation.Native/util.h index 193702ac5e..2dbca03e9c 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/util.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/util.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "string.h" @@ -35,6 +36,9 @@ std::vector GetEnvironmentValues(const WSTRING& name); // GetEnvironmentVariables returns list of all environment variable std::vector GetEnvironmentVariables(const std::vector &prefixes); +// GetEnabledEnvironmentValues returns collection of enabled elements from values_map +std::vector GetEnabledEnvironmentValues(const bool enabled_by_default, const std::unordered_map &values_map); + // Convert Hex to string WSTRING HexStr(const void* data, int len); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationExtensions.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationExtensions.cs index 2c662f9c2d..8fd68e70b7 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationExtensions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationExtensions.cs @@ -14,59 +14,28 @@ // limitations under the License. // +using System.Globalization; + namespace OpenTelemetry.AutoInstrumentation.Configurations; internal static class ConfigurationExtensions { - public static IList ParseEnabledEnumList(this Configuration source, string enabledConfiguration, string disabledConfiguration, string error) + public static IList ParseEnabledEnumList(this Configuration source, bool enabledByDefault, string enabledConfigurationTemplate) where TEnum : struct, Enum, IConvertible { - var instrumentations = new Dictionary(); - var enabledInstrumentations = source.GetString(enabledConfiguration); - if (enabledInstrumentations != null) - { - if (enabledInstrumentations == Constants.ConfigurationValues.None) - { - return Array.Empty(); - } + var allConfigurations = Enum.GetValues(typeof(TEnum)).Cast().ToArray(); + var enabledConfigurations = new List(allConfigurations.Length); - foreach (var instrumentation in enabledInstrumentations.Split(Constants.ConfigurationValues.Separator)) - { - if (Enum.TryParse(instrumentation, out TEnum parsedType)) - { - instrumentations[instrumentation] = parsedType; - } - else - { - throw new FormatException(string.Format(error, instrumentation)); - } - } - } - else + foreach (var configuration in allConfigurations) { - instrumentations = Enum.GetValues(typeof(TEnum)) - .Cast() - .ToDictionary( - key => Enum.GetName(typeof(TEnum), key)!, - val => val); - } + var configurationEnabled = source.GetBool(string.Format(CultureInfo.InvariantCulture, enabledConfigurationTemplate, configuration)) ?? enabledByDefault; - var disabledInstrumentations = source.GetString(disabledConfiguration); - if (disabledInstrumentations != null) - { - foreach (var instrumentation in disabledInstrumentations.Split(Constants.ConfigurationValues.Separator)) + if (configurationEnabled) { - if (Enum.TryParse(instrumentation, out TEnum _)) - { - instrumentations.Remove(instrumentation); - } - else - { - throw new FormatException(string.Format(error, instrumentation)); - } + enabledConfigurations.Add(configuration); } } - return instrumentations.Values.ToList(); + return enabledConfigurations; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs index 2c41956add..f42066e470 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs @@ -55,6 +55,11 @@ internal static class ConfigurationKeys /// public const string SetupSdk = "OTEL_DOTNET_AUTO_SETUP_SDK"; + /// + /// Configuration key for enabling all instrumentations. + /// + public const string InstrumentationEnabled = "OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED"; + /// /// Configuration keys for traces. /// @@ -82,14 +87,14 @@ public static class Traces public const string ConsoleExporterEnabled = "OTEL_DOTNET_AUTO_TRACES_CONSOLE_EXPORTER_ENABLED"; /// - /// Configuration key for comma separated list of enabled trace instrumentations. + /// Configuration key for disabling all trace instrumentations. /// - public const string Instrumentations = "OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS"; + public const string TracesInstrumentationEnabled = "OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED"; /// - /// Configuration key for comma separated list of disabled trace instrumentations. + /// Configuration key template for disabled trace instrumentations. /// - public const string DisabledInstrumentations = "OTEL_DOTNET_AUTO_TRACES_DISABLED_INSTRUMENTATIONS"; + public const string EnabledTracesInstrumentationTemplate = "OTEL_DOTNET_AUTO_TRACES_{0}_INSTRUMENTATION_ENABLED"; /// /// Configuration key for additional names to be added to the tracer at the startup. @@ -146,14 +151,14 @@ public static class Metrics public const string ConsoleExporterEnabled = "OTEL_DOTNET_AUTO_METRICS_CONSOLE_EXPORTER_ENABLED"; /// - /// Configuration key for comma separated list of enabled metric instrumentations. + /// Configuration key for disabling all metrics instrumentations. /// - public const string Instrumentations = "OTEL_DOTNET_AUTO_METRICS_ENABLED_INSTRUMENTATIONS"; + public const string MetricsInstrumentationEnabled = "OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED"; /// - /// Configuration key for comma separated list of disabled metric instrumentations. + /// Configuration key template for enabled metric instrumentations. /// - public const string DisabledInstrumentations = "OTEL_DOTNET_AUTO_METRICS_DISABLED_INSTRUMENTATIONS"; + public const string EnabledMetricsInstrumentationTemplate = "OTEL_DOTNET_AUTO_METRICS_{0}_INSTRUMENTATION_ENABLED"; /// /// Configuration key for additional names to be added to the meter at the startup. @@ -189,14 +194,14 @@ public static class Logs public const string IncludeFormattedMessage = "OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE"; /// - /// Configuration key for comma separated list of enabled logs instrumentations. + /// Configuration key for disabling all log instrumentations. /// - public const string Instrumentations = "OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS"; + public const string LogsInstrumentationEnabled = "OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED"; /// - /// Configuration key for comma separated list of disabled logs instrumentations. + /// Configuration key template for enabled log instrumentations. /// - public const string DisabledInstrumentations = "OTEL_DOTNET_AUTO_LOGS_DISABLED_INSTRUMENTATIONS"; + public const string EnabledLogsInstrumentationTemplate = "OTEL_DOTNET_AUTO_LOGS_{0}_INSTRUMENTATION_ENABLED"; } /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs index 2267277130..121cd7035e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs @@ -53,10 +53,13 @@ protected override void OnLoad(Configuration configuration) ConsoleExporterEnabled = configuration.GetBool(ConfigurationKeys.Logs.ConsoleExporterEnabled) ?? false; IncludeFormattedMessage = configuration.GetBool(ConfigurationKeys.Logs.IncludeFormattedMessage) ?? false; + var instrumentationEnabledByDefault = + configuration.GetBool(ConfigurationKeys.Logs.LogsInstrumentationEnabled) ?? + configuration.GetBool(ConfigurationKeys.InstrumentationEnabled) ?? true; + EnabledInstrumentations = configuration.ParseEnabledEnumList( - enabledConfiguration: ConfigurationKeys.Logs.Instrumentations, - disabledConfiguration: ConfigurationKeys.Logs.DisabledInstrumentations, - error: "The \"{0}\" is not recognized as supported logs instrumentation and cannot be enabled or disabled."); + enabledByDefault: instrumentationEnabledByDefault, + enabledConfigurationTemplate: ConfigurationKeys.Logs.EnabledLogsInstrumentationTemplate); } private static LogExporter ParseLogExporter(Configuration configuration) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs index de30770c28..64be6ace47 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs @@ -51,10 +51,13 @@ protected override void OnLoad(Configuration configuration) MetricExporter = ParseMetricExporter(configuration); ConsoleExporterEnabled = configuration.GetBool(ConfigurationKeys.Metrics.ConsoleExporterEnabled) ?? false; + var instrumentationEnabledByDefault = + configuration.GetBool(ConfigurationKeys.Metrics.MetricsInstrumentationEnabled) ?? + configuration.GetBool(ConfigurationKeys.InstrumentationEnabled) ?? true; + EnabledInstrumentations = configuration.ParseEnabledEnumList( - enabledConfiguration: ConfigurationKeys.Metrics.Instrumentations, - disabledConfiguration: ConfigurationKeys.Metrics.DisabledInstrumentations, - error: "The \"{0}\" is not recognized as supported metrics instrumentation and cannot be enabled or disabled."); + enabledByDefault: instrumentationEnabledByDefault, + enabledConfigurationTemplate: ConfigurationKeys.Metrics.EnabledMetricsInstrumentationTemplate); var additionalSources = configuration.GetString(ConfigurationKeys.Metrics.AdditionalSources); if (additionalSources != null) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index e722f1135b..99b2f3ba86 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -76,10 +76,13 @@ protected override void OnLoad(Configuration configuration) TracesExporter = ParseTracesExporter(configuration); ConsoleExporterEnabled = configuration.GetBool(ConfigurationKeys.Traces.ConsoleExporterEnabled) ?? false; + var instrumentationEnabledByDefault = + configuration.GetBool(ConfigurationKeys.Traces.TracesInstrumentationEnabled) ?? + configuration.GetBool(ConfigurationKeys.InstrumentationEnabled) ?? true; + EnabledInstrumentations = configuration.ParseEnabledEnumList( - enabledConfiguration: ConfigurationKeys.Traces.Instrumentations, - disabledConfiguration: ConfigurationKeys.Traces.DisabledInstrumentations, - error: "The \"{0}\" is not recognized as supported trace instrumentation and cannot be enabled or disabled."); + enabledByDefault: instrumentationEnabledByDefault, + enabledConfigurationTemplate: ConfigurationKeys.Traces.EnabledTracesInstrumentationTemplate); var additionalSources = configuration.GetString(ConfigurationKeys.Traces.AdditionalSources); if (additionalSources != null) diff --git a/test/IntegrationTests/AspNetTests.cs b/test/IntegrationTests/AspNetTests.cs index 7bcadde9cb..b1fcbf3d04 100644 --- a/test/IntegrationTests/AspNetTests.cs +++ b/test/IntegrationTests/AspNetTests.cs @@ -108,7 +108,8 @@ public async Task SubmitMetrics() _environmentVariables["OTEL_METRICS_EXPORTER"] = "otlp"; _environmentVariables["OTEL_EXPORTER_OTLP_ENDPOINT"] = collectorUrl; _environmentVariables["OTEL_METRIC_EXPORT_INTERVAL"] = "1000"; - _environmentVariables["OTEL_DOTNET_AUTO_METRICS_ENABLED_INSTRUMENTATIONS"] = "AspNet"; // Helps to reduce noise by enabling only AspNet metrics. + _environmentVariables["OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED"] = "false"; // Helps to reduce noise by enabling only AspNet metrics. + _environmentVariables["OTEL_DOTNET_AUTO_METRICS_AspNet_INSTRUMENTATION_ENABLED"] = "true"; // Helps to reduce noise by enabling only AspNet metrics. var webPort = TcpPortProvider.GetOpenPort(); await using var container = await StartContainerAsync(webPort); await CallTestApplicationEndpoint(webPort); diff --git a/test/IntegrationTests/GraphQLTests.cs b/test/IntegrationTests/GraphQLTests.cs index 6ac59207ac..ae726759bb 100644 --- a/test/IntegrationTests/GraphQLTests.cs +++ b/test/IntegrationTests/GraphQLTests.cs @@ -60,7 +60,8 @@ public async Task SubmitsTraces(bool setDocument) Expect(collector, spanName: "subscription NotImplementedSub", graphQLOperationType: "subscription", graphQLOperationName: "NotImplementedSub", graphQLDocument: "subscription NotImplementedSub{throwNotImplementedException{name}}", setDocument: setDocument, verifyFailure: VerifyNotImplementedException); SetEnvironmentVariable("OTEL_DOTNET_AUTO_GRAPHQL_SET_DOCUMENT", setDocument.ToString()); - SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS", "GraphQL"); + SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED", "false"); + SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_GraphQL_INSTRUMENTATION_ENABLED", "true"); SetEnvironmentVariable("OTEL_TRACES_SAMPLER", "always_on"); SetEnvironmentVariable("OTEL_DOTNET_AUTO_NETFX_REDIRECT_ENABLED", "false"); diff --git a/test/IntegrationTests/GrpcNetClientTests.cs b/test/IntegrationTests/GrpcNetClientTests.cs index 4e675c9f70..64e7724115 100644 --- a/test/IntegrationTests/GrpcNetClientTests.cs +++ b/test/IntegrationTests/GrpcNetClientTests.cs @@ -37,7 +37,8 @@ public void SubmitsTraces() // Grpc.Net.Client is using various version of http communication under the hood. // Enabling only GrpcNetClient instrumentation to have consistent set of spans. - SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS", "GrpcNetClient"); + SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED", "false"); + SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_GrpcNetClient_INSTRUMENTATION_ENABLED", "true"); RunTestApplication(); collector.AssertExpectations(); diff --git a/test/IntegrationTests/ModuleTests.cs b/test/IntegrationTests/ModuleTests.cs index 0437b37a83..2341a4b23b 100644 --- a/test/IntegrationTests/ModuleTests.cs +++ b/test/IntegrationTests/ModuleTests.cs @@ -14,14 +14,10 @@ // limitations under the License. // -using System.IO; -using System.Threading.Tasks; using IntegrationTests.Helpers; using Newtonsoft.Json; using OpenTelemetry.AutoInstrumentation; using OpenTelemetry.AutoInstrumentation.Configurations; -using VerifyXunit; -using Xunit; using Xunit.Abstractions; namespace IntegrationTests; @@ -73,8 +69,7 @@ public async Task DefaultNoExporters() [Fact] public async Task Minimal() { - SetEnvironmentVariable(ConfigurationKeys.Traces.Instrumentations, Constants.ConfigurationValues.None); - SetEnvironmentVariable(ConfigurationKeys.Metrics.Instrumentations, Constants.ConfigurationValues.None); + SetEnvironmentVariable(ConfigurationKeys.InstrumentationEnabled, "false"); SetEnvironmentVariable(ConfigurationKeys.Traces.Exporter, Constants.ConfigurationValues.None); SetEnvironmentVariable(ConfigurationKeys.Metrics.Exporter, Constants.ConfigurationValues.None); SetEnvironmentVariable(ConfigurationKeys.Logs.Exporter, Constants.ConfigurationValues.None); diff --git a/test/IntegrationTests/SmokeTests.cs b/test/IntegrationTests/SmokeTests.cs index 4782b947af..ee5898a710 100644 --- a/test/IntegrationTests/SmokeTests.cs +++ b/test/IntegrationTests/SmokeTests.cs @@ -35,7 +35,6 @@ public SmokeTests(ITestOutputHelper output) : base("Smoke", output) { SetEnvironmentVariable("OTEL_SERVICE_NAME", ServiceName); - SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS", "HttpClient"); } [Fact] @@ -53,7 +52,7 @@ public void WhenStartupHookIsNotEnabled() #if NETFRAMEWORK VerifyTestApplicationInstrumented(); #else - // on .NET Core it is required to set DOTNET_STARTUP_HOOKS + // on .NET it is required to set DOTNET_STARTUP_HOOKS VerifyTestApplicationNotInstrumented(); #endif } @@ -119,6 +118,7 @@ public void TracesResource() collector.ResourceExpector.Expect("telemetry.sdk.version", typeof(OpenTelemetry.Resources.Resource).Assembly.GetCustomAttribute()!.Version); collector.ResourceExpector.Expect("telemetry.auto.version", OpenTelemetry.AutoInstrumentation.Constants.Tracer.Version); + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES", "MyCompany.MyProduct.MyLibrary"); RunTestApplication(); @@ -137,6 +137,7 @@ public void MetricsResource() collector.ResourceExpector.Expect("telemetry.sdk.version", typeof(OpenTelemetry.Resources.Resource).Assembly.GetCustomAttribute()!.Version); collector.ResourceExpector.Expect("telemetry.auto.version", OpenTelemetry.AutoInstrumentation.Constants.Tracer.Version); + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable("OTEL_DOTNET_AUTO_METRICS_ADDITIONAL_SOURCES", "MyCompany.MyProduct.MyLibrary"); RunTestApplication(); @@ -156,6 +157,7 @@ public void LogsResource() collector.ResourceExpector.Expect("telemetry.sdk.version", typeof(OpenTelemetry.Resources.Resource).Assembly.GetCustomAttribute()!.Version); collector.ResourceExpector.Expect("telemetry.auto.version", OpenTelemetry.AutoInstrumentation.Constants.Tracer.Version); + EnableOnlyHttpClientTraceInstrumentation(); EnableBytecodeInstrumentation(); RunTestApplication(); @@ -171,6 +173,7 @@ public void OtlpTracesExporter() SetExporter(collector); collector.Expect("MyCompany.MyProduct.MyLibrary", span => span.Name == "SayHello"); + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES", "MyCompany.MyProduct.MyLibrary"); RunTestApplication(); @@ -184,6 +187,7 @@ public void ZipkinExporter() using var collector = new MockZipkinCollector(Output); collector.Expect(span => span.Name == "SayHello" && span.Tags?.GetValueOrDefault("otel.library.name") == "MyCompany.MyProduct.MyLibrary"); + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable("OTEL_TRACES_EXPORTER", "zipkin"); SetEnvironmentVariable("OTEL_EXPORTER_ZIPKIN_ENDPOINT", $"http://localhost:{collector.Port}/api/v2/spans"); SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES", "MyCompany.MyProduct.MyLibrary"); @@ -197,6 +201,7 @@ public void ZipkinExporter() [Trait("Category", "EndToEnd")] public void PrometheusExporter() { + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable("LONG_RUNNING", "true"); SetEnvironmentVariable("OTEL_METRICS_EXPORTER", "prometheus"); SetEnvironmentVariable("OTEL_DOTNET_AUTO_METRICS_ADDITIONAL_SOURCES", "MyCompany.MyProduct.MyLibrary"); @@ -249,6 +254,7 @@ public void SubmitLogs() SetExporter(collector); collector.Expect(logRecord => Convert.ToString(logRecord.Body) == "{ \"stringValue\": \"Example log message\" }"); + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable("OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE", "true"); EnableBytecodeInstrumentation(); RunTestApplication(); @@ -257,7 +263,8 @@ public void SubmitLogs() } [Theory] - [InlineData("OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS", "none")] + [InlineData("OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED", "false")] + [InlineData("OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED", "false")] [InlineData("OTEL_DOTNET_AUTO_LOGS_ENABLED", "false")] [InlineData("OTEL_LOGS_EXPORTER", "none")] [Trait("Category", "EndToEnd")] @@ -266,6 +273,7 @@ public void LogsNoneInstrumentations(string envVarName, string envVarVal) using var collector = new MockLogsCollector(Output); SetExporter(collector); + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable(envVarName, envVarVal); EnableBytecodeInstrumentation(); RunTestApplication(); @@ -276,8 +284,8 @@ public void LogsNoneInstrumentations(string envVarName, string envVarVal) #endif [Theory] - [InlineData("OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS", "none")] - [InlineData("OTEL_DOTNET_AUTO_TRACES_ENABLED", "false")] + [InlineData("OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED", "false")] + [InlineData("OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED", "false")] [InlineData("OTEL_TRACES_EXPORTER", "none")] [Trait("Category", "EndToEnd")] public void TracesNoneInstrumentations(string envVarName, string envVarVal) @@ -290,7 +298,8 @@ public void TracesNoneInstrumentations(string envVarName, string envVarVal) } [Theory] - [InlineData("OTEL_DOTNET_AUTO_METRICS_ENABLED_INSTRUMENTATIONS", "none")] + [InlineData("OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED", "false")] + [InlineData("OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED", "false")] [InlineData("OTEL_DOTNET_AUTO_METRICS_ENABLED", "false")] [InlineData("OTEL_METRICS_EXPORTER", "none")] [Trait("Category", "EndToEnd")] @@ -298,6 +307,7 @@ public void MetricsNoneInstrumentations(string envVarName, string envVarVal) { using var collector = new MockMetricsCollector(Output); SetExporter(collector); + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable(envVarName, envVarVal); RunTestApplication(); collector.AssertEmpty(); @@ -309,6 +319,7 @@ public void LogsDisabledInstrumentation() { using var collector = new MockLogsCollector(Output); SetEnvironmentVariable("OTEL_DOTNET_AUTO_LOGS_DISABLED_INSTRUMENTATIONS", "ILogger"); + EnableOnlyHttpClientTraceInstrumentation(); EnableBytecodeInstrumentation(); RunTestApplication(); collector.AssertEmpty(); @@ -319,8 +330,8 @@ public void LogsDisabledInstrumentation() public void MetricsDisabledInstrumentation() { using var collector = new MockMetricsCollector(Output); - SetEnvironmentVariable("OTEL_DOTNET_AUTO_METRICS_ENABLED_INSTRUMENTATIONS", "HttpClient"); - SetEnvironmentVariable("OTEL_DOTNET_AUTO_METRICS_DISABLED_INSTRUMENTATIONS", "HttpClient"); + SetEnvironmentVariable("OTEL_DOTNET_AUTO_METRICS_HttpClient_INSTRUMENTATION_ENABLED", "false"); + EnableOnlyHttpClientTraceInstrumentation(); EnableBytecodeInstrumentation(); RunTestApplication(); collector.AssertEmpty(); @@ -332,7 +343,8 @@ public void TracesDisabledInstrumentation() { using var collector = new MockSpansCollector(Output); SetExporter(collector); - SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_DISABLED_INSTRUMENTATIONS", "AspNet,HttpClient"); + SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_AspNet_INSTRUMENTATION_ENABLED", "false"); + SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_HttpClient_INSTRUMENTATION_ENABLED", "false"); RunTestApplication(); collector.AssertEmpty(); } @@ -350,6 +362,7 @@ private void VerifyTestApplicationInstrumented() collector.Expect("OpenTelemetry.Instrumentation.Http.HttpClient"); #endif + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES", "MyCompany.MyProduct.MyLibrary"); RunTestApplication(); @@ -361,9 +374,16 @@ private void VerifyTestApplicationNotInstrumented() using var collector = new MockSpansCollector(Output); SetExporter(collector); + EnableOnlyHttpClientTraceInstrumentation(); SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES", "MyCompany.MyProduct.MyLibrary"); RunTestApplication(); collector.AssertEmpty(); } + + private void EnableOnlyHttpClientTraceInstrumentation() + { + SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED", "false"); + SetEnvironmentVariable("OTEL_DOTNET_AUTO_TRACES_HttpClient_INSTRUMENTATION_ENABLED", "true"); + } } diff --git a/test/OpenTelemetry.AutoInstrumentation.Native.Tests/integration_loader_test.cpp b/test/OpenTelemetry.AutoInstrumentation.Native.Tests/integration_loader_test.cpp index 28ceaacf47..b7d2e70a8b 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Native.Tests/integration_loader_test.cpp +++ b/test/OpenTelemetry.AutoInstrumentation.Native.Tests/integration_loader_test.cpp @@ -16,7 +16,7 @@ using namespace trace; TEST(IntegrationLoaderTest, HandlesMissingFile) { std::vector integrations; - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {}, true, {}, true, {}); LoadIntegrationsFromFile(L"missing-file", integrations, configuration); EXPECT_EQ(0, integrations.size()); } @@ -25,7 +25,7 @@ TEST(IntegrationLoaderTest, HandlesInvalidIntegrationNoName) { std::vector integrations; std::stringstream str("[{}]"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); // 0 because name is required EXPECT_EQ(0, integrations.size()); @@ -35,7 +35,7 @@ TEST(IntegrationLoaderTest, HandlesInvalidIntegrationBadJson) { std::vector integrations; std::stringstream str("["); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); EXPECT_EQ(0, integrations.size()); } @@ -44,7 +44,7 @@ TEST(IntegrationLoaderTest, HandlesInvalidIntegrationNotAnObject) { std::vector integrations; std::stringstream str("[1,2,3]"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); EXPECT_EQ(0, integrations.size()); } @@ -55,7 +55,7 @@ TEST(IntegrationLoaderTest, HandlesInvalidIntegrationNotAnArray) std::stringstream str(R"TEXT( {"name": "test-integration"} )TEXT"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-integration"}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); EXPECT_EQ(0, integrations.size()); } @@ -75,7 +75,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithMethodReplacements) }] )TEXT"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-integration"}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); EXPECT_EQ(1, integrations.size()); EXPECT_STREQ(L"test-integration", integrations[0].integration_name.c_str()); @@ -96,7 +96,7 @@ TEST(IntegrationLoaderTest, DoesNotCrashWithOutOfRangeVersion) }] )TEXT"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-integration"}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); EXPECT_EQ(1, integrations.size()); EXPECT_STREQ(L"test-integration", integrations[0].integration_name.c_str()); @@ -128,7 +128,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithMissingCaller) }] )TEXT"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-integration"}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); EXPECT_EQ(1, integrations.size()); EXPECT_STREQ(L"test-integration", integrations[0].integration_name.c_str()); @@ -167,7 +167,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithInvalidTarget) }] )TEXT"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-integration"}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); EXPECT_EQ(1, integrations.size()); EXPECT_STREQ(L"test-integration", integrations[0].integration_name.c_str()); @@ -201,7 +201,7 @@ TEST(IntegrationLoaderTest, LoadsFromEnvironment) const std::vector expected_names = {L"test-integration-1", L"test-integration-2"}; std::vector actual_names; std::vector integrations; - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-integration-1", L"test-integration-2"}, true, {}, true, {}); LoadIntegrationsFromEnvironment(integrations, configuration); for (auto& integration : integrations) { @@ -228,7 +228,7 @@ TEST(IntegrationLoaderTest, DeserializesSignatureTypeArray) }] )TEXT"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-integration"}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); const auto target = integrations[0].replacement.target_method; EXPECT_STREQ(L"System.Void", target.signature_types[0].c_str()); @@ -247,7 +247,7 @@ TEST(IntegrationLoaderTest, SupportsEnabledTraceIntegrations) { const std::vector expected_names = {L"test-trace-integration-2"}; std::vector actual_names; - const LoadIntegrationConfiguration configuration(true, {L"test-trace-integration-2"}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-trace-integration-2"}, true, {}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); for (auto& integration : integrations) { @@ -268,8 +268,7 @@ TEST(IntegrationLoaderTest, SupportsEnabledMetricIntegrations) { const std::vector expected_names = { L"test-metric-integration-2"}; std::vector actual_names; - const LoadIntegrationConfiguration configuration( - true, {}, {}, true, {L"test-metric-integration-2"}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {}, true, {L"test-metric-integration-2"}, true, {}); LoadIntegrationsFromStream(str, integrations, configuration); for (auto& integration : integrations) { actual_names.push_back(integration.integration_name); @@ -289,7 +288,7 @@ TEST(IntegrationLoaderTest, SupportsEnabledLogIntegrations) const std::vector expected_names = {L"test-log-integration-2"}; std::vector actual_names; - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {L"test-log-integration-2"}, {}); + const LoadIntegrationConfiguration configuration(true, {}, true, {}, true, {L"test-log-integration-2"}); LoadIntegrationsFromStream(str, integrations, configuration); for (auto& integration : integrations) { @@ -298,109 +297,6 @@ TEST(IntegrationLoaderTest, SupportsEnabledLogIntegrations) EXPECT_EQ(expected_names, actual_names); } -TEST(IntegrationLoaderTest, SupportsDisabledTraceIntegrations) -{ - std::vector integrations; - std::stringstream str(R"TEXT( - [ - { "name": "test-trace-integration-1", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-trace-integration-2", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] } - ] - )TEXT"); - - const std::vector expected_names = {L"test-trace-integration-1"}; - std::vector actual_names; - const LoadIntegrationConfiguration configuration( - true, {}, {L"test-trace-integration-2"}, true, {}, {}, true, {}, {}); - LoadIntegrationsFromStream(str, integrations, configuration); - for (auto& integration : integrations) - { - actual_names.push_back(integration.integration_name); - } - EXPECT_EQ(expected_names, actual_names); -} - -TEST(IntegrationLoaderTest, SupportsDisabledMetricIntegrations) -{ - std::vector integrations; - std::stringstream str(R"TEXT( - [ - { "name": "test-metric-integration-1", "type": "Metric", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-metric-integration-2", "type": "Metric", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] } - ] - )TEXT"); - - const std::vector expected_names = {L"test-metric-integration-1"}; - std::vector actual_names; - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {L"test-metric-integration-2"}, true, {}, {}); - LoadIntegrationsFromStream(str, integrations, configuration); - for (auto& integration : integrations) - { - actual_names.push_back(integration.integration_name); - } - EXPECT_EQ(expected_names, actual_names); -} - -TEST(IntegrationLoaderTest, SupportsDisabledLogIntegrations) -{ - std::vector integrations; - std::stringstream str(R"TEXT( - [ - { "name": "test-log-integration-1", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-log-integration-2", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] } - ] - )TEXT"); - - const std::vector expected_names = {L"test-log-integration-1"}; - std::vector actual_names; - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {L"test-log-integration-2"}); - LoadIntegrationsFromStream(str, integrations, configuration); - for (auto& integration : integrations) - { - actual_names.push_back(integration.integration_name); - } - EXPECT_EQ(expected_names, actual_names); -} - -TEST(IntegrationLoaderTest, SupportsEnabledAndDisabledIntegrations) -{ - std::vector integrations; - std::stringstream str(R"TEXT( - [ - { "name": "test-trace-integration-1", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-trace-integration-2", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-trace-integration-3", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-metric-integration-1", "type": "Metric", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-metric-integration-2", "type": "Metric", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-metric-integration-3", "type": "Metric", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-log-integration-1", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-log-integration-2", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] }, - { "name": "test-log-integration-3", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {} }] } - ] - )TEXT"); - - const std::vector expected_names = {L"test-trace-integration-1", L"test-log-integration-1", L"test-metric-integration-1"}; - std::vector actual_names; - const LoadIntegrationConfiguration configuration( - true, - {L"test-trace-integration-1", L"test-trace-integration-2"}, - {L"test-trace-integration-2", L"test-trace-integration-3"}, - true, - {L"test-metric-integration-1", L"test-metric-integration-2"}, - {L"test-metric-integration-2", L"test-metric-integration-3"}, - true, - {L"test-log-integration-1", L"test-log-integration-2"}, - {L"test-log-integration-2", L"test-log-integration-3"}); - - LoadIntegrationsFromStream(str, integrations, configuration); - - for (auto& integration : integrations) - { - actual_names.push_back(integration.integration_name); - } - EXPECT_EQ(expected_names, actual_names); -} - TEST(IntegrationLoaderTest, SupportsDisableAllIntegrations) { std::vector integrations; std::stringstream str(R"TEXT( @@ -413,7 +309,7 @@ TEST(IntegrationLoaderTest, SupportsDisableAllIntegrations) { const std::vector expected_names = {}; std::vector actual_names; - const LoadIntegrationConfiguration configuration(false, {}, {}, false, {}, {}, false, {}, {}); + const LoadIntegrationConfiguration configuration(false, {}, false, {}, false, {}); LoadIntegrationsFromStream(str, integrations, configuration); for (auto& integration : integrations) { @@ -435,7 +331,7 @@ TEST(IntegrationLoaderTest, DuplicatedIntegrations) { ] )TEXT"); - const LoadIntegrationConfiguration configuration(true, {}, {}, true, {}, {}, true, {}, {}); + const LoadIntegrationConfiguration configuration(true, {L"test-integration-1"}, true, {L"test-integration-1"}, true, {L"test-integration-1"}); LoadIntegrationsFromStream(str, integrations, configuration); EXPECT_EQ(4, integrations.size()); diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ConfigurationTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ConfigurationTests.cs index d1afe8fb1d..6a1a5f722c 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ConfigurationTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ConfigurationTests.cs @@ -33,106 +33,66 @@ private enum TestEnum } [Fact] - public void ParseEnabledEnumList_Default() + public void ParseEnabledEnumList_Default_Enabled() { var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection())); var list = source.ParseEnabledEnumList( - enabledConfiguration: "TEST_ENABLED_VALUES", - disabledConfiguration: "TEST_DISABLED_VALUES", - error: "Invalid enum value: {0}"); + enabledByDefault: true, + enabledConfigurationTemplate: "TEST_CONFIGURATION_{0}_ENABLED"); list.Should().Equal(TestEnum.Test1, TestEnum.Test2, TestEnum.Test3); } [Fact] - public void ParseEnabledEnumList_Enabled() + public void ParseEnabledEnumList_Default_Disabled() { - var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection() - { - { "TEST_ENABLED_VALUES", "Test1,Test3" } - })); + var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection())); var list = source.ParseEnabledEnumList( - enabledConfiguration: "TEST_ENABLED_VALUES", - disabledConfiguration: "TEST_DISABLED_VALUES", - error: "Invalid enum value: {0}"); + enabledByDefault: false, + enabledConfigurationTemplate: "TEST_CONFIGURATION_{0}_ENABLED"); - list.Should().Equal(TestEnum.Test1, TestEnum.Test3); + list.Should().BeEmpty(); } [Fact] - public void ParseEnabledEnumList_Disabled() + public void ParseEnabledEnumList_SelectivelyEnabled() { - var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection() + var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection { - { "TEST_DISABLED_VALUES", "Test2" } + { "TEST_CONFIGURATION_Test1_ENABLED", "true" }, + { "TEST_CONFIGURATION_Test3_ENABLED", "true" } })); var list = source.ParseEnabledEnumList( - enabledConfiguration: "TEST_ENABLED_VALUES", - disabledConfiguration: "TEST_DISABLED_VALUES", - error: "Invalid enum value: {0}"); + enabledByDefault: false, + enabledConfigurationTemplate: "TEST_CONFIGURATION_{0}_ENABLED"); list.Should().Equal(TestEnum.Test1, TestEnum.Test3); } [Fact] - public void ParseEnabledEnumList_None() + public void ParseEnabledEnumList_SelectivelyDisabled() { - var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection() + var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection { - { "TEST_ENABLED_VALUES", "none" } + { "TEST_CONFIGURATION_Test2_ENABLED", "false" }, })); var list = source.ParseEnabledEnumList( - enabledConfiguration: "TEST_ENABLED_VALUES", - disabledConfiguration: "TEST_DISABLED_VALUES", - error: "Invalid enum value: {0}"); - - list.Should().BeEmpty(); - } + enabledByDefault: true, + enabledConfigurationTemplate: "TEST_CONFIGURATION_{0}_ENABLED"); - [Fact] - public void ParseEnabledEnumList_Invalid() - { - var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection() - { - { "TEST_ENABLED_VALUES", "invalid" } - })); - - var act = () => source.ParseEnabledEnumList( - enabledConfiguration: "TEST_ENABLED_VALUES", - disabledConfiguration: "TEST_DISABLED_VALUES", - error: "Invalid enum value: {0}"); - - act.Should().Throw() - .WithMessage("Invalid enum value: invalid"); - } - - [Fact] - public void ParseDisabledEnumList_Invalid() - { - var source = new Configuration(new NameValueConfigurationSource(new NameValueCollection() - { - { "TEST_DISABLED_VALUES", "invalid" } - })); - - var act = () => source.ParseEnabledEnumList( - enabledConfiguration: "TEST_ENABLED_VALUES", - disabledConfiguration: "TEST_DISABLED_VALUES", - error: "Invalid enum value: {0}"); - - act.Should().Throw() - .WithMessage("Invalid enum value: invalid"); + list.Should().Equal(TestEnum.Test1, TestEnum.Test3); } [Fact] public void ParseEmptyAsNull_CompositeConfigurationSource() { var mockSource = new Mock(); - mockSource.Setup(x => x.GetString(It.Is(x => x == "TEST_NULL_VALUE"))).Returns(k => null); - mockSource.Setup(x => x.GetString(It.Is(x => x == "TEST_EMPTY_VALUE"))).Returns(k => string.Empty); + mockSource.Setup(x => x.GetString(It.Is(key => key == "TEST_NULL_VALUE"))).Returns(_ => null); + mockSource.Setup(x => x.GetString(It.Is(key => key == "TEST_EMPTY_VALUE"))).Returns(_ => string.Empty); var compositeSource = new Configuration(mockSource.Object); using (new AssertionScope()) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs index d01d817317..aaec6e88a3 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs @@ -32,9 +32,7 @@ public SettingsTests() public static IEnumerable ExporterEnvVarAndLoadSettingsAction() { yield return new object[] { ConfigurationKeys.Traces.Exporter, new Action(() => Settings.FromDefaultSources()) }; - yield return new object[] { ConfigurationKeys.Traces.Instrumentations, new Action(() => Settings.FromDefaultSources()) }; yield return new object[] { ConfigurationKeys.Metrics.Exporter, new Action(() => Settings.FromDefaultSources()) }; - yield return new object[] { ConfigurationKeys.Metrics.Instrumentations, new Action(() => Settings.FromDefaultSources()) }; yield return new object[] { ConfigurationKeys.Logs.Exporter, new Action(() => Settings.FromDefaultSources()) }; yield return new object[] { ConfigurationKeys.Sdk.Propagators, new Action(() => Settings.FromDefaultSources()) }; } @@ -199,24 +197,14 @@ internal void Propagators_SupportedValues(string propagators, Propagator[] expec #endif internal void TracerSettings_Instrumentations_SupportedValues(string tracerInstrumentation, TracerInstrumentation expectedTracerInstrumentation) { - Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.Instrumentations, tracerInstrumentation); + Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesInstrumentationEnabled, "false"); + Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Traces.EnabledTracesInstrumentationTemplate, tracerInstrumentation), "true"); var settings = Settings.FromDefaultSources(); settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { expectedTracerInstrumentation }); } - [Fact] - internal void TracerSettings_DisabledInstrumentations() - { - Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.Instrumentations, $"{nameof(TracerInstrumentation.AspNet)},{nameof(TracerInstrumentation.GraphQL)}"); - Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.DisabledInstrumentations, nameof(TracerInstrumentation.GraphQL)); - - var settings = Settings.FromDefaultSources(); - - settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { TracerInstrumentation.AspNet }); - } - [Fact] internal void TracerSettings_TracerSampler() { @@ -240,45 +228,26 @@ internal void TracerSettings_TracerSampler() [InlineData(nameof(MetricInstrumentation.NServiceBus), MetricInstrumentation.NServiceBus)] internal void MeterSettings_Instrumentations_SupportedValues(string meterInstrumentation, MetricInstrumentation expectedMetricInstrumentation) { - Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Instrumentations, meterInstrumentation); + Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.MetricsInstrumentationEnabled, "false"); + Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Metrics.EnabledMetricsInstrumentationTemplate, meterInstrumentation), "true"); var settings = Settings.FromDefaultSources(); settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { expectedMetricInstrumentation }); } - [Fact] - internal void MeterSettings_DisabledInstrumentations() - { - Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Instrumentations, $"{nameof(MetricInstrumentation.NetRuntime)},{nameof(MetricInstrumentation.AspNet)}"); - Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.DisabledInstrumentations, nameof(MetricInstrumentation.AspNet)); - - var settings = Settings.FromDefaultSources(); - - settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { MetricInstrumentation.NetRuntime }); - } - [Theory] [InlineData(nameof(LogInstrumentation.ILogger), LogInstrumentation.ILogger)] internal void LogSettings_Instrumentations_SupportedValues(string logInstrumentation, LogInstrumentation expectedLogInstrumentation) { - Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Instrumentations, logInstrumentation); + Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.LogsInstrumentationEnabled, "false"); + Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Logs.EnabledLogsInstrumentationTemplate, logInstrumentation), "true"); var settings = Settings.FromDefaultSources(); settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { expectedLogInstrumentation }); } - [Fact] - internal void LogSettings_DisabledInstrumentations() - { - Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.DisabledInstrumentations, nameof(LogInstrumentation.ILogger)); - - var settings = Settings.FromDefaultSources(); - - settings.EnabledInstrumentations.Should().BeEmpty(); - } - [Theory] [InlineData("true", true)] [InlineData("false", false)] @@ -330,16 +299,29 @@ internal void FlushOnUnhandledException_DependsOnCorrespondingEnvVariable(string 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), null); + } + Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.Exporter, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.IncludeFormattedMessage, null); - Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.Instrumentations, null); - Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.DisabledInstrumentations, null); + + Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.MetricsInstrumentationEnabled, null); + foreach (var metricInstrumentation in Enum.GetValues(typeof(MetricInstrumentation)).Cast()) + { + Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Metrics.EnabledMetricsInstrumentationTemplate, metricInstrumentation), null); + } + Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Exporter, null); - Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Instrumentations, null); - Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.DisabledInstrumentations, null); + Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesInstrumentationEnabled, null); + foreach (var tracerInstrumentation in Enum.GetValues(typeof(TracerInstrumentation)).Cast()) + { + Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.Traces.EnabledTracesInstrumentationTemplate, tracerInstrumentation), null); + } + Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.Exporter, null); - Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.Instrumentations, null); - Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.DisabledInstrumentations, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesSampler, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesSamplerArguments, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.InstrumentationOptions.GraphQLSetDocument, null); diff --git a/test/test-applications/integrations/TestApplication.CustomSdk/TestApplication.CustomSdk.csproj b/test/test-applications/integrations/TestApplication.CustomSdk/TestApplication.CustomSdk.csproj index 1708732ed8..69c606222d 100644 --- a/test/test-applications/integrations/TestApplication.CustomSdk/TestApplication.CustomSdk.csproj +++ b/test/test-applications/integrations/TestApplication.CustomSdk/TestApplication.CustomSdk.csproj @@ -9,7 +9,7 @@ - + diff --git a/tools/IntegrationsJsonGenerator/Program.cs b/tools/IntegrationsJsonGenerator/Program.cs index 1d71f228e0..631cbcf230 100644 --- a/tools/IntegrationsJsonGenerator/Program.cs +++ b/tools/IntegrationsJsonGenerator/Program.cs @@ -32,7 +32,7 @@ var assemblyInstrumentMethodAttributes = autoInstrumentationLib.DefinedTypes .Where(type => InheritsFrom(type, instrumentMethodAttributeName)).Select(x => x.FullName); -var integrations = new Dictionary<(string, string), Integration>(); +var integrations = new Dictionary<(string IntegrationType, string IntegrationName), Integration>(); foreach (var typeInfo in autoInstrumentationLib.GetTypes()) { foreach (var attribute in typeInfo.GetCustomAttributes() @@ -40,33 +40,48 @@ { var integration = ConvertToIntegration(typeInfo.FullName!, attribute); - if (!integrations.ContainsKey((integration.IntegartionType, integration.IntegrationName))) + if (!integrations.ContainsKey((integration.IntegrationType, integration.IntegrationName))) { integrations.Add( - (integration.IntegartionType, integration.IntegrationName), + (integration.IntegrationType, integration.IntegrationName), new Integration { Name = integration.IntegrationName, - Type = integration.IntegartionType, + Type = integration.IntegrationType, MethodReplacements = new List { integration.MethodReplacement } }); } else { - var integration2 = integrations[(integration.IntegartionType, integration.IntegrationName)]; + var integration2 = integrations[(integration.IntegrationType, integration.IntegrationName)]; integration2.MethodReplacements.Add(integration.MethodReplacement); } } } -var productionIntegrations = integrations.Where(x => x.Key.Item2 != "StrongNamedValidation").Select(x => x.Value) +var productionIntegrations = integrations.Where(x => x.Key.IntegrationName != "StrongNamedValidation").Select(x => x.Value) .OrderBy(x => x.Name).ToArray(); -var testIntegrations = integrations.Where(x => x.Key.Item2 == "StrongNamedValidation").Select(x => AppendMockIntegrations(x.Value)) +var testIntegrations = integrations.Where(x => x.Key.IntegrationName == "StrongNamedValidation").Select(x => AppendMockIntegrations(x.Value)) .OrderBy(x => x.Name).ToArray(); +Dictionary> byteCodeIntegrationsByType = new(); + +foreach (var (integrationType, integrationName) in integrations.Keys) +{ + if (byteCodeIntegrationsByType.TryGetValue(integrationType, out var integrationNames)) + { + integrationNames.Add(integrationName); + } + else + { + byteCodeIntegrationsByType.Add(integrationType, new List { integrationName }); + } +} + UpdateIntegrationFile(Path.Combine(solutionFolder, "integrations.json"), productionIntegrations); UpdateIntegrationFile(Path.Combine(solutionFolder, "test", "IntegrationTests", "StrongNamedTestsIntegrations.json"), testIntegrations); +UpdateNativeInstrumentationFile(Path.Combine(solutionFolder, "src", "OpenTelemetry.AutoInstrumentation.Native", "bytecode_instrumentations.h"), byteCodeIntegrationsByType); bool InheritsFrom(Type type, string baseType) { @@ -86,7 +101,7 @@ bool InheritsFrom(Type type, string baseType) } } -(string IntegartionType, string IntegrationName, MethodReplacement MethodReplacement) ConvertToIntegration(string wrapperTypeName, Attribute attribute) +(string IntegrationType, string IntegrationName, MethodReplacement MethodReplacement) ConvertToIntegration(string wrapperTypeName, Attribute attribute) { var integrationName = GetPropertyValue("IntegrationName", attribute); var integrationType = GetPropertyValue("Type", attribute).ToString()!; @@ -159,6 +174,32 @@ void UpdateIntegrationFile(string filePath, Integration[] productionIntegrations JsonSerializer.Serialize(fileStream, productionIntegrations1, jsonSerializerOptions); } +void UpdateNativeInstrumentationFile(string filePath, Dictionary> bytecodeIntegrations) +{ + using var fileStream = new FileStream(filePath, FileMode.Truncate); + + using var writer = new StreamWriter(fileStream); + writer.WriteLine($"// Auto-generated file, do not change it - generated by the {nameof(IntegrationsJsonGenerator)}"); + writer.WriteLine("#ifndef BYTECODE_INSTRUMENTATIONS_H"); + writer.WriteLine("#define BYTECODE_INSTRUMENTATIONS_H"); + writer.WriteLine(); + writer.WriteLine("#include \"string.h\""); + writer.WriteLine(); + writer.WriteLine("namespace trace"); + writer.WriteLine("{"); + foreach (var bytecodeIntegration in bytecodeIntegrations) + { + writer.Write("inline std::unordered_map "); + writer.Write(bytecodeIntegration.Key.ToLowerInvariant()); + writer.Write("_integration_names = {"); + writer.Write(string.Join(", ", bytecodeIntegration.Value.Select(name => $"{{WStr(\"{name}\"), WStr(\"OTEL_DOTNET_AUTO_{bytecodeIntegration.Key.ToUpperInvariant()}S_{name}_INSTRUMENTATION_ENABLED\")}}"))); + writer.WriteLine("};"); + } + + writer.WriteLine("}"); + writer.WriteLine("#endif"); +} + static string GetSourceFilePathName([CallerFilePath] string? callerFilePath = null) => callerFilePath ?? string.Empty;