Skip to content

Commit 4c2c5fd

Browse files
committed
Additional notes regarding alignment with the config SDK
1 parent 8351132 commit 4c2c5fd

File tree

2 files changed

+403
-5
lines changed

2 files changed

+403
-5
lines changed

design/configuration-analysis-deep-dives.md

Lines changed: 202 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1883,8 +1883,209 @@ Key design constraints for the OpAMP package:
18831883
telemetry policies) are free to implement their own `IConfigurationProvider`
18841884
against the OpAMP client — the SDK's abstractions do not prevent this.
18851885

1886-
[Deep Dive
1886+
--> [Deep Dive
18871887
C](configuration-analysis-deep-dives.md#c-otlp-exporter-snapshot-architecture-and-reload-path)
18881888
covers OTLP-specific reload. [Deep Dive
18891889
D](configuration-analysis-deep-dives.md#d-sampler-reloadability-design) covers
18901890
sampler reload via `ReloadableSampler`.
1891+
1892+
---
1893+
1894+
## I. Configuration SDK Spec Alignment
1895+
1896+
This section covers implementation details for aligning with the [Configuration
1897+
SDK
1898+
specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk.md).
1899+
The open design questions (in-memory model, Parse/Create operations,
1900+
ConfigProvider) are discussed in [SS5.1 of the executive
1901+
summary](configuration-analysis.md#51-spec-alignment--configuration-sdk-operations).
1902+
This deep dive focuses on concrete implementation requirements.
1903+
1904+
### I.1 YAML Environment Variable Substitution
1905+
1906+
The spec defines a `${VAR:-default}` substitution syntax for YAML configuration
1907+
files with detailed rules that differ from .NET's `IConfiguration` environment
1908+
variable provider. The substitution must happen during YAML parsing, before
1909+
values enter the `IConfiguration` tree.
1910+
1911+
#### I.1.1 Spec Requirements Summary
1912+
1913+
The substitution rules (from the [data model
1914+
spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/data-model.md#environment-variable-substitution)):
1915+
1916+
- `${VAR}` -- substitute the value of environment variable `VAR`
1917+
- `${VAR:-fallback}` -- substitute `VAR`, or `fallback` if `VAR` is undefined,
1918+
empty, or null
1919+
- `$$` -- escape sequence producing a literal `$`; the resolved `$` is not
1920+
considered for further substitution matching
1921+
- Substitution applies only to scalar values, not mapping keys
1922+
- Substitution is not recursive -- the result of one substitution is not
1923+
scanned for further `${...}` references
1924+
- YAML structure injection via env vars is prohibited -- substituted values
1925+
are always scalars
1926+
- Node types are interpreted after substitution (e.g. `${BOOL_VALUE}` where
1927+
`BOOL_VALUE=true` resolves to YAML boolean `true`, not string `"true"`)
1928+
- Invalid substitution references (e.g. `${VAR:?error}`) must produce a parse
1929+
error with no partial results
1930+
- The optional `env:` prefix is supported: `${env:VAR}` is equivalent to
1931+
`${VAR}`
1932+
1933+
#### I.1.2 Implementation Approach
1934+
1935+
The substitution should be implemented within the custom YAML
1936+
`IConfigurationProvider`. The processing order is:
1937+
1938+
```text
1939+
1. Read YAML file from disk
1940+
2. Perform ${VAR:-default} substitution on all scalar values
1941+
3. Parse substituted YAML into IConfiguration key/value pairs
1942+
4. Expose via standard IConfigurationProvider interface
1943+
```
1944+
1945+
Step 2 processes the raw YAML text (or the parsed YAML DOM scalar nodes)
1946+
before projecting into `IConfiguration`. This ensures type coercion happens
1947+
after substitution, matching the spec requirement.
1948+
1949+
#### I.1.3 Interplay with IConfiguration Environment Variable Loading
1950+
1951+
The SDK currently uses a vendored `EnvironmentVariablesConfigurationProvider` to
1952+
make `OTEL_*` env vars available as `IConfiguration` keys. When `OTEL_CONFIG_FILE`
1953+
is active, these two env-var mechanisms overlap:
1954+
1955+
| Mechanism | When it runs | What it does |
1956+
| --- | --- | --- |
1957+
| YAML `${VAR}` substitution | YAML parse time | Replaces placeholders in YAML scalar values with env var values |
1958+
| `EnvironmentVariablesConfigurationProvider` | `IConfiguration` build time | Makes all `OTEL_*` env vars available as `IConfiguration` keys that can override options |
1959+
1960+
The spec states that when `OTEL_CONFIG_FILE` is set, the config file is the
1961+
authoritative source and environment variables should not override values
1962+
defined in the file (see [Risk
1963+
3.1](configuration-analysis-risks.md#31-otel_config_file-vs-iconfiguration-hierarchy--resolution-via-sdk-option)).
1964+
The YAML `${VAR}` substitution is the spec's mechanism for env-var-driven
1965+
values within declarative config.
1966+
1967+
**Recommended behaviour when `OTEL_CONFIG_FILE` is active:**
1968+
1969+
- The `EnvironmentVariablesConfigurationProvider` for OTel-specific keys should
1970+
**not** be layered above the YAML provider in the `IConfiguration` source
1971+
chain. This prevents env vars from silently overriding YAML-defined values.
1972+
- The YAML provider's `${VAR}` substitution is the only path for env vars to
1973+
influence values defined in the YAML file.
1974+
- Env vars not represented in the YAML file (e.g. `OTEL_SERVICE_NAME` when
1975+
`resource.attributes.service.name` is absent from the YAML) should still be
1976+
available via the standard env var provider for properties that the YAML file
1977+
does not define. The priority model should be: YAML-defined values (with
1978+
`${VAR}` substitution already applied) take precedence over env var fallbacks
1979+
for the same logical property.
1980+
1981+
**When `OTEL_CONFIG_FILE` is not set:** The current behaviour is unchanged.
1982+
The `EnvironmentVariablesConfigurationProvider` remains the primary source for
1983+
`OTEL_*` keys.
1984+
1985+
#### I.1.4 Testing Considerations
1986+
1987+
The substitution implementation needs test coverage for:
1988+
1989+
- Basic substitution (`${VAR}` with defined and undefined vars)
1990+
- Default values (`${VAR:-fallback}`)
1991+
- Escape sequences (`$$`, `$$$`, `$$$$`)
1992+
- Type preservation after substitution (bool, int, float, string)
1993+
- Structure injection prevention (env var containing newlines/colons)
1994+
- Non-recursive substitution (`${VAR}` where VAR's value contains `${...}`)
1995+
- Invalid substitution references producing parse errors
1996+
- The `env:` prefix variant
1997+
1998+
The spec provides a comprehensive examples table that can be translated
1999+
directly into test cases.
2000+
2001+
### I.2 Schema Validation Requirements
2002+
2003+
The spec requires two distinct validation layers, only one of which the current
2004+
design addresses.
2005+
2006+
#### I.2.1 Two-Layer Validation Model
2007+
2008+
| Layer | What it validates | When it runs | Current status |
2009+
| --- | --- | --- | --- |
2010+
| **Schema validation** | YAML structure conforms to the config data model: required fields present, types correct, no unknown keys, valid nesting | During Parse, before values enter `IConfiguration` | **Not addressed** |
2011+
| **Options validation** | Individual option values are semantically valid: port in range, endpoint is valid URI, sampler arg in `[0.0, 1.0]` | During `DelegatingOptionsFactory.Create`, via `IValidateOptions<T>` | Addressed in [Risk 1.1](configuration-analysis-risks.md#11-options-validation-is-completely-absent) (Step 0a) |
2012+
2013+
Both layers are needed. Schema validation catches structural problems early
2014+
(before any SDK component construction). Options validation catches semantic
2015+
problems that schema alone cannot express.
2016+
2017+
#### I.2.2 Schema Validation Implementation
2018+
2019+
The spec's configuration data model is defined as a [JSON
2020+
Schema](https://github.com/open-telemetry/opentelemetry-configuration). Schema
2021+
validation can be implemented by:
2022+
2023+
1. Deserializing the YAML file into a JSON-compatible DOM
2024+
2. Validating against the published JSON Schema (or a compiled representation)
2025+
3. Reporting all violations with file location context (line/column) before
2026+
any `IConfiguration` projection
2027+
2028+
For Option C (typed model for Parse, `IConfiguration` for Create -- see
2029+
[SS5.1.1](configuration-analysis.md#511-in-memory-configuration-model)), schema
2030+
validation falls out naturally from typed deserialization: if the YAML cannot
2031+
be deserialized into the typed `OpenTelemetryConfiguration` model, Parse returns
2032+
an error.
2033+
2034+
For Option A (`IConfiguration` only), schema validation must be a separate step
2035+
before or during the YAML-to-`IConfiguration` projection.
2036+
2037+
#### I.2.3 Unknown Key Handling
2038+
2039+
The spec's JSON Schema defines the valid set of keys. The YAML provider should
2040+
detect and report unknown keys rather than silently ignoring them, since
2041+
unknown keys almost always indicate typos:
2042+
2043+
```yaml
2044+
tracer_provider:
2045+
processors:
2046+
- batch:
2047+
exporter:
2048+
otlp:
2049+
endpont: https://collector.example.com:4317 # typo: "endpont"
2050+
```
2051+
2052+
Without schema validation, `endpont` silently becomes an unused
2053+
`IConfiguration` key and the endpoint defaults to `localhost:4317`.
2054+
2055+
### I.3 `file_format` Versioning
2056+
2057+
The spec requires a `file_format` field at the root of every configuration
2058+
file:
2059+
2060+
```yaml
2061+
file_format: "0.4"
2062+
sdk:
2063+
traces:
2064+
sampler:
2065+
type: parentbased_traceidratio
2066+
arg: 0.5
2067+
```
2068+
2069+
#### I.3.1 Requirements
2070+
2071+
- The YAML `IConfigurationProvider` must read `file_format` before processing
2072+
the rest of the file
2073+
- If `file_format` is missing, Parse must return an error
2074+
- If `file_format` specifies a version the SDK does not support, Parse must
2075+
return an error with a clear message identifying supported versions
2076+
- The SDK should document which `file_format` versions it supports per release
2077+
2078+
#### I.3.2 Version Compatibility Policy
2079+
2080+
The `file_format` version follows the `opentelemetry-configuration` repository's
2081+
[versioning
2082+
policy](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md).
2083+
The SDK should support:
2084+
2085+
- The current stable `file_format` version
2086+
- Optionally, a limited set of prior versions with documented deprecation
2087+
timeline
2088+
2089+
The version check should happen as the first step in Parse, before env var
2090+
substitution or schema validation, so that version-incompatible files fail
2091+
immediately with an actionable error.

0 commit comments

Comments
 (0)