-
Notifications
You must be signed in to change notification settings - Fork 889
[Config] Declarative config (phase 1) initial design and scalar values #7413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0d1e68b
216be4f
acda79a
3293c2b
854ec49
0048ae7
4cd240d
b355b55
d8d5c3c
27123de
606de0a
6905833
f179a52
d1a357b
8a00b12
b97ba4a
40ae35f
4e5ce6a
b459ccc
174d1e4
894aa7c
2eaa8f6
e6bda43
f0be9f8
aa8ee88
ee74af7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
martincostello marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,192 @@ | ||
| # OpenTelemetry .NET Diagnostic: OTEL1006 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not think that we need this at all. As long as we stays on the prerelease channels. The experimental apis feature should be used to expose unstable public API in the already stable packages to indicate that some features will not work with stable releases. |
||
|
|
||
| ## Overview | ||
|
|
||
| This is an Experimental API diagnostic covering the following APIs: | ||
|
|
||
| * `DeclarativeConfigurationBuilderExtensions.AddOpenTelemetryDeclarativeConfiguration` | ||
| * `OpenTelemetryBuilderDeclarativeConfigurationExtensions.UseDeclarativeConfiguration` | ||
| * `DeclarativeConfigurationException` | ||
|
|
||
| Experimental APIs may be changed or removed in the future. | ||
|
|
||
| ## Details | ||
|
|
||
| The OpenTelemetry Specification defines a [declarative | ||
| configuration](https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/) | ||
| model that allows configuring the SDK from a YAML file rather than code or | ||
| environment variables. The `OpenTelemetry.Configuration.Declarative` package | ||
| provides a partial experimental implementation of this specification. | ||
|
|
||
| The APIs covered by this diagnostic wire a YAML configuration source into the | ||
| .NET `IConfiguration` pipeline so that OpenTelemetry SDK components (such as | ||
| resource detectors and the SDK-disabled flag) pick up values from the YAML file. | ||
|
|
||
| ### `AddOpenTelemetryDeclarativeConfiguration` | ||
|
|
||
| Adds the declarative YAML source directly to an `IConfigurationBuilder`: | ||
|
|
||
| ```csharp | ||
| // On HostApplicationBuilder (recommended): | ||
| builder.Configuration.AddOpenTelemetryDeclarativeConfiguration(); // reads OTEL_CONFIG_FILE | ||
| builder.Configuration.AddOpenTelemetryDeclarativeConfiguration("otel-config.yaml"); | ||
|
|
||
| // On HostBuilder (inside ConfigureAppConfiguration): | ||
| hostBuilder.ConfigureAppConfiguration(b => | ||
| b.AddOpenTelemetryDeclarativeConfiguration()); // reads OTEL_CONFIG_FILE | ||
| hostBuilder.ConfigureAppConfiguration(b => | ||
| b.AddOpenTelemetryDeclarativeConfiguration("otel-config.yaml")); | ||
|
martincostello marked this conversation as resolved.
|
||
| ``` | ||
|
|
||
| ### `UseDeclarativeConfiguration` | ||
|
|
||
| Wires the YAML source via `IOpenTelemetryBuilder`, detecting the host's | ||
| `IConfiguration` instance and inserting the source appropriately: | ||
|
|
||
| ```csharp | ||
| services.AddOpenTelemetry() | ||
| .UseDeclarativeConfiguration() // reads OTEL_CONFIG_FILE | ||
| .WithTracing(b => b.AddSource("MyApp.*")); | ||
| ``` | ||
|
|
||
| ### Recommended integration | ||
|
|
||
| | Host type | Preferred API | | ||
| | --- | --- | | ||
| | `HostApplicationBuilder` / `WebApplicationBuilder` | `builder.Configuration.AddOpenTelemetryDeclarativeConfiguration()` | | ||
| | Classic `HostBuilder` | `ConfigureAppConfiguration(b => b.AddOpenTelemetryDeclarativeConfiguration(...))` | | ||
| | Any host (alternative) | `services.AddOpenTelemetry().UseDeclarativeConfiguration()` | | ||
|
|
||
| **Pitfalls to avoid:** | ||
|
|
||
| * **`UseDeclarativeConfiguration()` requires `IConfiguration` to already be | ||
| registered** when it runs. If the host registers `IConfiguration` later, the | ||
| YAML source will not be visible to the SDK. | ||
|
martincostello marked this conversation as resolved.
|
||
| * **A second call to `UseDeclarativeConfiguration()` on the same | ||
| `IServiceCollection` is ignored.** Only the first file path applies; a later | ||
| call with a different path does not replace it (an EventSource warning is | ||
| emitted). | ||
|
|
||
| ### Precedence | ||
|
|
||
| The YAML source is appended after all sources already registered at the time of | ||
| the call. It therefore takes precedence over earlier sources such as environment | ||
| variables and `appsettings.json`. Sources added after the call take precedence | ||
| over YAML values. | ||
|
|
||
| The settings supported in this package currently map to SDK code paths that read | ||
| directly from `IConfiguration`, so `services.Configure<T>()` / | ||
| `PostConfigure<T>()` delegates do not override them. To override these values in | ||
| code, add a higher-priority `IConfiguration` source after the YAML source. | ||
|
|
||
| We are exposing these APIs experimentally while the specification and .NET | ||
| integration model mature. | ||
|
|
||
| **TL;DR** We want to gather feedback on the usability and integration design | ||
| before committing to a stable API shape. | ||
|
|
||
| ## Implementation notes | ||
|
|
||
| ### `IOptions` vs direct `IConfiguration` reads | ||
|
|
||
| The two settings currently supported (`OTEL_SDK_DISABLED`, | ||
| `OTEL_RESOURCE_ATTRIBUTES`) are consumed by the SDK via direct `IConfiguration` | ||
| reads rather than the .NET `IOptions<T>` pipeline: | ||
|
|
||
| * `OTEL_SDK_DISABLED` is read before the provider is constructed to decide | ||
| whether to return a real provider or a no-op. | ||
| * `OTEL_RESOURCE_ATTRIBUTES` is read by the resource detector. | ||
|
|
||
| Using `IOptions<T>` would add startup validation and make code-level | ||
| `Configure<T>` / `PostConfigure<T>` overrides work at the Options layer, but the | ||
| practical benefit is small for these settings: values are consumed once at | ||
| startup and cannot change an already-constructed provider. The code-override | ||
| story is already covered by `IConfiguration` source ordering (adding a | ||
| higher-priority source after the YAML source). | ||
|
|
||
| If future settings use `IOptions<T>` internally, `PostConfigure<T>` would then | ||
| take precedence over YAML-supplied values, which is the expected .NET idiom | ||
| (code beats configuration). | ||
|
|
||
| ### Runtime (dynamic) disabling | ||
|
|
||
| The `disabled` flag is evaluated once, when the provider is constructed. There | ||
| is no mechanism to flip a live provider from a real implementation to a no-op at | ||
| runtime. This matches the OTel specification (`OTEL_SDK_DISABLED` is read at | ||
| initialization only). | ||
|
|
||
| Once a real provider is built, its listener wiring is fixed. The closest | ||
| approximation is replacing the sampler with `AlwaysOff` at runtime, which still | ||
| leaves processors and exporters running. For runaway instrumentation, prefer | ||
| exporter timeouts, bounded batch queues, and process restart. | ||
|
|
||
| ### Environment-variable substitution ordering | ||
|
|
||
| The OTel spec states that node types must be interpreted *after* environment | ||
| variable substitution. | ||
|
|
||
| This implementation parses YAML first (YamlDotNet RepresentationModel preserves | ||
| scalar literals without type conversion), applies substitution to those strings, | ||
| then interprets types explicitly (for example `bool.TryParse` for `disabled`). | ||
| Outcomes are semantically equivalent for supported scalar fields today, with a | ||
| stronger guarantee that env vars cannot inject YAML structure because | ||
| substitution runs on already-tokenised scalar nodes. | ||
|
|
||
| ### Empty-string and null semantics | ||
|
|
||
| When an environment variable is unset and has no default, the spec replaces the | ||
| reference with an empty string, then applies YAML 1.2 Core Schema type | ||
| resolution - a plain empty scalar becomes `null`. Quoted empty strings remain | ||
| `""`. | ||
|
|
||
| All YAML 1.2 core schema null spellings - plain empty, `~`, `null`, `Null`, and | ||
| `NULL` - are treated as **present-null**. Quoted variants (e.g. `"null"`) remain | ||
| strings. | ||
|
|
||
| For scalar fields where the key is present but the value is unusable (malformed | ||
| node type, invalid parse), the parser selects **present-null** rather than | ||
| **absent**, because the key appeared in the document and `nullBehavior` applies | ||
| at Create time. | ||
|
|
||
| **Post-substitution null resolution:** because the spec requires that YAML type | ||
| resolution runs *after* substitution, a plain (unquoted) scalar whose | ||
| environment variable resolves to one of the null spellings (`null`, `Null`, | ||
| `NULL`, `~`) is treated as YAML null. For example: | ||
|
|
||
| ```yaml | ||
| resource: | ||
| attributes: | ||
| - name: my.attr | ||
| value: ${MY_VAR} # plain scalar | ||
| ``` | ||
|
|
||
| If `MY_VAR=null` the attribute is skipped (same as writing `value: null`). | ||
| If you need the literal string `"null"`, use a quoted scalar: `value: "${MY_VAR}"`. | ||
| The `InvalidResourceAttribute` EventSource event (Event ID 3) is emitted when an | ||
| attribute is skipped for this reason. | ||
|
|
||
| ### Resource attribute name validation | ||
|
|
||
| Names containing `,` or `=` are skipped and Event 3 is emitted; these characters | ||
| would corrupt the `key=value,key=value` flat format consumed by | ||
| `OtelEnvResourceDetector`. All other names that do not follow the OTel attribute | ||
| naming convention (`[a-zA-Z_][-a-zA-Z0-9_.]*`) are emitted verbatim and Event 22 | ||
| (`ResourceAttributeNameNotCompliant`) is emitted as a warning. This is a | ||
| .NET-projection constraint: the specification accepts attribute names verbatim | ||
| because they build typed resource objects rather than serializing to the env-var | ||
| format. | ||
|
|
||
| ### Empty configuration file | ||
|
|
||
| A file containing zero YAML documents is a no-op in overlay mode and does not | ||
| require a `file_format` field (unlike a non-empty document, which still | ||
| validates `file_format`). Event 23 (`EmptyConfigurationFile`) is emitted at | ||
| informational level so listeners can observe the intentional no-op. | ||
|
|
||
| ## Provide feedback | ||
|
|
||
| Please provide feedback on [issue #6380](https://github.com/open-telemetry/opentelemetry-dotnet/issues/6380) | ||
| if you are using or evaluating declarative configuration in your application. | ||
|
|
||
| Any feedback will help inform decisions about when to expose the API as stable | ||
| and what the final surface should look like. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| #nullable enable |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| #nullable enable | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line is redundant. Nullable is already in shipped.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just a directive for the analyser to understand if the entries are nullable or not. If you removed it, when a new API that is unshipped is added to the file the line would be needed to be added again. It's not about whether nullable as a feature shipped.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should inherit this information from Shipped folder. It is not needed to duplicate this info. Not a blocker. |
||
| Microsoft.Extensions.Configuration.DeclarativeConfigurationBuilderExtensions | ||
| [OTEL1006]OpenTelemetry.Configuration.Declarative.DeclarativeConfigurationException | ||
| [OTEL1006]OpenTelemetry.Configuration.Declarative.DeclarativeConfigurationException.DeclarativeConfigurationException() -> void | ||
| [OTEL1006]OpenTelemetry.Configuration.Declarative.DeclarativeConfigurationException.DeclarativeConfigurationException(string! message) -> void | ||
| [OTEL1006]OpenTelemetry.Configuration.Declarative.DeclarativeConfigurationException.DeclarativeConfigurationException(string! message, System.Exception! innerException) -> void | ||
| OpenTelemetry.OpenTelemetryBuilderDeclarativeConfigurationExtensions | ||
| [OTEL1006]static Microsoft.Extensions.Configuration.DeclarativeConfigurationBuilderExtensions.AddOpenTelemetryDeclarativeConfiguration(this Microsoft.Extensions.Configuration.IConfigurationBuilder! builder) -> Microsoft.Extensions.Configuration.IConfigurationBuilder! | ||
| [OTEL1006]static Microsoft.Extensions.Configuration.DeclarativeConfigurationBuilderExtensions.AddOpenTelemetryDeclarativeConfiguration(this Microsoft.Extensions.Configuration.IConfigurationBuilder! builder, string! filePath) -> Microsoft.Extensions.Configuration.IConfigurationBuilder! | ||
| [OTEL1006]static OpenTelemetry.OpenTelemetryBuilderDeclarativeConfigurationExtensions.UseDeclarativeConfiguration(this OpenTelemetry.IOpenTelemetryBuilder! builder) -> OpenTelemetry.IOpenTelemetryBuilder! | ||
| [OTEL1006]static OpenTelemetry.OpenTelemetryBuilderDeclarativeConfigurationExtensions.UseDeclarativeConfiguration(this OpenTelemetry.IOpenTelemetryBuilder! builder, string! filePath) -> OpenTelemetry.IOpenTelemetryBuilder! | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # Changelog | ||
|
|
||
| This file contains individual changes for the OpenTelemetry.Configuration.Declarative | ||
| package. For highlights and announcements covering all components see: [Release | ||
| Notes](../../RELEASENOTES.md). | ||
|
|
||
| ## Unreleased | ||
|
martincostello marked this conversation as resolved.
|
||
|
|
||
| * Initial implementation of the `OpenTelemetry.Configuration.Declarative` package. | ||
| Adds declarative configuration (YAML) support for the OpenTelemetry .NET SDK, | ||
| accepting any `file_format: "1.x"` document (built against schema v1.1), with | ||
| support for `disabled` and `resource.attributes` / `resource.attributes_list`. | ||
| ([#7413](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7413)) | ||
Uh oh!
There was an error while loading. Please reload this page.