Skip to content

Commit 2530c01

Browse files
merge master
2 parents a227c4e + fa7b1fe commit 2530c01

40 files changed

+1214
-693
lines changed

.craft.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
minVersion: 0.34.1
1+
minVersion: 2.17.0
22
targets:
33
- name: pypi
44
includeNames: /^sentry[_\-]sdk.*$/

.git-blame-ignore-revs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
afea4a017bf13f78e82f725ea9d6a56a8e02cb34
33
23a340a9dca60eea36de456def70c00952a33556
44
973dda79311cf6b9cb8f1ba67ca0515dfaf9f49c
5+
e275c9e94323b429f39196881fb992d81a2e52ea

.github/release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,28 @@ changelog:
1010
- "Changelog: Feature"
1111
commit_patterns:
1212
- "^feat\\b"
13+
semver: minor
1314
- title: Bug Fixes 🐛
1415
labels:
1516
- "Changelog: Bugfix"
1617
commit_patterns:
1718
- "^(fix|bugfix)\\b"
19+
semver: patch
1820
- title: Deprecations 🏗️
1921
labels:
2022
- "Changelog: Deprecation"
2123
commit_patterns:
2224
- "deprecat" # deprecation, deprecated
25+
semver: patch
2326
- title: Documentation 📚
2427
labels:
2528
- "Changelog: Docs"
2629
commit_patterns:
2730
- "^docs?\\b"
31+
semver: patch
2832
- title: Internal Changes 🔧
2933
labels:
3034
- "Changelog: Internal"
3135
commit_patterns:
3236
- "^(build|ref|chore|ci|tests?)\\b"
37+
semver: patch

CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,39 @@
11
# Changelog
22

