Skip to content

Commit 44d8911

Browse files
alliasgherMikeGoldsmithxrmx
authored
fix(sdk): use sys.orig_argv for process.command to handle python -m invocations (#5083)
* fix(sdk): use sys.orig_argv for process.command to handle python -m invocations ProcessResourceDetector populated process.command, process.command_line, and process.command_args from sys.argv. For applications launched via `python -m <module>`, the interpreter rewrites sys.argv[0] to the resolved module path, so the ``-m <module>`` portion of the original invocation is lost and the detector emits misleading telemetry. Python 3.10+ exposes sys.orig_argv which preserves the original arguments received by the interpreter. Since the SDK already requires Python >= 3.10, switch to sys.orig_argv (with a getattr fallback for safety). This also aligns with the OTel semantic conventions that reference /proc/<pid>/cmdline for these attributes. Fixes #4518 Signed-off-by: Ali <alliasgher123@gmail.com> * nit: drop sys.orig_argv fallback and use PR number in changelog Two review nits from MikeGoldsmith: - sys.orig_argv has been available since Python 3.10; the SDK now requires 3.10+ so the getattr fallback is dead code. Use sys.orig_argv directly and update the comment. - CHANGELOG entries should reference the PR number, not the issue number. Signed-off-by: Ali <alliasgher123@gmail.com> * test: remove redundant sys.argv patch from test_process_detector Signed-off-by: Ali <alliasgher123@gmail.com> * test: drop superfluous sys.argv mock in python-m test The detector reads only sys.orig_argv, so patching sys.argv had no effect on the test's outcome. Keep only the sys.orig_argv patch. Signed-off-by: Ali <alliasgher123@gmail.com> --------- Signed-off-by: Ali <alliasgher123@gmail.com> Co-authored-by: Mike Goldsmith <goldsmith.mike@gmail.com> Co-authored-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
1 parent 849cfac commit 44d8911

3 files changed

Lines changed: 40 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2828
([#5076](https://github.com/open-telemetry/opentelemetry-python/pull/5076))
2929
- `opentelemetry-semantic-conventions`: use `X | Y` union annotation
3030
([#5096](https://github.com/open-telemetry/opentelemetry-python/pull/5096))
31+
- `opentelemetry-sdk`: Fix `ProcessResourceDetector` to use `sys.orig_argv` so that `process.command`, `process.command_line`, and `process.command_args` reflect the original invocation for `python -m <module>` runs (where `sys.argv[0]` is rewritten to the module path)
32+
([#5083](https://github.com/open-telemetry/opentelemetry-python/pull/5083))
3133
- `opentelemetry-sdk`: make resource detector ordering deterministic
3234
([#5120](https://github.com/open-telemetry/opentelemetry-python/pull/5120))
3335
- Add WeaverLiveCheck test util

opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,16 @@ def detect(self) -> "Resource":
385385
_process_pid = os.getpid()
386386
_process_executable_name = sys.executable
387387
_process_executable_path = os.path.dirname(_process_executable_name)
388-
_process_command = sys.argv[0]
389-
_process_command_line = " ".join(sys.argv)
390-
_process_command_args = sys.argv
388+
# Use sys.orig_argv, which preserves the original arguments received
389+
# by the interpreter. This correctly captures ``python -m <module>``
390+
# invocations where sys.argv is rewritten to the resolved module path
391+
# and the ``-m <module>`` information is lost. sys.orig_argv also
392+
# aligns with /proc/<pid>/cmdline, which the OTel semantic
393+
# conventions reference for these attributes.
394+
_process_argv = list(sys.orig_argv)
395+
_process_command = _process_argv[0] if _process_argv else ""
396+
_process_command_line = " ".join(_process_argv)
397+
_process_command_args = _process_argv
391398
resource_info = {
392399
PROCESS_RUNTIME_DESCRIPTION: sys.version,
393400
PROCESS_RUNTIME_NAME: sys.implementation.name,

opentelemetry-sdk/tests/resources/test_resources.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ def test_service_name_env_precedence(self):
574574
)
575575

576576
@patch(
577-
"sys.argv",
577+
"sys.orig_argv",
578578
["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"],
579579
)
580580
def test_process_detector(self):
@@ -620,15 +620,39 @@ def test_process_detector(self):
620620
os.path.dirname(sys.executable),
621621
)
622622
self.assertEqual(
623-
aggregated_resource.attributes[PROCESS_COMMAND], sys.argv[0]
623+
aggregated_resource.attributes[PROCESS_COMMAND], sys.orig_argv[0]
624624
)
625625
self.assertEqual(
626626
aggregated_resource.attributes[PROCESS_COMMAND_LINE],
627-
" ".join(sys.argv),
627+
" ".join(sys.orig_argv),
628628
)
629629
self.assertEqual(
630630
aggregated_resource.attributes[PROCESS_COMMAND_ARGS],
631-
tuple(sys.argv),
631+
tuple(sys.orig_argv),
632+
)
633+
634+
@patch("sys.orig_argv", ["/usr/bin/python", "-m", "myapp"])
635+
def test_process_detector_uses_orig_argv_for_python_m(self):
636+
"""For ``python -m <module>`` invocations sys.argv[0] is rewritten to
637+
the resolved module path, losing the ``-m <module>`` information.
638+
sys.orig_argv preserves the original invocation and must be preferred.
639+
See https://github.com/open-telemetry/opentelemetry-python/issues/4518.
640+
"""
641+
aggregated_resource = get_aggregated_resources(
642+
[ProcessResourceDetector()], Resource({"foo": "bar"})
643+
)
644+
645+
self.assertEqual(
646+
aggregated_resource.attributes[PROCESS_COMMAND],
647+
"/usr/bin/python",
648+
)
649+
self.assertEqual(
650+
aggregated_resource.attributes[PROCESS_COMMAND_LINE],
651+
"/usr/bin/python -m myapp",
652+
)
653+
self.assertEqual(
654+
aggregated_resource.attributes[PROCESS_COMMAND_ARGS],
655+
("/usr/bin/python", "-m", "myapp"),
632656
)
633657

634658
def test_resource_detector_entry_points_default(self):

0 commit comments

Comments
 (0)