Skip to content

[Tracing] Update DD_TAGS tests to remove empty tag values #3985

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

Closed
Closed
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
2 changes: 1 addition & 1 deletion manifests/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ tests/:
test_config_consistency.py:
Test_Config_Dogstatsd: missing_feature
Test_Config_RateLimit: v2.15.0
Test_Config_Tags: missing_feature
Test_Config_Tags: v2.0.0
Test_Config_TraceAgentURL: v2.0.0
Test_Config_TraceEnabled: v2.12.2
Test_Config_TraceLogDirectory: missing_feature
Expand Down
83 changes: 62 additions & 21 deletions tests/parametric/test_config_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,25 +288,64 @@ def test_setting_trace_rate_limit(self, library_env, test_agent, test_library):
), "Expected at least one trace to be rate-limited with sampling priority -1."


class TagTest:
def __init__(self, expected_span_tags, agent_host_tags):
self.expected_span_tags = expected_span_tags
self.agent_host_tags = agent_host_tags


# Feedback 1: Only difference is comma-split. Can we detect by looking at host-tags with commas present in them?
# Feedback 2: Tracer is doing the right thing to discard <KEY>:<VALUE> tags where KEY is empty
tag_scenarios: dict = {
"key1:value1,key2:value2": [("key1", "value1"), ("key2", "value2")],
"key1:value1 key2:value2": [("key1", "value1"), ("key2", "value2")],
"env:test aKey:aVal bKey:bVal cKey:": [("env", "test"), ("aKey", "aVal"), ("bKey", "bVal"), ("cKey", "")],
"env:test,aKey:aVal,bKey:bVal,cKey:": [("env", "test"), ("aKey", "aVal"), ("bKey", "bVal"), ("cKey", "")],
"env:test,aKey:aVal bKey:bVal cKey:": [("env", "test"), ("aKey", "aVal bKey:bVal cKey:")],
"env:test bKey :bVal dKey: dVal cKey:": [
("env", "test"),
("bKey", ""),
("dKey", ""),
("dVal", ""),
("cKey", ""),
],
"env :test, aKey : aVal bKey:bVal cKey:": [("env", "test"), ("aKey", "aVal bKey:bVal cKey:")],
"env:keyWithA:Semicolon bKey:bVal cKey": [("env", "keyWithA:Semicolon"), ("bKey", "bVal"), ("cKey", "")],
"env:keyWith: , , Lots:Of:Semicolons ": [("env", "keyWith:"), ("Lots", "Of:Semicolons")],
"a:b,c,d": [("a", "b"), ("c", ""), ("d", "")],
"a,1": [("a", ""), ("1", "")],
"a:b:c:d": [("a", "b:c:d")],
"key1:value1,key2:value2": TagTest( # See Feedback 1
expected_span_tags=[("key1", "value1"), ("key2", "value2")], agent_host_tags=[("key1:value1,key2:value2")]
),
"key1:value1 key2:value2": TagTest(
expected_span_tags=[("key1", "value1"), ("key2", "value2")], # OK
agent_host_tags=["key1:value1", "key2:value2"],
),
"env:test aKey:aVal bKey:bVal cKey:": TagTest(
expected_span_tags=[("env", "test"), ("aKey", "aVal"), ("bKey", "bVal"), ("cKey", "")], # OK
agent_host_tags=["env:test", "aKey:aVal", "bKey:bVal", "cKey:"],
),
"env:test,aKey:aVal,bKey:bVal,cKey:": TagTest( # See Feedback 1
expected_span_tags=[("env", "test"), ("aKey", "aVal"), ("bKey", "bVal"), ("cKey", "")],
agent_host_tags=["env:test,aKey:aVal,bKey:bVal,cKey:"],
),
# New test case adopted from the above ^ to take the simple comma-separated list into a (comma+space)-separated list
"env:test ,aKey:aVal, bKey:bVal, cKey:": TagTest( # Feedback: Can we recommend users update their DD_TAGS to be (comma+space)-separate in their ENV variables AND toggle a feature flag to trim the commas?
expected_span_tags=[("env", "test"), ("aKey", "aVal"), ("bKey", "bVal"), ("cKey", "")],
agent_host_tags=["env:test", ",aKey:aVal,", "bKey:bVal,", "cKey:"],
),
"env:test,aKey:aVal bKey:bVal cKey:": TagTest( # See Feedback 1
expected_span_tags=[("env", "test"), ("aKey", "aVal bKey:bVal cKey:")],
agent_host_tags=["env:test,aKey:aVal", "bKey:bVal", "cKey:"],
),
"env:test bKey :bVal dKey: dVal cKey:": TagTest(
expected_span_tags=[("env", "test"), ("bKey", ""), ("dKey", ""), ("dVal", ""), ("cKey", "")], # See Feedback 2
agent_host_tags=["env:test", "bKey", ":bVal", "dKey:", "dVal", "cKey:"],
),
"env :test, aKey : aVal bKey:bVal cKey:": TagTest( # See Feedback 1 and Feedback 2
expected_span_tags=[("env", "test"), ("aKey", "aVal bKey:bVal cKey:")],
agent_host_tags=["env", ":", ":test,", "aKey", "aVal", "bKey:bVal", "cKey:"],
),
"env:keyWithA:Semicolon bKey:bVal cKey": TagTest( # OK
expected_span_tags=[("env", "keyWithA:Semicolon"), ("bKey", "bVal"), ("cKey", "")],
agent_host_tags=["env:keyWithA:Semicolon", "bKey:bVal", "cKey"],
),
"env:keyWith: , , Lots:Of:Semicolons ": TagTest( # See Feedback 1
expected_span_tags=[("env", "keyWith:"), ("Lots", "Of:Semicolons")],
agent_host_tags=["env:keyWith:", ",", "Lots:Of:Semicolons"],
),
"a:b,c,d": TagTest( # See Feedback 1
expected_span_tags=[("a", "b"), ("c", ""), ("d", "")], agent_host_tags=["a:b,c,d"]
),
"a,1": TagTest( # See Feedback 1
expected_span_tags=[("a", ""), ("1", "")], agent_host_tags=["a,1"]
),
"a:b:c:d": TagTest( # OK
expected_span_tags=[("a", "b:c:d")], agent_host_tags=["a:b:c:d"]
),
}


