Class: Bulldogger::Probe::Bucket
- Inherits:
-
Object
- Object
- Bulldogger::Probe::Bucket
- Defined in:
- lib/bulldogger/probe/bucket.rb
Overview
One params/returns aggregate: a running tally of observed classes and nil-ness (updated on every call), plus a bounded, fully-serialized sample of the first max_samples values.
Tally and sample are deliberately split: contract-verbs.md measured full serialization at ~24us/event, which would blow the probe overhead budget on a call-dense target if it ran on every call. Class name and nil? never touch #inspect, so the tally stays cheap regardless of how many calls a session sees.
Instance Method Summary collapse
-
#initialize(formatter:, max_samples:, redacted_name: false) ⇒ Bucket
constructor
A new instance of Bucket.
-
#merge!(other) ⇒ Object
Folds another Bucket's tally into this one.
- #record(value) ⇒ Object
- #to_h ⇒ Object
Constructor Details
#initialize(formatter:, max_samples:, redacted_name: false) ⇒ Bucket
Returns a new instance of Bucket.
15 16 17 18 19 20 21 22 23 |
# File 'lib/bulldogger/probe/bucket.rb', line 15 def initialize(formatter:, max_samples:, redacted_name: false) @formatter = formatter @max_samples = max_samples @redacted_name = redacted_name @classes = Hash.new(0) @nil_count = 0 @samples = [] @count = 0 end |
Instance Method Details
#merge!(other) ⇒ Object
Folds another Bucket's tally into this one. This is the finish-time merge step for thread-local aggregation: each thread records into its own Bucket with no lock, and totals are combined once, in one place, instead of every call taking a Mutex to update a single shared Bucket.
Samples are re-capped at @max_samples here too: each thread-local Bucket already capped its own samples independently, so without this cap a target hit by N threads could publish up to N * max_samples samples, silently widening the documented limit just because more than one thread happened to record some of the calls.
54 55 56 57 58 59 60 61 62 63 |
# File 'lib/bulldogger/probe/bucket.rb', line 54 def merge!(other) @count += other.count other.classes.each { |klass, n| @classes[klass] += n } @nil_count += other.nil_count other.samples.each do |sample| break if @samples.size >= @max_samples @samples << sample end end |
#record(value) ⇒ Object
25 26 27 28 29 30 |
# File 'lib/bulldogger/probe/bucket.rb', line 25 def record(value) @count += 1 @classes[safe_class_name(value)] += 1 @nil_count += 1 if value.nil? @samples << sample_for(value) if @samples.size < @max_samples end |
#to_h ⇒ Object
32 33 34 35 36 37 38 39 40 |
# File 'lib/bulldogger/probe/bucket.rb', line 32 def to_h h = { "classes" => @classes, "nil_count" => @nil_count, "samples" => @samples } omitted = @count - @samples.size # Present only when something was actually cut, so a reader # can trust its absence -- the same rule contract.md applies # to frames_omitted/locals_omitted. h["samples_omitted"] = omitted if omitted.positive? h end |