Skip to content

Commit d6c7379

Browse files
Merge branch 'master' into shellmayr/feat/auto-deactivate-lower-level-integartions
2 parents 4db7783 + 7264a9f commit d6c7379

File tree

12 files changed

+217
-144
lines changed

12 files changed

+217
-144
lines changed

scripts/populate_tox/package_dependencies.jsonl

Lines changed: 7 additions & 7 deletions
Large diffs are not rendered by default.

scripts/populate_tox/releases.jsonl

Lines changed: 16 additions & 16 deletions
Large diffs are not rendered by default.

sentry_sdk/client.py

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import sentry_sdk
1212
from sentry_sdk._compat import PY37, check_uwsgi_thread_support
13+
from sentry_sdk._metrics_batcher import MetricsBatcher
1314
from sentry_sdk.utils import (
1415
AnnotatedValue,
1516
ContextVar,
@@ -26,7 +27,6 @@
2627
get_before_send_log,
2728
get_before_send_metric,
2829
has_logs_enabled,
29-
has_metrics_enabled,
3030
)
3131
from sentry_sdk.serializer import serialize
3232
from sentry_sdk.tracing import trace
@@ -374,12 +374,7 @@ def _capture_envelope(envelope):
374374

375375
self.log_batcher = LogBatcher(capture_func=_capture_envelope)
376376

377-
self.metrics_batcher = None
378-
379-
if has_metrics_enabled(self.options):
380-
from sentry_sdk._metrics_batcher import MetricsBatcher
381-
382-
self.metrics_batcher = MetricsBatcher(capture_func=_capture_envelope)
377+
self.metrics_batcher = MetricsBatcher(capture_func=_capture_envelope)
383378

384379
max_request_body_size = ("always", "never", "small", "medium")
385380
if self.options["max_request_body_size"] not in max_request_body_size:
@@ -933,17 +928,18 @@ def _capture_log(self, log):
933928
if release is not None and "sentry.release" not in log["attributes"]:
934929
log["attributes"]["sentry.release"] = release
935930

936-
span = current_scope.span
937-
if span is not None and "sentry.trace.parent_span_id" not in log["attributes"]:
938-
log["attributes"]["sentry.trace.parent_span_id"] = span.span_id
931+
trace_context = current_scope.get_trace_context()
932+
trace_id = trace_context.get("trace_id")
933+
span_id = trace_context.get("span_id")
939934

940-
if log.get("trace_id") is None:
941-
transaction = current_scope.transaction
942-
propagation_context = isolation_scope.get_active_propagation_context()
943-
if transaction is not None:
944-
log["trace_id"] = transaction.trace_id
945-
elif propagation_context is not None:
946-
log["trace_id"] = propagation_context.trace_id
935+
if trace_id is not None and log.get("trace_id") is None:
936+
log["trace_id"] = trace_id
937+
938+
if (
939+
span_id is not None
940+
and "sentry.trace.parent_span_id" not in log["attributes"]
941+
):
942+
log["attributes"]["sentry.trace.parent_span_id"] = span_id
947943

948944
# The user, if present, is always set on the isolation scope.
949945
if isolation_scope._user is not None:
@@ -979,9 +975,10 @@ def _capture_log(self, log):
979975

980976
def _capture_metric(self, metric):
981977
# type: (Optional[Metric]) -> None
982-
if not has_metrics_enabled(self.options) or metric is None:
978+
if metric is None:
983979
return
984980

981+
current_scope = sentry_sdk.get_current_scope()
985982
isolation_scope = sentry_sdk.get_isolation_scope()
986983

987984
metric["attributes"]["sentry.sdk.name"] = SDK_INFO["name"]
@@ -995,16 +992,13 @@ def _capture_metric(self, metric):
995992
if release is not None and "sentry.release" not in metric["attributes"]:
996993
metric["attributes"]["sentry.release"] = release
997994

998-
span = sentry_sdk.get_current_span()
999-
metric["trace_id"] = "00000000-0000-0000-0000-000000000000"
995+
trace_context = current_scope.get_trace_context()
996+
trace_id = trace_context.get("trace_id")
997+
span_id = trace_context.get("span_id")
1000998

