lib/airbrake-ruby/stat.rb
require 'base64'
module Airbrake
# Stat is a data structure that allows accumulating performance data (route
# performance, SQL query performance and such). It's powered by TDigests.
#
# Usually, one Stat corresponds to one metric (route or query,
# etc.). Incrementing a stat means pushing new performance statistics.
#
# @example
# stat = Airbrake::Stat.new
# stat.increment_ms(2000)
# stat.to_h # Pack and serialize data so it can be transmitted.
#
# @since v3.2.0
class Stat
attr_accessor :sum, :sumsq, :tdigest
# @param [Float] sum The sum of duration in milliseconds
# @param [Float] sumsq The squared sum of duration in milliseconds
# @param [TDigest::TDigest] tdigest Packed durations. By default,
# compression is 20
def initialize(sum: 0.0, sumsq: 0.0, tdigest: TDigest.new(0.05))
@sum = sum
@sumsq = sumsq
@tdigest = tdigest
@mutex = Mutex.new
end
# @return [Hash{String=>Object}] stats as a hash with compressed TDigest
# (serialized as base64)
def to_h
@mutex.synchronize do
tdigest.compress!
{
'count' => tdigest.size,
'sum' => sum,
'sumsq' => sumsq,
'tdigest' => Base64.strict_encode64(tdigest.as_small_bytes),
}
end
end
# Increments tdigest timings and updates tdigest with given +ms+ value.
#
# @param [Float] ms
# @return [void]
def increment_ms(ms)
@mutex.synchronize do
self.sum += ms
self.sumsq += ms * ms
tdigest.push(ms)
end
end
# We define custom inspect so that we weed out uninformative TDigest, which
# is also very slow to dump when we log Airbrake::Stat.
#
# @return [String]
def inspect
"#<struct Airbrake::Stat count=#{tdigest.size}, sum=#{sum}, sumsq=#{sumsq}>"
end
alias pretty_print inspect
end
end