Skip to content

Commit 7897a0d

Browse files
committed
add methods for extracting data from sentry-trace and tracestate headers
1 parent 98a6cc6 commit 7897a0d

File tree

1 file changed

+92
-1
lines changed

1 file changed

+92
-1
lines changed

sentry_sdk/tracing_utils.py

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99

1010
from sentry_sdk.utils import (
1111
capture_internal_exceptions,
12+
Dsn,
1213
logger,
14+
to_base64,
1315
to_string,
1416
)
1517
from sentry_sdk._compat import PY2
@@ -26,8 +28,9 @@
2628
from typing import Generator
2729
from typing import Optional
2830
from typing import Any
31+
from typing import Union
2932

30-
from sentry_sdk.tracing import Span
33+
from sentry_sdk.tracing import Span, Transaction
3134

3235

3336
SENTRY_TRACE_REGEX = re.compile(
@@ -38,6 +41,33 @@
3841
"[ \t]*$" # whitespace
3942
)
4043

44+
# This is a normal base64 regex, modified to reflect that fact that we strip the
45+
# trailing = or == off
46+
b64 = base64_stripped = (
47+
# any of the characters in the base64 "alphabet", in multiples of 4
48+
"([a-zA-Z0-9+/]{4})*"
49+
# either nothing or 2 or 3 base64-alphabet characters (see
50+
# https://en.wikipedia.org/wiki/Base64#Decoding_Base64_without_padding for
51+
# why there's never only 1 extra character)
52+
"([a-zA-Z0-9+/]{2,3})?"
53+
)
54+
ov = outside_vendor_entry = r"\w+=\w+"
55+
56+
TRACESTATE_HEADER_REGEX = re.compile(
57+
# zero or more other vendors' entries, each followed by a comma,
58+
# captured together as one group
59+
"^((?:{ov},)*)"
60+
# sentry's entry, with only the value captured
61+
"(?:sentry=({b64}))?"
62+
# zero or more other vendors' entries, each preceded by a comma,
63+
# captured together as one group
64+
"((?:,{ov})*)$".format(ov=ov, b64=b64)
65+
)
66+
67+
TRACESTATE_SENTRY_VALUE_REGEX = re.compile(
68+
"sentry=({b64})^[a-zA-Z0-9+/]?".format(b64=b64)
69+
)
70+
4171

4272
class EnvironHeaders(Mapping): # type: ignore
4373
def __init__(
@@ -161,6 +191,67 @@ def maybe_create_breadcrumbs_from_span(hub, span):
161191
)
162192

163193

194+
def extract_sentrytrace_data(header):
195+
# type: (Optional[str]) -> typing.Mapping[str, Union[Optional[str], Optional[bool]]]
196+
197+
"""
198+
Given a `sentry-trace` header string, return a dictionary of data.
199+
"""
200+
trace_id = parent_span_id = parent_sampled = None
201+
202+
if header:
203+
if header.startswith("00-") and header.endswith("-00"):
204+
header = header[3:-3]
205+
206+
match = SENTRY_TRACE_REGEX.match(header)
207+
208+
if match:
209+
trace_id, parent_span_id, sampled_str = match.groups()
210+
211+
if trace_id:
212+
trace_id = "{:032x}".format(int(trace_id, 16))
213+
if parent_span_id:
214+
parent_span_id = "{:016x}".format(int(parent_span_id, 16))
215+
if sampled_str:
216+
parent_sampled = sampled_str != "0"
217+
218+
return {
219+
"trace_id": trace_id,
220+
"parent_span_id": parent_span_id,
221+
"parent_sampled": parent_sampled,
222+
}
223+
224+
225+
def extract_tracestate_data(header):
226+
# type: (Optional[str]) -> typing.Mapping[str, Optional[str]]
227+
"""
228+
Extracts the sentry tracestate value and any third-party data from the given
229+
tracestate header, returning a dictionary of data.
230+
"""
231+
sentry_value = third_party = None
232+
233+
if header:
234+
235+
match = TRACESTATE_HEADER_REGEX.match(header)
236+
237+
if match:
238+
before, sentry_value, after = match.groups()
239+
if before or after:
240+
# filter out empty strings, and make sure there aren't too many
241+
# commas between them
242+
third_party = ",".join(
243+
[value.strip(",") for value in [before, after] if value != ""]
244+
)
245+
246+
else:
247+
# if the header is malformed, at least try to grab sentry's part, if any
248+
sentry_value_match = TRACESTATE_SENTRY_VALUE_REGEX.search(header)
249+
if sentry_value_match:
250+
sentry_value = sentry_value_match.group(1)
251+
252+
return {"sentry_tracestate": sentry_value, "third_party_tracestate": third_party}
253+
254+
164255
def compute_new_tracestate(transaction):
165256
# type: (Transaction) -> str
166257
"""

0 commit comments

Comments
 (0)