Expand All @@ -315,14 +354,16 @@ def test_setting_trace_rate_limit(self, library_env, test_agent, test_library):
class Test_Config_Tags:
@parametrize("library_env", [{"DD_TAGS": key} for key in tag_scenarios.keys()])
def test_comma_space_tag_separation(self, library_env, test_agent, test_library):
expected_local_tags = []
expected_span_tags = []
if "DD_TAGS" in library_env:
expected_local_tags = tag_scenarios[library_env["DD_TAGS"]]
tagtest = tag_scenarios[library_env["DD_TAGS"]]
expected_span_tags = tagtest.expected_span_tags

with test_library:
with test_library.dd_start_span(name="sample_span"):
pass
span = find_only_span(test_agent.wait_for_num_traces(1))
for k, v in expected_local_tags:
for k, v in expected_span_tags:
assert k in span["meta"]
assert span["meta"][k] == v

Expand Down
22 changes: 21 additions & 1 deletion tests/test_semantic_conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
# Copyright 2021 Datadog, Inc.

import re
import pprint
from urllib.parse import urlparse

from utils import context, interfaces, bug, missing_feature, features, scenarios
from utils import context, interfaces, bug, missing_feature, features, scenarios, weblog

RUNTIME_LANGUAGE_MAP = {
"nodejs": "javascript",
Expand Down Expand Up @@ -323,6 +324,25 @@ def validator(span):
interfaces.library.validate_spans(validator=validator)


@scenarios.default
@features.tracing_configuration_consistency
class Test_Agent_DDTags:
"""Spans carry meta tags that were set in DD_TAGS agent environment"""

def setup_main(self):
self.r = weblog.get("/")

def test_main(self):
assert self.r.status_code == 200

spans = interfaces.agent.get_spans_list(self.r)
assert len(spans) == 1, "Agent received the incorrect amount of spans"

host_tags = interfaces.agent.get_host_tags()
pprint.pprint(host_tags["system"])
assert False


@features.data_integrity
@features.envoy_external_processing
@scenarios.external_processing
Expand Down
1 change: 1 addition & 0 deletions utils/_context/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ def __init__(self, host_log_folder, *, use_proxy=True, environment=None) -> None
"DD_APM_RECEIVER_PORT": self.apm_receiver_port,
"DD_DOGSTATSD_PORT": self.dogstatsd_port,
"DD_API_KEY": os.environ.get("DD_API_KEY", _FAKE_DD_API_KEY),
# To configure configure host tags, set the env variable "DD_TAGS" here
}
)

Expand Down
10 changes: 10 additions & 0 deletions utils/interfaces/_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ def add_traces_validation(self, validator, *, success_by_default=False):
validator=validator, success_by_default=success_by_default, path_filters=r"/api/v0\.[1-9]+/traces"
)

def get_host_tags(self):
for data in self.get_data(path_filters="/intake/"):
if "host-tags" not in data["request"]["content"]:
continue

if data["request"]["content"].get("host-tags"):
return data["request"]["content"]["host-tags"]

return {}

def get_spans(self, request=None):
"""Attempts to fetch the spans the agent will submit to the backend.

Expand Down
Loading