diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 9ef632ca60..88c80dfede 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -63,3 +63,99 @@ resource: process: # Detects process-level attributes (process.*) processruntime: # Detects process runtime attributes (process.runtime.*) ``` + +## Instrumentation Configuration + +You can configure traces, metrics, and logs instrumentations. +For more details and updates, see: [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 (.NET Framework) MVC/WebApi [Framework only] + aspnetcore: # ASP.NET Core [Core only] + azure: # Azure SDK [Core & Framework] + elasticsearch: # Elastic.Clients.Elasticsearch [Core & Framework] + elastictransport: # Elastic.Transport (>=0.4.16) [Core & Framework] + entityframeworkcore: # Entity Framework Core (>=6.0.12) [Core only] + graphql: # GraphQL (>=7.5.0) [Core only] + grpcnetclient: # Grpc.Net.Client (>=2.52.0 & <3.0.0) [Core & Framework] + httpclient: # System.Net.Http.HttpClient [Core & Framework] + kafka: # Confluent.Kafka (>=1.4.0 & <3.0.0) [Core & Framework] + masstransit: # MassTransit (>=8.0.0) [Core only] + mongodb: # MongoDB.Driver (>=2.7.0 <4.0.0) [Core & Framework] + mysqlconnector: # MySqlConnector (>=2.0.0) [Core only] + mysqldata: # MySql.Data (>=8.1.0) [Core only] + npgsql: # Npgsql (>=6.0.0) [Core only] + nservicebus: # NServiceBus (>=8.0.0 & <10.0.0) [Core & Framework] + oraclemda: # Oracle.ManagedDataAccess (>=23.4.0) [Core only] + rabbitmq: # RabbitMQ.Client (>=6.0.0) [Core & Framework] + quartz: # Quartz (>=3.4.0, not supported < .NET Framework 4.7.2) + sqlclient: # Microsoft.Data.SqlClient & System.Data.SqlClient [Core & Framework] + stackexchangeredis: # StackExchange.Redis (>=2.6.122 & <3.0.0) [Core only] + wcfclient: # WCF Client [Core & Framework] + wcfservice: # WCF Service [Framework only] + metrics: + aspnet: # ASP.NET metrics [Framework only] + aspnetcore: # ASP.NET Core metrics [Core only] + httpclient: # HttpClient metrics [Core & Framework] + netruntime: # .NET Runtime metrics [Core only] + nservicebus: # NServiceBus metrics [Core & Framework] + process: # Process metrics [Core & Framework] + sqlclient: # SQL Client metrics [Core & Framework] + logs: + ilogger: # Microsoft.Extensions.Logging (>=9.0.0) [Core & Framework] + log4net: # log4net (>=2.0.13 && <4.0.0) [Core & Framework] +``` + +## Instrumentation options + +``` yaml +instrumentation/development: + dotnet: + traces: + entityframeworkcore: + # Whether the Entity Framework Core 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 + 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 + sqlclient: + # Whether the SQL 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. + # Not supported on .NET Framework for System.Data.SqlClient. + # 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 +``` 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..f6c99a0778 --- /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 SetDbStatementForTextConfuguration? 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..0f498b9f39 --- /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_enbaled")] + 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 8e0fbf259e..c30f825638 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; @@ -22,4 +24,12 @@ 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; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs index 4fc1a1aa0a..94b59087fd 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; @@ -30,28 +31,76 @@ 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.EntityFrameworkCore != null) + { + EntityFrameworkCoreSetDbStatementForText = instrumentationConfiguration.EntityFrameworkCore.SetDbStatementForText; + } + + 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 text query in Entity Framework Core can be passed as a db.statement tag. @@ -67,22 +116,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 78732e0da8..18a9b49541 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.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; @@ -93,6 +94,13 @@ protected override void OnLoadEnvVar(Configuration configuration) InstrumentationOptions = new InstrumentationOptions(configuration); } + protected override void OnLoadFile(YamlConfiguration configuration) + { + EnabledInstrumentations = configuration.InstrumentationDevelopment?.DotNet?.Traces?.GetEnabledInstrumentations() ?? []; + + InstrumentationOptions = new InstrumentationOptions(configuration.InstrumentationDevelopment?.DotNet?.Traces); + } + private static IReadOnlyList ParseTracesExporter(Configuration configuration) { var tracesExporterEnvVar = configuration.GetString(ConfigurationKeys.Traces.Exporter); 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..ddbc8c8203 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml @@ -0,0 +1,25 @@ +instrumentation/development: + dotnet: + traces: + entityframeworkcore: + set_db_statement_for_text: true + 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..63258da73e --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs @@ -0,0 +1,132 @@ +// 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", "entityframeworkcore", "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.True(traces.EntityFrameworkCore!.SetDbStatementForText); + + 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 50c9bfa3f0..8a50dbe28a 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