Class: NatsWork::Metrics
- Inherits:
-
Object
- Object
- NatsWork::Metrics
- Defined in:
- lib/natswork/metrics.rb
Instance Attribute Summary collapse
-
#counters ⇒ Object
readonly
Returns the value of attribute counters.
-
#gauges ⇒ Object
readonly
Returns the value of attribute gauges.
-
#histograms ⇒ Object
readonly
Returns the value of attribute histograms.
-
#timers ⇒ Object
readonly
Returns the value of attribute timers.
Class Method Summary collapse
- .global ⇒ Object
- .method_missing(method, *args, &block) ⇒ Object
- .respond_to_missing?(method, include_private = false) ⇒ Boolean
Instance Method Summary collapse
-
#add_collector(collector) ⇒ Object
Add a metrics collector (e.g., StatsD, Prometheus).
- #counter(metric, tags = {}) ⇒ Object
- #disable! ⇒ Object
- #enable! ⇒ Object
-
#gauge(metric, value, tags = {}) ⇒ Object
Gauge - point-in-time value.
- #get_gauge(metric, tags = {}) ⇒ Object
-
#histogram(metric, value, tags = {}) ⇒ Object
Histogram - distribution of values.
- #histogram_stats(metric, tags = {}) ⇒ Object
-
#increment(metric, value = 1, tags = {}) ⇒ Object
Counter - always increasing value.
-
#initialize ⇒ Metrics
constructor
A new instance of Metrics.
- #remove_collector(collector) ⇒ Object
- #reset! ⇒ Object
- #snapshot ⇒ Object
-
#time(metric, tags = {}) ⇒ Object
Timer - measure duration.
- #timer_stats(metric, tags = {}) ⇒ Object
Constructor Details
#initialize ⇒ Metrics
Returns a new instance of Metrics.
9 10 11 12 13 14 15 16 17 |
# File 'lib/natswork/metrics.rb', line 9 def initialize @counters = Concurrent::Hash.new(0) @gauges = Concurrent::Hash.new(0) @histograms = Concurrent::Hash.new { |h, k| h[k] = [] } @timers = Concurrent::Hash.new { |h, k| h[k] = [] } @collectors = [] @enabled = true end |
Instance Attribute Details
#counters ⇒ Object (readonly)
Returns the value of attribute counters.
7 8 9 |
# File 'lib/natswork/metrics.rb', line 7 def counters @counters end |
#gauges ⇒ Object (readonly)
Returns the value of attribute gauges.
7 8 9 |
# File 'lib/natswork/metrics.rb', line 7 def gauges @gauges end |
#histograms ⇒ Object (readonly)
Returns the value of attribute histograms.
7 8 9 |
# File 'lib/natswork/metrics.rb', line 7 def histograms @histograms end |
#timers ⇒ Object (readonly)
Returns the value of attribute timers.
7 8 9 |
# File 'lib/natswork/metrics.rb', line 7 def timers @timers end |
Class Method Details
.global ⇒ Object
193 194 195 |
# File 'lib/natswork/metrics.rb', line 193 def global @global ||= new end |
.method_missing(method, *args, &block) ⇒ Object
197 198 199 200 201 202 203 |
# File 'lib/natswork/metrics.rb', line 197 def method_missing(method, *args, &block) if global.respond_to?(method) global.send(method, *args, &block) else super end end |
.respond_to_missing?(method, include_private = false) ⇒ Boolean
205 206 207 |
# File 'lib/natswork/metrics.rb', line 205 def respond_to_missing?(method, include_private = false) global.respond_to?(method, include_private) || super end |
Instance Method Details
#add_collector(collector) ⇒ Object
Add a metrics collector (e.g., StatsD, Prometheus)
116 117 118 |
# File 'lib/natswork/metrics.rb', line 116 def add_collector(collector) @collectors << collector if collector.respond_to?(:collect) end |
#counter(metric, tags = {}) ⇒ Object
29 30 31 |
# File 'lib/natswork/metrics.rb', line 29 def counter(metric, = {}) @counters[metric_key(metric, )] end |
#disable! ⇒ Object
128 129 130 |
# File 'lib/natswork/metrics.rb', line 128 def disable! @enabled = false end |
#enable! ⇒ Object
124 125 126 |
# File 'lib/natswork/metrics.rb', line 124 def enable! @enabled = true end |
#gauge(metric, value, tags = {}) ⇒ Object
Gauge - point-in-time value
34 35 36 37 38 39 40 41 |
# File 'lib/natswork/metrics.rb', line 34 def gauge(metric, value, = {}) return unless @enabled key = metric_key(metric, ) @gauges[key] = value notify_collectors(:gauge, metric, value, ) end |
#get_gauge(metric, tags = {}) ⇒ Object
43 44 45 |
# File 'lib/natswork/metrics.rb', line 43 def get_gauge(metric, = {}) @gauges[metric_key(metric, )] end |
#histogram(metric, value, tags = {}) ⇒ Object
Histogram - distribution of values
48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/natswork/metrics.rb', line 48 def histogram(metric, value, = {}) return unless @enabled key = metric_key(metric, ) @histograms[key] << value # Keep only last 1000 values to prevent memory bloat @histograms[key] = @histograms[key].last(1000) if @histograms[key].size > 1000 notify_collectors(:histogram, metric, value, ) end |
#histogram_stats(metric, tags = {}) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/natswork/metrics.rb', line 60 def histogram_stats(metric, = {}) values = @histograms[metric_key(metric, )] return nil if values.empty? sorted = values.sort { count: values.size, min: sorted.first, max: sorted.last, mean: values.sum.to_f / values.size, p50: percentile(sorted, 0.5), p95: percentile(sorted, 0.95), p99: percentile(sorted, 0.99) } end |
#increment(metric, value = 1, tags = {}) ⇒ Object
Counter - always increasing value
20 21 22 23 24 25 26 27 |
# File 'lib/natswork/metrics.rb', line 20 def increment(metric, value = 1, = {}) return unless @enabled key = metric_key(metric, ) @counters[key] += value notify_collectors(:counter, metric, @counters[key], ) end |
#remove_collector(collector) ⇒ Object
120 121 122 |
# File 'lib/natswork/metrics.rb', line 120 def remove_collector(collector) @collectors.delete(collector) end |
#reset! ⇒ Object
132 133 134 135 136 137 |
# File 'lib/natswork/metrics.rb', line 132 def reset! @counters.clear @gauges.clear @histograms.clear @timers.clear end |
#snapshot ⇒ Object
139 140 141 142 143 144 145 146 |
# File 'lib/natswork/metrics.rb', line 139 def snapshot { counters: @counters.to_h, gauges: @gauges.to_h, histograms: @histograms.transform_values { |v| histogram_stats_from_values(v) }, timers: @timers.transform_values { |v| histogram_stats_from_values(v) } } end |
#time(metric, tags = {}) ⇒ Object
Timer - measure duration
77 78 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 |
# File 'lib/natswork/metrics.rb', line 77 def time(metric, = {}) return yield unless @enabled start_time = Time.now begin result = yield duration = (Time.now - start_time) * 1000 # milliseconds key = metric_key(metric, ) @timers[key] << duration # Keep only last 1000 values @timers[key] = @timers[key].last(1000) if @timers[key].size > 1000 notify_collectors(:timer, metric, duration, ) result rescue StandardError duration = (Time.now - start_time) * 1000 key = metric_key(metric, ) @timers[key] << duration # Keep only last 1000 values @timers[key] = @timers[key].last(1000) if @timers[key].size > 1000 notify_collectors(:timer, metric, duration, .merge(status: 'error')) raise end end |
#timer_stats(metric, tags = {}) ⇒ Object
107 108 109 110 111 112 113 |
# File 'lib/natswork/metrics.rb', line 107 def timer_stats(metric, = {}) key = metric_key(metric, ) values = @timers[key] return nil if values.empty? histogram_stats_from_values(values) end |