Skip to content

Commit 09906fb

Browse files
committed
fix: Modify span filtering configuration setting
Signed-off-by: Cagri Yonca <cagri@ibm.com>
1 parent 9366542 commit 09906fb

2 files changed

Lines changed: 98 additions & 8 deletions

File tree

src/instana/options.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,11 @@ def set_span_filter_configurations(self) -> None:
268268
# The precedence is as follows:
269269
# environment variables > in-code configuration >
270270
# > agent config (configuration.yaml) > default value
271-
if any(k.startswith("INSTANA_TRACING_FILTER_") for k in os.environ):
272-
# Check for new span filtering env vars
271+
if any(
272+
k.startswith("INSTANA_TRACING_FILTER_") and os.environ[k]
273+
for k in os.environ
274+
):
275+
# Check for new span filtering env vars (only if at least one has a non-empty value)
273276
parsed_filter = parse_filter_rules_env_vars()
274277
if parsed_filter["exclude"] or parsed_filter["include"]:
275278
self.span_filters = parsed_filter
@@ -393,8 +396,14 @@ def set_tracing(self, tracing: Dict[str, Any]) -> None:
393396
@param tracing: tracing configuration dictionary
394397
@return: None
395398
"""
396-
if "filter" in tracing and not self.span_filters:
397-
self.span_filters = parse_filter_rules(tracing["filter"])
399+
if "filter" in tracing and not self._has_high_priority_span_filter_source():
400+
parsed = parse_filter_rules(tracing["filter"])
401+
for policy in ("exclude", "include"):
402+
rules = parsed.get(policy, [])
403+
if rules:
404+
if policy not in self.span_filters:
405+
self.span_filters[policy] = []
406+
self.span_filters[policy].extend(rules)
398407

399408
if "kafka" in tracing:
400409
if (
@@ -427,6 +436,21 @@ def set_tracing(self, tracing: Dict[str, Any]) -> None:
427436
# Handle stack trace configuration from agent config
428437
self.set_stack_trace_from_agent(tracing)
429438

439+
def _has_high_priority_span_filter_source(self) -> bool:
440+
"""Return True if a higher-priority span filter source (env var, YAML, or in-code config)
441+
has already been configured, in which case the agent-provided filter should be ignored."""
442+
return (
443+
any(
444+
k.startswith("INSTANA_TRACING_FILTER_") and os.environ[k]
445+
for k in os.environ
446+
)
447+
or "INSTANA_CONFIG_PATH" in os.environ
448+
or (
449+
isinstance(config.get("tracing"), dict)
450+
and "filter" in config["tracing"]
451+
)
452+
)
453+
430454
def _should_apply_agent_global_config(self) -> bool:
431455
"""Check if agent global config should be applied (lowest priority)."""
432456
has_env_vars = (

tests/test_options.py

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -689,8 +689,30 @@ def test_set_trace_configurations_by_agent_configuration(self) -> None:
689689
self.base_options = StandardOptions()
690690
self.base_options.set_tracing(test_tracing)
691691

692-
# set_tracing does not override span_filters when already set (has internal filters)
693-
assert self.base_options.span_filters == {"exclude": INTERNAL_SPAN_FILTERS}
692+
# Agent filter rules are appended after the internal filters (no high-priority source set).
693+
agent_exclude = [
694+
{
695+
"name": "service1",
696+
"suppression": True,
697+
"attributes": [
698+
{"key": "service", "values": ["service1"], "match_type": "strict"}
699+
],
700+
},
701+
{
702+
"name": "service2",
703+
"suppression": True,
704+
"attributes": [
705+
{
706+
"key": "method",
707+
"values": ["method1", "method2"],
708+
"match_type": "strict",
709+
}
710+
],
711+
},
712+
]
713+
assert self.base_options.span_filters == {
714+
"exclude": INTERNAL_SPAN_FILTERS + agent_exclude
715+
}
694716
assert self.base_options.kafka_trace_correlation
695717

696718
# Check disabled_spans list
@@ -908,7 +930,28 @@ def test_set_tracing(
908930
}
909931
self.standart_options.set_tracing(test_tracing)
910932

911-
assert self.standart_options.span_filters == {"exclude": INTERNAL_SPAN_FILTERS}
933+
# Agent filter rules are appended after the internal filters (no high-priority source set).
934+
expected_exclude = INTERNAL_SPAN_FILTERS + [
935+
{
936+
"name": "service1",
937+
"suppression": True,
938+
"attributes": [
939+
{"key": "service", "values": ["service1"], "match_type": "strict"}
940+
],
941+
},
942+
{
943+
"name": "service2",
944+
"suppression": True,
945+
"attributes": [
946+
{
947+
"key": "method",
948+
"values": ["method1", "method2"],
949+
"match_type": "strict",
950+
}
951+
],
952+
},
953+
]
954+
assert self.standart_options.span_filters == {"exclude": expected_exclude}
912955
assert not self.standart_options.kafka_trace_correlation
913956
assert (
914957
"Binary header format for Kafka is deprecated. Please use string header format."
@@ -972,7 +1015,30 @@ def test_set_from(self) -> None:
9721015
self.standart_options.secrets_matcher == test_res_data["secrets"]["matcher"]
9731016
)
9741017
assert self.standart_options.secrets_list == test_res_data["secrets"]["list"]
975-
assert self.standart_options.span_filters == {"exclude": INTERNAL_SPAN_FILTERS}
1018+
# Agent filter rules are appended after the internal filters.
1019+
agent_exclude = [
1020+
{
1021+
"name": "service1",
1022+
"suppression": True,
1023+
"attributes": [
1024+
{"key": "service", "values": ["service1"], "match_type": "strict"}
1025+
],
1026+
},
1027+
{
1028+
"name": "service2",
1029+
"suppression": True,
1030+
"attributes": [
1031+
{
1032+
"key": "method",
1033+
"values": ["method1", "method2"],
1034+
"match_type": "strict",
1035+
}
1036+
],
1037+
},
1038+
]
1039+
assert self.standart_options.span_filters == {
1040+
"exclude": INTERNAL_SPAN_FILTERS + agent_exclude
1041+
}
9761042

9771043
test_res_data2 = {
9781044
"extraHeaders": {"header1": "sample-match", "header2": ["sample", "list"]},

0 commit comments

Comments
 (0)