Skip to content

feat(config): Add TracerProvider support for declarative config#4985

Merged
xrmx merged 22 commits intoopen-telemetry:mainfrom
MikeGoldsmith:mike/config-tracer-provider
Apr 8, 2026
Merged

feat(config): Add TracerProvider support for declarative config#4985
xrmx merged 22 commits intoopen-telemetry:mainfrom
MikeGoldsmith:mike/config-tracer-provider

Conversation

@MikeGoldsmith
Copy link
Copy Markdown
Member

@MikeGoldsmith MikeGoldsmith commented Mar 16, 2026

Description

Implements create_tracer_provider() and configure_tracer_provider() for the declarative configuration pipeline, as part of the ongoing work tracked in the following PR:

Note

This PR is based on #4979 (Resource & Propagator creation) which must be merged first. The extra commits at the base of this branch will be dropped once that PR lands.

What's included

  • _tracer_provider.py: creates an SDK TracerProvider from declarative config
  • Supports all sampler types: always_on, always_off, trace_id_ratio_based, parent_based (with all 4 delegate samplers)
  • Supports BatchSpanProcessor and SimpleSpanProcessor
  • Supports OTLP HTTP, OTLP gRPC, and Console span exporters
  • Lazy imports for optional OTLP packages with a ConfigurationError if not installed
  • SpanLimits and sampler use OTel spec defaults for absent fields — no env-var leakage
  • configure_tracer_provider(None) is a no-op per spec/Java/JS behavior
  • 32 new tests covering all paths including env-var suppression

Env-var suppression

Python's TracerProvider reads OTEL_TRACES_SAMPLER when sampler=None, and SpanLimits reads OTEL_SPAN_*_LIMIT when fields are None. To match the spec's "what you see is what you get" semantics (and Java SDK behavior), we always pass explicit values — defaulting to spec defaults (e.g. ParentBased(root=ALWAYS_ON), 128 for count limits) rather than falling through to env vars.

Type of change

  • 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

How Has This Been Tested?

  • 32 unit tests in tests/_configuration/test_tracer_provider.py
  • Includes explicit tests that env vars (OTEL_TRACES_SAMPLER, OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT) are not read when config is used

Does This PR Require a Contrib Repo Change?

  • Yes.
  • No.

Checklist:

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

Assisted-by: Claude Sonnet 4.6

Implements create_resource() and create_propagator()/configure_propagator()
for the declarative file configuration. Resource creation does not read
OTEL_RESOURCE_ATTRIBUTES or run any detectors (matches Java/JS SDK behavior).
Propagator configuration always calls set_global_textmap to override Python's
default tracecontext+baggage, setting a noop CompositePropagator when no
propagator is configured.

Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
- _resource.py: refactor _coerce_attribute_value to dispatch table to
  avoid too-many-return-statements; fix short variable names k/v ->
  attr_key/attr_val; fix return type of _sdk_default_attributes to
  dict[str, str] to satisfy pyright
- _propagator.py: rename short variable names e -> exc, p -> propagator
- test_resource.py: move imports to top level; split TestCreateResource
  (25 methods) into three focused classes to satisfy too-many-public-methods
- test_propagator.py: add pylint disable for protected-access

Assisted-by: Claude Sonnet 4.6
- replace _sdk_default_attributes() with _DEFAULT_RESOURCE from resources module
- move _coerce_bool into dispatch tables for both scalar and array bool types,
  fixing a bug where bool_array with string values like "false" would coerce
  incorrectly via plain bool() (non-empty string -> True)
- add test for bool_array with string values to cover the bug

Assisted-by: Claude Sonnet 4.6
MikeGoldsmith added a commit to MikeGoldsmith/opentelemetry-python that referenced this pull request Mar 16, 2026
Assisted-by: Claude Sonnet 4.6
…erge

- collapse _SCALAR_COERCIONS and _ARRAY_COERCIONS into a single _COERCIONS
  dict using an _array() factory, reducing _coerce_attribute_value to two lines
- process attributes_list before attributes so explicit attributes naturally
  overwrite list entries without needing an explicit guard

