Low commit activity in last 3 years
A thread-safe in-process metrics library providing counters, gauges, histograms, and summaries with label support, timing helpers, and Prometheus, JSON, and StatsD export formats.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

philiprehberger-metric

Tests Gem Version Last updated

In-process application metrics with counters, gauges, histograms, and summaries

Requirements

  • Ruby >= 3.1

Installation

Add to your Gemfile:

gem "philiprehberger-metric"

Or install directly:

gem install philiprehberger-metric

Usage

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

Counters

Philiprehberger::Metric.counter("events_total", help: "Total events processed")
Philiprehberger::Metric.increment("events_total")
Philiprehberger::Metric.increment("events_total", labels: { type: "click" })

Gauges

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)

Histograms

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")

Summaries

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 }

Timing Helper

registry = Philiprehberger::Metric::Registry.new
registry.histogram("operation_duration", help: "Operation duration")

result = registry.time("operation_duration", labels: { op: "compute" }) do
  expensive_operation
end

Timer

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).

Bucket Helpers

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)

Introspection

Philiprehberger::Metric.counter("requests", help: "Requests")
Philiprehberger::Metric.registered?("requests") # => true
Philiprehberger::Metric.names                    # => ["requests"]
Philiprehberger::Metric.unregister("requests")

Prometheus Export

output = Philiprehberger::Metric.to_prometheus
# => "# HELP http_requests_total Total HTTP requests\n# TYPE http_requests_total counter\n..."

JSON Export

json = Philiprehberger::Metric.to_json
# => '{"http_requests_total":{"type":"counter","help":"Total HTTP requests","values":{...}}}'

StatsD Export

output = Philiprehberger::Metric.to_statsd
# => "http_requests_total,method=GET:1|c"

API

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

Counter

Counters 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

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT