Skip to content

Commit

Permalink
feat(metrics): Make a consistent noop flush behavior (#2428)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko authored Oct 10, 2023
1 parent 44ae06e commit 1b445c6
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 11 deletions.
15 changes: 4 additions & 11 deletions sentry_sdk/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ def _encode_metrics(flushable_buckets):
class MetricsAggregator(object):
ROLLUP_IN_SECONDS = 10.0
MAX_WEIGHT = 100000
FLUSHER_SLEEP_TIME = 5.0

def __init__(
self,
Expand Down Expand Up @@ -350,7 +351,7 @@ def _flush_loop(self):
while self._running or self._force_flush:
self._flush()
if self._running:
self._flush_event.wait(5.0)
self._flush_event.wait(self.FLUSHER_SLEEP_TIME)

def _flush(self):
# type: (...) -> None
Expand Down Expand Up @@ -442,6 +443,7 @@ def kill(self):
self._flusher.join()
self._flusher = None

@metrics_noop
def flush(self):
# type: (...) -> None
self._force_flush = True
Expand All @@ -463,16 +465,7 @@ def _emit(
encoded_metrics = _encode_metrics(flushable_buckets)
metric_item = Item(payload=encoded_metrics, type="statsd")
envelope = Envelope(items=[metric_item])

# A malfunctioning transport might create a forever loop of metric
# emission when it emits a metric in capture_envelope. We still
# allow the capture to take place, but interior metric incr calls
# or similar will be disabled. In the background thread this can
# never happen, but in the force flush case which happens in the
# foreground we might make it here unprotected.
with recursion_protection():
self._capture_func(envelope)

self._capture_func(envelope)
return envelope

def _serialize_tags(
Expand Down
32 changes: 32 additions & 0 deletions tests/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,3 +532,35 @@ def bad_capture_envelope(*args, **kwargs):
m = parse_metrics(envelope.items[0].payload.get_bytes())
assert len(m) == 1
assert m[0][1] == "counter@none"


def test_flush_recursion_protection_background_flush(
sentry_init, capture_envelopes, monkeypatch
):
monkeypatch.setattr(metrics.MetricsAggregator, "FLUSHER_SLEEP_TIME", 0.1)
sentry_init(
release="fun-release",
environment="not-fun-env",
_experiments={"enable_metrics": True},
)
envelopes = capture_envelopes()
test_client = Hub.current.client

real_capture_envelope = test_client.transport.capture_envelope

def bad_capture_envelope(*args, **kwargs):
metrics.incr("bad-metric")
return real_capture_envelope(*args, **kwargs)

monkeypatch.setattr(test_client.transport, "capture_envelope", bad_capture_envelope)

metrics.incr("counter")

# flush via sleep and flag
Hub.current.client.metrics_aggregator._force_flush = True
time.sleep(0.5)

(envelope,) = envelopes
m = parse_metrics(envelope.items[0].payload.get_bytes())
assert len(m) == 1
assert m[0][1] == "counter@none"

0 comments on commit 1b445c6

Please sign in to comment.