From b4a4120bbd6d76ed6798fa15d4625938ce3b601c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Fri, 21 Oct 2022 22:31:53 +0200 Subject: [PATCH] Enable/disable log instrumentations (#1475) * Introduce instrumentation types * extend generator * support for disabling logs bytecode integrations * update documentation * change LoggingBuilder instrumentation name to ILogger * Support managing log instrumentation in managed code * update changelog * PR feedback - config * add LogsNoneInstrumentations test Co-authored-by: Chris Ventura <45495992+nrcventura@users.noreply.github.com> --- CHANGELOG.md | 2 + docs/config.md | 12 +- integrations.json | 7 +- .../BootstrapperHostingStartup.cs | 10 +- .../cor_profiler.cpp | 7 +- .../environment_variables.h | 19 ++- .../integration_loader.cpp | 73 ++++++--- .../integration_loader.h | 24 ++- .../Configuration/ConfigurationKeys.cs | 10 ++ .../Configuration/LogInstrumentation.cs | 28 ++++ .../Configuration/LogSettings.cs | 11 ++ .../GraphQL/GraphQLExecuteAsyncAttribute.cs | 1 + .../InstrumentMethodAttribute.cs | 5 + .../Instrumentations/InstrumentationType.cs | 24 +++ .../Logger/LoggingBuilderIntegration.cs | 3 +- .../MongoDb/MongoClientIntegration.cs | 3 +- .../StackExchangeRedisIntegration.cs | 12 +- .../StackExchangeRedisIntegrationAsync.cs | 9 +- .../StrongNamedValidation.cs | 3 +- .../Helpers/MockLogsCollector.cs | 9 ++ test/IntegrationTests/SmokeTests.cs | 13 +- .../StrongNamedTestsIntegrations.json | 1 + .../integration_loader_test.cpp | 152 ++++++++++++------ .../Configuration/SettingsTests.cs | 24 +++ .../IntegrationsJsonGenerator/Integration.cs | 3 + tools/IntegrationsJsonGenerator/Program.cs | 6 +- 26 files changed, 367 insertions(+), 104 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configuration/LogInstrumentation.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentationType.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3bcb606..86a4b61ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Support ASP.NET Core OpenTelemetry Log exporter related environment variables: - `OTEL_LOGS_EXPORTER`, - `OTEL_DOTNET_AUTO_LOGS_CONSOLE_EXPORTER_ENABLED`, + - `OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS`, + - `OTEL_DOTNET_AUTO_LOGS_DISABLED_INSTRUMENTATIONS`, - `OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE`. - Support `OTEL_DOTNET_AUTO_GRAPHQL_SET_DOCUMENT` (default value: `false`) environment variable which controls whether `graphql.document` attribute diff --git a/docs/config.md b/docs/config.md index 4107e3c41..5022cd813 100644 --- a/docs/config.md +++ b/docs/config.md @@ -25,10 +25,12 @@ for more details. | 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 `none` to disable all trace instrumentations. | all available 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 `none` to disable all metric instrumentations. | all available instrumentations | +| `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. | | ### Traces instrumentations @@ -61,9 +63,9 @@ for more details. ### Logs instrumentations -| ID | Instrumented library | Supported versions | Instrumentation type | -|----|---------------------------------------------------------------------------------------------------------------------------------|--------------------|------------------------| -| | [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) **Not supported on .NET Framework** | ≥6.0.0 | bytecode or source [1] | +| ID | Instrumented library | Supported versions | Instrumentation type | +|---------|---------------------------------------------------------------------------------------------------------------------------------|--------------------|------------------------| +| ILogger | [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) **Not supported on .NET Framework** | ≥6.0.0 | bytecode or source [1] | **[1]**: For ASP.NET Core applications, the `LoggingBuilder` instrumentation can be enabled without using the .NET CLR Profiler by setting diff --git a/integrations.json b/integrations.json index fcf182eb1..be44f81c5 100644 --- a/integrations.json +++ b/integrations.json @@ -1,6 +1,7 @@ [ { "name": "GraphQL", + "type": "Trace", "method_replacements": [ { "caller": {}, @@ -51,7 +52,8 @@ ] }, { - "name": "LoggingBuilder", + "name": "ILogger", + "type": "Log", "method_replacements": [ { "caller": {}, @@ -80,6 +82,7 @@ }, { "name": "MongoDB", + "type": "Trace", "method_replacements": [ { "caller": {}, @@ -108,6 +111,7 @@ }, { "name": "MySqlData", + "type": "Trace", "method_replacements": [ { "caller": {}, @@ -135,6 +139,7 @@ }, { "name": "StackExchangeRedis", + "type": "Trace", "method_replacements": [ { "caller": {}, diff --git a/src/OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper/BootstrapperHostingStartup.cs b/src/OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper/BootstrapperHostingStartup.cs index 62e10a493..eb9c74235 100644 --- a/src/OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper/BootstrapperHostingStartup.cs +++ b/src/OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper/BootstrapperHostingStartup.cs @@ -28,14 +28,14 @@ namespace OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper; /// internal class BootstrapperHostingStartup : IHostingStartup { - private readonly LogSettings settings; + private readonly LogSettings _settings; /// /// Initializes a new instance of the class. /// public BootstrapperHostingStartup() { - settings = LogSettings.FromDefaultSources(); + _settings = LogSettings.FromDefaultSources(); } /// @@ -44,6 +44,12 @@ internal class BootstrapperHostingStartup : IHostingStartup /// The . public void Configure(IWebHostBuilder builder) { + if (!_settings.EnabledInstrumentations.Contains(LogInstrumentation.ILogger)) + { + BootstrapperEventSource.Log.Trace($"BootstrapperHostingStartup loaded, but {nameof(LogInstrumentation.ILogger)} instrumentation is disabled. Skipping."); + return; + } + try { builder.ConfigureLogging(logging => logging.AddOpenTelemetryLogs()); diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/cor_profiler.cpp b/src/OpenTelemetry.AutoInstrumentation.Native/cor_profiler.cpp index 300a0e1bf..e13d0e7a2 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/cor_profiler.cpp +++ b/src/OpenTelemetry.AutoInstrumentation.Native/cor_profiler.cpp @@ -179,7 +179,12 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown* cor_profiler_info_un rejit_handler = new RejitHandler(this->info_, callback); // load all integrations from JSON files - LoadIntegrationsFromEnvironment(integration_methods_, GetEnvironmentValues(environment::enabled_integrations), GetEnvironmentValues(environment::disabled_integrations)); + LoadIntegrationsFromEnvironment( + integration_methods_, + GetEnvironmentValues(environment::enabled_traces_integrations), + GetEnvironmentValues(environment::disabled_traces_integrations), + GetEnvironmentValues(environment::enabled_logs_integrations), + GetEnvironmentValues(environment::disabled_logs_integrations)); 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 986a45460..6b2cc40bb 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/environment_variables.h @@ -37,7 +37,7 @@ const WSTRING exclude_process_names = WStr("OTEL_DOTNET_AUTO_EXCLUDE_PROCESSES") // 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_integrations = +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 @@ -45,9 +45,24 @@ const WSTRING enabled_integrations = // 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_integrations = +const WSTRING disabled_traces_integrations = WStr("OTEL_DOTNET_AUTO_TRACES_DISABLED_INSTRUMENTATIONS"); +// 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"); + // Sets the directory for the profiler's log file. // If not set, default is // "%ProgramData%"\OpenTelemetry .NET AutoInstrumentation\logs\" on Windows or diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.cpp b/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.cpp index d42045703..6162c4f89 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.cpp +++ b/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.cpp @@ -1,7 +1,6 @@ #include "integration_loader.h" #include -#include #include "environment_variables.h" #include "logger.h" @@ -14,20 +13,25 @@ using json = nlohmann::json; void LoadIntegrationsFromEnvironment( std::vector& integrationMethods, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames) { + const std::vector& enabledTraceIntegrationNames, + const std::vector& disabledTraceIntegrationNames, + const std::vector& enabledLogIntegrationNames, + const std::vector& disabledLogIntegrationNames) { for (const WSTRING& filePath : GetEnvironmentValues(environment::integrations_path, ENV_VAR_PATH_SEPARATOR)) { Logger::Debug("Loading integrations from file: ", filePath); - LoadIntegrationsFromFile(filePath, integrationMethods, enabledIntegrationNames, disabledIntegrationNames); + LoadIntegrationsFromFile( + filePath, integrationMethods, enabledTraceIntegrationNames, disabledTraceIntegrationNames, enabledLogIntegrationNames, disabledLogIntegrationNames); } } void LoadIntegrationsFromFile( const WSTRING& file_path, std::vector& integrationMethods, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames) { + const std::vector& enabledTraceIntegrationNames, + const std::vector& disabledTraceIntegrationNames, + const std::vector& enabledLogIntegrationNames, + const std::vector& disabledLogIntegrationNames) { try { std::ifstream stream(ToString(file_path)); @@ -36,8 +40,10 @@ void LoadIntegrationsFromFile( { LoadIntegrationsFromStream(stream, integrationMethods, - enabledIntegrationNames, - disabledIntegrationNames); + enabledTraceIntegrationNames, + disabledTraceIntegrationNames, + enabledLogIntegrationNames, + disabledLogIntegrationNames); } else { @@ -66,8 +72,10 @@ void LoadIntegrationsFromFile( void LoadIntegrationsFromStream( std::istream& stream, std::vector& integrationMethods, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames) { + const std::vector& enabledTraceIntegrationNames, + const std::vector& disabledTraceIntegrationNames, + const std::vector& enabledLogIntegrationNames, + const std::vector& disabledLogIntegrationNames) { try { json j; @@ -78,7 +86,12 @@ void LoadIntegrationsFromStream( for (const auto& el : j) { - IntegrationFromJson(el, integrationMethods, enabledIntegrationNames, disabledIntegrationNames); + IntegrationFromJson(el, + integrationMethods, + enabledTraceIntegrationNames, + disabledTraceIntegrationNames, + enabledLogIntegrationNames, + disabledLogIntegrationNames); } } @@ -114,15 +127,6 @@ namespace const std::vector& enabledIntegrationNames, const std::vector& disabledIntegrationNames) { - // LoggingBuilder has to be always enabled. - // Technically it is not an instrumentation but - // it is using the same functionality. - // See https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/issues/1310. - if (name == WStr("LoggingBuilder")) - { - return true; - } - // check if the integration is disabled for (const WSTRING& disabledName : disabledIntegrationNames) { @@ -150,8 +154,10 @@ namespace void IntegrationFromJson(const json::value_type& src, std::vector& integrationMethods, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames) + const std::vector& enabledTraceIntegrationNames, + const std::vector& disabledTraceIntegrationNames, + const std::vector& enabledLogIntegrationNames, + const std::vector& disabledLogIntegrationNames) { if (!src.is_object()) { @@ -166,8 +172,29 @@ namespace return; } - if (!InstrumentationEnabled(name, enabledIntegrationNames, disabledIntegrationNames)) + const WSTRING type = ToWSTRING(src.value("type", "")); + if (name.empty()) { + Logger::Warn("Integration type is missing for integration: ", src.dump()); + return; + } + + if (type == WStr("Trace")) + { + if (!InstrumentationEnabled(name, enabledTraceIntegrationNames, disabledTraceIntegrationNames)) + { + return; + } + } + else if (type == WStr("Log")) + { + if (!InstrumentationEnabled(name, enabledLogIntegrationNames, disabledLogIntegrationNames)) { + return; + } + } + else + { + Logger::Warn("Unsupported type for integration: ", src.dump()); return; } diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.h b/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.h index 8a7f38e05..d2cb1fdd0 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/integration_loader.h @@ -19,29 +19,37 @@ using json = nlohmann::json; // in the OTEL_DOTNET_AUTO_INTEGRATIONS_FILE environment variable void LoadIntegrationsFromEnvironment( std::vector& integrationMethods, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames); + const std::vector& enabledTraceIntegrationNames, + const std::vector& disabledTraceIntegrationNames, + const std::vector& enabledLogIntegrationNames, + const std::vector& disabledLogIntegrationNames); // LoadIntegrationsFromFile loads the integrations from a file void LoadIntegrationsFromFile( const WSTRING& file_path, std::vector& integrationMethods, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames); + const std::vector& enabledTraceIntegrationNames, + const std::vector& disabledTraceIntegrationNames, + const std::vector& enabledLogIntegrationNames, + const std::vector& disabledLogIntegrationNames); // LoadIntegrationsFromFile loads the integrations from a stream void LoadIntegrationsFromStream( std::istream& stream, std::vector& integrationMethods, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames); + const std::vector& enabledTraceIntegrationNames, + const std::vector& disabledTraceIntegrationNames, + const std::vector& enabledLogIntegrationNames, + const std::vector& disabledLogIntegrationNames); namespace { void IntegrationFromJson(const json::value_type& src, std::vector& integrationMethods, - const std::vector& enabledIntegrationNames, - const std::vector& disabledIntegrationNames); + const std::vector& enabledTraceIntegrationNames, + const std::vector& disabledTraceIntegrationNames, + const std::vector& enabledLogIntegrationNames, + const std::vector& disabledLogIntegrationNames); void MethodReplacementFromJson(const json::value_type& src, const WSTRING& integrationName, std::vector& integrationMethods); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configuration/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configuration/ConfigurationKeys.cs index 404ddec00..9981a5b45 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configuration/ConfigurationKeys.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configuration/ConfigurationKeys.cs @@ -174,6 +174,16 @@ internal static class ConfigurationKeys /// should be included on generated s. /// public const string IncludeFormattedMessage = "OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE"; + + /// + /// Configuration key for comma separated list of enabled logs instrumentations. + /// + public const string Instrumentations = "OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS"; + + /// + /// Configuration key for comma separated list of disabled logs instrumentations. + /// + public const string DisabledInstrumentations = "OTEL_DOTNET_AUTO_LOGS_DISABLED_INSTRUMENTATIONS"; } /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configuration/LogInstrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Configuration/LogInstrumentation.cs new file mode 100644 index 000000000..cf31cc3d3 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configuration/LogInstrumentation.cs @@ -0,0 +1,28 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.AutoInstrumentation.Configuration; + +/// +/// Enum representing supported meter instrumentations. +/// +internal enum LogInstrumentation +{ + /// + /// ILogger instrumentation. + /// + ILogger +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configuration/LogSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configuration/LogSettings.cs index 0420e2833..6f83daf30 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configuration/LogSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configuration/LogSettings.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; +using OpenTelemetry.AutoInstrumentation.Util; namespace OpenTelemetry.AutoInstrumentation.Configuration; @@ -35,6 +36,11 @@ internal class LogSettings : Settings LogExporter = ParseLogExporter(source); ConsoleExporterEnabled = source.GetBool(ConfigurationKeys.Logs.ConsoleExporterEnabled) ?? false; IncludeFormattedMessage = source.GetBool(ConfigurationKeys.Logs.IncludeFormattedMessage) ?? false; + + EnabledInstrumentations = source.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."); } /// @@ -52,6 +58,11 @@ internal class LogSettings : Settings /// public bool ConsoleExporterEnabled { get; } + /// + /// Gets the list of enabled instrumentations. + /// + public IList EnabledInstrumentations { get; } + internal static LogSettings FromDefaultSources() { var configurationSource = new CompositeConfigurationSource diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/GraphQLExecuteAsyncAttribute.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/GraphQLExecuteAsyncAttribute.cs index 7dc4f3fe9..2bb5c34b6 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/GraphQLExecuteAsyncAttribute.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/GraphQL/GraphQLExecuteAsyncAttribute.cs @@ -24,5 +24,6 @@ internal class GraphQLExecuteAsyncAttribute : InstrumentMethodAttribute MethodName = "ExecuteAsync"; ReturnTypeName = "System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]"; ParameterTypeNames = new[] { "GraphQL.Execution.ExecutionContext" }; + Type = InstrumentationType.Trace; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentMethodAttribute.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentMethodAttribute.cs index cb591a199..a42aca916 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentMethodAttribute.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentMethodAttribute.cs @@ -101,4 +101,9 @@ internal class InstrumentMethodAttribute : Attribute /// Gets or sets the integration name. Allows to group several integration with a single integration name. /// public string IntegrationName { get; set; } + + /// + /// Gets or sets the integration type. + /// + public InstrumentationType Type { get; set; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentationType.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentationType.cs new file mode 100644 index 000000000..87e73534f --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/InstrumentationType.cs @@ -0,0 +1,24 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.AutoInstrumentation.Instrumentations; + +internal enum InstrumentationType +{ + Trace, + // Metric, + Log +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/Logger/LoggingBuilderIntegration.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/Logger/LoggingBuilderIntegration.cs index 895f38cce..34c61e663 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/Logger/LoggingBuilderIntegration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/Logger/LoggingBuilderIntegration.cs @@ -30,7 +30,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.Logger; ParameterTypeNames = new[] { "Microsoft.Extensions.DependencyInjection.IServiceCollection" }, MinimumVersion = "3.1.0", MaximumVersion = "6.*.*", - IntegrationName = "LoggingBuilder")] + IntegrationName = "ILogger", + Type = InstrumentationType.Log)] public class LoggingBuilderIntegration { /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/MongoDb/MongoClientIntegration.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/MongoDb/MongoClientIntegration.cs index f37c9725f..4395a2f89 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/MongoDb/MongoClientIntegration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/MongoDb/MongoClientIntegration.cs @@ -36,7 +36,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB; ParameterTypeNames = new[] { "MongoDB.Driver.MongoClientSettings" }, MinimumVersion = "2.13.3", MaximumVersion = "2.65535.65535", - IntegrationName = "MongoDB")] + IntegrationName = "MongoDB", + Type = InstrumentationType.Trace)] public class MongoClientIntegration { #if NETCOREAPP3_1_OR_GREATER diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StackExchangeRedis/StackExchangeRedisIntegration.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StackExchangeRedis/StackExchangeRedisIntegration.cs index 38e20ed18..b2c856d2f 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StackExchangeRedis/StackExchangeRedisIntegration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StackExchangeRedis/StackExchangeRedisIntegration.cs @@ -30,7 +30,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis; ParameterTypeNames = new[] { ClrNames.Object, StackExchangeRedisConstants.TextWriterTypeName }, MinimumVersion = StackExchangeRedisConstants.MinimumVersion, MaximumVersion = StackExchangeRedisConstants.MaximumVersion, - IntegrationName = StackExchangeRedisConstants.IntegrationName)] + IntegrationName = StackExchangeRedisConstants.IntegrationName, + Type = InstrumentationType.Trace)] [InstrumentMethod(// releases 2.1.50 - 2.5.43 AssemblyName = StackExchangeRedisConstants.AssemblyName, TypeName = StackExchangeRedisConstants.ConnectionMultiplexerTypeName, @@ -39,7 +40,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis; ParameterTypeNames = new[] { StackExchangeRedisConstants.ConfigurationOptionsTypeName, StackExchangeRedisConstants.TextWriterTypeName }, MinimumVersion = StackExchangeRedisConstants.MinimumVersion, MaximumVersion = StackExchangeRedisConstants.MaximumVersion, - IntegrationName = StackExchangeRedisConstants.IntegrationName)] + IntegrationName = StackExchangeRedisConstants.IntegrationName, + Type = InstrumentationType.Trace)] [InstrumentMethod(// releases 2.5.61 - 2.6.48 AssemblyName = StackExchangeRedisConstants.AssemblyName, TypeName = StackExchangeRedisConstants.ConnectionMultiplexerTypeName, @@ -48,7 +50,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis; ParameterTypeNames = new[] { StackExchangeRedisConstants.ConfigurationOptionsTypeName, StackExchangeRedisConstants.TextWriterTypeName, StackExchangeRedisConstants.NullableServerTypeTypeName }, MinimumVersion = StackExchangeRedisConstants.MinimumVersion, MaximumVersion = StackExchangeRedisConstants.MaximumVersion, - IntegrationName = StackExchangeRedisConstants.IntegrationName)] + IntegrationName = StackExchangeRedisConstants.IntegrationName, + Type = InstrumentationType.Trace)] [InstrumentMethod(// releases 2.6.66+ AssemblyName = StackExchangeRedisConstants.AssemblyName, TypeName = StackExchangeRedisConstants.ConnectionMultiplexerTypeName, @@ -57,7 +60,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis; ParameterTypeNames = new[] { StackExchangeRedisConstants.ConfigurationOptionsTypeName, StackExchangeRedisConstants.TextWriterTypeName, StackExchangeRedisConstants.NullableServerTypeTypeName, StackExchangeRedisConstants.EndPointCollectionTypeName }, MinimumVersion = StackExchangeRedisConstants.MinimumVersion, MaximumVersion = StackExchangeRedisConstants.MaximumVersion, - IntegrationName = StackExchangeRedisConstants.IntegrationName)] + IntegrationName = StackExchangeRedisConstants.IntegrationName, + Type = InstrumentationType.Trace)] public class StackExchangeRedisIntegration { /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StackExchangeRedis/StackExchangeRedisIntegrationAsync.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StackExchangeRedis/StackExchangeRedisIntegrationAsync.cs index 5bb949f15..8f1f5a256 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StackExchangeRedis/StackExchangeRedisIntegrationAsync.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StackExchangeRedis/StackExchangeRedisIntegrationAsync.cs @@ -30,7 +30,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis; ParameterTypeNames = new[] { ClrNames.Object, StackExchangeRedisConstants.TextWriterTypeName }, MinimumVersion = StackExchangeRedisConstants.MinimumVersion, MaximumVersion = StackExchangeRedisConstants.MaximumVersion, - IntegrationName = StackExchangeRedisConstants.IntegrationName)] + IntegrationName = StackExchangeRedisConstants.IntegrationName, + Type = InstrumentationType.Trace)] [InstrumentMethod(// releases 2.1.50 - 2.5.43 AssemblyName = StackExchangeRedisConstants.AssemblyName, TypeName = StackExchangeRedisConstants.ConnectionMultiplexerTypeName, @@ -39,7 +40,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis; ParameterTypeNames = new[] { StackExchangeRedisConstants.ConfigurationOptionsTypeName, StackExchangeRedisConstants.TextWriterTypeName }, MinimumVersion = StackExchangeRedisConstants.MinimumVersion, MaximumVersion = StackExchangeRedisConstants.MaximumVersion, - IntegrationName = StackExchangeRedisConstants.IntegrationName)] + IntegrationName = StackExchangeRedisConstants.IntegrationName, + Type = InstrumentationType.Trace)] [InstrumentMethod(// releases 2.5.61+ AssemblyName = StackExchangeRedisConstants.AssemblyName, TypeName = StackExchangeRedisConstants.ConnectionMultiplexerTypeName, @@ -48,7 +50,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis; ParameterTypeNames = new[] { StackExchangeRedisConstants.ConfigurationOptionsTypeName, StackExchangeRedisConstants.TextWriterTypeName, StackExchangeRedisConstants.NullableServerTypeTypeName }, MinimumVersion = StackExchangeRedisConstants.MinimumVersion, MaximumVersion = StackExchangeRedisConstants.MaximumVersion, - IntegrationName = StackExchangeRedisConstants.IntegrationName)] + IntegrationName = StackExchangeRedisConstants.IntegrationName, + Type = InstrumentationType.Trace)] public class StackExchangeRedisIntegrationAsync { /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StrongNamedValidation/StrongNamedValidation.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StrongNamedValidation/StrongNamedValidation.cs index b70662da7..ce03b56d0 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StrongNamedValidation/StrongNamedValidation.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/StrongNamedValidation/StrongNamedValidation.cs @@ -33,7 +33,8 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations.Validations; ParameterTypeNames = new string[0], MinimumVersion = "1.0.0", MaximumVersion = "1.65535.65535", - IntegrationName = "StrongNamedValidation")] + IntegrationName = "StrongNamedValidation", + Type = InstrumentationType.Trace)] public class StrongNamedValidation { private static readonly ActivitySource ValidationActivitySource = new ActivitySource("TestApplication.StrongNamedValidation"); diff --git a/test/IntegrationTests/Helpers/MockLogsCollector.cs b/test/IntegrationTests/Helpers/MockLogsCollector.cs index 9ad6fbc9f..0117f6237 100644 --- a/test/IntegrationTests/Helpers/MockLogsCollector.cs +++ b/test/IntegrationTests/Helpers/MockLogsCollector.cs @@ -139,6 +139,15 @@ public class MockLogsCollector : IDisposable } } + public void AssertEmpty(TimeSpan? timeout = null) + { + timeout ??= DefaultWaitTimeout; + if (_logs.TryTake(out var logRecord, timeout.Value)) + { + Assert.Fail($"Expected nothing, but got: {logRecord}"); + } + } + private static void FailExpectations( List missingExpectations, List expectationsMet, diff --git a/test/IntegrationTests/SmokeTests.cs b/test/IntegrationTests/SmokeTests.cs index 4902534b1..bf8b6792f 100644 --- a/test/IntegrationTests/SmokeTests.cs +++ b/test/IntegrationTests/SmokeTests.cs @@ -14,7 +14,6 @@ // limitations under the License. // -using System.Collections.Immutable; using System.Net; using System.Net.Http; using System.Reflection; @@ -272,6 +271,18 @@ public class SmokeTests : TestHelper collector.AssertExpectations(); } + + [Fact] + [Trait("Category", "EndToEnd")] + public async Task LogsNoneInstrumentations() + { + using var collector = await MockLogsCollector.Start(Output); + + SetEnvironmentVariable("OTEL_DOTNET_AUTO_LOGS_ENABLED_INSTRUMENTATIONS", "none"); + RunTestApplication(logsAgentPort: collector.Port, enableClrProfiler: true); + + collector.AssertEmpty(5.Seconds()); + } #endif private async Task VerifyTestApplicationInstrumented(bool enableStartupHook = true, bool enableClrProfiler = true) diff --git a/test/IntegrationTests/StrongNamedTestsIntegrations.json b/test/IntegrationTests/StrongNamedTestsIntegrations.json index d570a0996..486b28acc 100644 --- a/test/IntegrationTests/StrongNamedTestsIntegrations.json +++ b/test/IntegrationTests/StrongNamedTestsIntegrations.json @@ -1,6 +1,7 @@ [ { "name": "StrongNamedValidation", + "type": "Trace", "method_replacements": [ { "caller": {}, diff --git a/test/OpenTelemetry.AutoInstrumentation.Native.Tests/integration_loader_test.cpp b/test/OpenTelemetry.AutoInstrumentation.Native.Tests/integration_loader_test.cpp index 836121467..27225fdf9 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; - LoadIntegrationsFromFile(L"missing-file", integrations, {}, {}); + LoadIntegrationsFromFile(L"missing-file", integrations, {}, {}, {}, {}); EXPECT_EQ(0, integrations.size()); } @@ -24,7 +24,7 @@ TEST(IntegrationLoaderTest, HandlesInvalidIntegrationNoName) { std::vector integrations; std::stringstream str("[{}]"); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); // 0 because name is required EXPECT_EQ(0, integrations.size()); } @@ -33,7 +33,7 @@ TEST(IntegrationLoaderTest, HandlesInvalidIntegrationBadJson) { std::vector integrations; std::stringstream str("["); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); EXPECT_EQ(0, integrations.size()); } @@ -41,7 +41,7 @@ TEST(IntegrationLoaderTest, HandlesInvalidIntegrationNotAnObject) { std::vector integrations; std::stringstream str("[1,2,3]"); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); EXPECT_EQ(0, integrations.size()); } @@ -51,7 +51,7 @@ TEST(IntegrationLoaderTest, HandlesInvalidIntegrationNotAnArray) std::stringstream str(R"TEXT( {"name": "test-integration"} )TEXT"); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); EXPECT_EQ(0, integrations.size()); } @@ -61,6 +61,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithMethodReplacements) std::stringstream str(R"TEXT( [{ "name": "test-integration", + "type": "Trace", "method_replacements": [{ "caller": { }, "target": { "assembly": "Assembly.One", "type": "Type.One", "method": "Method.One", "minimum_major": 0, "minimum_minor": 1, "maximum_major": 10, "maximum_minor": 0 }, @@ -69,7 +70,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithMethodReplacements) }] )TEXT"); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); EXPECT_EQ(1, integrations.size()); EXPECT_STREQ(L"test-integration", integrations[0].integration_name.c_str()); } @@ -80,6 +81,7 @@ TEST(IntegrationLoaderTest, DoesNotCrashWithOutOfRangeVersion) std::stringstream str(R"TEXT( [{ "name": "test-integration", + "type": "Trace", "method_replacements": [{ "caller": { }, "target": { "assembly": "Assembly.One", "type": "Type.One", "method": "Method.One", "minimum_major": 0, "minimum_minor": 1, "maximum_major": 75555, "maximum_minor": 0 }, @@ -88,7 +90,7 @@ TEST(IntegrationLoaderTest, DoesNotCrashWithOutOfRangeVersion) }] )TEXT"); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); EXPECT_EQ(1, integrations.size()); EXPECT_STREQ(L"test-integration", integrations[0].integration_name.c_str()); @@ -111,6 +113,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithMissingCaller) std::stringstream str(R"TEXT( [{ "name": "test-integration", + "type": "Trace", "method_replacements": [{ "target": { "assembly": "Assembly.One", "type": "Type.One", "method": "Method.One", "minimum_major": 1, "minimum_minor": 2, "maximum_major": 10, "maximum_minor": 99 }, "wrapper": { "assembly": "Assembly.Two", "type": "Type.Two", "method": "Method.Two", "signature": [0, 1, 1, 28], "action": "CallTargetModification" } @@ -118,7 +121,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithMissingCaller) }] )TEXT"); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); EXPECT_EQ(1, integrations.size()); EXPECT_STREQ(L"test-integration", integrations[0].integration_name.c_str()); @@ -148,6 +151,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithInvalidTarget) std::stringstream str(R"TEXT( [{ "name": "test-integration", + "type": "Trace", "method_replacements": [{ "target": 1234, "wrapper": { "assembly": "Assembly.Two", "type": "Type.Two", "method": "Method.Two", "action": "CallTargetModification" } @@ -155,7 +159,7 @@ TEST(IntegrationLoaderTest, HandlesSingleIntegrationWithInvalidTarget) }] )TEXT"); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); EXPECT_EQ(1, integrations.size()); EXPECT_STREQ(L"test-integration", integrations[0].integration_name.c_str()); @@ -172,12 +176,12 @@ TEST(IntegrationLoaderTest, LoadsFromEnvironment) std::ofstream f; f.open(temp_name1); f << R"TEXT( - [{ "name": "test-integration-1", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }] + [{ "name": "test-integration-1", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }] )TEXT"; f.close(); f.open(temp_name2); f << R"TEXT( - [{ "name": "test-integration-2", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }] + [{ "name": "test-integration-2", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }] )TEXT"; f.close(); @@ -188,7 +192,7 @@ TEST(IntegrationLoaderTest, LoadsFromEnvironment) const std::vector expected_names = {L"test-integration-1", L"test-integration-2"}; std::vector actual_names; std::vector integrations; - LoadIntegrationsFromEnvironment(integrations, {}, {}); + LoadIntegrationsFromEnvironment(integrations, {}, {}, {}, {}); for (auto& integration : integrations) { actual_names.push_back(integration.integration_name); @@ -205,6 +209,7 @@ TEST(IntegrationLoaderTest, DeserializesSignatureTypeArray) std::stringstream str(R"TEXT( [{ "name": "test-integration", + "type": "Trace", "method_replacements": [{ "caller": { }, "target": { "assembly": "Assembly.One", "type": "Type.One", "method": "Method.One", "signature_types": ["System.Void", "_", "FakeClient.Pipeline'1"] }, @@ -213,25 +218,25 @@ TEST(IntegrationLoaderTest, DeserializesSignatureTypeArray) }] )TEXT"); - LoadIntegrationsFromStream(str, integrations, {}, {}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {}); const auto target = integrations[0].replacement.target_method; EXPECT_STREQ(L"System.Void", target.signature_types[0].c_str()); EXPECT_STREQ(L"_", target.signature_types[1].c_str()); EXPECT_STREQ(L"FakeClient.Pipeline'1", target.signature_types[2].c_str()); } -TEST(IntegrationLoaderTest, SupportsEnabledIntegrations) { +TEST(IntegrationLoaderTest, SupportsEnabledTraceIntegrations) { std::vector integrations; std::stringstream str(R"TEXT( [ - { "name": "test-integration-1", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, - { "name": "test-integration-2", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] } + { "name": "test-trace-integration-1", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, + { "name": "test-trace-integration-2", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] } ] )TEXT"); - const std::vector expected_names = {L"test-integration-2"}; + const std::vector expected_names = {L"test-trace-integration-2"}; std::vector actual_names; - LoadIntegrationsFromStream(str, integrations, {L"test-integration-2"}, {}); + LoadIntegrationsFromStream(str, integrations, {L"test-trace-integration-2"}, {}, {}, {}); for (auto& integration : integrations) { actual_names.push_back(integration.integration_name); @@ -239,42 +244,91 @@ TEST(IntegrationLoaderTest, SupportsEnabledIntegrations) { EXPECT_EQ(expected_names, actual_names); } -TEST(IntegrationLoaderTest, SupportsDisabledIntegrations) { +TEST(IntegrationLoaderTest, SupportsEnabledLogIntegrations) +{ std::vector integrations; std::stringstream str(R"TEXT( - [ - { "name": "test-integration-1", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, - { "name": "test-integration-2", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] } - ] - )TEXT"); - - const std::vector expected_names = {L"test-integration-1"}; + [ + { "name": "test-log-integration-1", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, + { "name": "test-log-integration-2", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] } + ] + )TEXT"); + + const std::vector expected_names = {L"test-log-integration-2"}; std::vector actual_names; - LoadIntegrationsFromStream(str, integrations, {}, {L"test-integration-2"}); - 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-integration-1", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, - { "name": "test-integration-2", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, - { "name": "test-integration-3", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] } - ] - )TEXT"); - - const std::vector expected_names = {L"test-integration-1"}; - std::vector actual_names; - LoadIntegrationsFromStream(str, integrations, - {L"test-integration-1", L"test-integration-2"}, - {L"test-integration-2", L"test-integration-3"}); + LoadIntegrationsFromStream(str, integrations, {}, {}, {L"test-log-integration-2"}, {}); for (auto& integration : integrations) { - actual_names.push_back(integration.integration_name); + actual_names.push_back(integration.integration_name); + } + 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": {"action": "CallTargetModification"} }] }, + { "name": "test-trace-integration-2", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] } + ] + )TEXT"); + + const std::vector expected_names = {L"test-trace-integration-1"}; + std::vector actual_names; + LoadIntegrationsFromStream(str, integrations, {}, {L"test-trace-integration-2"}, {}, {}); + 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": {"action": "CallTargetModification"} }] }, + { "name": "test-log-integration-2", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] } + ] + )TEXT"); + + const std::vector expected_names = {L"test-log-integration-1"}; + std::vector actual_names; + LoadIntegrationsFromStream(str, integrations, {}, {}, {}, {L"test-log-integration-2"}); + 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": {"action": "CallTargetModification"} }] }, + { "name": "test-trace-integration-2", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, + { "name": "test-trace-integration-3", "type": "Trace", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, + { "name": "test-log-integration-1", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, + { "name": "test-log-integration-2", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] }, + { "name": "test-log-integration-3", "type": "Log", "method_replacements": [{ "caller": {}, "target": {}, "wrapper": {"action": "CallTargetModification"} }] } + ] + )TEXT"); + + const std::vector expected_names = {L"test-trace-integration-1", L"test-log-integration-1"}; + std::vector actual_names; + LoadIntegrationsFromStream(str, integrations, + {L"test-trace-integration-1", L"test-trace-integration-2"}, + {L"test-trace-integration-2", L"test-trace-integration-3"}, + {L"test-log-integration-1", L"test-log-integration-2"}, + {L"test-log-integration-2", L"test-log-integration-3"}); + + for (auto& integration : integrations) + { + actual_names.push_back(integration.integration_name); } EXPECT_EQ(expected_names, actual_names); } diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configuration/SettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configuration/SettingsTests.cs index 258f431b4..7f1845130 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configuration/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configuration/SettingsTests.cs @@ -98,6 +98,7 @@ public class SettingsTests : IDisposable settings.LogExporter.Should().Be(LogExporter.Otlp); settings.OtlpExportProtocol.Should().Be(OtlpExportProtocol.HttpProtobuf); settings.ConsoleExporterEnabled.Should().BeFalse(); + settings.EnabledInstrumentations.Should().NotBeEmpty(); settings.Plugins.Should().BeEmpty(); settings.IncludeFormattedMessage.Should().BeFalse(); settings.Http2UnencryptedSupportEnabled.Should().BeFalse(); @@ -231,6 +232,27 @@ public class SettingsTests : IDisposable 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); + + var settings = LogSettings.FromDefaultSources(); + + settings.EnabledInstrumentations.Should().BeEquivalentTo(new List { expectedLogInstrumentation }); + } + + [Fact] + internal void LogSettings_DisabledInstrumentations() + { + Environment.SetEnvironmentVariable(ConfigurationKeys.Logs.DisabledInstrumentations, nameof(LogInstrumentation.ILogger)); + + var settings = LogSettings.FromDefaultSources(); + + settings.EnabledInstrumentations.Should().BeEmpty(); + } + [Theory] [InlineData("true", true)] [InlineData("false", false)] @@ -297,6 +319,8 @@ public class SettingsTests : IDisposable { 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.Exporter, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.Instrumentations, null); Environment.SetEnvironmentVariable(ConfigurationKeys.Metrics.DisabledInstrumentations, null); diff --git a/tools/IntegrationsJsonGenerator/Integration.cs b/tools/IntegrationsJsonGenerator/Integration.cs index 172051668..6cd28bedd 100644 --- a/tools/IntegrationsJsonGenerator/Integration.cs +++ b/tools/IntegrationsJsonGenerator/Integration.cs @@ -22,6 +22,9 @@ internal class Integration [JsonPropertyName("name")] public string Name { get; set; } + [JsonPropertyName("type")] + public string Type { get; set; } + [JsonPropertyName("method_replacements")] public IList MethodReplacements { get; set; } } diff --git a/tools/IntegrationsJsonGenerator/Program.cs b/tools/IntegrationsJsonGenerator/Program.cs index 1096c5466..96dfcc350 100644 --- a/tools/IntegrationsJsonGenerator/Program.cs +++ b/tools/IntegrationsJsonGenerator/Program.cs @@ -50,6 +50,7 @@ foreach (var typeInfo in autoInstrumentationLib.GetTypes()) new Integration { Name = integration.IntegrationName, + Type = integration.IntegartionType, MethodReplacements = new List { integration.MethodReplacement } }); } @@ -88,9 +89,10 @@ bool InheritsFrom(Type type, string baseType) } } -(string IntegrationName, MethodReplacement MethodReplacement) ConvertToIntegration(string wrapperTypeName, Attribute attribute) +(string IntegartionType, string IntegrationName, MethodReplacement MethodReplacement) ConvertToIntegration(string wrapperTypeName, Attribute attribute) { var integrationName = GetPropertyValue("IntegrationName", attribute); + var integrationType = GetPropertyValue("Type", attribute).ToString(); var methodReplacement = new MethodReplacement { @@ -133,7 +135,7 @@ bool InheritsFrom(Type type, string baseType) methodReplacement.Target.MaximumPath = int.Parse(maxVersion[2]); } - return (integrationName, methodReplacement); + return (integrationType, integrationName, methodReplacement); } T GetPropertyValue(string propertyName, Attribute attribute)