1001-
if span:
1002-
metric["trace_id"] = span.trace_id
1003-
metric["span_id"] = span.span_id
1004-
else:
1005-
propagation_context = isolation_scope.get_active_propagation_context()
1006-
if propagation_context and propagation_context.trace_id:
1007-
metric["trace_id"] = propagation_context.trace_id
999+
metric["trace_id"] = trace_id or "00000000-0000-0000-0000-000000000000"
1000+
if span_id is not None:
1001+
metric["span_id"] = span_id
10081002

10091003
if isolation_scope._user is not None:
10101004
for metric_attribute, user_attribute in (

sentry_sdk/integrations/anthropic.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@
2222

2323
try:
2424
try:
25-
from anthropic import NOT_GIVEN
25+
from anthropic import NotGiven
2626
except ImportError:
27-
NOT_GIVEN = None
27+
NotGiven = None
28+
29+
try:
30+
from anthropic import Omit
31+
except ImportError:
32+
Omit = None
2833

2934
from anthropic.resources import AsyncMessages, Messages
3035

@@ -168,12 +173,13 @@ def _set_input_data(span, kwargs, integration):
168173
}
169174
for key, attribute in kwargs_keys_to_attributes.items():
170175
value = kwargs.get(key)
171-
if value is not NOT_GIVEN and value is not None:
176+
177+
if value is not None and _is_given(value):
172178
set_data_normalized(span, attribute, value)
173179

174180
# Input attributes: Tools
175181
tools = kwargs.get("tools")
176-
if tools is not NOT_GIVEN and tools is not None and len(tools) > 0:
182+
if tools is not None and _is_given(tools) and len(tools) > 0:
177183
set_data_normalized(
178184
span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools)
179185
)
@@ -419,3 +425,15 @@ async def _sentry_patched_create_async(*args, **kwargs):
419425
span.__exit__(None, None, None)
420426

421427
return _sentry_patched_create_async
428+
429+
430+
def _is_given(obj):
431+
# type: (Any) -> bool
432+
"""
433+
Check for givenness safely across different anthropic versions.
434+
"""
435+
if NotGiven is not None and isinstance(obj, NotGiven):
436+
return False
437+
if Omit is not None and isinstance(obj, Omit):
438+
return False
439+
return True

sentry_sdk/scope.py

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@
107107

108108
global_event_processors = [] # type: List[EventProcessor]
109109

110+
# A function returning a (trace_id, span_id) tuple
111+
# from an external tracing source (such as otel)
112+
_external_propagation_context_fn = None # type: Optional[Callable[[], Optional[Tuple[str, str]]]]
113+
110114

111115
class ScopeType(Enum):
112116
CURRENT = "current"
@@ -142,6 +146,25 @@ def add_global_event_processor(processor):
142146
global_event_processors.append(processor)
143147

144148

149+
def register_external_propagation_context(fn):
150+
# type: (Callable[[], Optional[Tuple[str, str]]]) -> None
151+
global _external_propagation_context_fn
152+
_external_propagation_context_fn = fn
153+
154+
155+
def remove_external_propagation_context():
156+
# type: () -> None
157+
global _external_propagation_context_fn
158+
_external_propagation_context_fn = None
159+
160+
161+
def get_external_propagation_context():
162+
# type: () -> Optional[Tuple[str, str]]
163+
return (
164+
_external_propagation_context_fn() if _external_propagation_context_fn else None
165+
)
166+
167+
145168
def _attr_setter(fn):
146169
# type: (Any) -> Any
147170
return property(fset=fn, doc=fn.__doc__)
@@ -562,21 +585,29 @@ def get_baggage(self, *args, **kwargs):
562585
return self.get_isolation_scope().get_baggage()
563586

564587
def get_trace_context(self):
565-
# type: () -> Any
588+
# type: () -> Dict[str, Any]
566589
"""
567590
Returns the Sentry "trace" context from the Propagation Context.
568591
"""
569-
if self._propagation_context is None:
570-
return None
592+
if has_tracing_enabled(self.get_client().options) and self._span is not None:
593+
return self._span.get_trace_context()
571594

572-
trace_context = {
573-
"trace_id": self._propagation_context.trace_id,
574-
"span_id": self._propagation_context.span_id,
575-
"parent_span_id": self._propagation_context.parent_span_id,
576-
"dynamic_sampling_context": self.get_dynamic_sampling_context(),
577-
} # type: Dict[str, Any]
595+
# if we are tracing externally (otel), those values take precedence
596+
external_propagation_context = get_external_propagation_context()
597+
if external_propagation_context:
598+
trace_id, span_id = external_propagation_context
599+
return {"trace_id": trace_id, "span_id": span_id}
578600

