diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index c5ee3fd538..773db8f9e3 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -172,6 +172,94 @@ propagator: composite_list: ${OTEL_PROPAGATORS} ``` +## Instrumentation Configuration + +You can configure traces, metrics, and logs instrumentations. +Each entry in the example list below is equivalent to setting the corresponding +environment variable described in the [Instrumentation list and documentation](config.md#instrumentations). +To disable a instrumentation, comment out or remove its corresponding entry. + +``` yaml +instrumentation/development: + dotnet: + traces: + aspnet: # ASP.NET + aspnetcore: # ASP.NET Core + azure: # Azure SDK + elasticsearch: # Elastic.Clients.Elasticsearch + elastictransport: # Elastic.Transport + entityframeworkcore: # Entity Framework Core + graphql: # GraphQL + grpcnetclient: # Grpc.Net.Client + httpclient: # System.Net.Http.HttpClient + kafka: # Confluent.Kafka + masstransit: # MassTransit + mongodb: # MongoDB.Driver + mysqlconnector: # MySqlConnector + mysqldata: # MySql.Data + npgsql: # Npgsql + nservicebus: # NServiceBus + oraclemda: # Oracle.ManagedDataAccess + rabbitmq: # RabbitMQ.Client + quartz: # Quartz + sqlclient: # Microsoft.Data.SqlClient & System.Data.SqlClient + stackexchangeredis: # StackExchange.Redis + wcfclient: # WCF Client + wcfservice: # WCF Service + metrics: + aspnet: # ASP.NET metrics + aspnetcore: # ASP.NET Core metrics + httpclient: # HttpClient metrics + netruntime: # .NET Runtime metrics + nservicebus: # NServiceBus metrics + process: # Process metrics + sqlclient: # SQL Client metrics + logs: + ilogger: # Microsoft.Extensions.Logging + log4net: # Log4Net +``` + +## Instrumentation options + +``` yaml +instrumentation/development: + dotnet: + traces: + graphql: + # Whether the GraphQL instrumentation can pass raw queries through the graphql.document attribute. Queries might contain sensitive information. + # Default is false + set_document: false + oraclemda: + # Whether the Oracle Client instrumentation can pass SQL statements through the db.statement attribute. Queries might contain sensitive information. If set to false, db.statement is recorded only for executing stored procedures. + # Default is false + set_db_statement_for_text: false + aspnet: + # A comma-separated list of HTTP header names. ASP.NET instrumentations will capture HTTP request header values for all configured header names. + capture_request_headers: "X-Key,X-Custom-Header,X-Header-Example" + # A comma-separated list of HTTP header names. ASP.NET instrumentations will capture HTTP response header values for all configured header names. + capture_response_headers: "X-Key,X-Custom-Header,X-Header-Example" + aspnetcore: + # A comma-separated list of HTTP header names. ASP.NET Core instrumentations will capture HTTP request header values for all configured header names. + capture_request_headers: "X-Key,X-Custom-Header,X-Header-Example" + # A comma-separated list of HTTP header names. ASP.NET Core instrumentations will capture HTTP response header values for all configured header names. + capture_response_headers: "X-Key,X-Custom-Header,X-Header-Example" + httpclient: + # A comma-separated list of HTTP header names. HTTP Client instrumentations will capture HTTP request header values for all configured header names. + capture_request_headers: "X-Key,X-Custom-Header,X-Header-Example" + # A comma-separated list of HTTP header names. HTTP Client instrumentations will capture HTTP response header values for all configured header names. + capture_response_headers: "X-Key,X-Custom-Header,X-Header-Example" + grpcnetclient: + # A comma-separated list of gRPC metadata names. Grpc.Net.Client instrumentations will capture gRPC request metadata values for all configured metadata names. + capture_request_metadata: "X-Key,X-Custom-Header,X-Header-Example" + # A comma-separated list of gRPC metadata names. Grpc.Net.Client instrumentations will capture gRPC response metadata values for all configured metadata names. + capture_response_metadata: "X-Key,X-Custom-Header,X-Header-Example" + logs: + log4net: + # Logs bridge is disabled by default + # More info about log4net bridge can be found at https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/blob/main/docs/log4net-bridge.md + bridge_enabled: true +``` + ### Configuration based instrumentation Documentation for configuration based instrumentation can be found in [nocode-instrumentation.md](nocode-instrumentation.md). diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationExtensions.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationExtensions.cs index 3006c28463..e4ad3cabb8 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationExtensions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationExtensions.cs @@ -32,9 +32,9 @@ public static IReadOnlyList ParseList(this Configuration source, string if (string.IsNullOrWhiteSpace(values)) { - return Array.Empty(); + return []; } - return values!.Split(new[] { valueSeparator }, StringSplitOptions.RemoveEmptyEntries); + return values!.Split([valueSeparator], StringSplitOptions.RemoveEmptyEntries); } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs new file mode 100644 index 0000000000..2d261c844f --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs @@ -0,0 +1,25 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +[EmptyObjectOnEmptyYaml] +internal class CaptureHeadersConfiguration +{ + /// + /// Gets or sets a comma-separated list of HTTP header names. + /// Instrumentations will capture HTTP request header values for all configured header names. + /// + [YamlMember(Alias = "capture_request_headers")] + public string? CaptureRequestHeaders { get; set; } + + /// + /// Gets or sets a comma-separated list of HTTP header names. + /// Instrumentations will capture HTTP response header values for all configured header names. + /// + [YamlMember(Alias = "capture_response_headers")] + public string? CaptureResponseHeaders { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs new file mode 100644 index 0000000000..5f0f32e2af --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs @@ -0,0 +1,25 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +[EmptyObjectOnEmptyYaml] +internal class CaptureMetadataConfiguration +{ + /// + /// Gets or sets a comma-separated list of gRPC metadata names. + /// Grpc.Net.Client instrumentations will capture gRPC request metadata values for all configured metadata names. + /// + [YamlMember(Alias = "capture_request_metadata")] + public string? CaptureRequestMetadata { get; set; } + + /// + /// Gets or sets a comma-separated list of gRPC metadata names. + /// Grpc.Net.Client instrumentations will capture gRPC response metadata values for all configured metadata names. + /// + [YamlMember(Alias = "capture_response_metadata")] + public string? CaptureResponseMetadata { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs new file mode 100644 index 0000000000..d0d99d6bdc --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetInstrumentation +{ + /// + /// Gets or sets the configuration for .NET traces instrumentation. + /// + [YamlMember(Alias = "traces")] + public DotNetTraces? Traces { get; set; } + + /// + /// Gets or sets the configuration for .NET metrics instrumentation. + /// + [YamlMember(Alias = "metrics")] + public DotNetMetrics? Metrics { get; set; } + + /// + /// Gets or sets the configuration for .NET logs instrumentation. + /// + [YamlMember(Alias = "logs")] + public DotNetLogs? Logs { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs new file mode 100644 index 0000000000..b854c06aca --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetLogs +{ + /// + /// Gets or sets the ILogger logs instrumentation configuration. + /// + [YamlMember(Alias = "ilogger")] + public object? ILogger { get; set; } + + /// + /// Gets or sets the Log4Net logs instrumentation configuration. + /// + [YamlMember(Alias = "log4net")] + public Log4NetBridgeEnabled? Log4Net { get; set; } + + /// + /// Returns the list of enabled log instrumentations. + /// + public IReadOnlyList GetEnabledInstrumentations() + { + var result = new List(); + + if (ILogger != null) + { + result.Add(LogInstrumentation.ILogger); + } + + if (Log4Net != null) + { + result.Add(LogInstrumentation.Log4Net); + } + + return result; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs new file mode 100644 index 0000000000..1872d08058 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs @@ -0,0 +1,79 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Reflection; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetMetrics +{ +#if NETFRAMEWORK + /// + /// Gets or sets the ASP.NET metrics instrumentation configuration. + /// + [YamlMember(Alias = "aspnet")] + public object? AspNet { get; set; } +#endif + +#if NET + /// + /// Gets or sets the ASP.NET Core metrics instrumentation configuration. + /// + [YamlMember(Alias = "aspnetcore")] + public object? AspNetCore { get; set; } +#endif + + /// + /// Gets or sets the HttpClient metrics instrumentation configuration. + /// + [YamlMember(Alias = "httpclient")] + public object? HttpClient { get; set; } + + /// + /// Gets or sets the .NET runtime metrics instrumentation configuration. + /// + [YamlMember(Alias = "netruntime")] + public object? NetRuntime { get; set; } + + /// + /// Gets or sets the NServiceBus metrics instrumentation configuration. + /// + [YamlMember(Alias = "nservicebus")] + public object? NServiceBus { get; set; } + + /// + /// Gets or sets the process metrics instrumentation configuration. + /// + [YamlMember(Alias = "process")] + public object? Process { get; set; } + + /// + /// Gets or sets the SqlClient metrics instrumentation configuration. + /// + [YamlMember(Alias = "sqlclient")] + public object? SqlClient { get; set; } + + /// + /// Returns the list of enabled metric instrumentations. + /// + public IReadOnlyList GetEnabledInstrumentations() + { + var enabled = new List(); + var properties = typeof(DotNetMetrics).GetProperties(BindingFlags.Instance | BindingFlags.Public); + + foreach (var prop in properties) + { + var value = prop.GetValue(this); + if (value != null) + { + if (Enum.TryParse(prop.Name, out var instrumentation)) + { + enabled.Add(instrumentation); + } + } + } + + return enabled; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs new file mode 100644 index 0000000000..e6efeaadd4 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs @@ -0,0 +1,175 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Reflection; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetTraces +{ +#if NETFRAMEWORK + /// + /// Gets or sets the ASP.NET traces instrumentation configuration. + /// + [YamlMember(Alias = "aspnet")] + public CaptureHeadersConfiguration? AspNet { get; set; } + + /// + /// Gets or sets the WCF service traces instrumentation configuration. + /// + [YamlMember(Alias = "wcfservice")] + public object? WcfService { get; set; } +#endif + +#if NET + /// + /// Gets or sets the ASP.NET Core traces instrumentation configuration. + /// + [YamlMember(Alias = "aspnetcore")] + public CaptureHeadersConfiguration? AspNetCore { get; set; } + + /// + /// Gets or sets the StackExchange.Redis traces instrumentation configuration. + /// + [YamlMember(Alias = "stackexchangeredis")] + public object? StackExchangeRedis { get; set; } + + /// + /// Gets or sets the Entity Framework Core traces instrumentation configuration. + /// + [YamlMember(Alias = "entityframeworkcore")] + public object? EntityFrameworkCore { get; set; } + + /// + /// Gets or sets the GraphQL traces instrumentation configuration. + /// + [YamlMember(Alias = "graphql")] + public GraphQLSetDocumentConfiguration? GraphQL { get; set; } + + /// + /// Gets or sets the MassTransit traces instrumentation configuration. + /// + [YamlMember(Alias = "masstransit")] + public object? MassTransit { get; set; } + + /// + /// Gets or sets the MySqlData traces instrumentation configuration. + /// + [YamlMember(Alias = "mysqldata")] + public object? MySqlData { get; set; } +#endif + + /// + /// Gets or sets the Azure traces instrumentation configuration. + /// + [YamlMember(Alias = "azure")] + public object? Azure { get; set; } + + /// + /// Gets or sets the Elasticsearch traces instrumentation configuration. + /// + [YamlMember(Alias = "elasticsearch")] + public object? Elasticsearch { get; set; } + + /// + /// Gets or sets the ElasticTransport traces instrumentation configuration. + /// + [YamlMember(Alias = "elastictransport")] + public object? ElasticTransport { get; set; } + + /// + /// Gets or sets the Grpc.Net.Client traces instrumentation configuration. + /// + [YamlMember(Alias = "grpcnetclient")] + public CaptureMetadataConfiguration? GrpcNetClient { get; set; } + + /// + /// Gets or sets the HttpClient traces instrumentation configuration. + /// + [YamlMember(Alias = "httpclient")] + public CaptureHeadersConfiguration? HttpClient { get; set; } + + /// + /// Gets or sets the Kafka traces instrumentation configuration. + /// + [YamlMember(Alias = "kafka")] + public object? Kafka { get; set; } + + /// + /// Gets or sets the MongoDB traces instrumentation configuration. + /// + [YamlMember(Alias = "mongodb")] + public object? MongoDb { get; set; } + + /// + /// Gets or sets the MySqlConnector traces instrumentation configuration. + /// + [YamlMember(Alias = "mysqlconnector")] + public object? MySqlConnector { get; set; } + + /// + /// Gets or sets the Npgsql traces instrumentation configuration. + /// + [YamlMember(Alias = "npgsql")] + public object? Npgsql { get; set; } + + /// + /// Gets or sets the NServiceBus traces instrumentation configuration. + /// + [YamlMember(Alias = "nservicebus")] + public object? NServiceBus { get; set; } + + /// + /// Gets or sets the Oracle MDA traces instrumentation configuration. + /// + [YamlMember(Alias = "oraclemda")] + public SetDbStatementForTextConfuguration? OracleMda { get; set; } + + /// + /// Gets or sets the RabbitMQ traces instrumentation configuration. + /// + [YamlMember(Alias = "rabbitmq")] + public object? RabbitMq { get; set; } + + /// + /// Gets or sets the Quartz traces instrumentation configuration. + /// + [YamlMember(Alias = "quartz")] + public object? Quartz { get; set; } + + /// + /// Gets or sets the SqlClient traces instrumentation configuration. + /// + [YamlMember(Alias = "sqlclient")] + public object? SqlClient { get; set; } + + /// + /// Gets or sets the WCF client traces instrumentation configuration. + /// + [YamlMember(Alias = "wcfclient")] + public object? WcfClient { get; set; } + + /// + /// Returns the list of enabled traces instrumentations. + /// + public IReadOnlyList GetEnabledInstrumentations() + { + var enabled = new List(); + var properties = typeof(DotNetTraces).GetProperties(BindingFlags.Instance | BindingFlags.Public); + + foreach (var prop in properties) + { + var value = prop.GetValue(this); + if (value != null) + { + if (Enum.TryParse(prop.Name, out var instrumentation)) + { + enabled.Add(instrumentation); + } + } + } + + return enabled; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/GraphQLSetDocumentConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/GraphQLSetDocumentConfiguration.cs new file mode 100644 index 0000000000..4656904370 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/GraphQLSetDocumentConfiguration.cs @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +[EmptyObjectOnEmptyYaml] +internal class GraphQLSetDocumentConfiguration +{ + /// + /// Gets or sets a value indicating whether the GraphQL instrumentation can pass raw queries through the graphql.document attribute. + /// Queries might contain sensitive information. + /// + [YamlMember(Alias = "set_document")] + public bool SetDocument { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs new file mode 100644 index 0000000000..7768f51e0b --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class InstrumentationDevelopment +{ + /// + /// Gets or sets the configuration for .NET language-specific instrumentation libraries. + /// + [YamlMember(Alias = "dotnet")] + public DotNetInstrumentation? DotNet { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Log4NetBridgeEnabled.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Log4NetBridgeEnabled.cs new file mode 100644 index 0000000000..288108f53e --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Log4NetBridgeEnabled.cs @@ -0,0 +1,17 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +[EmptyObjectOnEmptyYaml] +internal class Log4NetBridgeEnabled +{ + /// + /// Gets or sets a value indicating whether the Log4Net bridge is enabled. + /// + [YamlMember(Alias = "bridge_enabled")] + public bool BridgeEnabled { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs new file mode 100644 index 0000000000..2d52867df5 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +[EmptyObjectOnEmptyYaml] +internal class SetDbStatementForTextConfuguration +{ + /// + /// Gets or sets a value indicating whether SQL statements are passed through the db.statement attribute. + /// If false, db.statement is recorded only for executing stored procedures. + /// + [YamlMember(Alias = "set_db_statement_for_text")] + public bool SetDbStatementForText { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs index 11502f813a..269a9d6a1c 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using System.Reflection; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; @@ -23,6 +25,14 @@ internal class YamlConfiguration [YamlMember(Alias = "resource")] public ResourceConfiguration? Resource { get; set; } + /// + /// Gets or sets the instrumentation development configuration. + /// Configure instrumentation. + /// This type is in development and subject to breaking changes in minor versions. + /// + [YamlMember(Alias = "instrumentation/development")] + public InstrumentationDevelopment? InstrumentationDevelopment { get; set; } + /// /// Gets or sets the tracer provider configuration. /// Configure tracer provider. diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs index 38fabdc2cd..2179027ef6 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.HeadersCapture; namespace OpenTelemetry.AutoInstrumentation.Configurations; @@ -29,28 +30,71 @@ internal InstrumentationOptions(Configuration configuration) OracleMdaSetDbStatementForText = configuration.GetBool(ConfigurationKeys.Traces.InstrumentationOptions.OracleMdaSetDbStatementForText) ?? false; } + internal InstrumentationOptions(DotNetTraces? instrumentationConfiguration) + { + if (instrumentationConfiguration != null) + { +#if NETFRAMEWORK + if (instrumentationConfiguration.AspNet != null) + { + AspNetInstrumentationCaptureRequestHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNet.CaptureRequestHeaders, AdditionalTag.CreateHttpRequestCache); + AspNetInstrumentationCaptureResponseHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNet.CaptureResponseHeaders, AdditionalTag.CreateHttpResponseCache); + } +#endif +#if NET + if (instrumentationConfiguration.AspNetCore != null) + { + AspNetCoreInstrumentationCaptureRequestHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNetCore.CaptureRequestHeaders, AdditionalTag.CreateHttpRequestCache); + AspNetCoreInstrumentationCaptureResponseHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNetCore.CaptureResponseHeaders, AdditionalTag.CreateHttpResponseCache); + } + + if (instrumentationConfiguration.GraphQL != null) + { + GraphQLSetDocument = instrumentationConfiguration.GraphQL.SetDocument; + } +#endif + + if (instrumentationConfiguration.GrpcNetClient != null) + { + GrpcNetClientInstrumentationCaptureRequestMetadata = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.GrpcNetClient.CaptureRequestMetadata, AdditionalTag.CreateGrpcRequestCache); + GrpcNetClientInstrumentationCaptureResponseMetadata = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.GrpcNetClient.CaptureResponseMetadata, AdditionalTag.CreateGrpcResponseCache); + } + + if (instrumentationConfiguration.HttpClient != null) + { + HttpInstrumentationCaptureRequestHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.HttpClient.CaptureRequestHeaders, AdditionalTag.CreateHttpRequestCache); + HttpInstrumentationCaptureResponseHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.HttpClient.CaptureResponseHeaders, AdditionalTag.CreateHttpResponseCache); + } + + if (instrumentationConfiguration.OracleMda != null) + { + OracleMdaSetDbStatementForText = instrumentationConfiguration.OracleMda.SetDbStatementForText; + } + } + } + #if NETFRAMEWORK /// /// Gets the list of HTTP request headers to be captured as the span tags by ASP.NET instrumentation. /// - public IReadOnlyList AspNetInstrumentationCaptureRequestHeaders { get; } + public IReadOnlyList AspNetInstrumentationCaptureRequestHeaders { get; } = []; /// /// Gets the list of HTTP response headers to be captured as the span tags by ASP.NET instrumentation. /// - public IReadOnlyList AspNetInstrumentationCaptureResponseHeaders { get; } + public IReadOnlyList AspNetInstrumentationCaptureResponseHeaders { get; } = []; #endif #if NET /// /// Gets the list of HTTP request headers to be captured as the span tags by ASP.NET Core instrumentation. /// - public IReadOnlyList AspNetCoreInstrumentationCaptureRequestHeaders { get; } + public IReadOnlyList AspNetCoreInstrumentationCaptureRequestHeaders { get; } = []; /// /// Gets the list of HTTP response headers to be captured as the span tags by ASP.NET Core instrumentation. /// - public IReadOnlyList AspNetCoreInstrumentationCaptureResponseHeaders { get; } + public IReadOnlyList AspNetCoreInstrumentationCaptureResponseHeaders { get; } = []; /// /// Gets a value indicating whether GraphQL query can be passed as a Document tag. @@ -61,22 +105,22 @@ internal InstrumentationOptions(Configuration configuration) /// /// Gets the list of request metadata to be captured as the span tags by Grpc.Net.Client instrumentation. /// - public IReadOnlyList GrpcNetClientInstrumentationCaptureRequestMetadata { get; } + public IReadOnlyList GrpcNetClientInstrumentationCaptureRequestMetadata { get; } = []; /// /// Gets the list of response metadata to be captured as the span tags by Grpc.Net.Client instrumentation. /// - public IReadOnlyList GrpcNetClientInstrumentationCaptureResponseMetadata { get; } + public IReadOnlyList GrpcNetClientInstrumentationCaptureResponseMetadata { get; } = []; /// /// Gets the list of HTTP request headers to be captured as the span tags by HTTP instrumentation. /// - public IReadOnlyList HttpInstrumentationCaptureRequestHeaders { get; } + public IReadOnlyList HttpInstrumentationCaptureRequestHeaders { get; } = []; /// /// Gets the list of HTTP response headers to be captured as the span tags by HTTP instrumentation. /// - public IReadOnlyList HttpInstrumentationCaptureResponseHeaders { get; } + public IReadOnlyList HttpInstrumentationCaptureResponseHeaders { get; } = []; /// /// Gets a value indicating whether text query in Oracle Client can be passed as a db.statement tag. diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs index 0b15291aa5..a912ffdb89 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.AutoInstrumentation.Logging; @@ -64,6 +65,16 @@ protected override void OnLoadEnvVar(Configuration configuration) enabledConfigurationTemplate: ConfigurationKeys.Logs.EnabledLogsInstrumentationTemplate); } + protected override void OnLoadFile(YamlConfiguration configuration) + { + EnabledInstrumentations = configuration.InstrumentationDevelopment?.DotNet?.Logs?.GetEnabledInstrumentations() ?? []; + + if (EnabledInstrumentations.Contains(LogInstrumentation.Log4Net)) + { + EnableLog4NetBridge = configuration.InstrumentationDevelopment?.DotNet?.Logs?.Log4Net?.BridgeEnabled ?? false; + } + } + private static IReadOnlyList ParseLogExporter(Configuration configuration) { var logExporterEnvVar = configuration.GetString(ConfigurationKeys.Logs.Exporter); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs index ed5dd28906..86c73c2096 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.AutoInstrumentation.Logging; @@ -66,6 +67,11 @@ protected override void OnLoadEnvVar(Configuration configuration) MetricsEnabled = configuration.GetBool(ConfigurationKeys.Metrics.MetricsEnabled) ?? true; } + protected override void OnLoadFile(YamlConfiguration configuration) + { + EnabledInstrumentations = configuration.InstrumentationDevelopment?.DotNet?.Metrics?.GetEnabledInstrumentations() ?? []; + } + private static IReadOnlyList ParseMetricExporter(Configuration configuration) { var metricsExporterEnvVar = configuration.GetString(ConfigurationKeys.Metrics.Exporter); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index bb3d6b01bf..c257f7c292 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -112,6 +112,10 @@ protected override void OnLoadFile(YamlConfiguration configuration) } Processors = processors; + + EnabledInstrumentations = configuration.InstrumentationDevelopment?.DotNet?.Traces?.GetEnabledInstrumentations() ?? []; + + InstrumentationOptions = new InstrumentationOptions(configuration.InstrumentationDevelopment?.DotNet?.Traces); } private static List ParseTracesExporter(Configuration configuration) diff --git a/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/AdditionalTag.cs b/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/AdditionalTag.cs index a47a7b8ba0..014d07c49e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/AdditionalTag.cs +++ b/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/AdditionalTag.cs @@ -34,4 +34,25 @@ public static AdditionalTag CreateHttpResponseCache(string key) { return new AdditionalTag(key, Constants.HttpSpanAttributes.AttributeHttpResponseHeaderPrefix); } + + public override bool Equals(object? obj) + { + if (obj is AdditionalTag other) + { + return Key == other.Key && TagName == other.TagName; + } + + return false; + } + + public override int GetHashCode() + { + unchecked + { + var hash = 17; + hash = (hash * 23) + (Key != null ? Key.GetHashCode() : 0); + hash = (hash * 23) + (TagName != null ? TagName.GetHashCode() : 0); + return hash; + } + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs b/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs index ff7aea146f..8d858bca27 100644 --- a/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs @@ -18,4 +18,21 @@ public static IReadOnlyList ParseHeaders(this Configuration sourc return headers.Select(stringToHeaderCacheConverter).ToArray(); } + + public static IReadOnlyList ParseHeaders(string? headersList, Func stringToHeaderCacheConverter) + { + if (string.IsNullOrWhiteSpace(headersList)) + { + return []; + } + + var headers = headersList!.Split([Constants.ConfigurationValues.Separator], StringSplitOptions.RemoveEmptyEntries); + + if (headers.Length == 0) + { + return []; + } + + return headers.Select(stringToHeaderCacheConverter).ToArray(); + } } diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs new file mode 100644 index 0000000000..b37bec364d --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs @@ -0,0 +1,150 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using OpenTelemetry.AutoInstrumentation.HeadersCapture; +using Xunit; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; + +public class FilebasedInstrumentationSettingsTests +{ + [Fact] + public void LoadFile_SetsEnabledTracesInstrumentations_IfPresent() + { + var instrumentation = new DotNetInstrumentation + { + Traces = new DotNetTraces + { + Azure = new object(), + Elasticsearch = new object() + } + }; + + var conf = new YamlConfiguration + { + InstrumentationDevelopment = new InstrumentationDevelopment + { + DotNet = instrumentation + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.NotNull(settings.EnabledInstrumentations); + Assert.Contains(TracerInstrumentation.Azure, settings.EnabledInstrumentations); + Assert.Contains(TracerInstrumentation.Elasticsearch, settings.EnabledInstrumentations); + } + + [Fact] + public void LoadFile_SetsEnabledTracesInstrumentationOption() + { + var instrumentation = new DotNetInstrumentation + { + Traces = new DotNetTraces + { + GrpcNetClient = new CaptureMetadataConfiguration + { + CaptureRequestMetadata = "x-request-id", + CaptureResponseMetadata = "x-response-id" + }, + OracleMda = new SetDbStatementForTextConfuguration + { + SetDbStatementForText = true + }, + HttpClient = new CaptureHeadersConfiguration + { + CaptureRequestHeaders = "x-request-id", + CaptureResponseHeaders = "x-response-id" + } + } + }; + + var conf = new YamlConfiguration + { + InstrumentationDevelopment = new InstrumentationDevelopment + { + DotNet = instrumentation + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.NotNull(settings.EnabledInstrumentations); + Assert.Contains(TracerInstrumentation.GrpcNetClient, settings.EnabledInstrumentations); + Assert.Contains(TracerInstrumentation.OracleMda, settings.EnabledInstrumentations); + Assert.Contains(TracerInstrumentation.HttpClient, settings.EnabledInstrumentations); + + Assert.True(settings.InstrumentationOptions.OracleMdaSetDbStatementForText); + Assert.Contains(AdditionalTag.CreateGrpcRequestCache("x-request-id"), settings.InstrumentationOptions.GrpcNetClientInstrumentationCaptureRequestMetadata); + Assert.Contains(AdditionalTag.CreateGrpcResponseCache("x-response-id"), settings.InstrumentationOptions.GrpcNetClientInstrumentationCaptureResponseMetadata); + Assert.Contains(AdditionalTag.CreateHttpRequestCache("x-request-id"), settings.InstrumentationOptions.HttpInstrumentationCaptureRequestHeaders); + Assert.Contains(AdditionalTag.CreateHttpResponseCache("x-response-id"), settings.InstrumentationOptions.HttpInstrumentationCaptureResponseHeaders); + } + + [Fact] + public void LoadFile_SetsEnabledMetricsInstrumentations_IfPresent() + { + var instrumentation = new DotNetInstrumentation + { + Metrics = new DotNetMetrics + { + HttpClient = new object(), + NetRuntime = new object() + } + }; + + var conf = new YamlConfiguration + { + InstrumentationDevelopment = new InstrumentationDevelopment + { + DotNet = instrumentation + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.NotNull(settings.EnabledInstrumentations); + Assert.Contains(MetricInstrumentation.HttpClient, settings.EnabledInstrumentations); + Assert.Contains(MetricInstrumentation.NetRuntime, settings.EnabledInstrumentations); + } + + [Fact] + public void LoadFile_SetsEnabledLogsInstrumentations_IfPresent() + { + var instrumentation = new DotNetInstrumentation + { + Logs = new DotNetLogs + { + ILogger = new object(), + Log4Net = new() + { + BridgeEnabled = true + }, + } + }; + + var conf = new YamlConfiguration + { + InstrumentationDevelopment = new InstrumentationDevelopment + { + DotNet = instrumentation + } + }; + + var settings = new LogSettings(); + + settings.LoadFile(conf); + + Assert.NotNull(settings.EnabledInstrumentations); + Assert.Contains(LogInstrumentation.ILogger, settings.EnabledInstrumentations); + Assert.Contains(LogInstrumentation.Log4Net, settings.EnabledInstrumentations); + Assert.True(settings.EnableLog4NetBridge); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml new file mode 100644 index 0000000000..f7d7926865 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml @@ -0,0 +1,23 @@ +instrumentation/development: + dotnet: + traces: + graphql: + set_document: true + oraclemda: + set_db_statement_for_text: true + aspnet: + capture_request_headers: "X-Key,X-Custom-Header,X-Header-Example" + capture_response_headers: "X-Key,X-Custom-Header,X-Header-Example" + aspnetcore: + capture_request_headers: "X-Key,X-Custom-Header,X-Header-Example" + capture_response_headers: "X-Key,X-Custom-Header,X-Header-Example" + httpclient: + capture_request_headers: "X-Key,X-Custom-Header,X-Header-Example" + capture_response_headers: "X-Key,X-Custom-Header,X-Header-Example" + grpcnetclient: + capture_request_metadata: "X-Key,X-Custom-Header,X-Header-Example" + capture_response_metadata: "X-Key,X-Custom-Header,X-Header-Example" + logs: + log4net: + bridge_enabled: true + diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml new file mode 100644 index 0000000000..8a849c345d --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml @@ -0,0 +1,38 @@ +instrumentation/development: + dotnet: + traces: + aspnet: + aspnetcore: + azure: + elasticsearch: + elastictransport: + entityframeworkcore: + graphql: + grpcnetclient: + httpclient: + kafka: + masstransit: + mongodb: + mysqlconnector: + mysqldata: + npgsql: + nservicebus: + oraclemda: + rabbitmq: + quartz: + sqlclient: + stackexchangeredis: + wcfclient: + wcfservice: + metrics: + aspnet: + aspnetcore: + httpclient: + netruntime: + nservicebus: + process: + sqlclient: + logs: + ilogger: + log4net: + diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs new file mode 100644 index 0000000000..fa456f87e6 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs @@ -0,0 +1,131 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Xunit; +using YamlParser = OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser.Parser; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased.Parser; + +public class ParserInstrumentationTests +{ + [Fact] + public void Parse_Instrumentation_ShouldPopulateModelCorrectly() + { + var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestInstrumentationFile.yaml"); + + Assert.NotNull(config); + Assert.NotNull(config.InstrumentationDevelopment); + Assert.NotNull(config.InstrumentationDevelopment.DotNet); + +#if NET + string[] expectedTraces = [ + "aspnetcore", "azure", "elasticsearch", "elastictransport", + "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", + "kafka", "masstransit", "mongodb", "mysqlconnector", + "mysqldata", "npgsql", "nservicebus", "oraclemda", "rabbitmq", + "quartz", "sqlclient", "stackexchangeredis", "wcfclient" + ]; +#endif +#if NETFRAMEWORK + string[] expectedTraces = [ + "aspnet", "azure", "elasticsearch", "elastictransport", + "grpcnetclient", "httpclient", "kafka", "mongodb", + "mysqlconnector", "npgsql", "nservicebus", "oraclemda", + "rabbitmq", "quartz", "sqlclient", "wcfclient", "wcfservice" + ]; +#endif + + var traces = config.InstrumentationDevelopment.DotNet.Traces; + Assert.NotNull(traces); + + foreach (var alias in expectedTraces) + { + FileBasedTestHelper.AssertAliasPropertyExists(traces, alias); + } + +#if NET + string[] expectedMetrics = + [ + "aspnetcore", "httpclient", "netruntime", + "nservicebus", "process", "sqlclient" + ]; +#endif +#if NETFRAMEWORK + string[] expectedMetrics = + [ + "aspnet", "httpclient", "netruntime", + "nservicebus", "process", "sqlclient" + ]; +#endif + + var metrics = config.InstrumentationDevelopment.DotNet.Metrics; + Assert.NotNull(metrics); + + foreach (var alias in expectedMetrics) + { + FileBasedTestHelper.AssertAliasPropertyExists(metrics, alias); + } + + string[] expectedLogs = ["ilogger", "log4net"]; + + var logs = config.InstrumentationDevelopment.DotNet.Logs; + Assert.NotNull(logs); + + foreach (var alias in expectedLogs) + { + FileBasedTestHelper.AssertAliasPropertyExists(logs, alias); + } + } + + [Fact] + public void Parse_InstrumentationConfiguration_ShouldPopulateModelCorrectly() + { + var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml"); + + Assert.NotNull(config); + Assert.NotNull(config.InstrumentationDevelopment); + Assert.NotNull(config.InstrumentationDevelopment.DotNet); + +#if NET + string[] expectedTraces = [ + "aspnetcore", "graphql", "grpcnetclient", "httpclient", "oraclemda" + ]; +#endif +#if NETFRAMEWORK + string[] expectedTraces = [ + "aspnet", "httpclient", "oraclemda", "grpcnetclient" + ]; +#endif + + var traces = config.InstrumentationDevelopment.DotNet.Traces; + Assert.NotNull(traces); + + foreach (var alias in expectedTraces) + { + FileBasedTestHelper.AssertAliasPropertyExists(traces, alias); + } + + var logs = config.InstrumentationDevelopment.DotNet.Logs; + Assert.NotNull(logs); + Assert.NotNull(logs.Log4Net); + + Assert.True(traces.OracleMda!.SetDbStatementForText); + Assert.Equal("X-Key,X-Custom-Header,X-Header-Example", traces.HttpClient!.CaptureRequestHeaders); + Assert.Equal("X-Key,X-Custom-Header,X-Header-Example", traces.HttpClient!.CaptureResponseHeaders); + + Assert.Equal("X-Key,X-Custom-Header,X-Header-Example", traces.GrpcNetClient!.CaptureRequestMetadata); + Assert.Equal("X-Key,X-Custom-Header,X-Header-Example", traces.GrpcNetClient!.CaptureResponseMetadata); +#if NET + Assert.True(traces.GraphQL!.SetDocument); + + Assert.Equal("X-Key,X-Custom-Header,X-Header-Example", traces.AspNetCore!.CaptureRequestHeaders); + Assert.Equal("X-Key,X-Custom-Header,X-Header-Example", traces.AspNetCore!.CaptureResponseHeaders); + +#endif +#if NETFRAMEWORK + Assert.Equal("X-Key,X-Custom-Header,X-Header-Example", traces.AspNet!.CaptureRequestHeaders); + Assert.Equal("X-Key,X-Custom-Header,X-Header-Example", traces.AspNet!.CaptureResponseHeaders); +#endif + Assert.True(logs.Log4Net.BridgeEnabled); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj index 1bd11da871..f866f161f3 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj @@ -12,6 +12,12 @@ + + PreserveNewest + + + PreserveNewest + PreserveNewest