-
Notifications
You must be signed in to change notification settings - Fork 468
chore(internal): add process_tags to APM payload #15146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 28 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
d76a11d
chore(internal): add process_tags to first span of each payload
dubloom a3643d8
tests(process_tags): add tests
dubloom a52e8cc
lint
dubloom f943f2a
fix: suitespec
dubloom 660bd64
fix: telemetry test
dubloom ace7fae
Merge branch 'main' into dubloom/process-tags-collection
dubloom 78dd521
fix telemetry 2
dubloom dd58490
simplify process_tags (brett review)
dubloom f47539e
Merge branch 'main' into dubloom/process-tags-collection
dubloom 184ef53
update python version
dubloom be2973e
put tests within internal suite
dubloom c6b4d7f
remove sys hack
dubloom c6cb1be
make tests compatible with CI
dubloom 974b474
Merge branch 'main' into dubloom/process-tags-collection
dubloom 7416466
lint
dubloom 0428dcd
brett review
dubloom b66d6a4
Merge branch 'main' into dubloom/process-tags-collection
dubloom 71b5ed7
Merge branch 'main' into dubloom/process-tags-collection
dubloom a123350
Merge branch 'main' into dubloom/process-tags-collection
dubloom 32ddf35
improve tag normalization
dubloom ee77b0e
Merge branch 'main' into dubloom/process-tags-collection
dubloom f5c3eee
Merge branch 'main' into dubloom/process-tags-collection
dubloom 7cf4143
gab review
dubloom ae20207
improving normalization
dubloom f70b7ed
Merge branch 'main' into dubloom/process-tags-collection
dubloom efe28fa
remove print
dubloom f957552
Update tests/internal/test_process_tags.py
dubloom 86f04db
Merge branch 'main' into dubloom/process-tags-collection
dubloom 914d52a
add a test that activates the feature with env variable
dubloom fdd6480
chore(di): add process_tags (#15225)
dubloom fa3dbb8
Merge branch 'main' into dubloom/process-tags-collection
dubloom aa23d07
lint
dubloom 30436ab
Merge branch 'main' into dubloom/process-tags-collection
dubloom File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import os | ||
| from pathlib import Path | ||
| import re | ||
| import sys | ||
| from typing import Optional | ||
|
|
||
| from ddtrace.internal.logger import get_logger | ||
| from ddtrace.internal.settings._config import config | ||
|
|
||
|
|
||
| log = get_logger(__name__) | ||
|
|
||
| ENTRYPOINT_NAME_TAG = "entrypoint.name" | ||
| ENTRYPOINT_WORKDIR_TAG = "entrypoint.workdir" | ||
| ENTRYPOINT_TYPE_TAG = "entrypoint.type" | ||
| ENTRYPOINT_TYPE_SCRIPT = "script" | ||
| ENTRYPOINT_BASEDIR_TAG = "entrypoint.basedir" | ||
|
|
||
| _CONSECUTIVE_UNDERSCORES_PATTERN = re.compile(r"_{2,}") | ||
| _ALLOWED_CHARS = _ALLOWED_CHARS = frozenset("abcdefghijklmnopqrstuvwxyz0123456789/:._-") | ||
| MAX_LENGTH = 200 | ||
|
|
||
|
|
||
| def normalize_tag_value(value: str) -> str: | ||
| # we copy the behavior of the agent which | ||
| # checks the size on the original value and not on | ||
| # an intermediary normalized step | ||
| if len(value) > MAX_LENGTH: | ||
| value = value[:MAX_LENGTH] | ||
|
|
||
| result = value.lower() | ||
|
|
||
| def is_allowed_char(char: str) -> str: | ||
| # ASCII alphanumeric and special chars: / : . _ - | ||
| if char in _ALLOWED_CHARS: | ||
| return char | ||
| # Unicode letters and digits | ||
| if char.isalpha() or char.isdigit(): | ||
| return char | ||
| return "_" | ||
|
|
||
| result = "".join(is_allowed_char(char) for char in result) | ||
| result = _CONSECUTIVE_UNDERSCORES_PATTERN.sub("_", result) | ||
| return result.strip("_") | ||
|
|
||
|
|
||
| def generate_process_tags() -> Optional[str]: | ||
| if not config._process_tags_enabled: | ||
| return None | ||
|
|
||
| try: | ||
| return ",".join( | ||
| f"{key}:{normalize_tag_value(value)}" | ||
| for key, value in sorted( | ||
P403n1x87 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| [ | ||
| (ENTRYPOINT_WORKDIR_TAG, os.path.basename(os.getcwd())), | ||
| (ENTRYPOINT_BASEDIR_TAG, Path(sys.argv[0]).resolve().parent.name), | ||
| (ENTRYPOINT_NAME_TAG, os.path.splitext(os.path.basename(sys.argv[0]))[0]), | ||
| (ENTRYPOINT_TYPE_TAG, ENTRYPOINT_TYPE_SCRIPT), | ||
dubloom marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ] | ||
| ) | ||
| ) | ||
| except Exception as e: | ||
| log.debug("failed to get process_tags: %s", e) | ||
| return None | ||
|
|
||
|
|
||
| process_tags = generate_process_tags() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| from unittest.mock import patch | ||
|
|
||
| import pytest | ||
|
|
||
| from ddtrace.internal import process_tags | ||
| from ddtrace.internal.process_tags import normalize_tag_value | ||
| from ddtrace.internal.settings._config import config | ||
| from tests.subprocesstest import run_in_subprocess | ||
| from tests.utils import TracerTestCase | ||
| from tests.utils import process_tag_reload | ||
|
|
||
|
|
||
| TEST_SCRIPT_PATH = "/path/to/test_script.py" | ||
| TEST_WORKDIR_PATH = "/path/to/workdir" | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "input_tag,expected", | ||
| [ | ||
| ("#test_starting_hash", "test_starting_hash"), | ||
| ("TestCAPSandSuch", "testcapsandsuch"), | ||
| ("Test Conversion Of Weird !@#$%^&**() Characters", "test_conversion_of_weird_characters"), | ||
| ("$#weird_starting", "weird_starting"), | ||
| ("allowed:c0l0ns", "allowed:c0l0ns"), | ||
| ("1love", "1love"), | ||
| ("/love2", "/love2"), | ||
| ("ünicöde", "ünicöde"), | ||
| ("ünicöde:metäl", "ünicöde:metäl"), | ||
| ("Data🐨dog🐶 繋がっ⛰てて", "data_dog_繋がっ_てて"), | ||
| (" spaces ", "spaces"), | ||
| (" #hashtag!@#spaces #__<># ", "hashtag_spaces"), | ||
| (":testing", ":testing"), | ||
| ("_foo", "foo"), | ||
| (":::test", ":::test"), | ||
| ("contiguous_____underscores", "contiguous_underscores"), | ||
| ("foo_", "foo"), | ||
| ("\u017Fodd_\u017Fcase\u017F", "\u017Fodd_\u017Fcase\u017F"), | ||
| ("", ""), | ||
| (" ", ""), | ||
| ("ok", "ok"), | ||
| ("™Ö™Ö™™Ö™", "ö_ö_ö"), | ||
| ("AlsO:ök", "also:ök"), | ||
| (":still_ok", ":still_ok"), | ||
| ("___trim", "trim"), | ||
| ("12.:trim@", "12.:trim"), | ||
| ("12.:trim@@", "12.:trim"), | ||
| ("fun:ky__tag/1", "fun:ky_tag/1"), | ||
| ("fun:ky@tag/2", "fun:ky_tag/2"), | ||
| ("fun:ky@@@tag/3", "fun:ky_tag/3"), | ||
| ("tag:1/2.3", "tag:1/2.3"), | ||
| ("---fun:k####y_ta@#g/1_@@#", "---fun:k_y_ta_g/1"), | ||
| ("AlsO:œ#@ö))œk", "also:œ_ö_œk"), | ||
| ("test\x99\x8faaa", "test_aaa"), | ||
| ("test\x99\x8f", "test"), | ||
| ("a" * 888, "a" * 200), | ||
| ("a" + "🐶" * 799 + "b", "a"), | ||
| ("a" + "\ufffd", "a"), | ||
| ("a" + "\ufffd" + "\ufffd", "a"), | ||
| ("a" + "\ufffd" + "\ufffd" + "b", "a_b"), | ||
| ( | ||
| "A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | ||
| "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | ||
| " 000000000000", | ||
| "a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | ||
| "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | ||
| "_0", | ||
| ), | ||
| ], | ||
| ) | ||
| def test_normalize_tag(input_tag, expected): | ||
| assert normalize_tag_value(input_tag) == expected | ||
|
|
||
|
|
||
| class TestProcessTags(TracerTestCase): | ||
brettlangdon marked this conversation as resolved.
Show resolved
Hide resolved
dubloom marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| def setUp(self): | ||
| super(TestProcessTags, self).setUp() | ||
| self._original_process_tags_enabled = config._process_tags_enabled | ||
| self._original_process_tags = process_tags.process_tags | ||
|
|
||
| def tearDown(self): | ||
| config._process_tags_enabled = self._original_process_tags_enabled | ||
| process_tags.process_tags = self._original_process_tags | ||
| super().tearDown() | ||
|
|
||
| @pytest.mark.snapshot | ||
| def test_process_tags_deactivated(self): | ||
dubloom marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| config._process_tags_enabled = False | ||
| process_tag_reload() | ||
|
|
||
| with self.tracer.trace("test"): | ||
| pass | ||
|
|
||
| @pytest.mark.snapshot | ||
| def test_process_tags_activated(self): | ||
| with patch("sys.argv", [TEST_SCRIPT_PATH]), patch("os.getcwd", return_value=TEST_WORKDIR_PATH): | ||
| config._process_tags_enabled = True | ||
| process_tag_reload() | ||
|
|
||
| with self.tracer.trace("parent"): | ||
| with self.tracer.trace("child"): | ||
| pass | ||
|
|
||
| @pytest.mark.snapshot | ||
| def test_process_tags_edge_case(self): | ||
| with patch("sys.argv", ["/test_script"]), patch("os.getcwd", return_value=TEST_WORKDIR_PATH): | ||
| config._process_tags_enabled = True | ||
| process_tag_reload() | ||
|
|
||
| with self.tracer.trace("span"): | ||
| pass | ||
|
|
||
| @pytest.mark.snapshot | ||
| def test_process_tags_error(self): | ||
| with patch("sys.argv", []), patch("os.getcwd", return_value=TEST_WORKDIR_PATH): | ||
| config._process_tags_enabled = True | ||
|
|
||
| with self.override_global_config(dict(_telemetry_enabled=False)): | ||
| with patch("ddtrace.internal.process_tags.log") as mock_log: | ||
| process_tag_reload() | ||
|
|
||
| with self.tracer.trace("span"): | ||
| pass | ||
|
|
||
| # Check if debug log was called | ||
| mock_log.debug.assert_called_once() | ||
| call_args = mock_log.debug.call_args[0] | ||
| assert ( | ||
| "failed to get process_tags" in call_args[0] | ||
| ), f"Expected error message not found. Got: {call_args[0]}" | ||
|
|
||
| @pytest.mark.snapshot | ||
| @run_in_subprocess(env_overrides=dict(DD_TRACE_PARTIAL_FLUSH_ENABLED="true", DD_TRACE_PARTIAL_FLUSH_MIN_SPANS="2")) | ||
| def test_process_tags_partial_flush(self): | ||
| with patch("sys.argv", [TEST_SCRIPT_PATH]), patch("os.getcwd", return_value=TEST_WORKDIR_PATH): | ||
| config._process_tags_enabled = True | ||
| process_tag_reload() | ||
|
|
||
| with self.override_global_config(dict(_partial_flush_enabled=True, _partial_flush_min_spans=2)): | ||
| with self.tracer.trace("parent"): | ||
| with self.tracer.trace("child1"): | ||
| pass | ||
| with self.tracer.trace("child2"): | ||
| pass | ||
26 changes: 26 additions & 0 deletions
26
tests/snapshots/tests.internal.test_process_tags.TestProcessTags.test_edge_case.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| [[ | ||
| { | ||
| "name": "span", | ||
| "service": "tests.internal", | ||
| "resource": "span", | ||
| "trace_id": 0, | ||
| "span_id": 1, | ||
| "parent_id": 0, | ||
| "type": "", | ||
| "error": 0, | ||
| "meta": { | ||
| "_dd.p.dm": "-0", | ||
| "_dd.p.tid": "6911da3a00000000", | ||
| "_dd.tags.process": "entrypoint.basedir:,entrypoint.name:test_script,entrypoint.type:script,entrypoint.workdir:workdir", | ||
| "language": "python", | ||
| "runtime-id": "c9342b8003de45feb0bf56d32ece46a1" | ||
| }, | ||
| "metrics": { | ||
| "_dd.top_level": 1, | ||
| "_dd.tracer_kr": 1.0, | ||
| "_sampling_priority_v1": 1, | ||
| "process_id": 605 | ||
| }, | ||
| "duration": 105292, | ||
| "start": 1762777658431833668 | ||
| }]] |
38 changes: 38 additions & 0 deletions
38
...apshots/tests.internal.test_process_tags.TestProcessTags.test_process_tags_activated.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| [[ | ||
| { | ||
| "name": "parent", | ||
| "service": "tests.internal", | ||
| "resource": "parent", | ||
| "trace_id": 0, | ||
| "span_id": 1, | ||
| "parent_id": 0, | ||
| "type": "", | ||
| "error": 0, | ||
| "meta": { | ||
| "_dd.p.dm": "-0", | ||
| "_dd.p.tid": "6911dc5a00000000", | ||
| "_dd.tags.process": "entrypoint.basedir:to,entrypoint.name:test_script,entrypoint.type:script,entrypoint.workdir:workdir", | ||
| "language": "python", | ||
| "runtime-id": "2d5de91f8dd9442cad7faca5554a09f1" | ||
| }, | ||
| "metrics": { | ||
| "_dd.top_level": 1, | ||
| "_dd.tracer_kr": 1.0, | ||
| "_sampling_priority_v1": 1, | ||
| "process_id": 605 | ||
| }, | ||
| "duration": 231542, | ||
| "start": 1762778202287875128 | ||
| }, | ||
| { | ||
| "name": "child", | ||
| "service": "tests.internal", | ||
| "resource": "child", | ||
| "trace_id": 0, | ||
| "span_id": 2, | ||
| "parent_id": 1, | ||
| "type": "", | ||
| "error": 0, | ||
| "duration": 55500, | ||
| "start": 1762778202287999128 | ||
| }]] |
25 changes: 25 additions & 0 deletions
25
...shots/tests.internal.test_process_tags.TestProcessTags.test_process_tags_deactivated.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| [[ | ||
| { | ||
| "name": "test", | ||
| "service": "tests.internal", | ||
| "resource": "test", | ||
| "trace_id": 0, | ||
| "span_id": 1, | ||
| "parent_id": 0, | ||
| "type": "", | ||
| "error": 0, | ||
| "meta": { | ||
| "_dd.p.dm": "-0", | ||
| "_dd.p.tid": "6911dc5a00000000", | ||
| "language": "python", | ||
| "runtime-id": "2d5de91f8dd9442cad7faca5554a09f1" | ||
| }, | ||
| "metrics": { | ||
| "_dd.top_level": 1, | ||
| "_dd.tracer_kr": 1.0, | ||
| "_sampling_priority_v1": 1, | ||
| "process_id": 605 | ||
| }, | ||
| "duration": 22292, | ||
| "start": 1762778202327669586 | ||
| }]] |
26 changes: 26 additions & 0 deletions
26
...apshots/tests.internal.test_process_tags.TestProcessTags.test_process_tags_edge_case.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| [[ | ||
| { | ||
| "name": "span", | ||
| "service": "tests.internal", | ||
| "resource": "span", | ||
| "trace_id": 0, | ||
| "span_id": 1, | ||
| "parent_id": 0, | ||
| "type": "", | ||
| "error": 0, | ||
| "meta": { | ||
| "_dd.p.dm": "-0", | ||
| "_dd.p.tid": "6911dc5a00000000", | ||
| "_dd.tags.process": "entrypoint.basedir:,entrypoint.name:test_script,entrypoint.type:script,entrypoint.workdir:workdir", | ||
| "language": "python", | ||
| "runtime-id": "2d5de91f8dd9442cad7faca5554a09f1" | ||
| }, | ||
| "metrics": { | ||
| "_dd.top_level": 1, | ||
| "_dd.tracer_kr": 1.0, | ||
| "_sampling_priority_v1": 1, | ||
| "process_id": 605 | ||
| }, | ||
| "duration": 35458, | ||
| "start": 1762778202321224878 | ||
| }]] |
25 changes: 25 additions & 0 deletions
25
...s/snapshots/tests.internal.test_process_tags.TestProcessTags.test_process_tags_error.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| [[ | ||
| { | ||
| "name": "span", | ||
| "service": "tests.internal", | ||
| "resource": "span", | ||
| "trace_id": 0, | ||
| "span_id": 1, | ||
| "parent_id": 0, | ||
| "type": "", | ||
| "error": 0, | ||
| "meta": { | ||
| "_dd.p.dm": "-0", | ||
| "_dd.p.tid": "6911db6e00000000", | ||
| "language": "python", | ||
| "runtime-id": "c59cb90aad3246579bc4421d1cca07c8" | ||
| }, | ||
| "metrics": { | ||
| "_dd.top_level": 1, | ||
| "_dd.tracer_kr": 1.0, | ||
| "_sampling_priority_v1": 1, | ||
| "process_id": 605 | ||
| }, | ||
| "duration": 102833, | ||
| "start": 1762777966446950922 | ||
| }]] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.