Skip to content

api: conditionally load entrypoints for OTEL_PYTHON_CONTEXT#5144

Open
codeboten wants to merge 25 commits into
open-telemetry:mainfrom
codeboten:codeboten/load-context-api
Open

api: conditionally load entrypoints for OTEL_PYTHON_CONTEXT#5144
codeboten wants to merge 25 commits into
open-telemetry:mainfrom
codeboten:codeboten/load-context-api

Conversation

@codeboten
Copy link
Copy Markdown
Contributor

@codeboten codeboten commented Apr 24, 2026

Description

This prevents unnecessarily importing the entry points library, reducing the memory footprint of loading the API by about a MB (27%):

Scenario Memory before Memory after delta
Import API only 5.43 MB 4.49 MB -940 KB
API + get_tracer (no-op) 5.05 MB 4.10 MB -950 KB

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Ran unit tests locallt

Does This PR Require a Contrib Repo Change?

  • No.

Checklist:

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

This prevents unnecessarily importing the entry points library, reducing
the memory footprint of loading the API by about a MB (27%):

|Scenario | Memory before | Memory after | delta |
| - | - | - | - |
|Import API only | 5.43 MB | 4.49 MB | -940 KB |
|API + get_tracer (no-op) | 5.05 MB | 4.10 MB | -950 KB |

Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
@codeboten codeboten requested a review from a team as a code owner April 24, 2026 20:43
@codeboten codeboten marked this pull request as draft April 24, 2026 20:43
Copy link
Copy Markdown
Member

@MikeGoldsmith MikeGoldsmith left a comment

Choose a reason for hiding this comment

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

Looks good, thanks @codeboten. Please add a changelog entry 👍🏻

Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
@codeboten codeboten marked this pull request as ready for review April 27, 2026 16:49
@codeboten
Copy link
Copy Markdown
Contributor Author

added changelog, ptal

Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

@codeboten codeboten left a comment

Choose a reason for hiding this comment

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

dont think the check-links failure is related to this change

Copy link
Copy Markdown
Member

@MikeGoldsmith MikeGoldsmith left a comment

Choose a reason for hiding this comment

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

Nice, thanks @codeboten 🚀

@github-project-automation github-project-automation Bot moved this to Approved PRs in Python PR digest Apr 29, 2026
@codeboten
Copy link
Copy Markdown
Contributor Author

@open-telemetry/python-maintainers is there anything else needed on this pr to move it forward?

@herin049
Copy link
Copy Markdown
Contributor

@open-telemetry/python-maintainers is there anything else needed on this pr to move it forward?

@codeboten There are a large number of PRs in the backlog, so unfortunately it's just a bit of a waiting game.

@codeboten
Copy link
Copy Markdown
Contributor Author

thanks @herin049, just making sure there isn't something i should be doing here :)

@emdneto
Copy link
Copy Markdown
Member

emdneto commented May 12, 2026

Thanks for the PR!

Just a heads-up: we no longer update CHANGELOG.md directly. The changelog is now generated from changelog fragments using Towncrier.

Please add the appropriate changelog fragment for this change instead of editing CHANGELOG.md manually. You can find the instructions and expected format in CONTRIBUTING.md.

@xrmx
Copy link
Copy Markdown
Contributor

xrmx commented May 13, 2026

We have a WIP PR that will remove importlib_metadata dependency so maybe we can revise this after that to check if importlib.metadata has the same footprint?

codeboten added 2 commits May 14, 2026 08:17
Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
@MikeGoldsmith
Copy link
Copy Markdown
Member

MikeGoldsmith commented May 14, 2026

We have a WIP PR that will remove importlib_metadata dependency so maybe we can revise this after that to check if importlib.metadata has the same footprint?

Is there any harm is accepting this and then updating to the other PR to update the import library if we want to accept it? This PR predates the importlib PR by 3 weeks and been approved for 2 weeks.

This is the PR:

@xrmx
Copy link
Copy Markdown
Contributor

xrmx commented May 14, 2026

We have a WIP PR that will remove importlib_metadata dependency so maybe we can revise this after that to check if importlib.metadata has the same footprint?

Is there any harm is accepting this and then updating to the other PR to update the import library if we want to accept it? This PR predates the importlib PR by 3 weeks and been approved for 2 weeks.

Sorry I'm assuming that moving the import of importlib_metadata into the user of that code takes part in improving memory usage and startup time. Then I was asking to double check that's the case with the stdlib version as well. If that's not the case then we can put back it at the top level?

@codeboten
Copy link
Copy Markdown
Contributor Author

I've run some comparisons on top of the changes in the importlib-metadata PR and here's the results:

Scenario Without branch With branch Savings
1. Python baseline (no OTel)
2. Import opentelemetry API 5.85 MB 5.58 MB 279 KB
3. API + get_tracer (no-op) 5.47 MB 5.20 MB 280 KB
4. SDK TracerProvider (no exporter) 8.38 MB 8.11 MB 279 KB
5. SDK TracerProvider + OTLP 17.93 MB 17.66 MB 278 KB
6. SDK MeterProvider (no exporter) 9.18 MB 8.90 MB 278 KB
7. SDK LoggerProvider (no exporter) 8.26 MB 7.98 MB 278 KB
8. Full SDK 9.87 MB 9.60 MB 278 KB

Copy link
Copy Markdown
Member

@aabmass aabmass left a comment

Choose a reason for hiding this comment

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

@xrmx OK to merge this? It looks like it's still a noticeable improvement