Assisted-by: Claude Sonnet 4.6
Comment thread opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_resource.py
@MikeGoldsmith MikeGoldsmith changed the title feat(config): TracerProvider creation from declarative config feat(config): Add TracerProvider support for declarative config Mar 18, 2026
Assisted-by: Claude Sonnet 4.6
Adds _run_detectors() stub and _filter_attributes() to create_resource(),
providing the shared scaffolding for detector PRs to build on. Detectors
are opt-in: nothing runs unless explicitly listed under
detection_development.detectors in the config. The include/exclude
attribute filter mirrors other SDK behaviour.

Assisted-by: Claude Sonnet 4.6
Merges service.name=unknown_service into base before running detectors,
so detectors (e.g. service) can override it. Previously it was added to
config_attrs and merged last, which would have silently overridden any
detector-provided service.name.

Assisted-by: Claude Sonnet 4.6
MikeGoldsmith added a commit to MikeGoldsmith/opentelemetry-python that referenced this pull request Mar 20, 2026
Assisted-by: Claude Sonnet 4.6
@MikeGoldsmith MikeGoldsmith force-pushed the mike/config-tracer-provider branch from a54d5b1 to 9653d67 Compare March 20, 2026 14:30
Implements create_tracer_provider() and configure_tracer_provider() for
the declarative configuration pipeline (tracking issue open-telemetry#3631 step 5).

Key behaviors:
- Never reads OTEL_TRACES_SAMPLER or OTEL_SPAN_*_LIMIT env vars; absent
  config fields use OTel spec defaults (matching Java SDK behavior)
- Default sampler is ParentBased(root=ALWAYS_ON) per the OTel spec
- SpanLimits absent fields use hardcoded defaults (128) not env vars
- configure_tracer_provider(None) is a no-op per spec/Java/JS behavior
- OTLP exporter fields pass None through so the exporter reads its own
  env vars for unspecified values
- Lazy imports for optional OTLP packages with ConfigurationError on missing
- Supports all 4 ParentBased delegate samplers

Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
- add # noqa: PLC0415 to lazy OTLP imports (ruff also enforces this)
- move SDK imports to top-level (BatchSpanProcessor, etc.)
- convert test helper methods to @staticmethod to satisfy no-self-use
- add pylint: disable=protected-access for private member access in tests
- fix return type annotation on _create_span_processor

Assisted-by: Claude Sonnet 4.6
@MikeGoldsmith MikeGoldsmith force-pushed the mike/config-tracer-provider branch from 9653d67 to 232b06f Compare March 20, 2026 18:35
Comment thread opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_tracer_provider.py Outdated
Comment thread opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_tracer_provider.py Outdated
Comment thread opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_propagator.py Outdated
Comment thread opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_resource.py Outdated
@MikeGoldsmith MikeGoldsmith marked this pull request as ready for review April 3, 2026 15:24
@MikeGoldsmith MikeGoldsmith requested a review from a team as a code owner April 3, 2026 15:24
Assisted-by: Claude Sonnet 4.6
@xrmx xrmx merged commit f764e45 into open-telemetry:main Apr 8, 2026
509 checks passed
@MikeGoldsmith MikeGoldsmith added the config Issues and PRs related to implementing Declarative Config label Apr 8, 2026
@MikeGoldsmith MikeGoldsmith deleted the mike/config-tracer-provider branch April 9, 2026 14:12
chimchim89 pushed a commit to chimchim89/opentelemetry-python that referenced this pull request Apr 15, 2026
…-telemetry#4985)

* config: add resource and propagator creation from declarative config

Implements create_resource() and create_propagator()/configure_propagator()
for the declarative file configuration. Resource creation does not read
OTEL_RESOURCE_ATTRIBUTES or run any detectors (matches Java/JS SDK behavior).
Propagator configuration always calls set_global_textmap to override Python's
default tracecontext+baggage, setting a noop CompositePropagator when no
propagator is configured.

Assisted-by: Claude Sonnet 4.6

* update changelog with PR number

Assisted-by: Claude Sonnet 4.6

* fix pylint, pyright and ruff errors in resource/propagator config

- _resource.py: refactor _coerce_attribute_value to dispatch table to
  avoid too-many-return-statements; fix short variable names k/v ->
  attr_key/attr_val; fix return type of _sdk_default_attributes to
  dict[str, str] to satisfy pyright
- _propagator.py: rename short variable names e -> exc, p -> propagator
- test_resource.py: move imports to top level; split TestCreateResource
  (25 methods) into three focused classes to satisfy too-many-public-methods
- test_propagator.py: add pylint disable for protected-access

Assisted-by: Claude Sonnet 4.6

* address review feedback: use _DEFAULT_RESOURCE, fix bool_array coercion

- replace _sdk_default_attributes() with _DEFAULT_RESOURCE from resources module
- move _coerce_bool into dispatch tables for both scalar and array bool types,
  fixing a bug where bool_array with string values like "false" would coerce
  incorrectly via plain bool() (non-empty string -> True)
- add test for bool_array with string values to cover the bug

Assisted-by: Claude Sonnet 4.6

* fix linter

* address review feedback: single coercion table, simplify attributes merge

- collapse _SCALAR_COERCIONS and _ARRAY_COERCIONS into a single _COERCIONS
  dict using an _array() factory, reducing _coerce_attribute_value to two lines
- process attributes_list before attributes so explicit attributes naturally
  overwrite list entries without needing an explicit guard

Assisted-by: Claude Sonnet 4.6

* use Callable type annotation on _array helper

Assisted-by: Claude Sonnet 4.6

* add detection infrastructure foundations for resource detectors

Adds _run_detectors() stub and _filter_attributes() to create_resource(),
providing the shared scaffolding for detector PRs to build on. Detectors
are opt-in: nothing runs unless explicitly listed under
detection_development.detectors in the config. The include/exclude
attribute filter mirrors other SDK behaviour.

Assisted-by: Claude Sonnet 4.6

* move service.name default into base resource

Merges service.name=unknown_service into base before running detectors,
so detectors (e.g. service) can override it. Previously it was added to
config_attrs and merged last, which would have silently overridden any
detector-provided service.name.

Assisted-by: Claude Sonnet 4.6

* remove unused logging import from _propagator.py

Assisted-by: Claude Sonnet 4.6

* add TracerProvider creation from declarative config

Implements create_tracer_provider() and configure_tracer_provider() for
the declarative configuration pipeline (tracking issue open-telemetry#3631 step 5).

Key behaviors:
- Never reads OTEL_TRACES_SAMPLER or OTEL_SPAN_*_LIMIT env vars; absent
  config fields use OTel spec defaults (matching Java SDK behavior)
- Default sampler is ParentBased(root=ALWAYS_ON) per the OTel spec
- SpanLimits absent fields use hardcoded defaults (128) not env vars
- configure_tracer_provider(None) is a no-op per spec/Java/JS behavior
- OTLP exporter fields pass None through so the exporter reads its own
  env vars for unspecified values
- Lazy imports for optional OTLP packages with ConfigurationError on missing
- Supports all 4 ParentBased delegate samplers

Assisted-by: Claude Sonnet 4.6

* add changelog entry for PR open-telemetry#4985

Assisted-by: Claude Sonnet 4.6

* fix CI lint/type failures in tracer provider config

- add # noqa: PLC0415 to lazy OTLP imports (ruff also enforces this)
- move SDK imports to top-level (BatchSpanProcessor, etc.)
- convert test helper methods to @staticmethod to satisfy no-self-use
- add pylint: disable=protected-access for private member access in tests
- fix return type annotation on _create_span_processor

Assisted-by: Claude Sonnet 4.6

* fix pylint no-self-use on TestCreateSampler._make_provider

Assisted-by: Claude Sonnet 4.6

* use allowlist for bool coercion in declarative config resource

Assisted-by: Claude Sonnet 4.6

* address review feedback: simplify resource filter and propagator loading

Assisted-by: Claude Sonnet 4.6

* fix ruff formatting

Assisted-by: Claude Sonnet 4.6

* fix pyright: wrap EntryPoints in iter() for next() compatibility

Assisted-by: Claude Sonnet 4.6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config Issues and PRs related to implementing Declarative Config

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants