Skip to content

Implement declarative config ConfigProvider / ConfigProperties API - #5486

Open
ocelotl wants to merge 4 commits into
open-telemetry:mainfrom
ocelotl:issue_5485_configprovider
Open

Implement declarative config ConfigProvider / ConfigProperties API#5486
ocelotl wants to merge 4 commits into
open-telemetry:mainfrom
ocelotl:issue_5485_configprovider

Conversation

@ocelotl

@ocelotl ocelotl commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the declarative configuration Instrumentation Configuration API
(configuration/api.md),
which was previously not implemented in Python.

  • ConfigProperties — a typed, schemaless read view over a parsed
    configuration mapping node: get_string, get_bool, get_int, get_float,
    get_config (nested view), get_config_list, get_scalar_list, keys(),
    and __contains__. Getters return None on a missing key or type mismatch,
    matching the spec and Java's DeclarativeConfigProperties semantics.
  • ConfigProvider — holds the ConfigProperties for the .instrumentation
    config node and exposes get_instrumentation_config().
  • A global default ConfigProvider with get_config_provider() /
    set_config_provider(), so instrumentation libraries can access configuration
    during initialization.
  • configure_sdk now builds a ConfigProvider from the .instrumentation
    node and installs it as the global (empty when the node is absent).

All symbols are exported from opentelemetry.configuration.

Scope

This PR is intentionally scoped to the API surface (ConfigProvider /
ConfigProperties) and its wiring into configure_sdk. The related but separate
concern of making Create/configure_sdk return the top-level SDK components as
a pure builder is not included here and can be tracked separately.

Fixes #5485.

Type of change

  • New feature (non-breaking change which adds functionality)

ConfigProvider is Development stability in the spec; the package is already
marked experimental. ConfigProperties is Stable in the spec.

How Has This Been Tested?

  • New opentelemetry-configuration/tests/test_config_provider.py (26 tests)
    covering scalar getters, type-mismatch/None behavior, bool/int
    disambiguation, nested get_config/get_config_list/get_scalar_list,
    dataclass-node normalization, and the global provider get/set.
  • Full opentelemetry-configuration suite passes locally (406 passed, 29
    subtests) — no regressions from the configure_sdk wiring.

Does This PR Require a Contrib Repo Change?

No.

Checklist

  • Followed the style guidelines of this project
  • Unit tests have been added
  • Added a changelog entry (.changelog/5485.added; will rename to the PR
    number if preferred)

ocelotl added 2 commits July 29, 2026 17:19
Adds the Instrumentation Configuration API from the declarative
configuration spec (configuration/api.md), which was previously
unimplemented in Python:

- ConfigProperties: a typed, schemaless read view over a parsed
  configuration mapping node, with get_string/get_bool/get_int/
  get_float, get_config, get_config_list, get_scalar_list, and key
  introspection. Getters return None on a missing key or type mismatch,
  matching the spec and Java's DeclarativeConfigProperties semantics.
- ConfigProvider: holds the ConfigProperties for the instrumentation
  config node and exposes get_instrumentation_config().
- A global default ConfigProvider with get_config_provider() /
  set_config_provider(), so instrumentation libraries can access it.
- configure_sdk now builds a ConfigProvider from the .instrumentation
  node and sets it as the global.

Fixes open-telemetry#5485.
Make the global ConfigProvider consistent with the other OpenTelemetry
globals (tracer/meter/logger):

- set_config_provider is now set-once, guarded by a thread-safe Once. A
  second call logs a warning and keeps the existing provider instead of
  overwriting it (the previous version warned but overwrote, and was not
  thread-safe).
- get_config_provider returns a NoOpConfigProvider (empty instrumentation
  config) when none is set, rather than None, so callers can traverse the
  config tree without None checks — mirroring ProxyTracerProvider and
  Java's ConfigProvider.noop(). Its return type is now non-optional.
@ocelotl

ocelotl commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Updated the global ConfigProvider to follow the same convention as set_tracer_provider/get_tracer_provider (and metrics/_logs):

  • set_config_provider is now set-once, guarded by a thread-safe Once. A second call logs "Overriding of current ConfigProvider is not allowed" and keeps the existing provider (previously it warned but overwrote, and wasn't thread-safe).
  • get_config_provider() now returns a NoOpConfigProvider (empty instrumentation config) when none is set instead of None, so callers can traverse the tree without None checks — mirroring ProxyTracerProvider and Java's ConfigProvider.noop(). Return type is non-optional.

NoOpConfigProvider is exported. Added a set-once test; full opentelemetry-configuration suite passes (407 passed, 29 subtests).

ocelotl added 2 commits July 29, 2026 18:48
…list getters

Address further consistency gaps with existing opentelemetry-python APIs:

- get_config_provider now returns a forwarding ProxyConfigProvider (reads
  the global lazily) instead of a frozen no-op, so a provider obtained
  before set_config_provider still resolves to the one installed later —
  matching ProxyTracerProvider / ProxyLoggerProvider. NoOpConfigProvider is
  kept as an explicit no-op (mirroring NoOpTracerProvider).
- ConfigProperties getters now log a warning when a key is present with an
  incompatible type, instead of silently returning None (matching the
  package's own logging habits and Java's DeclarativeConfigProperties).
- Replaced get_scalar_list(name, type) with typed getters get_string_list,
  get_bool_list, get_int_list, get_float_list, consistent with the scalar
  getters and avoiding a runtime type argument.
- keys() now returns a set (matching the spec's "set of property keys").
…f import order

- Rename changelog fragment 5485.added -> 5486.added to match the PR number
  (the changelog check requires <PR_NUMBER>.<type>).
- Make ConfigProperties._log_type_mismatch a staticmethod (it does not use
  self) to satisfy pylint R6301 (no-self-use).
- Disable protected-access in the test setUp that resets the module globals
  (pylint W0212).
- Sort imports in the test module (ruff I001).
@ocelotl
ocelotl marked this pull request as ready for review July 30, 2026 00:59
@ocelotl
ocelotl requested a review from a team as a code owner July 30, 2026 00:59
@ocelotl

ocelotl commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

@jack-berg @trask @mmanciop

_logger.warning("Overriding of current ConfigProvider is not allowed")


def get_config_provider() -> ConfigProvider:

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.

I'm not sure if making the ConfigProvider accessible before initialization in a similar manner to Tracers/Loggers/Meter is desirable in this case. Why not just forward it as an argument to the instrument function on instrumentor classes and provide a no-op config provider if not initialized? What exactly is the global state buying us here as opposed to threading it through regular function calls? I'd imagine that receiving a ProxyConfigProvider instance wouldn't be that useful since consumers will almost always read from the configuration immediately.

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

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Instrumentation Configuration API (ConfigProvider / ConfigProperties) is not implemented

2 participants