From e63db2d891b960a9f03c65fb66d226e79e75b1cd Mon Sep 17 00:00:00 2001 From: Louis Tricot Date: Thu, 6 Nov 2025 17:07:27 +0100 Subject: [PATCH 1/3] chore(di): add process_tags --- ddtrace/debugging/_encoding.py | 4 ++ tests/debugging/test_encoding.py | 67 ++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/ddtrace/debugging/_encoding.py b/ddtrace/debugging/_encoding.py index 3d4ecbc0f8c..a558200f113 100644 --- a/ddtrace/debugging/_encoding.py +++ b/ddtrace/debugging/_encoding.py @@ -20,6 +20,7 @@ from ddtrace.debugging._signal.log import LogSignal from ddtrace.debugging._signal.snapshot import Snapshot from ddtrace.internal import forksafe +from ddtrace.internal import process_tags from ddtrace.internal._encoding import BufferFull from ddtrace.internal.logger import get_logger from ddtrace.internal.utils.formats import format_trace_id @@ -113,6 +114,9 @@ def _build_log_track_payload( "timestamp": int(signal.timestamp * 1e3), # milliseconds, } + if p_tags := process_tags.process_tags: + payload["process_tags"] = p_tags + # Add the correlation IDs if available if context is not None and context.trace_id is not None: payload["dd"] = { diff --git a/tests/debugging/test_encoding.py b/tests/debugging/test_encoding.py index 7604c98afe3..84872ba8d74 100644 --- a/tests/debugging/test_encoding.py +++ b/tests/debugging/test_encoding.py @@ -250,6 +250,73 @@ def test_batch_json_encoder(): assert queue.count == 0 +def test_process_tags_are_not_included_by_default(): + s = Snapshot( + probe=create_snapshot_line_probe(probe_id="batch-test", source_file="foo.py", line=42), + frame=inspect.currentframe(), + thread=threading.current_thread(), + ) + buffer_size = 30 * (1 << 20) + queue = SignalQueue(encoder=LogSignalJsonEncoder(None), buffer_size=buffer_size) + + s.line({}) + + queue = SignalQueue(encoder=LogSignalJsonEncoder("test-service")) + queue.put(s) + data = queue.flush() + assert data is not None + payload, _ = data + decoded = json.loads(payload.decode()) + assert "process_tags" not in decoded[0] + + +def test_process_tags_are_included(): + from unittest.mock import patch + + from ddtrace.internal.process_tags import _process_tag_reload + from ddtrace.internal.process_tags.constants import ENTRYPOINT_BASEDIR_TAG + from ddtrace.internal.process_tags.constants import ENTRYPOINT_NAME_TAG + from ddtrace.internal.process_tags.constants import ENTRYPOINT_TYPE_SCRIPT + from ddtrace.internal.process_tags.constants import ENTRYPOINT_TYPE_TAG + from ddtrace.internal.process_tags.constants import ENTRYPOINT_WORKDIR_TAG + from ddtrace.settings._config import config + + try: + with patch("sys.argv", ["/path/to/test_script.py"]), patch("os.getcwd", return_value="/path/to/workdir"): + config._process_tags_enabled = True + _process_tag_reload() + s = Snapshot( + probe=create_snapshot_line_probe(probe_id="batch-test", source_file="foo.py", line=42), + frame=inspect.currentframe(), + thread=threading.current_thread(), + ) + buffer_size = 30 * (1 << 20) + queue = SignalQueue(encoder=LogSignalJsonEncoder(None), buffer_size=buffer_size) + + s.line({}) + + queue = SignalQueue(encoder=LogSignalJsonEncoder("test-service")) + queue.put(s) + data = queue.flush() + assert data is not None + payload, _ = data + decoded = json.loads(payload.decode()) + + assert "process_tags" in decoded[0] + + expected_raw = ( + f"{ENTRYPOINT_BASEDIR_TAG}:to," + f"{ENTRYPOINT_NAME_TAG}:test_script," + f"{ENTRYPOINT_TYPE_TAG}:{ENTRYPOINT_TYPE_SCRIPT}," + f"{ENTRYPOINT_WORKDIR_TAG}:workdir" + ) + + assert decoded[0]["process_tags"] == expected_raw + finally: + config._process_tags_enabled = False + _process_tag_reload() + + def test_batch_flush_reencode(): s = Snapshot( probe=create_snapshot_line_probe(probe_id="batch-test", source_file="foo.py", line=42), From f82a7d222610bf8bfdfa177001ebe490f10462fe Mon Sep 17 00:00:00 2001 From: Louis Tricot Date: Wed, 12 Nov 2025 16:46:51 +0100 Subject: [PATCH 2/3] review --- tests/debugging/test_encoding.py | 57 +++++++++++--------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/tests/debugging/test_encoding.py b/tests/debugging/test_encoding.py index 84872ba8d74..4fc304dc2ef 100644 --- a/tests/debugging/test_encoding.py +++ b/tests/debugging/test_encoding.py @@ -271,50 +271,33 @@ def test_process_tags_are_not_included_by_default(): def test_process_tags_are_included(): - from unittest.mock import patch - - from ddtrace.internal.process_tags import _process_tag_reload - from ddtrace.internal.process_tags.constants import ENTRYPOINT_BASEDIR_TAG - from ddtrace.internal.process_tags.constants import ENTRYPOINT_NAME_TAG - from ddtrace.internal.process_tags.constants import ENTRYPOINT_TYPE_SCRIPT - from ddtrace.internal.process_tags.constants import ENTRYPOINT_TYPE_TAG - from ddtrace.internal.process_tags.constants import ENTRYPOINT_WORKDIR_TAG - from ddtrace.settings._config import config + from ddtrace.internal.settings._config import config + from tests.utils import process_tag_reload try: - with patch("sys.argv", ["/path/to/test_script.py"]), patch("os.getcwd", return_value="/path/to/workdir"): - config._process_tags_enabled = True - _process_tag_reload() - s = Snapshot( - probe=create_snapshot_line_probe(probe_id="batch-test", source_file="foo.py", line=42), - frame=inspect.currentframe(), - thread=threading.current_thread(), - ) - buffer_size = 30 * (1 << 20) - queue = SignalQueue(encoder=LogSignalJsonEncoder(None), buffer_size=buffer_size) + config._process_tags_enabled = True + process_tag_reload() + s = Snapshot( + probe=create_snapshot_line_probe(probe_id="batch-test", source_file="foo.py", line=42), + frame=inspect.currentframe(), + thread=threading.current_thread(), + ) + buffer_size = 30 * (1 << 20) + queue = SignalQueue(encoder=LogSignalJsonEncoder(None), buffer_size=buffer_size) - s.line({}) + s.line({}) - queue = SignalQueue(encoder=LogSignalJsonEncoder("test-service")) - queue.put(s) - data = queue.flush() - assert data is not None - payload, _ = data - decoded = json.loads(payload.decode()) - - assert "process_tags" in decoded[0] - - expected_raw = ( - f"{ENTRYPOINT_BASEDIR_TAG}:to," - f"{ENTRYPOINT_NAME_TAG}:test_script," - f"{ENTRYPOINT_TYPE_TAG}:{ENTRYPOINT_TYPE_SCRIPT}," - f"{ENTRYPOINT_WORKDIR_TAG}:workdir" - ) + queue = SignalQueue(encoder=LogSignalJsonEncoder("test-service")) + queue.put(s) + data = queue.flush() + assert data is not None + payload, _ = data + decoded = json.loads(payload.decode()) - assert decoded[0]["process_tags"] == expected_raw + assert "process_tags" in decoded[0] finally: config._process_tags_enabled = False - _process_tag_reload() + process_tag_reload() def test_batch_flush_reencode(): From e17639356a458eed94077f73c0d5df19573d1fef Mon Sep 17 00:00:00 2001 From: Louis Tricot Date: Tue, 18 Nov 2025 16:05:56 +0100 Subject: [PATCH 3/3] improve tests --- tests/debugging/test_encoding.py | 57 +++++++++++++++++--------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/tests/debugging/test_encoding.py b/tests/debugging/test_encoding.py index 4fc304dc2ef..225dfbb975b 100644 --- a/tests/debugging/test_encoding.py +++ b/tests/debugging/test_encoding.py @@ -270,34 +270,39 @@ def test_process_tags_are_not_included_by_default(): assert "process_tags" not in decoded[0] +@pytest.mark.subprocess( + env=dict( + DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED="true", + ) +) def test_process_tags_are_included(): - from ddtrace.internal.settings._config import config - from tests.utils import process_tag_reload + import inspect + import json + import threading - try: - config._process_tags_enabled = True - process_tag_reload() - s = Snapshot( - probe=create_snapshot_line_probe(probe_id="batch-test", source_file="foo.py", line=42), - frame=inspect.currentframe(), - thread=threading.current_thread(), - ) - buffer_size = 30 * (1 << 20) - queue = SignalQueue(encoder=LogSignalJsonEncoder(None), buffer_size=buffer_size) - - s.line({}) - - queue = SignalQueue(encoder=LogSignalJsonEncoder("test-service")) - queue.put(s) - data = queue.flush() - assert data is not None - payload, _ = data - decoded = json.loads(payload.decode()) - - assert "process_tags" in decoded[0] - finally: - config._process_tags_enabled = False - process_tag_reload() + from ddtrace.debugging._encoding import LogSignalJsonEncoder + from ddtrace.debugging._encoding import SignalQueue + from ddtrace.debugging._signal.snapshot import Snapshot + from tests.debugging.utils import create_snapshot_line_probe + + s = Snapshot( + probe=create_snapshot_line_probe(probe_id="batch-test", source_file="foo.py", line=42), + frame=inspect.currentframe(), + thread=threading.current_thread(), + ) + buffer_size = 30 * (1 << 20) + queue = SignalQueue(encoder=LogSignalJsonEncoder(None), buffer_size=buffer_size) + + s.line({}) + + queue = SignalQueue(encoder=LogSignalJsonEncoder("test-service")) + queue.put(s) + data = queue.flush() + assert data is not None + payload, _ = data + decoded = json.loads(payload.decode()) + + assert "process_tags" in decoded[0] def test_batch_flush_reencode():