In-process application metrics with counters, gauges, histograms, and summaries
gem install philiprehberger-metricIn-process application metrics with counters, gauges, histograms, and summaries
Add to your Gemfile:
gem "philiprehberger-metric"
Or install directly:
gem install philiprehberger-metric
require "philiprehberger/metric"
Philiprehberger::Metric.counter("http_requests_total", help: "Total HTTP requests")
Philiprehberger::Metric.increment("http_requests_total", labels: { method: "GET" })
counter = Philiprehberger::Metric.get("http_requests_total")
counter.get(labels: { method: "GET" }) # => 1
Philiprehberger::Metric.counter("events_total", help: "Total events processed")
Philiprehberger::Metric.increment("events_total")
Philiprehberger::Metric.increment("events_total", labels: { type: "click" })
Philiprehberger::Metric.gauge("temperature", help: "Current temperature")
Philiprehberger::Metric.set("temperature", 72.5)
gauge = Philiprehberger::Metric.get("temperature")
gauge.increment
gauge.decrement
gauge.add(2.5) # relative adjustment; negative values subtract
gauge.add(-1)
Philiprehberger::Metric.histogram("request_duration", help: "Request duration", buckets: [0.1, 0.5, 1, 5, 10])
Philiprehberger::Metric.observe("request_duration", 0.342)
data = Philiprehberger::Metric.snapshot("request_duration")
Philiprehberger::Metric.summary("response_size", help: "Response sizes", quantiles: [0.5, 0.9, 0.99])
Philiprehberger::Metric.observe("response_size", 1024)
Philiprehberger::Metric.observe("response_size", 2048)
summary = Philiprehberger::Metric.get("response_size")
summary.get # => { count: 2, sum: 3072.0, 0.5 => 1024.0, 0.9 => 2048.0, 0.99 => 2048.0 }
registry = Philiprehberger::Metric::Registry.new
registry.histogram("operation_duration", help: "Operation duration")
result = registry.time("operation_duration", labels: { op: "compute" }) do
expensive_operation
end
For flows where a block is awkward (for example, when start and stop live in different methods or callbacks), use Timer for a scoped manual-stop alternative.
Philiprehberger::Metric.histogram("job_duration", help: "Job duration")
timer = Philiprehberger::Metric::Timer.new("job_duration")
do_work
timer.stop(labels: { job: "import" })
# => elapsed seconds (Float); stop is idempotent — subsequent calls return the cached value
Pass a specific registry with Timer.new("job_duration", registry: my_registry). #elapsed reads the current elapsed seconds without stopping, and #reset discards a running timer (after reset, #stop raises).
linear = Philiprehberger::Metric::Histogram.linear_buckets(start: 0.1, width: 0.1, count: 5)
# => [0.1, 0.2, 0.3, 0.4, 0.5]
exp = Philiprehberger::Metric::Histogram.exponential_buckets(start: 1, factor: 2, count: 4)
# => [1, 2, 4, 8]
Philiprehberger::Metric.histogram("payload_bytes", help: "Payload size", buckets: exp)
Philiprehberger::Metric.counter("requests", help: "Requests")
Philiprehberger::Metric.registered?("requests") # => true
Philiprehberger::Metric.names # => ["requests"]
Philiprehberger::Metric.unregister("requests")
output = Philiprehberger::Metric.to_prometheus
# => "# HELP http_requests_total Total HTTP requests\n# TYPE http_requests_total counter\n..."
json = Philiprehberger::Metric.to_json
# => '{"http_requests_total":{"type":"counter","help":"Total HTTP requests","values":{...}}}'
output = Philiprehberger::Metric.to_statsd
# => "http_requests_total,method=GET:1|c"
Metric (Module)| Method | Description |
|---|---|
.counter(name, help:) | Register a counter metric |
.gauge(name, help:) | Register a gauge metric |
.histogram(name, help:, buckets:) | Register a histogram metric |
.summary(name, help:, quantiles:) | Register a summary metric |
.increment(name, labels:) | Increment a counter |
.set(name, value, labels:) | Set a gauge value |
.observe(name, value, labels:) | Observe a histogram or summary value |
.time(name, labels:) { block } | Measure block duration as histogram observation |
.get(name) | Get a registered metric by name |
.snapshot(name) | Get a snapshot of a metric's values |
.to_prometheus | Export all metrics in Prometheus text format |
.to_json | Export all metrics as JSON |
.to_statsd | Export all metrics in StatsD line protocol |
.names | List names of all registered metrics |
.registered?(name) | Check whether a metric is registered |
.unregister(name, strict:) | Remove a metric; strict: true raises if the metric is missing |
.reset | Reset and clear all registered metrics |
CounterCounters are monotonic: #increment rejects negative amounts and raises Philiprehberger::Metric::Error. Use a Gauge for values that can decrease.
| Method | Description |
|---|---|
#increment(amount:, labels:) | Increment the counter (raises on negative amount) |
#get(labels:) | Get the current value |
Gauge| Method | Description |
|---|---|
#set(value, labels:) | Set the gauge value |
#increment(amount:, labels:) | Increment the gauge |
#decrement(amount:, labels:) | Decrement the gauge |
#add(value, labels:) | Atomically add a value to the gauge (negative subtracts) |
#get(labels:) | Get the current value |
Histogram| Method | Description |
|---|---|
.linear_buckets(start:, width:, count:) | Build a linear sequence of bucket boundaries |
.exponential_buckets(start:, factor:, count:) | Build an exponential sequence of bucket boundaries |
#observe(value, labels:) | Observe a value |
#get(labels:) | Get bucket counts, sum, and count |
Summary| Method | Description |
|---|---|
#observe(value, labels:) | Observe a value |
#get(labels:) | Get quantile values, sum, and count |
Timer| Method | Description |
|---|---|
.new(histogram_name, registry:) | Start a new timer bound to a registered histogram |
#stop(labels:) | Record the elapsed seconds as a histogram observation; idempotent (cached return) |
#elapsed | Return the current elapsed seconds without stopping |
#reset | Discard the running timer; subsequent #stop raises Error |
bundle install
bundle exec rspec
bundle exec rubocop
If you find this project useful: