Skip to content

Commit faa327c

Browse files
fix: Add hard limit to metrics batcher (#5068)
Introduce a hard limit on the number of elements in the metrics batcher. The size constraint prevents the metrics batcher from using too much memory. Closes #5055
1 parent e8d5f1b commit faa327c

File tree

3 files changed

+53
-2
lines changed

3 files changed

+53
-2
lines changed

sentry_sdk/_metrics_batcher.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,18 @@
1313

1414
class MetricsBatcher:
1515
MAX_METRICS_BEFORE_FLUSH = 1000
16+
MAX_METRICS_BEFORE_DROP = 10_000
1617
FLUSH_WAIT_TIME = 5.0
1718

1819
def __init__(
1920
self,
2021
capture_func, # type: Callable[[Envelope], None]
22+
record_lost_func, # type: Callable[..., None]
2123
):
2224
# type: (...) -> None
2325
self._metric_buffer = [] # type: List[Metric]
2426
self._capture_func = capture_func
27+
self._record_lost_func = record_lost_func
2528
self._running = True
2629
self._lock = threading.Lock()
2730

@@ -72,6 +75,14 @@ def add(
7275
return None
7376

7477
with self._lock:
78+
if len(self._metric_buffer) >= self.MAX_METRICS_BEFORE_DROP:
79+
self._record_lost_func(
80+
reason="queue_overflow",
81+
data_category="trace_metric",
82+
quantity=1,
83+
)
84+
return None
85+
7586
self._metric_buffer.append(metric)
7687
if len(self._metric_buffer) >= self.MAX_METRICS_BEFORE_FLUSH:
7788
self._flush_event.set()

sentry_sdk/client.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
from typing import Union
6363
from typing import TypeVar
6464

65-
from sentry_sdk._types import Event, Hint, SDKInfo, Log, Metric
65+
from sentry_sdk._types import Event, Hint, SDKInfo, Log, Metric, EventDataCategory
6666
from sentry_sdk.integrations import Integration
6767
from sentry_sdk.scope import Scope
6868
from sentry_sdk.session import Session
@@ -357,6 +357,19 @@ def _capture_envelope(envelope):
357357
if self.transport is not None:
358358
self.transport.capture_envelope(envelope)
359359

360+
def _record_lost_event(
361+
reason, # type: str
362+
data_category, # type: EventDataCategory
363+
quantity=1, # type: int
364+
):
365+
# type: (...) -> None
366+
if self.transport is not None:
367+
self.transport.record_lost_event(
368+
reason=reason,
369+
data_category=data_category,
370+
quantity=quantity,
371+
)
372+
360373
try:
361374
_client_init_debug.set(self.options["debug"])
362375
self.transport = make_transport(self.options)
@@ -377,7 +390,10 @@ def _capture_envelope(envelope):
377390

378391
self.metrics_batcher = None
379392
if has_metrics_enabled(self.options):
380-
self.metrics_batcher = MetricsBatcher(capture_func=_capture_envelope)
393+
self.metrics_batcher = MetricsBatcher(
394+
capture_func=_capture_envelope,
395+
record_lost_func=_record_lost_event,
396+
)
381397

382398
max_request_body_size = ("always", "never", "small", "medium")
383399
if self.options["max_request_body_size"] not in max_request_body_size:

tests/test_metrics.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,27 @@ def _before_metric(record, hint):
243243
assert len(metrics) == 1
244244
assert metrics[0]["name"] == "test.keep"
245245
assert before_metric_called
246+
247+
248+
def test_batcher_drops_metrics(sentry_init, monkeypatch):
249+
sentry_init()
250+
client = sentry_sdk.get_client()
251+
252+
def no_op_flush():
253+
pass
254+
255+
monkeypatch.setattr(client.metrics_batcher, "_flush", no_op_flush)
256+
257+
lost_event_calls = []
258+
259+
def record_lost_event(reason, data_category, quantity):
260+
lost_event_calls.append((reason, data_category, quantity))
261+
262+
monkeypatch.setattr(client.metrics_batcher, "_record_lost_func", record_lost_event)
263+
264+
for i in range(10_005): # 5 metrics over the hard limit
265+
sentry_sdk.metrics.count("test.counter", 1)
266+
267+
assert len(lost_event_calls) == 5
268+
for lost_event_call in lost_event_calls:
269+
assert lost_event_call == ("queue_overflow", "trace_metric", 1)

0 commit comments

Comments
 (0)