Skip to content

opentelemetry-configuration: split Parse/Create per the configuration spec - #5829

Open
herin049 wants to merge 3 commits into
open-telemetry:mainfrom
herin049:fix/configuration-create-sdk
Open

herin049 wants to merge 3 commits into
open-telemetry:mainfrom
herin049:fix/configuration-create-sdk

Conversation

@herin049

Copy link
Copy Markdown
Contributor

Description

Aligns opentelemetry-configuration with the declarative configuration spec's Parse and Create operations.

  • load_config_file -> load_config: accepts a path or a text stream (with file_format).
  • New create_sdk(config) -> SdkComponents: stateless; returns the tracer/meter/logger providers, propagator, and resource. configure_sdk now creates first and only then installs globals.
  • Omitted provider sections yield no-op providers; disabled: true keeps the configured propagator. Providers already created are shut down if creation fails.
  • One-of schema types (e.g. Sampler) reject zero or multiple choices at construction.
  • SDK: MeterProvider.add_metric_reader now sets the reader's meter provider, and readers added at runtime are included in force_flush/shutdown.

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist:

See contributing.md for styleguide, changelog guidelines, and more.

  • I am a human and not a bot
  • I have run tox -e precommit
  • I have run tox -e typecheck
  • I have run the relevant tests and linting tox environments
  • This requires the following PR in contrib:

@herin049
herin049 requested a review from a team as a code owner October 26, 2026 03:41
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-11-05 19:18 UTC

Two things need attention:

  • Required checks are failing — investigate the failures.
  • 5 review items — respond to each (e.g. link a commit, explain why not, ask a follow-up):
    • Inline threads: 1, 2, 3, 4, 5
Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Should this be with reviewers? Comment /dashboard route:reviewers to route it to them.
  • Anything wrong — including the routing? Report it with what you expected; it helps us improve the dashboard.

@herin049 herin049 added the Approve Public API check This label shows that the public symbols added or changed in a PR are strictly necessary label Oct 26, 2026
@herin049
herin049 force-pushed the fix/configuration-create-sdk branch 2 times, most recently from 93ecc00 to dde4865 Compare October 26, 2026 03:47
@herin049
herin049 force-pushed the fix/configuration-create-sdk branch from dde4865 to 6f16380 Compare November 4, 2026 04:44
@herin049
herin049 requested a balanced review from Copilot November 4, 2026 04:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Choice-validation errors reject valid configurations and accept empty samplers, while a metric-reader registration race can cause KeyError and failure-path cleanup can leak resources or mask the original configuration error.

4 open issues
What changed in this PR

This PR separates declarative configuration parsing from SDK creation, allowing applications to build isolated SDK components before optionally installing them globally.

Changes:

  • Replaces load_config_file with path-or-stream load_config, and adds create_sdk and SdkComponents.
  • Adds one-of model validation, no-op provider defaults, failure cleanup, and self-observability wiring.
  • Updates metric-reader lifecycle handling, documentation, unit tests, and Docker scenarios.