579-
return trace_context
601+
propagation_context = self.get_active_propagation_context()
602+
if propagation_context is None:
603+
return {}
604+
605+
return {
606+
"trace_id": propagation_context.trace_id,
607+
"span_id": propagation_context.span_id,
608+
"parent_span_id": propagation_context.parent_span_id,
609+
"dynamic_sampling_context": self.get_dynamic_sampling_context(),
610+
}
580611

581612
def trace_propagation_meta(self, *args, **kwargs):
582613
# type: (*Any, **Any) -> str
@@ -1438,10 +1469,7 @@ def _apply_contexts_to_event(self, event, hint, options):
14381469

14391470
# Add "trace" context
14401471
if contexts.get("trace") is None:
1441-
if has_tracing_enabled(options) and self._span is not None:
1442-
contexts["trace"] = self._span.get_trace_context()
1443-
else:
1444-
contexts["trace"] = self.get_trace_context()
1472+
contexts["trace"] = self.get_trace_context()
14451473

14461474
def _apply_flags_to_event(self, event, hint, options):
14471475
# type: (Event, Hint, Optional[Dict[str, Any]]) -> None

sentry_sdk/utils.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,14 +2047,6 @@ def get_before_send_log(options):
20472047
)
20482048

20492049

2050-
def has_metrics_enabled(options):
2051-
# type: (Optional[dict[str, Any]]) -> bool
2052-
if options is None:
2053-
return False
2054-
2055-
return bool(options["_experiments"].get("enable_metrics", False))
2056-
2057-
20582050
def get_before_send_metric(options):
20592051
# type: (Optional[dict[str, Any]]) -> Optional[Callable[[Metric, Hint], Optional[Metric]]]
20602052
if options is None:

tests/integrations/logging/test_logging.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,10 @@ def test_logger_with_all_attributes(sentry_init, capture_envelopes):
478478

479479
assert attributes.pop("sentry.sdk.name").startswith("sentry.python")
480480