Comment thread opentelemetry-api/src/opentelemetry/context/__init__.py
codeboten added 3 commits May 19, 2026 07:22
Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
Comment thread opentelemetry-api/src/opentelemetry/util/_providers.py
@aabmass
Copy link
Copy Markdown
Member

aabmass commented May 20, 2026

From public API Check

opentelemetry-api/src/opentelemetry/propagate/__init__.py:0: propagators: Public object was removed
opentelemetry-api/src/opentelemetry/propagate/__init__.py:0: environ_propagators: Public object was removed
opentelemetry-api/src/opentelemetry/propagate/__init__.py:0: propagator: Public object was removed

I wonder if anyone in the wild was using these accidentally exposed imports. We could probably do a quick GH search to check if this inadvertently breaks anyone.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR reduces the baseline import cost of opentelemetry-api by deferring entry_points usage (and related metadata machinery) until it’s actually needed, especially around context selection via OTEL_PYTHON_CONTEXT.

Changes:

  • Lazily import entry_points in provider loading utilities to avoid importing entry point machinery during a plain API import.
  • Update propagator initialization to avoid entry_points when OTEL_PROPAGATORS is unset (use direct default propagator classes instead).
  • Update runtime context initialization to return ContextVarsRuntimeContext directly when OTEL_PYTHON_CONTEXT is not set, and only consult entry points when it is set.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
opentelemetry-api/src/opentelemetry/util/_providers.py Moves entry_points import inside _load_provider to avoid import-time overhead unless env-driven provider loading occurs.
opentelemetry-api/src/opentelemetry/propagate/init.py Introduces _load_propagators() and avoids entry point loading for the default propagators when OTEL_PROPAGATORS is unset.
opentelemetry-api/src/opentelemetry/context/init.py Avoids entry_points unless OTEL_PYTHON_CONTEXT is explicitly configured; falls back directly to ContextVarsRuntimeContext.
.changelog/5144.changed Adds a changelog entry for the conditional entry point import behavior change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .changelog/5144.changed Outdated
Comment on lines +128 to +140
# pylint: disable=import-outside-toplevel,no-name-in-module
from opentelemetry.util._importlib_metadata import ( # noqa: PLC0415
entry_points,
)

propagators: list[textmap.TextMapPropagator] = []
for propagator in configured.split(","):
propagator = propagator.strip()
if propagator.lower() == "none":
logger.debug(
"OTEL_PROPAGATORS environment variable contains none, removing all propagators"
)
return composite.CompositePropagator([])
Comment on lines +25 to 41
configured_context = os.environ.get(OTEL_PYTHON_CONTEXT)
if not configured_context:
return ContextVarsRuntimeContext()

# FIXME use a better implementation of a configuration manager
# to avoid having to get configuration values straight from
# environment variables
default_context = "contextvars_context"

configured_context = environ.get(OTEL_PYTHON_CONTEXT, default_context) # type: str
# pylint: disable=import-outside-toplevel,no-name-in-module
from opentelemetry.util._importlib_metadata import ( # noqa: PLC0415
entry_points,
)

try:
return next( # type: ignore
iter( # type: ignore
entry_points( # type: ignore
group="opentelemetry_context",
name=configured_context,
return next(
iter(
entry_points(
group="opentelemetry_context", name=configured_context
)
)
).load()()
@xrmx
Copy link
Copy Markdown
Contributor

xrmx commented May 20, 2026

@xrmx OK to merge this? It looks like it's still a noticeable improvement

I'm not opposed to merge this since we have a bunch of approvals already and there's some memory savings. I haven't profiled this myself so I don't know what part of the changes is responsible of the savings and I'm not sure all the delayed imports in this PRs (e.g. the propagators) makes a difference or not.

Out of scope for to this PR but if we are going to think about memory optimizations we should probably track something in benchmarks so we can see if there's regressions.
Speaking of optimizations, auto-instrumentation sdk config is probalby the biggest user of entry points so if they are a pain point there we can have the biggest wins.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@aabmass
Copy link
Copy Markdown
Member

aabmass commented May 20, 2026

Agreed no lazy imports. IMO we should just wait for 3.15 since it's been solved in python.

Speaking of optimizations, auto-instrumentation sdk config is probalby the biggest user of entry points so if they are a pain point there we can have the biggest wins.

I believe this PR is trying to optimizing the opposite case, where entry_points can be totally avoided easily. (sorry if I'm recapping what you already knew)

codeboten added 3 commits May 20, 2026 14:59
Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
@codeboten
Copy link
Copy Markdown
Contributor Author

From public API Check

opentelemetry-api/src/opentelemetry/propagate/__init__.py:0: propagators: Public object was removed
opentelemetry-api/src/opentelemetry/propagate/__init__.py:0: environ_propagators: Public object was removed
opentelemetry-api/src/opentelemetry/propagate/__init__.py:0: propagator: Public object was removed

I wonder if anyone in the wild was using these accidentally exposed imports. We could probably do a quick GH search to check if this inadvertently breaks anyone.

I ended up putting those back, didn't want to break a public api

@aabmass aabmass enabled auto-merge May 21, 2026 02:37
@aabmass
Copy link
Copy Markdown
Member

aabmass commented May 21, 2026

Thank you @codeboten! I turned on auto merge which should start once the Copilot comments are resolved

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

Labels

None yet

Projects

Status: Approved PRs

Development

Successfully merging this pull request may close these issues.

7 participants