-
Notifications
You must be signed in to change notification settings - Fork 910
feat(config): support OTEL_CONFIG_FILE in the SDK configurator #5271
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
Open
MikeGoldsmith
wants to merge
24
commits into
open-telemetry:main
Choose a base branch
from
MikeGoldsmith:mike/config-file-env-routing
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+123
−0
Open
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
e5d6932
recursively convert parsed dicts to typed dataclasses in loader
MikeGoldsmith 582c37f
rename changelog fragment to PR #5269
MikeGoldsmith b302f93
tighten typing on conversion module
MikeGoldsmith 3a6fd21
isolate typing.get_type_hints call to placate astroid 3.x on py3.14
MikeGoldsmith 131378c
inline the typing.get_type_hints wrap
MikeGoldsmith 3720621
add configure_sdk orchestrator for declarative config
MikeGoldsmith fd6c20a
rename changelog fragment to PR #5270
MikeGoldsmith 7066419
honor OTEL_CONFIG_FILE in the SDK configurator
MikeGoldsmith da80d63
rename changelog fragment to PR #5271
MikeGoldsmith b6e4702
use ExemplarFilter for enum coercion test fixture; allow 'astroid' in…
MikeGoldsmith 83e17bd
Merge branch 'mike/config-recursive-dict-conversion' into mike/config…
MikeGoldsmith 52365e2
Merge branch 'mike/config-orchestrator' into mike/config-file-env-rou…
MikeGoldsmith 3fc2669
fix lint on test_sdk.py: hoist import, disable no-self-use
MikeGoldsmith 119bc83
Merge branch 'mike/config-orchestrator' into mike/config-file-env-rou…
MikeGoldsmith 417d451
silence pylint/ruff on intentional lazy imports
MikeGoldsmith 41667ca
remove extra blank line after imports (ruff I001)
MikeGoldsmith 297da35
Merge branch 'mike/config-orchestrator' into mike/config-file-env-rou…
MikeGoldsmith 2b2d47b
collapse multi-line @patch decorators (ruff format)
MikeGoldsmith 70c93d9
add end-to-end loader tests covering YAML -> typed config -> factory
MikeGoldsmith 828c54b
Merge branch 'mike/config-recursive-dict-conversion' into mike/config…
MikeGoldsmith 62cdfa4
Merge branch 'mike/config-orchestrator' into mike/config-file-env-rou…
MikeGoldsmith 111fc4a
Merge branch 'main' into mike/config-file-env-routing
MikeGoldsmith e111ebf
Merge branch 'main' into mike/config-file-env-routing
MikeGoldsmith 73982d9
address review feedback on OTEL_CONFIG_FILE routing
MikeGoldsmith File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| `opentelemetry-sdk`: declarative config loader now recursively converts parsed dicts into typed dataclass instances, including nested dataclasses, lists of dataclasses, and enum values. End-to-end YAML/JSON → SDK configuration now works via the factory functions. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| `opentelemetry-sdk`: add `configure_sdk(config)` to the declarative configuration API. Single entry point that takes a parsed `OpenTelemetryConfiguration`, builds the resource, and applies the tracer/meter/logger providers and propagator globally. Honors the top-level `disabled` flag. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| `opentelemetry-sdk`: the SDK configurator now honors the `OTEL_CONFIG_FILE` environment variable. When set, the SDK loads and applies the referenced declarative configuration file (YAML or JSON) in place of the env-var-based init path. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| [codespell] | ||
| # skipping auto generated folders | ||
| skip = ./.tox,./.mypy_cache,./docs/_build,./target,*/LICENSE,./venv,.git,./opentelemetry-semantic-conventions,*-requirements*.txt | ||
| ignore-words-list = ans,ue,ot,hist,ro | ||
| ignore-words-list = ans,ue,ot,hist,ro,astroid |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_conversion.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| # Copyright The OpenTelemetry Authors | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| """Recursive dict-to-dataclass conversion for parsed config data. | ||
|
|
||
| The YAML/JSON loader produces nested dicts. Factory functions expect typed | ||
| dataclass instances (e.g. ``TracerProvider``, ``SpanProcessor``). This module | ||
| walks each field's type annotation and converts nested dicts into their | ||
| corresponding dataclass types. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import dataclasses | ||
| import enum | ||
| import types | ||
| import typing | ||
| from collections.abc import Mapping | ||
| from typing import Any, TypeVar, Union, get_args, get_origin | ||
|
|
||
| _T = TypeVar("_T") | ||
|
|
||
|
|
||
| def _unwrap_optional(type_hint: Any) -> Any: | ||
| """Strip ``None`` from a ``X | None`` / ``Optional[X]`` annotation. | ||
|
|
||
| Returns the unwrapped type, or the original hint if not a Union with None. | ||
| """ | ||
| origin = get_origin(type_hint) | ||
| if origin is Union or origin is types.UnionType: | ||
| non_none = [t for t in get_args(type_hint) if t is not type(None)] | ||
| if len(non_none) == 1: | ||
| return non_none[0] | ||
| return type_hint | ||
|
|
||
|
|
||
| def _convert_value(value: Any, type_hint: Any) -> Any: | ||
| """Convert a value according to its type hint. | ||
|
|
||
| Recursively converts dicts to dataclasses and lists of dicts to lists of | ||
| dataclasses. Other values (primitives, enums, ``dict[str, Any]`` aliases) | ||
| pass through unchanged. | ||
| """ | ||
| if value is None: | ||
| return None | ||
|
|
||
| unwrapped = _unwrap_optional(type_hint) | ||
| origin = get_origin(unwrapped) | ||
|
|
||
| # list[X] — recurse on each element | ||
| if origin is list and isinstance(value, list): | ||
| args = get_args(unwrapped) | ||
| if args: | ||
| item_type = args[0] | ||
| return [_convert_value(item, item_type) for item in value] | ||
| return value | ||
|
|
||
| # Direct dataclass type — recurse | ||
| if ( | ||
| isinstance(unwrapped, type) | ||
| and dataclasses.is_dataclass(unwrapped) | ||
| and isinstance(value, dict) | ||
| ): | ||
| return _dict_to_dataclass(value, unwrapped) | ||
|
|
||
| # Enum type — coerce string/value to the Enum member | ||
| if ( | ||
| isinstance(unwrapped, type) | ||
| and issubclass(unwrapped, enum.Enum) | ||
| and not isinstance(value, unwrapped) | ||
| ): | ||
| return unwrapped(value) | ||
|
|
||
| return value | ||
|
|
||
|
|
||
| def _dict_to_dataclass(data: Mapping[str, Any], cls: type[_T]) -> _T: | ||
| """Recursively convert a mapping to a dataclass instance. | ||
|
|
||
| For each key in ``data``: | ||
| - If it matches a known dataclass field, the value is converted according | ||
| to that field's type annotation (recursing for nested dataclasses). | ||
| - Unknown keys are passed through as kwargs; classes decorated with | ||
| ``@_additional_properties`` will capture them on the instance's | ||
| ``additional_properties`` attribute. | ||
|
|
||
| ``ClassVar`` fields (e.g. the ``additional_properties`` annotation on | ||
| decorated dataclasses) are ignored as expected. | ||
|
|
||
| Raises: | ||
| TypeError: If ``cls`` is not a dataclass type. | ||
| """ | ||
| if not dataclasses.is_dataclass(cls): | ||
| raise TypeError(f"{cls.__name__} is not a dataclass") | ||
|
|
||
| # Annotated as ``dict[str, Any]`` so astroid stops tracing into | ||
| # ``typing.get_type_hints`` — under pylint 3.x that path leads into | ||
| # Python 3.14's ``annotationlib`` (which uses t-strings) and crashes. | ||
| hints: dict[str, Any] = dict( | ||
| typing.get_type_hints(cls, include_extras=False) | ||
| ) | ||
| known_fields = {f.name for f in dataclasses.fields(cls)} | ||
| kwargs: dict[str, Any] = {} | ||
|
|
||
| for key, value in data.items(): | ||
| if key in known_fields: | ||
| type_hint = hints.get(key) | ||
| kwargs[key] = _convert_value(value, type_hint) | ||
| else: | ||
| # Unknown key — @_additional_properties decorator will capture it. | ||
| kwargs[key] = value | ||
|
|
||
| return cls(**kwargs) |
64 changes: 64 additions & 0 deletions
64
opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_sdk.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| # Copyright The OpenTelemetry Authors | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| """Top-level orchestrator for declarative SDK configuration. | ||
|
|
||
| Takes a parsed ``OpenTelemetryConfiguration`` and applies it by calling | ||
| each per-signal ``configure_*`` factory in order. This is the single | ||
| entry point for "apply this config" on the declarative path. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import logging | ||
|
|
||
| from opentelemetry.sdk._configuration._logger_provider import ( | ||
| configure_logger_provider, | ||
| ) | ||
| from opentelemetry.sdk._configuration._meter_provider import ( | ||
| configure_meter_provider, | ||
| ) | ||
| from opentelemetry.sdk._configuration._propagator import configure_propagator | ||
| from opentelemetry.sdk._configuration._resource import create_resource | ||
| from opentelemetry.sdk._configuration._tracer_provider import ( | ||
| configure_tracer_provider, | ||
| ) | ||
| from opentelemetry.sdk._configuration.models import OpenTelemetryConfiguration | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def configure_sdk(config: OpenTelemetryConfiguration) -> None: | ||
| """Configure the global SDK from a parsed declarative configuration. | ||
|
|
||
| Builds a :class:`Resource` from ``config.resource`` and applies it to | ||
| each signal provider. Sets the global tracer provider, meter provider, | ||
| logger provider, and text map propagator from their respective config | ||
| sections. Sections absent from the config (``None``) leave the | ||
| corresponding global untouched — matching the spec's "noop default" | ||
| behavior. | ||
|
|
||
| Honors the top-level ``disabled`` flag: when true, no globals are set. | ||
|
|
||
| Args: | ||
| config: Parsed ``OpenTelemetryConfiguration`` (typically from | ||
| ``load_config_file``). | ||
|
|
||
| Example: | ||
| >>> from opentelemetry.sdk._configuration.file import ( | ||
| ... load_config_file, configure_sdk, | ||
| ... ) | ||
| >>> config = load_config_file("otel-config.yaml") | ||
| >>> configure_sdk(config) | ||
| """ | ||
| if config.disabled: | ||
| _logger.info( | ||
| "Declarative configuration has disabled=true; skipping SDK setup." | ||
| ) | ||
| return | ||
|
|
||
| resource = create_resource(config.resource) | ||
| configure_tracer_provider(config.tracer_provider, resource) | ||
| configure_meter_provider(config.meter_provider, resource) | ||
| configure_logger_provider(config.logger_provider, resource) | ||
| configure_propagator(config.propagator) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.