Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changelog/5535.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`opentelemetry-sdk`: fix values for `process.executable.name` and `process.executable.path` to match semantic conventions.
Original file line number Diff line number Diff line change
Expand Up @@ -367,21 +367,20 @@ def detect(self) -> "Resource":
)
)
_process_pid = os.getpid()
_process_executable_name = sys.executable
_process_executable_path = os.path.dirname(_process_executable_name)
# Use sys.orig_argv, which preserves the original arguments received
# by the interpreter. This correctly captures ``python -m <module>``
# invocations where sys.argv is rewritten to the resolved module path
# and the ``-m <module>`` information is lost. Only read argv[0] by
# default because full command arguments are opt-in.
_process_command = sys.orig_argv[0] if sys.orig_argv else ""
executable = sys.executable or ""
resource_info: dict[str, AttributeValue] = {
PROCESS_RUNTIME_DESCRIPTION: sys.version,
PROCESS_RUNTIME_NAME: sys.implementation.name,
PROCESS_RUNTIME_VERSION: _runtime_version,
PROCESS_PID: _process_pid,
PROCESS_EXECUTABLE_NAME: _process_executable_name,
PROCESS_EXECUTABLE_PATH: _process_executable_path,
PROCESS_EXECUTABLE_NAME: os.path.basename(executable),
PROCESS_EXECUTABLE_PATH: executable,
PROCESS_COMMAND: _process_command,
}
if self._include_command_args:
Expand Down
21 changes: 18 additions & 3 deletions opentelemetry-sdk/tests/resources/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ def test_service_name_env_precedence(self):
"sys.orig_argv",
["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"],
)
@patch("sys.executable", "/usr/bin/uvicorn")
def test_process_detector(self):
initial_resource = Resource({"foo": "bar"})
aggregated_resource = get_aggregated_resources([ProcessResourceDetector()], initial_resource)
Expand Down Expand Up @@ -662,13 +663,13 @@ def test_process_detector(self):

self.assertEqual(
aggregated_resource.attributes[PROCESS_EXECUTABLE_NAME],
sys.executable,
"uvicorn",
)
self.assertEqual(
aggregated_resource.attributes[PROCESS_EXECUTABLE_PATH],
os.path.dirname(sys.executable),
"/usr/bin/uvicorn",
)
self.assertEqual(aggregated_resource.attributes[PROCESS_COMMAND], sys.orig_argv[0])
self.assertEqual(aggregated_resource.attributes[PROCESS_COMMAND], "uvicorn")
self.assertNotIn(
PROCESS_COMMAND_LINE,
aggregated_resource.attributes,
Expand Down Expand Up @@ -769,6 +770,20 @@ def test_process_detector_uses_orig_argv_for_python_m_on_opt_in(self):
("/usr/bin/python", "-m", "myapp"),
)

@patch("sys.executable", None)
def test_process_detector_handles_missing_executable(self):
initial_resource = Resource({"foo": "bar"})
aggregated_resource = get_aggregated_resources([ProcessResourceDetector()], initial_resource)

self.assertEqual(
aggregated_resource.attributes[PROCESS_EXECUTABLE_NAME],
"",
)
self.assertEqual(
aggregated_resource.attributes[PROCESS_EXECUTABLE_PATH],
"",
)

def test_resource_detector_entry_points_default(self):
resource = Resource({}).create()

Expand Down
Loading