From 10d1342dcc4c177cb4af033a4d2c5a8bea223637 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 29 Sep 2025 12:32:09 +0200 Subject: [PATCH 01/21] [FileBased] Add Instrumentation --- .../Configurations/ConfigurationExtensions.cs | 4 +- .../CaptureHeadersConfiguration.cs | 25 +++ .../CaptureMetadataConfiguration.cs | 25 +++ .../DotNetInstrumentation.cs | 27 +++ .../FileBasedConfiguration/DotNetLogs.cs | 41 ++++ .../FileBasedConfiguration/DotNetMetrics.cs | 79 ++++++++ .../FileBasedConfiguration/DotNetTraces.cs | 175 ++++++++++++++++++ .../InstrumentationDevelopment.cs | 15 ++ .../SetDbStatementForTextConfuguration.cs | 18 ++ .../SetDocumentConfiguration.cs | 18 ++ .../YamlConfiguration.cs | 10 + .../Configurations/InstrumentationOptions.cs | 65 ++++++- .../Configurations/LogSettings.cs | 6 + .../Configurations/MetricSettings.cs | 6 + .../Configurations/TracerSettings.cs | 8 + .../RegexGenerator.g.cs | 8 +- .../HeaderConfigurationExtensions.cs | 17 ++ .../FilebasedInstrumentationSettingsTests.cs | 140 ++++++++++++++ .../Files/TestInstrumentationFile.yaml | 37 ++++ .../Parser/ParserInstrumentationTests.cs | 79 ++++++++ ...Telemetry.AutoInstrumentation.Tests.csproj | 3 + 21 files changed, 792 insertions(+), 14 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs 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..302cad8780 --- /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 object? 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..4345eddb3c --- /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 SetDocumentConfiguration? 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/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/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/SetDocumentConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs new file mode 100644 index 0000000000..b2baee5616 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.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 SetDocumentConfiguration +{ + /// + /// 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/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..d316d47ce2 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,11 @@ protected override void OnLoadEnvVar(Configuration configuration) enabledConfigurationTemplate: ConfigurationKeys.Logs.EnabledLogsInstrumentationTemplate); } + protected override void OnLoadFile(YamlConfiguration configuration) + { + EnabledInstrumentations = configuration.InstrumentationDevelopment?.DotNet?.Logs?.GetEnabledInstrumentations() ?? []; + } + 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/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs b/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs index 4fd90b8111..dfab32133e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs @@ -25,7 +25,7 @@ partial class EnvVarTypeConverter /// ○ Match '}'.
/// /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.41914")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.36514")] private static partial global::System.Text.RegularExpressions.Regex GetEnvVarRegex() => global::System.Text.RegularExpressions.Generated.GetEnvVarRegex_0.Instance; } } @@ -43,7 +43,7 @@ namespace System.Text.RegularExpressions.Generated using System.Threading; /// Custom -derived type for the GetEnvVarRegex method. - [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.41914")] + [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.36514")] file sealed class GetEnvVarRegex_0 : Regex { /// Cached, thread-safe singleton instance. @@ -59,7 +59,7 @@ private GetEnvVarRegex_0() base.factory = new RunnerFactory(); base.capsize = 3; } - + /// Provides a factory for creating instances to be used by methods on . private sealed class RunnerFactory : RegexRunnerFactory { @@ -324,7 +324,7 @@ void UncaptureUntil(int capturePosition) } /// Helper methods used by generated -derived implementations. - [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.41914")] + [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.36514")] file static class Utilities { /// Default timeout value set in , or if none was set. 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..ebc3476978 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs @@ -0,0 +1,140 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +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 = new[] { "x-request-id", "x-b3-traceid" }, + CaptureResponseMetadata = new[] { "x-response-id", "x-b3-traceid" } + }, +#if NET + EntityFrameworkCore = new SetDbStatementForTextConfuguration + { + SetDbStatementForText = true + }, +#endif + HttpClient = new CaptureHeadersConfiguration + { + CaptureRequestHeaders = new[] { "x-request-id", "x-b3-traceid" }, + CaptureResponseHeaders = new[] { "x-response-id", "x-b3-traceid" } + } + } + }; + + 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_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 object(), + } + }; + + 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); + } +} 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..cb7919c494 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml @@ -0,0 +1,37 @@ +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: + 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..e0d410029c --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs @@ -0,0 +1,79 @@ +// 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_FullConfigYaml_ShouldPopulateModelCorrectly() + { + var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestInstrumentatioFile.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); + } + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj index 50c9bfa3f0..ea7d1f44ef 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj @@ -12,6 +12,9 @@ + + PreserveNewest + PreserveNewest From a5ac594da5e13393208788e73f780d3e15f64551 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 13:54:56 +0200 Subject: [PATCH 02/21] [File-Based] Add Instrumentation option tests --- .../HeadersCapture/AdditionalTag.cs | 21 ++++++++ .../FilebasedInstrumentationSettingsTests.cs | 26 ++++++---- .../TestInstrumentationConfigurationFile.yaml | 22 ++++++++ .../Parser/ParserInstrumentationTests.cs | 52 ++++++++++++++++++- ...Telemetry.AutoInstrumentation.Tests.csproj | 3 ++ 5 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml 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/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs index ebc3476978..88be64b899 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs @@ -3,6 +3,7 @@ using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using OpenTelemetry.AutoInstrumentation.HeadersCapture; using Xunit; namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; @@ -41,25 +42,23 @@ public void LoadFile_SetsEnabledTracesInstrumentations_IfPresent() [Fact] public void LoadFile_SetsEnabledTracesInstrumentationOption() { -/* var instrumentation = new DotNetInstrumentation + var instrumentation = new DotNetInstrumentation { Traces = new DotNetTraces { GrpcNetClient = new CaptureMetadataConfiguration { - CaptureRequestMetadata = new[] { "x-request-id", "x-b3-traceid" }, - CaptureResponseMetadata = new[] { "x-response-id", "x-b3-traceid" } + CaptureRequestMetadata = "x-request-id", + CaptureResponseMetadata = "x-response-id" }, -#if NET - EntityFrameworkCore = new SetDbStatementForTextConfuguration + OracleMda = new SetDbStatementForTextConfuguration { SetDbStatementForText = true }, -#endif HttpClient = new CaptureHeadersConfiguration { - CaptureRequestHeaders = new[] { "x-request-id", "x-b3-traceid" }, - CaptureResponseHeaders = new[] { "x-response-id", "x-b3-traceid" } + CaptureRequestHeaders = "x-request-id", + CaptureResponseHeaders = "x-response-id" } } }; @@ -77,8 +76,15 @@ public void LoadFile_SetsEnabledTracesInstrumentationOption() settings.LoadFile(conf); Assert.NotNull(settings.EnabledInstrumentations); - Assert.Contains(TracerInstrumentation.Azure, settings.EnabledInstrumentations); - Assert.Contains(TracerInstrumentation.Elasticsearch, 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] 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..77e591634a --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml @@ -0,0 +1,22 @@ +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=Value" + capture_response_headers: "X-Key=Value" + aspnetcore: + capture_request_headers: "X-Key=Value" + capture_response_headers: "X-Key=Value" + httpclient: + capture_request_headers: "X-Key=Value" + capture_response_headers: "X-Key=Value" + grpcnetclient: + capture_request_metadata: "X-Key=Value" + capture_response_metadata: "X-Key=Value" + diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs index e0d410029c..fcafb42769 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs @@ -9,9 +9,9 @@ namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased.Parse public class ParserInstrumentationTests { [Fact] - public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() + public void Parse_Instrumentation_ShouldPopulateModelCorrectly() { - var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestInstrumentatioFile.yaml"); + var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestInstrumentationFile.yaml"); Assert.NotNull(config); Assert.NotNull(config.InstrumentationDevelopment); @@ -76,4 +76,52 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() 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); + } + + Assert.True(traces.OracleMda!.SetDbStatementForText); + Assert.Equal("X-Key=Value", traces.HttpClient!.CaptureRequestHeaders); + Assert.Equal("X-Key=Value", traces.HttpClient!.CaptureResponseHeaders); + + Assert.Equal("X-Key=Value", traces.GrpcNetClient!.CaptureRequestMetadata); + Assert.Equal("X-Key=Value", traces.GrpcNetClient!.CaptureResponseMetadata); +#if NET + Assert.True(traces.GraphQL!.SetDocument); + Assert.True(traces.EntityFrameworkCore!.SetDbStatementForText); + + Assert.Equal("X-Key=Value", traces.AspNetCore!.CaptureRequestHeaders); + Assert.Equal("X-Key=Value", traces.AspNetCore!.CaptureResponseHeaders); + +#endif +#if NETFRAMEWORK + Assert.Equal("X-Key=Value", traces.AspNet!.CaptureRequestHeaders); + Assert.Equal("X-Key=Value", traces.AspNet!.CaptureResponseHeaders); +#endif + } } diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj index ea7d1f44ef..8a50dbe28a 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj @@ -12,6 +12,9 @@ + + PreserveNewest + PreserveNewest From bde4ef5ae7b2bccabe64726c28fdfaab87990132 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 13:58:24 +0200 Subject: [PATCH 03/21] [File-Based] Add instrumentation docs --- docs/file-based-configuration.md | 89 ++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 9ef632ca60..9ef9fbf811 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -63,3 +63,92 @@ 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) + +``` 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: + 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=Value" + # 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=Value" + 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=Value" + # 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=Value" + 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=Value" + # 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=Value" + 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=Value" + # 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=Value" +``` From bb63fe8a7e9248b28721e5558217d5b13883faf2 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 14:29:36 +0200 Subject: [PATCH 04/21] fix --- .../RegexGenerator.g.cs | 428 ------------------ 1 file changed, 428 deletions(-) delete mode 100644 src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs diff --git a/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs b/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs deleted file mode 100644 index dfab32133e..0000000000 --- a/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs +++ /dev/null @@ -1,428 +0,0 @@ -// -#nullable enable -#pragma warning disable CS0162 // Unreachable code -#pragma warning disable CS0164 // Unreferenced label -#pragma warning disable CS0219 // Variable assigned but never used - -namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser -{ - partial class EnvVarTypeConverter - { - /// - /// Pattern:
- /// \\$\\{([A-Z0-9_]+)(?::-([^}]*))?\\}
- /// Options:
- /// RegexOptions.Compiled
- /// Explanation:
- /// - /// ○ Match the string "${".
- /// ○ 1st capture group.
- /// ○ Match a character in the set [0-9A-Z_] greedily at least once.
- /// ○ Optional (greedy).
- /// ○ Match the string ":-".
- /// ○ 2nd capture group.
- /// ○ Match a character other than '}' greedily any number of times.
- /// ○ Match '}'.
- ///
- ///
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.36514")] - private static partial global::System.Text.RegularExpressions.Regex GetEnvVarRegex() => global::System.Text.RegularExpressions.Generated.GetEnvVarRegex_0.Instance; - } -} - -namespace System.Text.RegularExpressions.Generated -{ - using System; - using System.Buffers; - using System.CodeDom.Compiler; - using System.Collections; - using System.ComponentModel; - using System.Globalization; - using System.Runtime.CompilerServices; - using System.Text.RegularExpressions; - using System.Threading; - - /// Custom -derived type for the GetEnvVarRegex method. - [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.36514")] - file sealed class GetEnvVarRegex_0 : Regex - { - /// Cached, thread-safe singleton instance. - internal static readonly GetEnvVarRegex_0 Instance = new(); - - /// Initializes the instance. - private GetEnvVarRegex_0() - { - base.pattern = "\\$\\{([A-Z0-9_]+)(?::-([^}]*))?\\}"; - base.roptions = RegexOptions.Compiled; - ValidateMatchTimeout(Utilities.s_defaultTimeout); - base.internalMatchTimeout = Utilities.s_defaultTimeout; - base.factory = new RunnerFactory(); - base.capsize = 3; - } - - /// Provides a factory for creating instances to be used by methods on . - private sealed class RunnerFactory : RegexRunnerFactory - { - /// Creates an instance of a used by methods on . - protected override RegexRunner CreateInstance() => new Runner(); - - /// Provides the runner that contains the custom logic implementing the specified regular expression. - private sealed class Runner : RegexRunner - { - /// Scan the starting from base.runtextstart for the next match. - /// The text being scanned by the regular expression. - protected override void Scan(ReadOnlySpan inputSpan) - { - // Search until we can't find a valid starting position, we find a match, or we reach the end of the input. - while (TryFindNextPossibleStartingPosition(inputSpan) && - !TryMatchAtCurrentPosition(inputSpan) && - base.runtextpos != inputSpan.Length) - { - base.runtextpos++; - if (Utilities.s_hasTimeout) - { - base.CheckTimeout(); - } - } - } - - /// Search starting from base.runtextpos for the next location a match could possibly start. - /// The text being scanned by the regular expression. - /// true if a possible match was found; false if no more matches are possible. - private bool TryFindNextPossibleStartingPosition(ReadOnlySpan inputSpan) - { - int pos = base.runtextpos; - - // Any possible match is at least 4 characters. - if (pos <= inputSpan.Length - 4) - { - // The pattern has the literal "${" at the beginning of the pattern. Find the next occurrence. - // If it can't be found, there's no match. - int i = inputSpan.Slice(pos).IndexOf("${"); - if (i >= 0) - { - base.runtextpos = pos + i; - return true; - } - } - - // No match found. - base.runtextpos = inputSpan.Length; - return false; - } - - /// Determine whether at base.runtextpos is a match for the regular expression. - /// The text being scanned by the regular expression. - /// true if the regular expression matches at the current position; otherwise, false. - private bool TryMatchAtCurrentPosition(ReadOnlySpan inputSpan) - { - int pos = base.runtextpos; - int matchStart = pos; - int capture_starting_pos = 0; - int charloop_capture_pos = 0; - int charloop_starting_pos = 0, charloop_ending_pos = 0; - int charloop_starting_pos1 = 0, charloop_ending_pos1 = 0; - int loop_iteration = 0; - int stackpos = 0; - ReadOnlySpan slice = inputSpan.Slice(pos); - - // Match the string "${". - if (!slice.StartsWith("${")) - { - UncaptureUntil(0); - return false; // The input didn't match. - } - - // 1st capture group. - //{ - pos += 2; - slice = inputSpan.Slice(pos); - capture_starting_pos = pos; - - // Match a character in the set [0-9A-Z_] greedily at least once. - //{ - charloop_starting_pos = pos; - - int iteration = slice.IndexOfAnyExcept(Utilities.s_ascii_FF03FEFFFF8700000000); - if (iteration < 0) - { - iteration = slice.Length; - } - - if (iteration == 0) - { - UncaptureUntil(0); - return false; // The input didn't match. - } - - slice = slice.Slice(iteration); - pos += iteration; - - charloop_ending_pos = pos; - charloop_starting_pos++; - goto CharLoopEnd; - - CharLoopBacktrack: - UncaptureUntil(charloop_capture_pos); - - if (Utilities.s_hasTimeout) - { - base.CheckTimeout(); - } - - if (charloop_starting_pos >= charloop_ending_pos) - { - UncaptureUntil(0); - return false; // The input didn't match. - } - pos = --charloop_ending_pos; - slice = inputSpan.Slice(pos); - - CharLoopEnd: - charloop_capture_pos = base.Crawlpos(); - //} - - base.Capture(1, capture_starting_pos, pos); - - goto CaptureSkipBacktrack; - - CaptureBacktrack: - goto CharLoopBacktrack; - - CaptureSkipBacktrack:; - //} - - // Optional (greedy). - //{ - loop_iteration = 0; - - LoopBody: - Utilities.StackPush(ref base.runstack!, ref stackpos, base.Crawlpos(), pos); - - loop_iteration++; - - // Match the string ":-". - if (!slice.StartsWith(":-")) - { - goto LoopIterationNoMatch; - } - - // 2nd capture group. - //{ - pos += 2; - slice = inputSpan.Slice(pos); - int capture_starting_pos1 = pos; - - // Match a character other than '}' greedily any number of times. - //{ - charloop_starting_pos1 = pos; - - int iteration1 = slice.IndexOf('}'); - if (iteration1 < 0) - { - iteration1 = slice.Length; - } - - slice = slice.Slice(iteration1); - pos += iteration1; - - charloop_ending_pos1 = pos; - goto CharLoopEnd1; - - CharLoopBacktrack1: - UncaptureUntil(base.runstack![--stackpos]); - Utilities.StackPop(base.runstack!, ref stackpos, out charloop_ending_pos1, out charloop_starting_pos1); - - if (Utilities.s_hasTimeout) - { - base.CheckTimeout(); - } - - if (charloop_starting_pos1 >= charloop_ending_pos1) - { - goto LoopIterationNoMatch; - } - pos = --charloop_ending_pos1; - slice = inputSpan.Slice(pos); - - CharLoopEnd1: - Utilities.StackPush(ref base.runstack!, ref stackpos, charloop_starting_pos1, charloop_ending_pos1, base.Crawlpos()); - //} - - base.Capture(2, capture_starting_pos1, pos); - - Utilities.StackPush(ref base.runstack!, ref stackpos, capture_starting_pos1); - goto CaptureSkipBacktrack1; - - CaptureBacktrack1: - capture_starting_pos1 = base.runstack![--stackpos]; - goto CharLoopBacktrack1; - - CaptureSkipBacktrack1:; - //} - - - // The loop has an upper bound of 1. Continue iterating greedily if it hasn't yet been reached. - if (loop_iteration == 0) - { - goto LoopBody; - } - goto LoopEnd; - - // The loop iteration failed. Put state back to the way it was before the iteration. - LoopIterationNoMatch: - if (--loop_iteration < 0) - { - // Unable to match the remainder of the expression after exhausting the loop. - goto CaptureBacktrack; - } - pos = base.runstack![--stackpos]; - UncaptureUntil(base.runstack![--stackpos]); - slice = inputSpan.Slice(pos); - goto LoopEnd; - - LoopBacktrack: - if (Utilities.s_hasTimeout) - { - base.CheckTimeout(); - } - - if (loop_iteration == 0) - { - // No iterations of the loop remain to backtrack into. Fail the loop. - goto CaptureBacktrack; - } - goto CaptureBacktrack1; - LoopEnd:; - //} - - // Match '}'. - if (slice.IsEmpty || slice[0] != '}') - { - goto LoopBacktrack; - } - - // The input matched. - pos++; - base.runtextpos = pos; - base.Capture(0, matchStart, pos); - return true; - - // Undo captures until it reaches the specified capture position. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void UncaptureUntil(int capturePosition) - { - while (base.Crawlpos() > capturePosition) - { - base.Uncapture(); - } - } - } - } - } - - } - - /// Helper methods used by generated -derived implementations. - [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.36514")] - file static class Utilities - { - /// Default timeout value set in , or if none was set. - internal static readonly TimeSpan s_defaultTimeout = AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeout ? timeout : Regex.InfiniteMatchTimeout; - - /// Whether is non-infinite. - internal static readonly bool s_hasTimeout = s_defaultTimeout != Regex.InfiniteMatchTimeout; - - /// Pops 2 values from the backtracking stack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void StackPop(int[] stack, ref int pos, out int arg0, out int arg1) - { - arg0 = stack[--pos]; - arg1 = stack[--pos]; - } - - /// Pushes 1 value onto the backtracking stack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void StackPush(ref int[] stack, ref int pos, int arg0) - { - // If there's space available for the value, store it. - int[] s = stack; - int p = pos; - if ((uint)p < (uint)s.Length) - { - s[p] = arg0; - pos++; - return; - } - - // Otherwise, resize the stack to make room and try again. - WithResize(ref stack, ref pos, arg0); - - // Resize the backtracking stack array and push 1 value onto the stack. - [MethodImpl(MethodImplOptions.NoInlining)] - static void WithResize(ref int[] stack, ref int pos, int arg0) - { - Array.Resize(ref stack, (pos + 0) * 2); - StackPush(ref stack, ref pos, arg0); - } - } - - /// Pushes 2 values onto the backtracking stack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1) - { - // If there's space available for all 2 values, store them. - int[] s = stack; - int p = pos; - if ((uint)(p + 1) < (uint)s.Length) - { - s[p] = arg0; - s[p + 1] = arg1; - pos += 2; - return; - } - - // Otherwise, resize the stack to make room and try again. - WithResize(ref stack, ref pos, arg0, arg1); - - // Resize the backtracking stack array and push 2 values onto the stack. - [MethodImpl(MethodImplOptions.NoInlining)] - static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1) - { - Array.Resize(ref stack, (pos + 1) * 2); - StackPush(ref stack, ref pos, arg0, arg1); - } - } - - /// Pushes 3 values onto the backtracking stack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1, int arg2) - { - // If there's space available for all 3 values, store them. - int[] s = stack; - int p = pos; - if ((uint)(p + 2) < (uint)s.Length) - { - s[p] = arg0; - s[p + 1] = arg1; - s[p + 2] = arg2; - pos += 3; - return; - } - - // Otherwise, resize the stack to make room and try again. - WithResize(ref stack, ref pos, arg0, arg1, arg2); - - // Resize the backtracking stack array and push 3 values onto the stack. - [MethodImpl(MethodImplOptions.NoInlining)] - static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1, int arg2) - { - Array.Resize(ref stack, (pos + 2) * 2); - StackPush(ref stack, ref pos, arg0, arg1, arg2); - } - } - - /// Supports searching for characters in or not in "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_". - internal static readonly SearchValues s_ascii_FF03FEFFFF8700000000 = SearchValues.Create("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_"); - } -} From 0eab3d195d4932fd52c8b17b1c5f1f294af10106 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 15:44:01 +0200 Subject: [PATCH 05/21] fix --- .../RegexGenerator.g.cs | 428 ++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs diff --git a/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs b/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs new file mode 100644 index 0000000000..0174f7df36 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs @@ -0,0 +1,428 @@ +// +#nullable enable +#pragma warning disable CS0162 // Unreachable code +#pragma warning disable CS0164 // Unreferenced label +#pragma warning disable CS0219 // Variable assigned but never used + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser +{ + partial class EnvVarTypeConverter + { + /// + /// Pattern:
+ /// \\$\\{([A-Z0-9_]+)(?::-([^}]*))?\\}
+ /// Options:
+ /// RegexOptions.Compiled
+ /// Explanation:
+ /// + /// ○ Match the string "${".
+ /// ○ 1st capture group.
+ /// ○ Match a character in the set [0-9A-Z_] greedily at least once.
+ /// ○ Optional (greedy).
+ /// ○ Match the string ":-".
+ /// ○ 2nd capture group.
+ /// ○ Match a character other than '}' greedily any number of times.
+ /// ○ Match '}'.
+ ///
+ ///
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.41914")] + private static partial global::System.Text.RegularExpressions.Regex GetEnvVarRegex() => global::System.Text.RegularExpressions.Generated.GetEnvVarRegex_0.Instance; + } +} + +namespace System.Text.RegularExpressions.Generated +{ + using System; + using System.Buffers; + using System.CodeDom.Compiler; + using System.Collections; + using System.ComponentModel; + using System.Globalization; + using System.Runtime.CompilerServices; + using System.Text.RegularExpressions; + using System.Threading; + + /// Custom -derived type for the GetEnvVarRegex method. + [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.41914")] + file sealed class GetEnvVarRegex_0 : Regex + { + /// Cached, thread-safe singleton instance. + internal static readonly GetEnvVarRegex_0 Instance = new(); + + /// Initializes the instance. + private GetEnvVarRegex_0() + { + base.pattern = "\\$\\{([A-Z0-9_]+)(?::-([^}]*))?\\}"; + base.roptions = RegexOptions.Compiled; + ValidateMatchTimeout(Utilities.s_defaultTimeout); + base.internalMatchTimeout = Utilities.s_defaultTimeout; + base.factory = new RunnerFactory(); + base.capsize = 3; + } + + /// Provides a factory for creating instances to be used by methods on . + private sealed class RunnerFactory : RegexRunnerFactory + { + /// Creates an instance of a used by methods on . + protected override RegexRunner CreateInstance() => new Runner(); + + /// Provides the runner that contains the custom logic implementing the specified regular expression. + private sealed class Runner : RegexRunner + { + /// Scan the starting from base.runtextstart for the next match. + /// The text being scanned by the regular expression. + protected override void Scan(ReadOnlySpan inputSpan) + { + // Search until we can't find a valid starting position, we find a match, or we reach the end of the input. + while (TryFindNextPossibleStartingPosition(inputSpan) && + !TryMatchAtCurrentPosition(inputSpan) && + base.runtextpos != inputSpan.Length) + { + base.runtextpos++; + if (Utilities.s_hasTimeout) + { + base.CheckTimeout(); + } + } + } + + /// Search starting from base.runtextpos for the next location a match could possibly start. + /// The text being scanned by the regular expression. + /// true if a possible match was found; false if no more matches are possible. + private bool TryFindNextPossibleStartingPosition(ReadOnlySpan inputSpan) + { + int pos = base.runtextpos; + + // Any possible match is at least 4 characters. + if (pos <= inputSpan.Length - 4) + { + // The pattern has the literal "${" at the beginning of the pattern. Find the next occurrence. + // If it can't be found, there's no match. + int i = inputSpan.Slice(pos).IndexOf("${"); + if (i >= 0) + { + base.runtextpos = pos + i; + return true; + } + } + + // No match found. + base.runtextpos = inputSpan.Length; + return false; + } + + /// Determine whether at base.runtextpos is a match for the regular expression. + /// The text being scanned by the regular expression. + /// true if the regular expression matches at the current position; otherwise, false. + private bool TryMatchAtCurrentPosition(ReadOnlySpan inputSpan) + { + int pos = base.runtextpos; + int matchStart = pos; + int capture_starting_pos = 0; + int charloop_capture_pos = 0; + int charloop_starting_pos = 0, charloop_ending_pos = 0; + int charloop_starting_pos1 = 0, charloop_ending_pos1 = 0; + int loop_iteration = 0; + int stackpos = 0; + ReadOnlySpan slice = inputSpan.Slice(pos); + + // Match the string "${". + if (!slice.StartsWith("${")) + { + UncaptureUntil(0); + return false; // The input didn't match. + } + + // 1st capture group. + //{ + pos += 2; + slice = inputSpan.Slice(pos); + capture_starting_pos = pos; + + // Match a character in the set [0-9A-Z_] greedily at least once. + //{ + charloop_starting_pos = pos; + + int iteration = slice.IndexOfAnyExcept(Utilities.s_ascii_FF03FEFFFF8700000000); + if (iteration < 0) + { + iteration = slice.Length; + } + + if (iteration == 0) + { + UncaptureUntil(0); + return false; // The input didn't match. + } + + slice = slice.Slice(iteration); + pos += iteration; + + charloop_ending_pos = pos; + charloop_starting_pos++; + goto CharLoopEnd; + + CharLoopBacktrack: + UncaptureUntil(charloop_capture_pos); + + if (Utilities.s_hasTimeout) + { + base.CheckTimeout(); + } + + if (charloop_starting_pos >= charloop_ending_pos) + { + UncaptureUntil(0); + return false; // The input didn't match. + } + pos = --charloop_ending_pos; + slice = inputSpan.Slice(pos); + + CharLoopEnd: + charloop_capture_pos = base.Crawlpos(); + //} + + base.Capture(1, capture_starting_pos, pos); + + goto CaptureSkipBacktrack; + + CaptureBacktrack: + goto CharLoopBacktrack; + + CaptureSkipBacktrack:; + //} + + // Optional (greedy). + //{ + loop_iteration = 0; + + LoopBody: + Utilities.StackPush(ref base.runstack!, ref stackpos, base.Crawlpos(), pos); + + loop_iteration++; + + // Match the string ":-". + if (!slice.StartsWith(":-")) + { + goto LoopIterationNoMatch; + } + + // 2nd capture group. + //{ + pos += 2; + slice = inputSpan.Slice(pos); + int capture_starting_pos1 = pos; + + // Match a character other than '}' greedily any number of times. + //{ + charloop_starting_pos1 = pos; + + int iteration1 = slice.IndexOf('}'); + if (iteration1 < 0) + { + iteration1 = slice.Length; + } + + slice = slice.Slice(iteration1); + pos += iteration1; + + charloop_ending_pos1 = pos; + goto CharLoopEnd1; + + CharLoopBacktrack1: + UncaptureUntil(base.runstack![--stackpos]); + Utilities.StackPop(base.runstack!, ref stackpos, out charloop_ending_pos1, out charloop_starting_pos1); + + if (Utilities.s_hasTimeout) + { + base.CheckTimeout(); + } + + if (charloop_starting_pos1 >= charloop_ending_pos1) + { + goto LoopIterationNoMatch; + } + pos = --charloop_ending_pos1; + slice = inputSpan.Slice(pos); + + CharLoopEnd1: + Utilities.StackPush(ref base.runstack!, ref stackpos, charloop_starting_pos1, charloop_ending_pos1, base.Crawlpos()); + //} + + base.Capture(2, capture_starting_pos1, pos); + + Utilities.StackPush(ref base.runstack!, ref stackpos, capture_starting_pos1); + goto CaptureSkipBacktrack1; + + CaptureBacktrack1: + capture_starting_pos1 = base.runstack![--stackpos]; + goto CharLoopBacktrack1; + + CaptureSkipBacktrack1:; + //} + + + // The loop has an upper bound of 1. Continue iterating greedily if it hasn't yet been reached. + if (loop_iteration == 0) + { + goto LoopBody; + } + goto LoopEnd; + + // The loop iteration failed. Put state back to the way it was before the iteration. + LoopIterationNoMatch: + if (--loop_iteration < 0) + { + // Unable to match the remainder of the expression after exhausting the loop. + goto CaptureBacktrack; + } + pos = base.runstack![--stackpos]; + UncaptureUntil(base.runstack![--stackpos]); + slice = inputSpan.Slice(pos); + goto LoopEnd; + + LoopBacktrack: + if (Utilities.s_hasTimeout) + { + base.CheckTimeout(); + } + + if (loop_iteration == 0) + { + // No iterations of the loop remain to backtrack into. Fail the loop. + goto CaptureBacktrack; + } + goto CaptureBacktrack1; + LoopEnd:; + //} + + // Match '}'. + if (slice.IsEmpty || slice[0] != '}') + { + goto LoopBacktrack; + } + + // The input matched. + pos++; + base.runtextpos = pos; + base.Capture(0, matchStart, pos); + return true; + + // Undo captures until it reaches the specified capture position. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void UncaptureUntil(int capturePosition) + { + while (base.Crawlpos() > capturePosition) + { + base.Uncapture(); + } + } + } + } + } + + } + + /// Helper methods used by generated -derived implementations. + [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.41914")] + file static class Utilities + { + /// Default timeout value set in , or if none was set. + internal static readonly TimeSpan s_defaultTimeout = AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeout ? timeout : Regex.InfiniteMatchTimeout; + + /// Whether is non-infinite. + internal static readonly bool s_hasTimeout = s_defaultTimeout != Regex.InfiniteMatchTimeout; + + /// Pops 2 values from the backtracking stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void StackPop(int[] stack, ref int pos, out int arg0, out int arg1) + { + arg0 = stack[--pos]; + arg1 = stack[--pos]; + } + + /// Pushes 1 value onto the backtracking stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void StackPush(ref int[] stack, ref int pos, int arg0) + { + // If there's space available for the value, store it. + int[] s = stack; + int p = pos; + if ((uint)p < (uint)s.Length) + { + s[p] = arg0; + pos++; + return; + } + + // Otherwise, resize the stack to make room and try again. + WithResize(ref stack, ref pos, arg0); + + // Resize the backtracking stack array and push 1 value onto the stack. + [MethodImpl(MethodImplOptions.NoInlining)] + static void WithResize(ref int[] stack, ref int pos, int arg0) + { + Array.Resize(ref stack, (pos + 0) * 2); + StackPush(ref stack, ref pos, arg0); + } + } + + /// Pushes 2 values onto the backtracking stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1) + { + // If there's space available for all 2 values, store them. + int[] s = stack; + int p = pos; + if ((uint)(p + 1) < (uint)s.Length) + { + s[p] = arg0; + s[p + 1] = arg1; + pos += 2; + return; + } + + // Otherwise, resize the stack to make room and try again. + WithResize(ref stack, ref pos, arg0, arg1); + + // Resize the backtracking stack array and push 2 values onto the stack. + [MethodImpl(MethodImplOptions.NoInlining)] + static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1) + { + Array.Resize(ref stack, (pos + 1) * 2); + StackPush(ref stack, ref pos, arg0, arg1); + } + } + + /// Pushes 3 values onto the backtracking stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1, int arg2) + { + // If there's space available for all 3 values, store them. + int[] s = stack; + int p = pos; + if ((uint)(p + 2) < (uint)s.Length) + { + s[p] = arg0; + s[p + 1] = arg1; + s[p + 2] = arg2; + pos += 3; + return; + } + + // Otherwise, resize the stack to make room and try again. + WithResize(ref stack, ref pos, arg0, arg1, arg2); + + // Resize the backtracking stack array and push 3 values onto the stack. + [MethodImpl(MethodImplOptions.NoInlining)] + static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1, int arg2) + { + Array.Resize(ref stack, (pos + 2) * 2); + StackPush(ref stack, ref pos, arg0, arg1, arg2); + } + } + + /// Supports searching for characters in or not in "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_". + internal static readonly SearchValues s_ascii_FF03FEFFFF8700000000 = SearchValues.Create("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_"); + } +} From 255c2e5c0c076d57b8c083de7a3a6cc73ea365ae Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 15:47:11 +0200 Subject: [PATCH 06/21] git ignore regex --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 684b673361..34426771b7 100644 --- a/.gitignore +++ b/.gitignore @@ -320,3 +320,5 @@ test/test-applications/integrations/dependency-libs/TestApplication.ContinuousPr /otel-dotnet-auto/ lychee/out.md + +C:\Repos\opentelemetry-dotnet-instrumentation\src\OpenTelemetry.AutoInstrumentation\Generated\net8.0\System.Text.RegularExpressions.Generator\System.Text.RegularExpressions.Generator.RegexGenerator\RegexGenerator.g.cs From b9833e32f318947fe6dd684bf529347aa6a8c16f Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 15:50:22 +0200 Subject: [PATCH 07/21] Update .gitignore for RegexGenerator file --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 34426771b7..ff66277cd9 100644 --- a/.gitignore +++ b/.gitignore @@ -321,4 +321,4 @@ test/test-applications/integrations/dependency-libs/TestApplication.ContinuousPr lychee/out.md -C:\Repos\opentelemetry-dotnet-instrumentation\src\OpenTelemetry.AutoInstrumentation\Generated\net8.0\System.Text.RegularExpressions.Generator\System.Text.RegularExpressions.Generator.RegexGenerator\RegexGenerator.g.cs +src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs From 9bf9d1e5f9e2c46dd4f38cbea8a8c0be509f36db Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 15:55:54 +0200 Subject: [PATCH 08/21] Fix formatting and spacing in RegexGenerator.g.cs --- .../RegexGenerator.g.cs | 364 +++++++++--------- 1 file changed, 182 insertions(+), 182 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs b/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs index 0174f7df36..4fd90b8111 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs @@ -1,4 +1,4 @@ -// +// #nullable enable #pragma warning disable CS0162 // Unreachable code #pragma warning disable CS0164 // Unreferenced label @@ -48,7 +48,7 @@ namespace System.Text.RegularExpressions.Generated { /// Cached, thread-safe singleton instance. internal static readonly GetEnvVarRegex_0 Instance = new(); - + /// Initializes the instance. private GetEnvVarRegex_0() { @@ -59,13 +59,13 @@ private GetEnvVarRegex_0() base.factory = new RunnerFactory(); base.capsize = 3; } - + /// Provides a factory for creating instances to be used by methods on . private sealed class RunnerFactory : RegexRunnerFactory { /// Creates an instance of a used by methods on . protected override RegexRunner CreateInstance() => new Runner(); - + /// Provides the runner that contains the custom logic implementing the specified regular expression. private sealed class Runner : RegexRunner { @@ -85,14 +85,14 @@ protected override void Scan(ReadOnlySpan inputSpan) } } } - + /// Search starting from base.runtextpos for the next location a match could possibly start. /// The text being scanned by the regular expression. /// true if a possible match was found; false if no more matches are possible. private bool TryFindNextPossibleStartingPosition(ReadOnlySpan inputSpan) { int pos = base.runtextpos; - + // Any possible match is at least 4 characters. if (pos <= inputSpan.Length - 4) { @@ -105,12 +105,12 @@ private bool TryFindNextPossibleStartingPosition(ReadOnlySpan inputSpan) return true; } } - + // No match found. base.runtextpos = inputSpan.Length; return false; } - + /// Determine whether at base.runtextpos is a match for the regular expression. /// The text being scanned by the regular expression. /// true if the regular expression matches at the current position; otherwise, false. @@ -125,189 +125,189 @@ private bool TryMatchAtCurrentPosition(ReadOnlySpan inputSpan) int loop_iteration = 0; int stackpos = 0; ReadOnlySpan slice = inputSpan.Slice(pos); - + // Match the string "${". if (!slice.StartsWith("${")) { UncaptureUntil(0); return false; // The input didn't match. } - + // 1st capture group. //{ - pos += 2; - slice = inputSpan.Slice(pos); - capture_starting_pos = pos; - - // Match a character in the set [0-9A-Z_] greedily at least once. - //{ - charloop_starting_pos = pos; - - int iteration = slice.IndexOfAnyExcept(Utilities.s_ascii_FF03FEFFFF8700000000); - if (iteration < 0) - { - iteration = slice.Length; - } - - if (iteration == 0) - { - UncaptureUntil(0); - return false; // The input didn't match. - } - - slice = slice.Slice(iteration); - pos += iteration; - - charloop_ending_pos = pos; - charloop_starting_pos++; - goto CharLoopEnd; - - CharLoopBacktrack: - UncaptureUntil(charloop_capture_pos); - - if (Utilities.s_hasTimeout) - { - base.CheckTimeout(); - } - - if (charloop_starting_pos >= charloop_ending_pos) - { - UncaptureUntil(0); - return false; // The input didn't match. - } - pos = --charloop_ending_pos; - slice = inputSpan.Slice(pos); - - CharLoopEnd: - charloop_capture_pos = base.Crawlpos(); + pos += 2; + slice = inputSpan.Slice(pos); + capture_starting_pos = pos; + + // Match a character in the set [0-9A-Z_] greedily at least once. + //{ + charloop_starting_pos = pos; + + int iteration = slice.IndexOfAnyExcept(Utilities.s_ascii_FF03FEFFFF8700000000); + if (iteration < 0) + { + iteration = slice.Length; + } + + if (iteration == 0) + { + UncaptureUntil(0); + return false; // The input didn't match. + } + + slice = slice.Slice(iteration); + pos += iteration; + + charloop_ending_pos = pos; + charloop_starting_pos++; + goto CharLoopEnd; + + CharLoopBacktrack: + UncaptureUntil(charloop_capture_pos); + + if (Utilities.s_hasTimeout) + { + base.CheckTimeout(); + } + + if (charloop_starting_pos >= charloop_ending_pos) + { + UncaptureUntil(0); + return false; // The input didn't match. + } + pos = --charloop_ending_pos; + slice = inputSpan.Slice(pos); + + CharLoopEnd: + charloop_capture_pos = base.Crawlpos(); + //} + + base.Capture(1, capture_starting_pos, pos); + + goto CaptureSkipBacktrack; + + CaptureBacktrack: + goto CharLoopBacktrack; + + CaptureSkipBacktrack:; //} - - base.Capture(1, capture_starting_pos, pos); - - goto CaptureSkipBacktrack; - - CaptureBacktrack: - goto CharLoopBacktrack; - - CaptureSkipBacktrack:; - //} - + // Optional (greedy). //{ - loop_iteration = 0; - - LoopBody: - Utilities.StackPush(ref base.runstack!, ref stackpos, base.Crawlpos(), pos); - - loop_iteration++; - - // Match the string ":-". - if (!slice.StartsWith(":-")) - { - goto LoopIterationNoMatch; - } - - // 2nd capture group. - //{ - pos += 2; - slice = inputSpan.Slice(pos); - int capture_starting_pos1 = pos; - - // Match a character other than '}' greedily any number of times. - //{ - charloop_starting_pos1 = pos; - - int iteration1 = slice.IndexOf('}'); - if (iteration1 < 0) - { - iteration1 = slice.Length; - } - - slice = slice.Slice(iteration1); - pos += iteration1; - - charloop_ending_pos1 = pos; - goto CharLoopEnd1; - - CharLoopBacktrack1: - UncaptureUntil(base.runstack![--stackpos]); - Utilities.StackPop(base.runstack!, ref stackpos, out charloop_ending_pos1, out charloop_starting_pos1); - - if (Utilities.s_hasTimeout) - { - base.CheckTimeout(); - } - - if (charloop_starting_pos1 >= charloop_ending_pos1) - { - goto LoopIterationNoMatch; - } - pos = --charloop_ending_pos1; - slice = inputSpan.Slice(pos); - - CharLoopEnd1: - Utilities.StackPush(ref base.runstack!, ref stackpos, charloop_starting_pos1, charloop_ending_pos1, base.Crawlpos()); - //} - - base.Capture(2, capture_starting_pos1, pos); - - Utilities.StackPush(ref base.runstack!, ref stackpos, capture_starting_pos1); - goto CaptureSkipBacktrack1; - - CaptureBacktrack1: - capture_starting_pos1 = base.runstack![--stackpos]; - goto CharLoopBacktrack1; - - CaptureSkipBacktrack1:; - //} - - - // The loop has an upper bound of 1. Continue iterating greedily if it hasn't yet been reached. - if (loop_iteration == 0) - { - goto LoopBody; - } - goto LoopEnd; - - // The loop iteration failed. Put state back to the way it was before the iteration. - LoopIterationNoMatch: - if (--loop_iteration < 0) - { - // Unable to match the remainder of the expression after exhausting the loop. - goto CaptureBacktrack; - } - pos = base.runstack![--stackpos]; - UncaptureUntil(base.runstack![--stackpos]); - slice = inputSpan.Slice(pos); - goto LoopEnd; - - LoopBacktrack: - if (Utilities.s_hasTimeout) - { - base.CheckTimeout(); - } - - if (loop_iteration == 0) - { - // No iterations of the loop remain to backtrack into. Fail the loop. - goto CaptureBacktrack; - } - goto CaptureBacktrack1; - LoopEnd:; + loop_iteration = 0; + + LoopBody: + Utilities.StackPush(ref base.runstack!, ref stackpos, base.Crawlpos(), pos); + + loop_iteration++; + + // Match the string ":-". + if (!slice.StartsWith(":-")) + { + goto LoopIterationNoMatch; + } + + // 2nd capture group. + //{ + pos += 2; + slice = inputSpan.Slice(pos); + int capture_starting_pos1 = pos; + + // Match a character other than '}' greedily any number of times. + //{ + charloop_starting_pos1 = pos; + + int iteration1 = slice.IndexOf('}'); + if (iteration1 < 0) + { + iteration1 = slice.Length; + } + + slice = slice.Slice(iteration1); + pos += iteration1; + + charloop_ending_pos1 = pos; + goto CharLoopEnd1; + + CharLoopBacktrack1: + UncaptureUntil(base.runstack![--stackpos]); + Utilities.StackPop(base.runstack!, ref stackpos, out charloop_ending_pos1, out charloop_starting_pos1); + + if (Utilities.s_hasTimeout) + { + base.CheckTimeout(); + } + + if (charloop_starting_pos1 >= charloop_ending_pos1) + { + goto LoopIterationNoMatch; + } + pos = --charloop_ending_pos1; + slice = inputSpan.Slice(pos); + + CharLoopEnd1: + Utilities.StackPush(ref base.runstack!, ref stackpos, charloop_starting_pos1, charloop_ending_pos1, base.Crawlpos()); + //} + + base.Capture(2, capture_starting_pos1, pos); + + Utilities.StackPush(ref base.runstack!, ref stackpos, capture_starting_pos1); + goto CaptureSkipBacktrack1; + + CaptureBacktrack1: + capture_starting_pos1 = base.runstack![--stackpos]; + goto CharLoopBacktrack1; + + CaptureSkipBacktrack1:; + //} + + + // The loop has an upper bound of 1. Continue iterating greedily if it hasn't yet been reached. + if (loop_iteration == 0) + { + goto LoopBody; + } + goto LoopEnd; + + // The loop iteration failed. Put state back to the way it was before the iteration. + LoopIterationNoMatch: + if (--loop_iteration < 0) + { + // Unable to match the remainder of the expression after exhausting the loop. + goto CaptureBacktrack; + } + pos = base.runstack![--stackpos]; + UncaptureUntil(base.runstack![--stackpos]); + slice = inputSpan.Slice(pos); + goto LoopEnd; + + LoopBacktrack: + if (Utilities.s_hasTimeout) + { + base.CheckTimeout(); + } + + if (loop_iteration == 0) + { + // No iterations of the loop remain to backtrack into. Fail the loop. + goto CaptureBacktrack; + } + goto CaptureBacktrack1; + LoopEnd:; //} - + // Match '}'. if (slice.IsEmpty || slice[0] != '}') { goto LoopBacktrack; } - + // The input matched. pos++; base.runtextpos = pos; base.Capture(0, matchStart, pos); return true; - + // Undo captures until it reaches the specified capture position. [MethodImpl(MethodImplOptions.AggressiveInlining)] void UncaptureUntil(int capturePosition) @@ -322,17 +322,17 @@ void UncaptureUntil(int capturePosition) } } - + /// Helper methods used by generated -derived implementations. [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "8.0.12.41914")] file static class Utilities { /// Default timeout value set in , or if none was set. internal static readonly TimeSpan s_defaultTimeout = AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeout ? timeout : Regex.InfiniteMatchTimeout; - + /// Whether is non-infinite. internal static readonly bool s_hasTimeout = s_defaultTimeout != Regex.InfiniteMatchTimeout; - + /// Pops 2 values from the backtracking stack. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void StackPop(int[] stack, ref int pos, out int arg0, out int arg1) @@ -340,7 +340,7 @@ internal static void StackPop(int[] stack, ref int pos, out int arg0, out int ar arg0 = stack[--pos]; arg1 = stack[--pos]; } - + /// Pushes 1 value onto the backtracking stack. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void StackPush(ref int[] stack, ref int pos, int arg0) @@ -354,10 +354,10 @@ internal static void StackPush(ref int[] stack, ref int pos, int arg0) pos++; return; } - + // Otherwise, resize the stack to make room and try again. WithResize(ref stack, ref pos, arg0); - + // Resize the backtracking stack array and push 1 value onto the stack. [MethodImpl(MethodImplOptions.NoInlining)] static void WithResize(ref int[] stack, ref int pos, int arg0) @@ -366,7 +366,7 @@ static void WithResize(ref int[] stack, ref int pos, int arg0) StackPush(ref stack, ref pos, arg0); } } - + /// Pushes 2 values onto the backtracking stack. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1) @@ -381,10 +381,10 @@ internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1) pos += 2; return; } - + // Otherwise, resize the stack to make room and try again. WithResize(ref stack, ref pos, arg0, arg1); - + // Resize the backtracking stack array and push 2 values onto the stack. [MethodImpl(MethodImplOptions.NoInlining)] static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1) @@ -393,7 +393,7 @@ static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1) StackPush(ref stack, ref pos, arg0, arg1); } } - + /// Pushes 3 values onto the backtracking stack. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1, int arg2) @@ -409,10 +409,10 @@ internal static void StackPush(ref int[] stack, ref int pos, int arg0, int arg1, pos += 3; return; } - + // Otherwise, resize the stack to make room and try again. WithResize(ref stack, ref pos, arg0, arg1, arg2); - + // Resize the backtracking stack array and push 3 values onto the stack. [MethodImpl(MethodImplOptions.NoInlining)] static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1, int arg2) @@ -421,7 +421,7 @@ static void WithResize(ref int[] stack, ref int pos, int arg0, int arg1, int arg StackPush(ref stack, ref pos, arg0, arg1, arg2); } } - + /// Supports searching for characters in or not in "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_". internal static readonly SearchValues s_ascii_FF03FEFFFF8700000000 = SearchValues.Create("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_"); } From bffc31d57227f5d1c177b7c958b73cbdc80b28ab Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 15:57:01 +0200 Subject: [PATCH 09/21] Remove gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index ff66277cd9..684b673361 100644 --- a/.gitignore +++ b/.gitignore @@ -320,5 +320,3 @@ test/test-applications/integrations/dependency-libs/TestApplication.ContinuousPr /otel-dotnet-auto/ lychee/out.md - -src/OpenTelemetry.AutoInstrumentation/Generated/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs From ee5baf5f782d9101d7a98153d21299aff6819385 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 16:58:14 +0200 Subject: [PATCH 10/21] fix test --- .../Configurations/FileBased/Files/TestInstrumentationFile.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml index cb7919c494..8a849c345d 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationFile.yaml @@ -25,6 +25,7 @@ instrumentation/development: wcfclient: wcfservice: metrics: + aspnet: aspnetcore: httpclient: netruntime: From 4eabeac839f132e4e1ff55413a2652bc1090c6f0 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 1 Oct 2025 16:59:01 +0200 Subject: [PATCH 11/21] fix docs --- docs/file-based-configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 9ef9fbf811..f472eef650 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -97,6 +97,7 @@ instrumentation/development: 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] From f5f13969a119bb1d35b5b0b7b4e630ebd478c34a Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 13 Oct 2025 09:36:38 +0200 Subject: [PATCH 12/21] [File-Based] Fix capture headers --- docs/file-based-configuration.md | 16 ++++++++-------- .../TestInstrumentationConfigurationFile.yaml | 16 ++++++++-------- .../Parser/ParserInstrumentationTests.cs | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index f472eef650..3b65478fbb 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -134,22 +134,22 @@ instrumentation/development: 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=Value" + capture_request_headers: "X-Key" # 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=Value" + capture_response_headers: "X-Key" 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=Value" + capture_request_headers: "X-Key" # 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=Value" + capture_response_headers: "X-Key" 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=Value" + capture_request_headers: "X-Key" # 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=Value" + capture_response_headers: "X-Key" 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=Value" + capture_request_metadata: "X-Key" # 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=Value" + capture_response_metadata: "X-Key" ``` diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml index 77e591634a..333ec58781 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml @@ -8,15 +8,15 @@ instrumentation/development: oraclemda: set_db_statement_for_text: true aspnet: - capture_request_headers: "X-Key=Value" - capture_response_headers: "X-Key=Value" + capture_request_headers: "X-Key" + capture_response_headers: "X-Key" aspnetcore: - capture_request_headers: "X-Key=Value" - capture_response_headers: "X-Key=Value" + capture_request_headers: "X-Key" + capture_response_headers: "X-Key" httpclient: - capture_request_headers: "X-Key=Value" - capture_response_headers: "X-Key=Value" + capture_request_headers: "X-Key" + capture_response_headers: "X-Key" grpcnetclient: - capture_request_metadata: "X-Key=Value" - capture_response_metadata: "X-Key=Value" + capture_request_metadata: "X-Key" + capture_response_metadata: "X-Key" diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs index fcafb42769..f1d9a95ca5 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs @@ -106,22 +106,22 @@ public void Parse_InstrumentationConfiguration_ShouldPopulateModelCorrectly() } Assert.True(traces.OracleMda!.SetDbStatementForText); - Assert.Equal("X-Key=Value", traces.HttpClient!.CaptureRequestHeaders); - Assert.Equal("X-Key=Value", traces.HttpClient!.CaptureResponseHeaders); + Assert.Equal("X-Key", traces.HttpClient!.CaptureRequestHeaders); + Assert.Equal("X-Key", traces.HttpClient!.CaptureResponseHeaders); - Assert.Equal("X-Key=Value", traces.GrpcNetClient!.CaptureRequestMetadata); - Assert.Equal("X-Key=Value", traces.GrpcNetClient!.CaptureResponseMetadata); + Assert.Equal("X-Key", traces.GrpcNetClient!.CaptureRequestMetadata); + Assert.Equal("X-Key", traces.GrpcNetClient!.CaptureResponseMetadata); #if NET Assert.True(traces.GraphQL!.SetDocument); Assert.True(traces.EntityFrameworkCore!.SetDbStatementForText); - Assert.Equal("X-Key=Value", traces.AspNetCore!.CaptureRequestHeaders); - Assert.Equal("X-Key=Value", traces.AspNetCore!.CaptureResponseHeaders); + Assert.Equal("X-Key", traces.AspNetCore!.CaptureRequestHeaders); + Assert.Equal("X-Key", traces.AspNetCore!.CaptureResponseHeaders); #endif #if NETFRAMEWORK - Assert.Equal("X-Key=Value", traces.AspNet!.CaptureRequestHeaders); - Assert.Equal("X-Key=Value", traces.AspNet!.CaptureResponseHeaders); + Assert.Equal("X-Key", traces.AspNet!.CaptureRequestHeaders); + Assert.Equal("X-Key", traces.AspNet!.CaptureResponseHeaders); #endif } } From 241ea19b3ffaf40a04ad8ba52150f09db92c65d2 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Thu, 16 Oct 2025 11:18:57 +0200 Subject: [PATCH 13/21] docs disable nstrumentation --- docs/file-based-configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 3b65478fbb..df8774d5f3 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -68,6 +68,7 @@ resource: 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: From 548f7e4dbd7ac6b854b7864fc3d1b045b202ddbc Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Thu, 16 Oct 2025 11:24:36 +0200 Subject: [PATCH 14/21] multiple headers in example --- docs/file-based-configuration.md | 16 ++++++++-------- .../TestInstrumentationConfigurationFile.yaml | 16 ++++++++-------- .../Parser/ParserInstrumentationTests.cs | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index df8774d5f3..31ffc1e1eb 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -135,22 +135,22 @@ instrumentation/development: 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" + 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" + 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" + 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" + 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" + 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" + 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" + 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" + capture_response_metadata: "X-Key,X-Custom-Header,X-Header-Example" ``` diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml index 333ec58781..6064d4c4df 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml @@ -8,15 +8,15 @@ instrumentation/development: oraclemda: set_db_statement_for_text: true aspnet: - capture_request_headers: "X-Key" - capture_response_headers: "X-Key" + 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" - capture_response_headers: "X-Key" + 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" - capture_response_headers: "X-Key" + 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" - capture_response_metadata: "X-Key" + capture_request_metadata: "X-Key,X-Custom-Header,X-Header-Example" + capture_response_metadata: "X-Key,X-Custom-Header,X-Header-Example" diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs index f1d9a95ca5..6cc704dc9e 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs @@ -106,22 +106,22 @@ public void Parse_InstrumentationConfiguration_ShouldPopulateModelCorrectly() } Assert.True(traces.OracleMda!.SetDbStatementForText); - Assert.Equal("X-Key", traces.HttpClient!.CaptureRequestHeaders); - Assert.Equal("X-Key", traces.HttpClient!.CaptureResponseHeaders); + 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", traces.GrpcNetClient!.CaptureRequestMetadata); - Assert.Equal("X-Key", traces.GrpcNetClient!.CaptureResponseMetadata); + 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", traces.AspNetCore!.CaptureRequestHeaders); - Assert.Equal("X-Key", traces.AspNetCore!.CaptureResponseHeaders); + 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", traces.AspNet!.CaptureRequestHeaders); - Assert.Equal("X-Key", traces.AspNet!.CaptureResponseHeaders); + 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 } } From 2c36af4ee84d9da63d5997871aeb045452231806 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Thu, 16 Oct 2025 11:26:33 +0200 Subject: [PATCH 15/21] `GraphQLSetDocumentConfiguration` instead of `SetDocumentConfiguration`. --- .../Configurations/FileBasedConfiguration/DotNetTraces.cs | 2 +- ...umentConfiguration.cs => GraphQLSetDocumentConfiguration.cs} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/{SetDocumentConfiguration.cs => GraphQLSetDocumentConfiguration.cs} (93%) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs index 4345eddb3c..f6c99a0778 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs @@ -45,7 +45,7 @@ internal class DotNetTraces /// Gets or sets the GraphQL traces instrumentation configuration. ///
[YamlMember(Alias = "graphql")] - public SetDocumentConfiguration? GraphQL { get; set; } + public GraphQLSetDocumentConfiguration? GraphQL { get; set; } /// /// Gets or sets the MassTransit traces instrumentation configuration. diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/GraphQLSetDocumentConfiguration.cs similarity index 93% rename from src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs rename to src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/GraphQLSetDocumentConfiguration.cs index b2baee5616..4656904370 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/GraphQLSetDocumentConfiguration.cs @@ -7,7 +7,7 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; [EmptyObjectOnEmptyYaml] -internal class SetDocumentConfiguration +internal class GraphQLSetDocumentConfiguration { /// /// Gets or sets a value indicating whether the GraphQL instrumentation can pass raw queries through the graphql.document attribute. From 65692bc9d5c0d31fabc4a5515e2072915de82995 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Thu, 16 Oct 2025 12:01:41 +0200 Subject: [PATCH 16/21] [FileBased] Add Log4Net Bridge support --- docs/file-based-configuration.md | 5 +++++ .../FileBasedConfiguration/DotNetLogs.cs | 2 +- .../Log4NetBridgeEnabled.cs | 17 +++++++++++++++++ .../Configurations/LogSettings.cs | 5 +++++ .../FilebasedInstrumentationSettingsTests.cs | 6 +++++- .../TestInstrumentationConfigurationFile.yaml | 3 +++ .../Parser/ParserInstrumentationTests.cs | 5 +++++ 7 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Log4NetBridgeEnabled.cs diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 31ffc1e1eb..88c80dfede 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -153,4 +153,9 @@ instrumentation/development: 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/FileBasedConfiguration/DotNetLogs.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs index 302cad8780..b854c06aca 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs @@ -17,7 +17,7 @@ internal class DotNetLogs /// Gets or sets the Log4Net logs instrumentation configuration. /// [YamlMember(Alias = "log4net")] - public object? Log4Net { get; set; } + public Log4NetBridgeEnabled? Log4Net { get; set; } /// /// Returns the list of enabled log instrumentations. 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/LogSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs index d316d47ce2..a912ffdb89 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs @@ -68,6 +68,11 @@ protected override void OnLoadEnvVar(Configuration configuration) 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) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs index 88be64b899..b37bec364d 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedInstrumentationSettingsTests.cs @@ -123,7 +123,10 @@ public void LoadFile_SetsEnabledLogsInstrumentations_IfPresent() Logs = new DotNetLogs { ILogger = new object(), - Log4Net = new object(), + Log4Net = new() + { + BridgeEnabled = true + }, } }; @@ -142,5 +145,6 @@ public void LoadFile_SetsEnabledLogsInstrumentations_IfPresent() 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 index 6064d4c4df..ddbc8c8203 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml @@ -19,4 +19,7 @@ instrumentation/development: 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/Parser/ParserInstrumentationTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs index 6cc704dc9e..63258da73e 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs @@ -105,6 +105,10 @@ public void Parse_InstrumentationConfiguration_ShouldPopulateModelCorrectly() 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); @@ -123,5 +127,6 @@ public void Parse_InstrumentationConfiguration_ShouldPopulateModelCorrectly() 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); } } From 8e7658eb4036395a1384d012ae293a97c2fd49c7 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 24 Oct 2025 12:10:30 +0200 Subject: [PATCH 17/21] remove set_db_statement_for_text for Entity Framework --- docs/file-based-configuration.md | 4 ---- .../Configurations/FileBasedConfiguration/DotNetTraces.cs | 2 +- .../Configurations/InstrumentationOptions.cs | 5 ----- .../Files/TestInstrumentationConfigurationFile.yaml | 2 -- .../FileBased/Parser/ParserInstrumentationTests.cs | 3 +-- 5 files changed, 2 insertions(+), 14 deletions(-) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 7419a6b37b..a561079598 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -224,10 +224,6 @@ instrumentation/development: 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 diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs index f6c99a0778..e6efeaadd4 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs @@ -39,7 +39,7 @@ internal class DotNetTraces /// Gets or sets the Entity Framework Core traces instrumentation configuration. /// [YamlMember(Alias = "entityframeworkcore")] - public SetDbStatementForTextConfuguration? EntityFrameworkCore { get; set; } + public object? EntityFrameworkCore { get; set; } /// /// Gets or sets the GraphQL traces instrumentation configuration. diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs index a6489229dd..2179027ef6 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs @@ -48,11 +48,6 @@ internal InstrumentationOptions(DotNetTraces? instrumentationConfiguration) AspNetCoreInstrumentationCaptureResponseHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNetCore.CaptureResponseHeaders, AdditionalTag.CreateHttpResponseCache); } - if (instrumentationConfiguration.EntityFrameworkCore != null) - { - EntityFrameworkCoreSetDbStatementForText = instrumentationConfiguration.EntityFrameworkCore.SetDbStatementForText; - } - if (instrumentationConfiguration.GraphQL != null) { GraphQLSetDocument = instrumentationConfiguration.GraphQL.SetDocument; diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml index ddbc8c8203..f7d7926865 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestInstrumentationConfigurationFile.yaml @@ -1,8 +1,6 @@ instrumentation/development: dotnet: traces: - entityframeworkcore: - set_db_statement_for_text: true graphql: set_document: true oraclemda: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs index 63258da73e..fa456f87e6 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserInstrumentationTests.cs @@ -88,7 +88,7 @@ public void Parse_InstrumentationConfiguration_ShouldPopulateModelCorrectly() #if NET string[] expectedTraces = [ - "aspnetcore", "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", "oraclemda" + "aspnetcore", "graphql", "grpcnetclient", "httpclient", "oraclemda" ]; #endif #if NETFRAMEWORK @@ -117,7 +117,6 @@ public void Parse_InstrumentationConfiguration_ShouldPopulateModelCorrectly() 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); From 0ec2986913431cd224150df89b42ac049bf48d52 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 24 Oct 2025 12:48:47 +0200 Subject: [PATCH 18/21] fix log4net bridge --- .../FileBasedConfiguration/Log4NetBridgeEnabled.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Log4NetBridgeEnabled.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Log4NetBridgeEnabled.cs index 0f498b9f39..288108f53e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Log4NetBridgeEnabled.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Log4NetBridgeEnabled.cs @@ -12,6 +12,6 @@ internal class Log4NetBridgeEnabled /// /// Gets or sets a value indicating whether the Log4Net bridge is enabled. /// - [YamlMember(Alias = "bridge_enbaled")] + [YamlMember(Alias = "bridge_enabled")] public bool BridgeEnabled { get; set; } } From ea047c04348648051323618269acd48d3778aace Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 24 Oct 2025 12:49:07 +0200 Subject: [PATCH 19/21] update docs --- docs/file-based-configuration.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index a561079598..0ccbb7c437 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -232,11 +232,6 @@ instrumentation/development: # 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" From 554d0b27c4b1269265d1a1e4dc205d0861142293 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 24 Oct 2025 13:31:40 +0200 Subject: [PATCH 20/21] update docs --- docs/file-based-configuration.md | 68 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 0ccbb7c437..55730a8eae 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -175,48 +175,48 @@ propagator: ## Instrumentation Configuration You can configure traces, metrics, and logs instrumentations. -For more details and updates, see: [Instrumentation list and documentation](config.md#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 (.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] + 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 [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] + 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 (>=9.0.0) [Core & Framework] - log4net: # log4net (>=2.0.13 && <4.0.0) [Core & Framework] -``` + ilogger: # Microsoft.Extensions.Logging + log4net: # Log4Net ## Instrumentation options From 138a94387bc1096184527734079eafa7c7f99662 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 24 Oct 2025 13:32:36 +0200 Subject: [PATCH 21/21] fix --- docs/file-based-configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 55730a8eae..773db8f9e3 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -217,6 +217,7 @@ instrumentation/development: logs: ilogger: # Microsoft.Extensions.Logging log4net: # Log4Net +``` ## Instrumentation options