8000 Remove custom_sampling_context (#3747) · getsentry/sentry-python@afd8cc5 · GitHub
[go: up one dir, main page]

Skip to content

Commit afd8cc5

Browse files
authored
Remove custom_sampling_context (#3747)
- Add support for the sampled flag for start_span and respect it when making sampling decisions. - Rework sampling_context in traces_sampler to work with span attributes instead. Make sure we still have the same data accessible as now. We could go one step further and change the format of sampling_context to just be the actual span attributes without any postprocessing into the current format. I kept the format in line with what we have now to make it easier to update. See #3746 Closes #3739 This is a breaking change since we're removing custom_sampling_context. It'll break multiple integrations until we fix them (see #3746).
1 parent 3f638f7 commit afd8cc5

File tree

8 files changed

+42
-36
lines changed

8 files changed

+42
-36
lines changed

MIGRATION_GUIDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
1919
- Redis integration: In Redis pipeline spans there is no `span["data"]["redis.commands"]` that contains a dict `{"count": 3, "first_ten": ["cmd1", "cmd2", ...]}` but instead `span["data"]["redis.commands.count"]` (containing `3`) and `span["data"]["redis.commands.first_ten"]` (containing `["cmd1", "cmd2", ...]`).
2020
- clickhouse-driver integration: The query is now available under the `db.query.text` span attribute (only if `send_default_pii` is `True`).
2121
- `sentry_sdk.init` now returns `None` instead of a context manager.
22+
- The `sampling_context` argument of `traces_sampler` now additionally contains all span attributes known at span start.
2223

2324
### Removed
2425

2526
- Spans no longer have a `description`. Use `name` instead.
2627
- Dropped support for Python 3.6.
28+
- The `custom_sampling_context` parameter of `start_transaction` has been removed. Use `attributes` instead to set key-value pairs of data that should be accessible in the traces sampler. Note that span attributes need to conform to the [OpenTelemetry specification](https://opentelemetry.io/docs/concepts/signals/traces/#attributes), meaning only certain types can be set as values.
2729
- The PyMongo integration no longer sets tags. The data is still accessible via span attributes.
2830
- The PyMongo integration doesn't set `operation_ids` anymore. The individual IDs (`operation_id`, `request_id`, `session_id`) are now accessible as separate span attributes.
2931
- `sentry_sdk.metrics` and associated metrics APIs have been removed as Sentry no longer accepts metrics data in this form. See https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Upcoming-API-Changes-to-Metrics

sentry_sdk/api.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
ExcInfo,
4141
MeasurementUnit,
4242
LogLevelStr,
43-
SamplingContext,
4443
)
4544
from sentry_sdk.tracing import Span, TransactionKwargs
4645

@@ -239,12 +238,8 @@ def flush(
239238
return get_client().flush(timeout=timeout, callback=callback)
240239

241240

242-
def start_span(
243-
*,
244-
custom_sampling_context=None,
245-
**kwargs, # type: Any
246-
):
247-
# type: (...) -> POTelSpan
241+
def start_span(**kwargs):
242+
# type: (type.Any) -> POTelSpan
248243
"""
249244
Start and return a span.
250245
@@ -257,13 +252,11 @@ def start_span(
257252
of the `with` block. If not using context managers, call the `finish()`
258253
method.
259254
"""
260-
# TODO: Consider adding type hints to the method signature.
261-
return get_current_scope().start_span(custom_sampling_context, **kwargs)
255+
return get_current_scope().start_span(**kwargs)
262256

263257

264258
def start_transaction(
265259
transaction=None, # type: Optional[Transaction]
266-
custom_sampling_context=None, # type: Optional[SamplingContext]
267260
**kwargs, # type: Unpack[TransactionKwargs]
268261
):
269262
# type: (...) -> POTelSpan
@@ -295,14 +288,12 @@ def start_transaction(
295288
296289
:param transaction: The transaction to start. If omitted, we create and
297290
start a new transaction.
298-
:param custom_sampling_context: The transaction's custom sampling context.
299291
:param kwargs: Optional keyword arguments to be passed to the Transaction
300292
constructor. See :py:class:`sentry_sdk.tracing.Transaction` for
301293
available arguments.
302294
"""
303295
return start_span(
304296
span=transaction,
305-
custom_sampling_context=custom_sampling_context,
306297
**kwargs,
307298
)
308299

sentry_sdk/integrations/opentelemetry/consts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ class SentrySpanAttribute:
3030
NAME = "sentry.name"
3131
SOURCE = "sentry.source"
3232
CONTEXT = "sentry.context"
33+
CUSTOM_SAMPLED = "sentry.custom_sampled" # used for saving start_span(sampled=X)

sentry_sdk/integrations/opentelemetry/sampler.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from typing import cast
33

44
from opentelemetry import trace
5-
65
from opentelemetry.sdk.trace.sampling import Sampler, SamplingResult, Decision
76
from opentelemetry.trace.span import TraceState
87

@@ -12,6 +11,7 @@
1211
from sentry_sdk.integrations.opentelemetry.consts import (
1312
TRACESTATE_SAMPLED_KEY,
1413
TRACESTATE_SAMPLE_RATE_KEY,
14+
SentrySpanAttribute,
1515
)
1616

1717
from typing import TYPE_CHECKING
@@ -114,28 +114,34 @@ def should_sample(
114114

115115
parent_span_context = trace.get_current_span(parent_context).get_span_context()
116116

117+
attributes = attributes or {}
118+
117119
# No tracing enabled, thus no sampling
118120
if not has_tracing_enabled(client.options):
119121
return dropped_result(parent_span_context, attributes)
120122

121-
sample_rate = None
123+
# Explicit sampled value provided at start_span
124+
if attributes.get(SentrySpanAttribute.CUSTOM_SAMPLED) is not None:
125+
sample_rate = float(attributes[SentrySpanAttribute.CUSTOM_SAMPLED])
126+
if sample_rate > 0:
127+
return sampled_result(parent_span_context, attributes, sample_rate)
128+
else:
129+
return dropped_result(parent_span_context, attributes)
122130

123-
# Check if sampled=True was passed to start_transaction
124-
# TODO-anton: Do we want to keep the start_transaction(sampled=True) thing?
131+
sample_rate = None
125132

126133
# Check if there is a traces_sampler
127134
# Traces_sampler is responsible to check parent sampled to have full transactions.
128135
has_traces_sampler = callable(client.options.get("traces_sampler"))
129136
if has_traces_sampler:
130-
# TODO-anton: Make proper sampling_context
131-
# TODO-neel-potel: Make proper sampling_context
132137
sampling_context = {
133138
"transaction_context": {
134139
"name": name,
140+
"op": attributes.get(SentrySpanAttribute.OP),
135141
},
136142
"parent_sampled": get_parent_sampled(parent_span_context, trace_id),
137143
}
138-
144+
sampling_context.update(attributes)
139145
sample_rate = client.options["traces_sampler"](sampling_context)
140146

141147
else:

sentry_sdk/integrations/opentelemetry/scope.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
from typing import Tuple, Optional, Generator, Dict, Any
2525
from typing_extensions import Unpack
2626

27-
from sentry_sdk._types import SamplingContext
2827
from sentry_sdk.tracing import TransactionKwargs
2928

3029

@@ -112,17 +111,17 @@ def _incoming_otel_span_context(self):
112111

113112
return span_context
114113

115-
def start_transaction(self, custom_sampling_context=None, **kwargs):
116-
# type: (Optional[SamplingContext], Unpack[TransactionKwargs]) -> POTelSpan
114+
def start_transaction(self, **kwargs):
115+
# type: (Unpack[TransactionKwargs]) -> POTelSpan
117116
"""
118117
.. deprecated:: 3.0.0
119118
This function is deprecated and will be removed in a future release.
120119
Use :py:meth:`sentry_sdk.start_span` instead.
121120
"""
122-
return self.start_span(custom_sampling_context=custom_sampling_context)
121+
return self.start_span(**kwargs)
123122

124-
def start_span(self, custom_sampling_context=None, **kwargs):
125-
# type: (Optional[SamplingContext], Any) -> POTelSpan
123+
def start_span(self, **kwargs):
124+
# type: (Any) -> POTelSpan
126125
return POTelSpan(**kwargs, scope=self)
127126

128127

sentry_sdk/scope.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -946,9 +946,7 @@ def add_breadcrumb(self, crumb=None, hint=None, **kwargs):
946946
while len(self._breadcrumbs) > max_breadcrumbs:
947947
self._breadcrumbs.popleft()
948948

949-
def start_transaction(
950-
self, transaction=None, custom_sampling_context=None, **kwargs
951-
):
949+
def start_transaction(self, transaction=None, **kwargs):
952950
# type: (Optional[Transaction], Optional[SamplingContext], Unpack[TransactionKwargs]) -> Union[Transaction, NoOpSpan]
953951
"""
954952
Start and return a transaction.
@@ -974,7 +972,6 @@ def start_transaction(
974972
975973
:param transaction: The transaction to start. If omitted, we create and
976974
start a new transaction.
977-
:param custom_sampling_context: The transaction's custom sampling context.
978975
:param kwargs: Optional keyword arguments to be passed to the Transaction
979976
constructor. See :py:class:`sentry_sdk.tracing.Transaction` for
980977
available arguments.
@@ -985,8 +982,6 @@ def start_transaction(
985982

986983
try_autostart_continuous_profiler()
987984

988-
custom_sampling_context = custom_sampling_context or {}
989-
990985
# if we haven't been given a transaction, make one
991986
transaction = Transaction(**kwargs)
992987

@@ -996,7 +991,6 @@ def start_transaction(
996991
"transaction_context": transaction.to_json(),
997992
"parent_sampled": transaction.parent_sampled,
998993
}
999-
sampling_context.update(custom_sampling_context)
1000994
transaction._set_initial_sampling_decision(sampling_context=sampling_context)
1001995

1002996
if transaction.sampled:

sentry_sdk/tracing.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343

4444
from typing_extensions import TypedDict, Unpack
4545

46+
from opentelemetry.utils import types as OTelSpanAttributes
47+
4648
P = ParamSpec("P")
4749
R = TypeVar("R")
4850

@@ -1202,10 +1204,12 @@ def __init__(
12021204
op=None, # type: Optional[str]
12031205
description=None, # type: Optional[str]
12041206
status=None, # type: Optional[str]
1207+
sampled=None, # type: Optional[bool]
12051208
start_timestamp=None, # type: Optional[Union[datetime, float]]
12061209
origin=None, # type: Optional[str]
12071210
name=None, # type: Optional[str]
12081211
source=TRANSACTION_SOURCE_CUSTOM, # type: str
1212+
attributes=None, # type: OTelSpanAttributes
12091213
only_if_parent=False, # type: bool
12101214
otel_span=None, # type: Optional[OtelSpan]
12111215
**_, # type: dict[str, object]
@@ -1230,6 +1234,9 @@ def __init__(
12301234
if skip_span:
12311235
self._otel_span = INVALID_SPAN
12321236
else:
1237+
from sentry_sdk.integrations.opentelemetry.consts import (
1238+
SentrySpanAttribute,
1239+
)
12331240
from sentry_sdk.integrations.opentelemetry.utils import (
12341241
convert_to_otel_timestamp,
12351242
)
@@ -1239,12 +1246,18 @@ def __init__(
12391246
start_timestamp = convert_to_otel_timestamp(start_timestamp)
12401247

12411248
span_name = name or description or op or ""
1249+
1250+
# Prepopulate some attrs so that they're accessible in traces_sampler
1251+
attributes = attributes or {}
1252+
attributes[SentrySpanAttribute.OP] = op
1253+
if sampled is not None:
1254+
attributes[SentrySpanAttribute.CUSTOM_SAMPLED] = sampled
1255+
12421256
self._otel_span = tracer.start_span(
1243-
span_name, start_time=start_timestamp
1257+
span_name, start_time=start_timestamp, attributes=attributes
12441258
)
12451259

12461260
self.origin = origin or DEFAULT_SPAN_ORIGIN
1247-
self.op = op
12481261
self.description = description
12491262
self.name = span_name
12501263
self.source = source

tests/tracing/test_sampling.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,13 @@ def test_passes_parent_sampling_decision_in_sampling_context(
211211
assert sampling_context["parent_sampled"]._mock_wraps is parent_sampling_decision
212212

213213

214-
def test_passes_custom_samling_context_from_start_transaction_to_traces_sampler(
214+
def test_passes_attributes_from_start_span_to_traces_sampler(
215215
sentry_init, DictionaryContaining # noqa: N803
216216
):
217217
traces_sampler = mock.Mock()
218218
sentry_init(traces_sampler=traces_sampler)
219219

220-
start_transaction(custom_sampling_context={"dogs": "yes", "cats": "maybe"})
220+
start_transaction(attributes={"dogs": "yes", "cats": "maybe"})
221221

222222
traces_sampler.assert_any_call(
223223
DictionaryContaining({"dogs": "yes", "cats": "maybe"})

0 commit comments

Comments
 (0)
0