481+
assert "sentry.trace.parent_span_id" in attributes
482+
assert isinstance(attributes["sentry.trace.parent_span_id"], str)
483+
del attributes["sentry.trace.parent_span_id"]
484+
481485
# Assert on the remaining non-dynamic attributes.
482486
assert attributes == {
483487
"foo": "bar",

tests/integrations/loguru/test_loguru.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,10 @@ def test_logger_with_all_attributes(
458458

459459
assert attributes.pop("sentry.sdk.name").startswith("sentry.python")
460460

461+
assert "sentry.trace.parent_span_id" in attributes
462+
assert isinstance(attributes["sentry.trace.parent_span_id"], str)
463+
del attributes["sentry.trace.parent_span_id"]
464+
461465
# Assert on the remaining non-dynamic attributes.
462466
assert attributes == {
463467
"logger.name": "tests.integrations.loguru.test_loguru",

tests/test_logs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ def test_logs_tied_to_transactions(sentry_init, capture_envelopes):
310310
"""
311311
Log messages are also tied to transactions.
312312
"""
313-
sentry_init(enable_logs=True)
313+
sentry_init(enable_logs=True, traces_sample_rate=1.0)
314314
envelopes = capture_envelopes()
315315

316316
with sentry_sdk.start_transaction(name="test-transaction") as trx:
@@ -326,7 +326,7 @@ def test_logs_tied_to_spans(sentry_init, capture_envelopes):
326326
"""
327327
Log messages are also tied to spans.
328328
"""
329-
sentry_init(enable_logs=True)
329+
sentry_init(enable_logs=True, traces_sample_rate=1.0)
330330
envelopes = capture_envelopes()
331331

332332
with sentry_sdk.start_transaction(name="test-transaction"):

tests/test_metrics.py

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,8 @@ def envelopes_to_metrics(envelopes):
3333
return res
3434

3535

36-
def test_metrics_disabled_by_default(sentry_init, capture_envelopes):
37-
sentry_init()
38-
39-
envelopes = capture_envelopes()
40-
41-
sentry_sdk.metrics.count("test.counter", 1)
42-
sentry_sdk.metrics.gauge("test.gauge", 42)
43-
sentry_sdk.metrics.distribution("test.distribution", 200)
44-
45-
assert len(envelopes) == 0
46-
47-
4836
def test_metrics_basics(sentry_init, capture_envelopes):
49-
sentry_init(_experiments={"enable_metrics": True})
37+
sentry_init()
5038
envelopes = capture_envelopes()
5139

5240
sentry_sdk.metrics.count("test.counter", 1)
@@ -77,7 +65,7 @@ def test_metrics_basics(sentry_init, capture_envelopes):
7765

7866

7967
def test_metrics_experimental_option(sentry_init, capture_envelopes):
80-
sentry_init(_experiments={"enable_metrics": True})
68+
sentry_init()
8169
envelopes = capture_envelopes()
8270

8371
sentry_sdk.metrics.count("test.counter", 5)
@@ -93,9 +81,7 @@ def test_metrics_experimental_option(sentry_init, capture_envelopes):
9381

9482

9583
def test_metrics_with_attributes(sentry_init, capture_envelopes):
96-
sentry_init(
97-
_experiments={"enable_metrics": True}, release="1.0.0", environment="test"
98-
)
84+
sentry_init(release="1.0.0", environment="test")
9985
envelopes = capture_envelopes()
10086

10187
sentry_sdk.metrics.count(
@@ -114,7 +100,7 @@ def test_metrics_with_attributes(sentry_init, capture_envelopes):
114100

115101

116102
def test_metrics_with_user(sentry_init, capture_envelopes):
117-
sentry_init(_experiments={"enable_metrics": True})
103+
sentry_init()
118104
envelopes = capture_envelopes()
119105

120106
sentry_sdk.set_user(
@@ -133,10 +119,10 @@ def test_metrics_with_user(sentry_init, capture_envelopes):
133119

134120

135121
def test_metrics_with_span(sentry_init, capture_envelopes):
136-
sentry_init(_experiments={"enable_metrics": True}, traces_sample_rate=1.0)
122+
sentry_init(traces_sample_rate=1.0)
137123
envelopes = capture_envelopes()
138124

139-
with sentry_sdk.start_transaction(op="test", name="test-span"):
125+
with sentry_sdk.start_transaction(op="test", name="test-span") as transaction:
140126
sentry_sdk.metrics.count("test.span.counter", 1)
141127

142128
get_client().flush()
@@ -145,24 +131,26 @@ def test_metrics_with_span(sentry_init, capture_envelopes):
145131
assert len(metrics) == 1
146132

147133
assert metrics[0]["trace_id"] is not None
148-
assert metrics[0]["trace_id"] != "00000000-0000-0000-0000-000000000000"
149-
assert metrics[0]["span_id"] is not None
134+
assert metrics[0]["trace_id"] == transaction.trace_id
135+
assert metrics[0]["span_id"] == transaction.span_id
150136

151137

152138
def test_metrics_tracing_without_performance(sentry_init, capture_envelopes):
153-
sentry_init(_experiments={"enable_metrics": True})
139+
sentry_init()
154140
envelopes = capture_envelopes()
155141

156-
sentry_sdk.metrics.count("test.span.counter", 1)
142+
with sentry_sdk.isolation_scope() as isolation_scope:
143+
sentry_sdk.metrics.count("test.span.counter", 1)
157144

158145
get_client().flush()
159146

160147
metrics = envelopes_to_metrics(envelopes)
161148
assert len(metrics) == 1
162149

163-
assert metrics[0]["trace_id"] is not None
164-
assert metrics[0]["trace_id"] != "00000000-0000-0000-0000-000000000000"
165-
assert metrics[0]["span_id"] is None
150+
propagation_context = isolation_scope._propagation_context
151+
assert propagation_context is not None
152+
assert metrics[0]["trace_id"] == propagation_context.trace_id
153+
assert metrics[0]["span_id"] == propagation_context.span_id
166154

167155

168156
def test_metrics_before_send(sentry_init, capture_envelopes):
@@ -190,7 +178,6 @@ def _before_metric(record, hint):
190178

191179
sentry_init(
192180
_experiments={
193-
"enable_metrics": True,
194181
"before_send_metric": _before_metric,
195182
},
196183
)

0 commit comments

Comments
 (0)