Class: Beacon::LogThrottle
- Inherits:
-
Object
- Object
- Beacon::LogThrottle
- Defined in:
- lib/beacon/log_throttle.rb
Overview
Per-key rate limiter for warn/log calls.
Without throttling, a misconfigured endpoint or a bad payload can fire the flusher’s/subscriber’s ‘warn` branch on every flush or every request — 60 lines/minute at 1 Hz, indefinitely — flooding production.log and burying the signal operators actually need.
Usage:
throttle = Beacon::LogThrottle.new(interval: 60.0)
throttle.warn(:flusher_5xx) { |count| "dropped batch (#{count} in the last window)" }
The block is only invoked when the key is allowed through, so the message-building cost is paid only on emitted lines. The count argument is the number of suppressed calls since the last emission plus one, so operators can see that “X happened (12 times)” without seeing 12 separate lines.
Thread-safe via a single Mutex.
**Keys must be low-cardinality** — the internal state map is not bounded. Use constant symbols (‘:circuit_open`, `:drop_500`) or symbols keyed by a fixed set (error class names). Do NOT key on per-request values like URLs, user IDs, or unbounded strings; the state map would grow indefinitely and you’d re-create the Card 3 ‘@name_cache` bug in a different shape.
Instance Method Summary collapse
-
#initialize(interval: 60.0, clock: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }) ⇒ LogThrottle
constructor
A new instance of LogThrottle.
-
#reset! ⇒ Object
Primarily for tests.
-
#warn(key) ⇒ Object
Emit a warn line for
keyif the last emission was more thanintervalseconds ago (or there was no previous emission).
Constructor Details
#initialize(interval: 60.0, clock: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }) ⇒ LogThrottle
Returns a new instance of LogThrottle.
28 29 30 31 32 33 |
# File 'lib/beacon/log_throttle.rb', line 28 def initialize(interval: 60.0, clock: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }) @interval = interval @clock = clock @mutex = Mutex.new @state = {} # key -> { last_at:, suppressed: } end |
Instance Method Details
#reset! ⇒ Object
Primarily for tests.
59 60 61 |
# File 'lib/beacon/log_throttle.rb', line 59 def reset! @mutex.synchronize { @state.clear } end |
#warn(key) ⇒ Object
Emit a warn line for key if the last emission was more than interval seconds ago (or there was no previous emission). Otherwise increment the suppressed counter and return nil. Yields ‘count` (Integer, >= 1) so the block can build a message like “X happened (count times in the last minute)”.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/beacon/log_throttle.rb', line 40 def warn(key) = nil @mutex.synchronize do state = @state[key] ||= { last_at: nil, suppressed: 0 } now = @clock.call if state[:last_at].nil? || now - state[:last_at] >= @interval count = state[:suppressed] + 1 state[:last_at] = now state[:suppressed] = 0 = yield(count) if block_given? else state[:suppressed] += 1 end end Kernel.warn("[beacon] #{}") if end |