3+
## 2.49.0
4+
5+
### New Features ✨
6+
7+
- feat(api): Add `Scope.set_attribute` by @sentrivana in [#5256](https://github.com/getsentry/sentry-python/pull/5256)
8+
9+
### Bug Fixes 🐛
10+
11+
- fix(grpc): Gate third-party imports by @alexander-alderman-webb in [#5246](https://github.com/getsentry/sentry-python/pull/5246)
12+
- fix(opentelemetry): Gate third-party imports by @alexander-alderman-webb in [#5247](https://github.com/getsentry/sentry-python/pull/5247)
13+
- fix(ray): Keep variadic kwargs last in signatures by @alexander-alderman-webb in [#5244](https://github.com/getsentry/sentry-python/pull/5244)
14+
- fix(trytond): Gate third-party imports by @alexander-alderman-webb in [#5245](https://github.com/getsentry/sentry-python/pull/5245)
15+
- Fix openai count_tokens by @sl0thentr0py in [#5281](https://github.com/getsentry/sentry-python/pull/5281)
16+
17+
### Documentation 📚
18+
19+
- docs: Fix typo in comment by @sentrivana in [#5280](https://github.com/getsentry/sentry-python/pull/5280)
20+
- docs: Fix `middleware_spans` docstring by @sentrivana in [#5279](https://github.com/getsentry/sentry-python/pull/5279)
21+
22+
### Internal Changes 🔧
23+
24+
- ref(scope): Set global attrs on global scope by @sentrivana in [#5259](https://github.com/getsentry/sentry-python/pull/5259)
25+
- chore: Ignore type migration for scripts/ and tests/ in blame by @alexander-alderman-webb in [#5284](https://github.com/getsentry/sentry-python/pull/5284)
26+
- ref: Properly override parent func by @sentrivana in [#5283](https://github.com/getsentry/sentry-python/pull/5283)
27+
- ci: Allow to use Craft's new auto-versioning by @sentrivana in [#5218](https://github.com/getsentry/sentry-python/pull/5218)
28+
- ref: Deduplicate batchers by @sentrivana in [#5263](https://github.com/getsentry/sentry-python/pull/5263)
29+
- tests: Add dedicated transport format test for metrics, logs by @sentrivana in [#5264](https://github.com/getsentry/sentry-python/pull/5264)
30+
- ci: 🤖 Update test matrix with new releases (01/05) by @github-actions in [#5273](https://github.com/getsentry/sentry-python/pull/5273)
31+
- tests: General logs tests should use Sentry logs API by @sentrivana in [#5262](https://github.com/getsentry/sentry-python/pull/5262)
32+
- tests: Test preserialization of attributes by @sentrivana in [#5260](https://github.com/getsentry/sentry-python/pull/5260)
33+
- ci: Unpin Pydantic 1.x version in tests by @alexander-alderman-webb in [#5261](https://github.com/getsentry/sentry-python/pull/5261)
34+
- ref: Make logs, metrics go via scope by @sentrivana in [#5213](https://github.com/getsentry/sentry-python/pull/5213)
35+
- ci: Fix failing arq, fastapi tests on 3.7; update test matrix by @sentrivana in [#5258](https://github.com/getsentry/sentry-python/pull/5258)
36+
337
## 2.48.0
438

539
Middleware spans are now disabled by default in Django, Starlette and FastAPI integrations. Set the `middleware_spans` integration-level

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to he
99
[![Discord](https://img.shields.io/discord/621778831602221064?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.com/invite/Ww9hbqr)
1010
[![X Follow](https://img.shields.io/twitter/follow/sentry?label=sentry&style=social)](https://x.com/intent/follow?screen_name=sentry)
1111
[![PyPi page link -- version](https://img.shields.io/pypi/v/sentry-sdk.svg)](https://pypi.python.org/pypi/sentry-sdk)
12-
<img src="https://img.shields.io/badge/python-3.7 | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 | 3.13-blue.svg" alt="python">
12+
<img src="https://img.shields.io/badge/python-3.7 | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 | 3.13 | 3.14-blue.svg" alt="python">
1313
[![Build Status](https://github.com/getsentry/sentry-python/actions/workflows/ci.yml/badge.svg)](https://github.com/getsentry/sentry-python/actions/workflows/ci.yml)
1414

1515
<br/>

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
copyright = "2019-{}, Sentry Team and Contributors".format(datetime.now().year)
3232
author = "Sentry Team and Contributors"
3333

34-
release = "2.48.0"
34+
release = "2.49.0"
3535
version = ".".join(release.split(".")[:2]) # The short X.Y version.
3636

3737

scripts/populate_tox/package_dependencies.jsonl

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

scripts/populate_tox/releases.jsonl

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

sentry_sdk/_batcher.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import os
2+
import random
3+
import threading
4+
from datetime import datetime, timezone
5+
from typing import TYPE_CHECKING, TypeVar, Generic
6+
7+
from sentry_sdk.utils import format_timestamp, safe_repr, serialize_attribute
8+
from sentry_sdk.envelope import Envelope, Item, PayloadRef
9+
10+
if TYPE_CHECKING:
11+
from typing import Optional, Callable, Any
12+
13+
T = TypeVar("T")
14+
15+
16+
class Batcher(Generic[T]):
17+
MAX_BEFORE_FLUSH = 100
18+
MAX_BEFORE_DROP = 1_000
19+
FLUSH_WAIT_TIME = 5.0
20+
21+
TYPE = ""
22+
CONTENT_TYPE = ""
23+
24+
def __init__(
25+
self,
26+
capture_func: "Callable[[Envelope], None]",
27+
record_lost_func: "Callable[..., None]",
28+
) -> None:
29+
self._buffer: "list[T]" = []
30+
self._capture_func = capture_func
31+
self._record_lost_func = record_lost_func
32+
self._running = True
33+
self._lock = threading.Lock()
34+
35+
self._flush_event: "threading.Event" = threading.Event()
36+
37+
self._flusher: "Optional[threading.Thread]" = None
38+
self._flusher_pid: "Optional[int]" = None
39+
40+
def _ensure_thread(self) -> bool:
41+
"""For forking processes we might need to restart this thread.
42+
This ensures that our process actually has that thread running.
43+
"""
44+
if not self._running:
45+
return False
46+
47+
pid = os.getpid()
48+
if self._flusher_pid == pid:
49+
return True
50+
51+
with self._lock:
52+
# Recheck to make sure another thread didn't get here and start the
53+
# the flusher in the meantime
54+
if self._flusher_pid == pid:
55+
return True
56+
57+
self._flusher_pid = pid
58+
59+
self._flusher = threading.Thread(target=self._flush_loop)
60+
self._flusher.daemon = True
61+
62+
try:
63+
self._flusher.start()
64+
except RuntimeError:
65+
# Unfortunately at this point the interpreter is in a state that no
66+
# longer allows us to spawn a thread and we have to bail.
67+
self._running = False
68+
return False
69+
70+
return True
71+
72+
def _flush_loop(self) -> None:
73+
while self._running:
74+
self._flush_event.wait(self.FLUSH_WAIT_TIME + random.random())
75+
self._flush_event.clear()
76+
self._flush()
77+
78+
def add(self, item: "T") -> None:
79+
if not self._ensure_thread() or self._flusher is None:
80+
return None
81+
82+
with self._lock:
83+
if len(self._buffer) >= self.MAX_BEFORE_DROP:
84+
self._record_lost(item)
85+
return None
86+
87+
self._buffer.append(item)
88+
if len(self._buffer) >= self.MAX_BEFORE_FLUSH:
89+
self._flush_event.set()
90+
91+
def kill(self) -> None:
92+
if self._flusher is None:
93+
return
94+
95+
self._running = False
96+
self._flush_event.set()
97+
self._flusher = None
98+
99+
def flush(self) -> None:
100+
self._flush()
101+
102+
def _add_to_envelope(self, envelope: "Envelope") -> None:
103+
envelope.add_item(
104+
Item(
105+
type=self.TYPE,
106+
content_type=self.CONTENT_TYPE,
107+
headers={
108+
"item_count": len(self._buffer),
109+
},
110+
payload=PayloadRef(
111+
json={
112+
"items": [
113+
self._to_transport_format(item) for item in self._buffer
114+
]
115+
}
116+
),
117+
)
118+
)
119+
120+
def _flush(self) -> "Optional[Envelope]":
121+
envelope = Envelope(
122+
headers={"sent_at": format_timestamp(datetime.now(timezone.utc))}
123+
)
124+
with self._lock:
125+
if len(self._buffer) == 0:
126+
return None
127+
128+
self._add_to_envelope(envelope)
129+
self._buffer.clear()
130+
131+
self._capture_func(envelope)
132+
return envelope
133+
134+
def _record_lost(self, item: "T") -> None:
135+
pass
136+
137+
@staticmethod
138+
def _to_transport_format(item: "T") -> "Any":
139+
pass

0 commit comments

Comments
 (0)