Skip to content

Commit 7772f77

Browse files
fix(botocore): [SVLS-5973] less noisy span pointers [backport 2.16] (#11422)
Backport ecd0ab1 from #11353 to 2.16. Span pointer issues should be debug messages rather than warnings since they are not really actionable from the perspective of our users. We'd also like to have some instrumentation telemetry to see how the logic is doing. ## Checklist - [x] PR author has checked that all the criteria below are met - The PR description includes an overview of the change - The PR description articulates the motivation for the change - The change includes tests OR the PR description describes a testing strategy - The PR description notes risks associated with the change, if any - Newly-added code is easy to change - The change follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) - The change includes or references documentation updates if necessary - Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [x] Reviewer has checked that all the criteria below are met - Title is accurate - All changes are related to the pull request's stated goal - Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - Testing strategy adequately addresses listed risks - Newly-added code is easy to change - Release note makes sense to a user of the library - If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) Co-authored-by: Aleksandr Pasechnik <[email protected]>
1 parent dda105d commit 7772f77

File tree

9 files changed

+706
-226
lines changed

9 files changed

+706
-226
lines changed

ddtrace/_trace/_span_pointer.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from ddtrace._trace._span_link import SpanLink
1010
from ddtrace._trace._span_link import SpanLinkKind
11+
from ddtrace._trace.telemetry import record_span_pointer_calculation_issue
1112
from ddtrace.internal.logger import get_logger
1213

1314

@@ -67,20 +68,28 @@ def __post_init__(self):
6768
def _standard_hashing_function(*elements: bytes) -> str:
6869
try:
6970
if not elements:
70-
raise ValueError("elements must not be empty")
71+
return _standard_hashing_function_failure("elements must not be empty")
7172

7273
# Please see the tests for more details about this logic.
7374
return sha256(b"|".join(elements)).hexdigest()[:32]
7475

7576
except Exception as e:
76-
log.warning(
77-
"failed to generate standard hash for span pointer: %s",
78-
str(e),
79-
)
80-
return _add_random_suffix(
81-
prefix=_STANDARD_HASHING_FUNCTION_FAILURE_PREFIX,
82-
minimum_length=32,
83-
)
77+
return _standard_hashing_function_failure(str(e))
78+
79+
80+
def _standard_hashing_function_failure(reason: str) -> str:
81+
log.debug(
82+
"failed to generate standard hash for span pointer: %s",
83+
reason,
84+
)
85+
record_span_pointer_calculation_issue(
86+
context="standard_hashing_function",
87+
)
88+
89+
return _add_random_suffix(
90+
prefix=_STANDARD_HASHING_FUNCTION_FAILURE_PREFIX,
91+
minimum_length=32,
92+
)
8493

8594

8695
def _add_random_suffix(*, prefix: str, minimum_length: int) -> str:

ddtrace/_trace/telemetry.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from typing import Optional
2+
from typing import Tuple
3+
4+
from ddtrace.internal.telemetry import telemetry_writer
5+
6+
7+
def record_span_pointer_calculation(context: str, span_pointer_count: int) -> None:
8+
telemetry_writer.add_count_metric(
9+
namespace="tracer",
10+
name="span_pointer_calculation",
11+
value=1,
12+
tags=(("context", context), ("count", _span_pointer_count_to_tag(span_pointer_count))),
13+
)
14+
15+
16+
def _span_pointer_count_to_tag(span_pointer_count: int) -> str:
17+
if span_pointer_count < 0:
18+
# this shouldn't be possible, but let's make sure
19+
return "negative"
20+
21+
elif span_pointer_count <= 5:
22+
return str(span_pointer_count)
23+
24+
elif span_pointer_count <= 10:
25+
return "6-10"
26+
27+
elif span_pointer_count <= 20:
28+
return "11-20"
29+
30+
elif span_pointer_count <= 50:
31+
return "21-50"
32+
33+
elif span_pointer_count <= 100:
34+
return "51-100"
35+
36+
else:
37+
return "101+"
38+
39+
40+
def record_span_pointer_calculation_issue(
41+
context: str, additional_tags: Optional[Tuple[Tuple[str, str], ...]] = None
42+
) -> None:
43+
tags: Tuple[Tuple[str, str], ...] = (("context", context),)
44+
if additional_tags:
45+
tags += additional_tags
46+
47+
telemetry_writer.add_count_metric(
48+
namespace="tracer",
49+
name="span_pointer_calculation.issue",
50+
value=1,
51+
tags=tags,
52+
)

ddtrace/_trace/utils_botocore/span_pointers/__init__.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
# import from here as well.
1515
from ddtrace._trace.utils_botocore.span_pointers.s3 import _aws_s3_object_span_pointer_description # noqa: F401
1616
from ddtrace._trace.utils_botocore.span_pointers.s3 import _extract_span_pointers_for_s3_response
17+
from ddtrace._trace.utils_botocore.span_pointers.telemetry import record_span_pointer_calculation
18+
from ddtrace._trace.utils_botocore.span_pointers.telemetry import record_span_pointer_calculation_issue
19+
from ddtrace.internal.logger import get_logger
20+
21+
22+
log = get_logger(__name__)
1723

1824

1925
def extract_span_pointers_from_successful_botocore_response(
@@ -23,12 +29,22 @@ def extract_span_pointers_from_successful_botocore_response(
2329
request_parameters: Dict[str, Any],
2430
response: Dict[str, Any],
2531
) -> List[_SpanPointerDescription]:
26-
if endpoint_name == "s3":
27-
return _extract_span_pointers_for_s3_response(operation_name, request_parameters, response)
32+
result = []
33+
34+
try:
35+
if endpoint_name == "s3":
36+
result = _extract_span_pointers_for_s3_response(operation_name, request_parameters, response)
37+
38+
elif endpoint_name == "dynamodb":
39+
result = _extract_span_pointers_for_dynamodb_response(
40+
dynamodb_primary_key_names_for_tables, operation_name, request_parameters, response
41+
)
42+
43+
except Exception as e:
44+
# Catch-all in case we miss something in the helpers
45+
log.debug("Error extracting span pointers from botocore response: %s", e)
46+
record_span_pointer_calculation_issue("extractor_root", "unexpected_error")
2847

29-
if endpoint_name == "dynamodb":
30-
return _extract_span_pointers_for_dynamodb_response(
31-
dynamodb_primary_key_names_for_tables, operation_name, request_parameters, response
32-
)
48+
record_span_pointer_calculation(span_pointer_count=len(result))
3349

34-
return []
50+
return result

0 commit comments

Comments
 (0)