Mobile crash-reporting and remote-logging systems can't ship every log line over a metered connection, so a collector admits events through a token bucket rate limiter:
tokens(t+Δt) = min(C, tokens(t) + R·Δt)
cost per admitted event = 1 token
if tokens ≥ 1: admit, tokens -= 1
else: drop the event
Every simulated tick, each of 8 devices emits DEBUG/INFO/WARN/ERROR/FATAL events as a Poisson-ish process at the rate you set. The bucket refills continuously at your bandwidth budget R (tokens/s) up to your chosen capacity C. When the queue in a tick exceeds the tokens available, something has to be dropped — the question is what:
- Priority strategy — the queue is sorted FATAL → ERROR → WARN → INFO → DEBUG before tokens are spent, so crash reports and errors are admitted first and only low-value DEBUG/INFO traffic is sampled away under load. This mirrors how real crash reporters (Crashlytics, Sentry) prioritize.
- Uniform strategy — the same queue is shuffled first, so every level has an equal chance of being dropped once the bucket is empty, including FATAL crash events.
The crash spike button injects a burst of extra ERROR/FATAL events for 3 seconds without raising the token budget — watch "FATAL/ERROR dropped" stay near zero under Priority admission and climb under Uniform admission, even though total drop-rate % looks similar in both modes. The top ring shows devices streaming events toward the collector (drag it to rotate the layout); the middle gauge is the live token bucket; the bottom strip is a rolling history of generated vs. ingested throughput plus this tick's admission queue.