From c0c53a748547dddb21b22a917c43f6bc65b0f1ec Mon Sep 17 00:00:00 2001 From: manvi Date: Mon, 4 May 2026 18:16:09 +0530 Subject: [PATCH 1/3] fix: batch pip installs in bootstrap for faster installs --- CHANGELOG.md | 3 ++- .../instrumentation/bootstrap.py | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93f0cab4fc..d06a1ad59e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#4457](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4457)) ### Fixed - +- `opentelemetry-instrumentation`: Batch all packages into a single `pip install` call in `bootstrap.py` to improve performance + ([#4484](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/4484)) - `opentelemetry-instrumentation-pika` Use `ObjectProxy` instead of `BaseObjectProxy` for `ReadyMessagesDequeProxy` to restore iterability with wrapt 2.x ([#4461](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4461)) - `opentelemetry-instrumentation-dbapi` Use `ObjectProxy` instead of `BaseObjectProxy` for `TracedCursorProxy` to restore iterability with wrapt 2.x diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py index 3fbee088e4..ee03ba7801 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py @@ -42,24 +42,24 @@ def _syscall(func): - def wrapper(package=None): + def wrapper(packages=None): try: - if package: - return func(package) + if packages: + return func(packages) return func() except SubprocessError as exp: cmd = getattr(exp, "cmd", None) if cmd: msg = f'Error calling system command "{" ".join(cmd)}"' - if package: - msg = f'{msg} for package "{package}"' + if packages: + msg = f'{msg} for package "{packages}"' raise RuntimeError(msg) return wrapper @_syscall -def _sys_pip_install(package): +def _sys_pip_install(packages): # explicit upgrade strategy to override potential pip config try: check_call( @@ -71,7 +71,7 @@ def _sys_pip_install(package): "-U", "--upgrade-strategy", "only-if-needed", - package, + *packages, ] ) except CalledProcessError as error: @@ -134,8 +134,9 @@ def _run_requirements(default_instrumentations, libraries): def _run_install(default_instrumentations, libraries): - for lib in _find_installed_libraries(default_instrumentations, libraries): - _sys_pip_install(lib) + libs = list(_find_installed_libraries(default_instrumentations, libraries)) + if libs: + _sys_pip_install(libs) _pip_check(libraries) From ad6581d4614b10d2fc1f1c5650353f48737800c8 Mon Sep 17 00:00:00 2001 From: manvi Date: Tue, 5 May 2026 10:50:11 +0530 Subject: [PATCH 2/3] update changelog with PR link --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d06a1ad59e..e56afd1e0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - `opentelemetry-instrumentation`: Batch all packages into a single `pip install` call in `bootstrap.py` to improve performance - ([#4484](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/4484)) + ([#4530](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4530)) - `opentelemetry-instrumentation-pika` Use `ObjectProxy` instead of `BaseObjectProxy` for `ReadyMessagesDequeProxy` to restore iterability with wrapt 2.x ([#4461](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4461)) - `opentelemetry-instrumentation-dbapi` Use `ObjectProxy` instead of `BaseObjectProxy` for `TracedCursorProxy` to restore iterability with wrapt 2.x From df930c40333ee415f90ddb1d0247e6d7d353ce54 Mon Sep 17 00:00:00 2001 From: manvi Date: Tue, 5 May 2026 21:51:04 +0530 Subject: [PATCH 3/3] fix: add --no-upgrade flag to skip -U in pip install --- .../instrumentation/bootstrap.py | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py index ee03ba7801..e0934b7334 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py @@ -42,10 +42,10 @@ def _syscall(func): - def wrapper(packages=None): + def wrapper(packages=None, upgrade=True): try: if packages: - return func(packages) + return func(packages, upgrade) return func() except SubprocessError as exp: cmd = getattr(exp, "cmd", None) @@ -59,21 +59,14 @@ def wrapper(packages=None): @_syscall -def _sys_pip_install(packages): +def _sys_pip_install(packages, upgrade=True): # explicit upgrade strategy to override potential pip config try: - check_call( - [ - sys.executable, - "-m", - "pip", - "install", - "-U", - "--upgrade-strategy", - "only-if-needed", - *packages, - ] - ) + cmd = [sys.executable, "-m", "pip", "install"] + if upgrade: + cmd += ["-U", "--upgrade-strategy", "only-if-needed"] + cmd += [*packages] + check_call(cmd) except CalledProcessError as error: print(error) @@ -133,10 +126,10 @@ def _run_requirements(default_instrumentations, libraries): ) -def _run_install(default_instrumentations, libraries): +def _run_install(default_instrumentations, libraries, upgrade=True): libs = list(_find_installed_libraries(default_instrumentations, libraries)) if libs: - _sys_pip_install(libs) + _sys_pip_install(libs, upgrade=upgrade) _pip_check(libraries) @@ -171,6 +164,11 @@ def run( be piped and appended to a requirements.txt file. """, ) + parser.add_argument( + "--no-upgrade", + action="store_true", + help="Do not upgrade packages with -U flag during install", + ) args = parser.parse_args() if libraries is None: @@ -179,8 +177,9 @@ def run( if default_instrumentations is None: default_instrumentations = gen_default_instrumentations - cmd = { - action_install: _run_install, - action_requirements: _run_requirements, - }[args.action] - cmd(default_instrumentations, libraries) + if args.action == action_install: + _run_install( + default_instrumentations, libraries, upgrade=not args.no_upgrade + ) + else: + _run_requirements(default_instrumentations, libraries)