File Description
tox.ini Supplies one-of metadata during model generation.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_self_observability/​scenario.yaml Defines internal-metrics expectations.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_self_observability/​run.py Emits spans and waits for metric collection.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_self_observability/​otel-config.yaml Configures trace and internal-metric export.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_omitted_providers_noop/​scenario.yaml Checks omitted providers remain no-op.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_omitted_providers_noop/​run.py Reports provider types and emits a span.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_omitted_providers_noop/​otel-config.yaml Configures only the tracer provider.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_disabled/​scenario.yaml Updates the description of disabled behavior.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_disabled_propagator/​scenario.yaml Checks propagation while providers are disabled.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_disabled_propagator/​run.py Reports extracted baggage and trace context.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​general_disabled_propagator/​otel-config.yaml Combines disabled providers with baggage propagation.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​error_sampler_no_choice/​scenario.yaml Checks rejection of an unselected sampler.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​error_sampler_no_choice/​run.py Attempts tracing after invalid configuration.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​error_sampler_no_choice/​otel-config.yaml Supplies a null sampler choice.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​error_partial_config_not_applied/​scenario.yaml Checks failed creation leaves globals unchanged.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​error_partial_config_not_applied/​run.py Reports the tracer provider after failure.
tests/​opentelemetry-docker-tests/​tests/​declconfig/​scenarios/​error_partial_config_not_applied/​otel-config.yaml Supplies an unavailable metric exporter.
pyproject.toml Adds the generated validation-decorator import.
opentelemetry-sdk/​tests/​metrics/​test_metrics.py Tests runtime reader registration and lifecycle.
opentelemetry-sdk/​tests/​_configuration/​test_configurator_file_routing.py Updates routing tests to load_config.
opentelemetry-sdk/​src/​opentelemetry/​sdk/​metrics/​_internal/​__init__.py Tracks runtime readers and initializes their metrics.
opentelemetry-sdk/​src/​opentelemetry/​sdk/​_configuration/​__init__.py Routes declarative startup through load_config.
opentelemetry-configuration/​tests/​test_tracer_provider.py Updates validation and self-metrics tests.
opentelemetry-configuration/​tests/​test_sdk.py Tests creation, global installation, and cleanup.
opentelemetry-configuration/​tests/​test_propagator.py Tests propagator creation without global installation.
opentelemetry-configuration/​tests/​test_meter_provider.py Tests reader cleanup and exporter metric wiring.
opentelemetry-configuration/​tests/​test_logger_provider.py Updates factory calls and validation expectations.
opentelemetry-configuration/​tests/​test_conversion.py Expects rejection of a null sampler choice.
opentelemetry-configuration/​tests/​test_common.py Adds decorator and generated-model validation tests.
opentelemetry-configuration/​tests/​file/​test_loader.py Tests renamed loading API and stream support.
opentelemetry-configuration/​tests/​file/​test_configurator_yaml.py Adopts load_config in YAML tests.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​models.py Applies one-of validation to generated models.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​file/​_loader.py Adds path-or-stream parsing and format selection.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​file/​__init__.py Updates file-configuration exports.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​_tracer_provider.py Threads the meter provider through trace components.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​_sdk.py Separates component creation from global installation.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​_propagator.py Removes the global-installation wrapper.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​_meter_provider.py Creates readers after their provider and adds cleanup.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​_logger_provider.py Threads the meter provider through logging components.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​_common.py Adds exactly-one-choice validation.
opentelemetry-configuration/​src/​opentelemetry/​configuration/​__init__.py Exposes and documents the new public API.
opentelemetry-configuration/​README.rst Documents separate parsing and creation workflows.
opentelemetry-configuration/​codegen/​README.md Explains generated one-of validation.
opentelemetry-configuration/​codegen/​one_of_template_data.py Derives validation flags from schema constraints.
opentelemetry-configuration/​codegen/​dataclass.jinja2 Emits the one-of validation decorator.
.changelog/​5829.changed Records the breaking configuration API changes.

Review effort: Balanced

``ValueError``.
"""
original_init = cls.__init__
field_names = tuple(f.name for f in dataclasses.fields(cls))
Comment on lines +651 to +654
# pylint: disable-next=protected-access
metric_reader._set_collect_callback(self._measurement_consumer.collect)
# pylint: disable-next=protected-access
metric_reader._set_meter_provider(self)
provider.add_metric_reader(_create_metric_reader(reader_config, provider))
except Exception:
# Shut down readers already added, e.g. a running periodic reader.
provider.shutdown()
if config is not None:
for proc_config in config.processors:
provider.add_span_processor(_create_span_processor(proc_config))
provider.add_span_processor(_create_span_processor(proc_config, meter_provider))
class _Choice:
first: dict | None = None
second: dict | None = None
additional_properties: ClassVar[dict[str, Any]]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here in test_common.py, ClassVar was removed from imports in #5286 (breaking precommit and lint) and should be field(default_factory=dict, init=False). Also, once _exactly_one_property filters if f.init, fields(model_cls) on lines 475 and 486 will need if field.init, and other = model_cls() on line 362 will need a built-in field (e.g. first = next(f.name for f in fields(model_cls) if f.init); other = model_cls(**{first: {}})) so other.additional_properties stays {}.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Approve Public API check This label shows that the public symbols added or changed in a PR are strictly necessary

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants