Class: Prometheus::Client::VmHistogram
- Defined in:
- lib/prometheus/client/vm_histogram.rb
Overview
A histogram samples observations (usually things like request durations or response sizes) and counts them in dynamic VictoriaMetrics buckets. It also provides a total count and sum of all observed values.
Constant Summary collapse
- E10MIN =
-9
- E10MAX =
18
- BUCKETS_PER_DECIMAL =
18
- DECIMAL_BUCKETS_COUNT =
E10MAX - E10MIN
- BUCKETS_COUNT =
DECIMAL_BUCKETS_COUNT * BUCKETS_PER_DECIMAL
- BUCKETS_MULTIPLIER =
10**(1.0 / BUCKETS_PER_DECIMAL)
- VMRANGES =
begin h = {} value = 10**E10MIN range_start = format('%.3e', value) BUCKETS_COUNT.times do |i| value *= BUCKETS_MULTIPLIER range_end = format('%.3e', value) h[i] = "#{range_start}...#{range_end}" range_start = range_end end # edge case fo zeros h[-1] = '0...1.000e-09' h end
- MAX_VMRANGE_BUCKET =
VMRANGES.keys.max
Instance Attribute Summary collapse
-
#buckets ⇒ Object
readonly
Returns the value of attribute buckets.
Attributes inherited from Metric
#docstring, #labels, #name, #preset_labels
Instance Method Summary collapse
- #get(labels: {}) ⇒ Object
- #init_label_set(labels) ⇒ Object
-
#initialize(name, docstring:, labels: [], preset_labels: {}, buckets: [], store_settings: {}) ⇒ VmHistogram
constructor
A new instance of VmHistogram.
-
#observe(value, labels: {}) ⇒ Object
Records a given value.
- #type ⇒ Object
-
#values ⇒ Object
Returns all label sets with their values expressed as hashes with their buckets.
- #with_labels(labels) ⇒ Object
Constructor Details
#initialize(name, docstring:, labels: [], preset_labels: {}, buckets: [], store_settings: {}) ⇒ VmHistogram
Returns a new instance of VmHistogram.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/prometheus/client/vm_histogram.rb', line 38 def initialize(name, docstring:, labels: [], preset_labels: {}, # VM histogram ignores passed buckets, accepts only for compatibility buckets: [], # rubocop:disable Lint/UnusedMethodArgument store_settings: {}) @buckets = %w[sum count] # TODO: this should take into account labels @non_nil_buckets = {} @base_label_set_cache = {} super(name, docstring: docstring, labels: labels, preset_labels: preset_labels, store_settings: store_settings) end |
Instance Attribute Details
#buckets ⇒ Object (readonly)
Returns the value of attribute buckets.
11 12 13 |
# File 'lib/prometheus/client/vm_histogram.rb', line 11 def buckets @buckets end |
Instance Method Details
#get(labels: {}) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/prometheus/client/vm_histogram.rb', line 118 def get(labels: {}) base_label_set = label_set_for(labels) all_buckets = @non_nil_buckets.keys + buckets @store.synchronize do all_buckets.each_with_object({}) do |bucket, acc| if @non_nil_buckets.key? bucket value = @store.get(labels: base_label_set.merge(vmrange: bucket.to_s)) acc[bucket.to_s] = value if value.positive? else acc[bucket.to_s] = @store.get(labels: base_label_set.merge(le: bucket.to_s)) end end end end |
#init_label_set(labels) ⇒ Object
147 148 149 150 151 152 153 154 155 |
# File 'lib/prometheus/client/vm_histogram.rb', line 147 def init_label_set(labels) base_label_set = label_set_for(labels) @store.synchronize do @buckets.each do |bucket| @store.set(labels: base_label_set.merge(le: bucket.to_s), val: 0) end end end |
#observe(value, labels: {}) ⇒ Object
Records a given value. The recorded value is usually positive or zero. A negative value is ignored.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/prometheus/client/vm_histogram.rb', line 79 def observe(value, labels: {}) return if value.to_f.nan? || value.negative? float_bucket_id = (Math.log10(value) - E10MIN) * BUCKETS_PER_DECIMAL bucket_id = if float_bucket_id.negative? -1 elsif float_bucket_id > MAX_VMRANGE_BUCKET MAX_VMRANGE_BUCKET else float_bucket_id.to_i end # Edge case for 10^n values, which must go to the lower bucket # according to Prometheus logic for `le`-based histograms bucket_id -= 1 if (float_bucket_id - bucket_id.to_f).abs < Float::EPSILON && bucket_id.positive? base_label_set = label_set_for(labels) # OPTIMIZE: probably we also can use cache for vmranges to avoid using .dup every time bucket_label_set = base_label_set.dup bucket_label_set[:vmrange] = VMRANGES[bucket_id] @non_nil_buckets[bucket_label_set[:vmrange]] = nil # just to track non empty buckets unless @base_label_set_cache.key? base_label_set @base_label_set_cache[base_label_set] = { sum: base_label_set.merge({ le: 'sum' }), count: base_label_set.merge({ le: 'count' }) } end @store.synchronize do @store.increment(labels: bucket_label_set, by: 1) @store.increment(labels: @base_label_set_cache[base_label_set][:sum], by: value) @store.increment(labels: @base_label_set_cache[base_label_set][:count], by: 1) end end |
#type ⇒ Object
73 74 75 |
# File 'lib/prometheus/client/vm_histogram.rb', line 73 def type :vm_histogram end |
#values ⇒ Object
Returns all label sets with their values expressed as hashes with their buckets
136 137 138 139 140 141 142 143 144 145 |
# File 'lib/prometheus/client/vm_histogram.rb', line 136 def values values = @store.all_values values.each_with_object({}) do |(label_set, v), acc| actual_label_set = label_set.reject { |l| [:vmrange, :le].include? l } acc[actual_label_set] ||= {} label_name = label_set[:vmrange] || label_set[:le] acc[actual_label_set][label_name.to_s] = v end end |
#with_labels(labels) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/prometheus/client/vm_histogram.rb', line 58 def with_labels(labels) new_metric = self.class.new(name, docstring: docstring, labels: @labels, preset_labels: preset_labels.merge(labels), buckets: @buckets, store_settings: @store_settings) # The new metric needs to use the same store as the "main" declared one, otherwise # any observations on that copy with the pre-set labels won't actually be exported. new_metric.replace_internal_store(@store) new_metric end |