SIGN IN SIGN UP

opentelemetry-configuration: substitute env vars after parsing (#5406) (#5407)

* opentelemetry-configuration: substitute env vars after parsing (#5406)

Environment variable substitution ran on the raw configuration file text
before parsing, so a ${VAR} reference inside a YAML comment was treated as
a real substitution -- an undefined variable in a comment crashed loading,
and documenting the substitution mechanism was impossible.

Parse the file first, then substitute only within scalar values (never in
comments or mapping keys), matching the configuration spec and the Java and
Node.js implementations. For an unquoted standalone ${VAR} reference the YAML
node's type tag is re-resolved from the substituted value so type coercion
still applies (e.g. ${LIMIT} -> int); quoted or embedded references resolve
to strings. JSON string values are substituted in place.

* Rename changelog fragment to PR number

* Rename substitute_env_vars parameter to configuration_value and clarify docstring

* Use 'configuration value' instead of 'scalar value' in docs and comments

* Explain the YAML node substitution and type re-resolution logic

* Add worked example tracing an unquoted standalone reference through the node walker

* Keep public parameter name of substitute_env_vars

substitute_env_vars is re-exported in
opentelemetry.configuration.file.__all__, so renaming its parameter is a
breaking public API change. Restore the parameter name to text to satisfy
the public-symbols-check while keeping the docstring that explains the
configuration-value semantics.

* Fix CI: ruff format docstring quotes and rename shadowing test parameter

* Reformat with ruff at line-length 120

* Substitute each YAML node once when anchors and aliases share it

An alias resolves to the same composed node as its anchor, so the walker
reached one node once per reference to it. That substituted the node
repeatedly, which re-read the previous pass's output: an anchored
$${TOKEN} became the literal ${TOKEN} on the first visit, and the second
visit resolved it as a real variable, defeating the escape and exposing
the value. Merge keys took the same path, since a merge key's value node
is the anchored mapping itself. A cyclic alias made the node tree a
graph with a loop, so the walk recursed until it raised RecursionError.

Thread a set of visited node ids through the traversal and return early
on a node already seen.
D
Diego Hurtado committed
953c8db3d83e522d079bd606362f273d0f001e30
Parent: 4f96edc
Committed by GitHub <noreply@github.com> on 8/25/2026, 10:03:34 AM