Module: Emrb::Instruments::ClassMethods
- Defined in:
- lib/emrb/instruments/instruments.rb
Overview
Provides the instrumentation facilities when including/extending Instruments.
Constant Summary collapse
- FORBIDDEN_IDENTIFIERS =
instance_methods
Instance Method Summary collapse
-
#block_opts(**opts) ⇒ Object
Internal: Validates the provided options to create a given instrument and performs the merge of all options with presets when they are present.
-
#check_identifier!(id) ⇒ Object
Internal: Validates whether the given identifier might override one of the class methods.
-
#counter(identifier, docs = "...") ⇒ Object
Initializes a new Prometheus counter using the provided identifier, documentation, and either optional keyword arguments or a block that returns the keyword arguments.
-
#gauge(identifier, docs = "...") ⇒ Object
Initializes a new Prometheus gauge using the provided identifier, documentation, and either optional keyword arguments or a block that returns the keyword arguments.
-
#histogram(identifier, docs = "...") ⇒ Object
Initializes a new Prometheus histogram using the provided identifier, documentation, and either optional keyword arguments or a block that returns the keyword arguments.
-
#id_for(identifier) ⇒ Object
Internal: validates whether to concatenate the given identifier with a pre-existing susbsystem name.
-
#push(job) ⇒ Object
push the current registry state to a Pushgateway.
-
#push_periodically(job, frequency = 10) ⇒ Object
Periodically invokes #push in a given frequency.
-
#subsystem(prefix, inherit_presets: false, **presets) ⇒ Object
Provides a way to compose metrics for different subsystems.
-
#summary(identifier, docs = "...") ⇒ Object
def do_a_call Metrics.call_duration.observe(Benchmark.realtime { < … > }) end end.
-
#with_presets(**labels) ⇒ Object
Allows instruments to be declared with preset labels.
Instance Method Details
#block_opts(**opts) ⇒ Object
Internal: Validates the provided options to create a given instrument and performs the merge of all options with presets when they are present.
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/emrb/instruments/instruments.rb', line 285 def block_opts(**opts, &) res = block_given? ? yield : opts return res if @presets.nil? res[:labels] = [] if res[:labels].nil? res[:labels].append(*@presets.keys) if res[:preset_labels].nil? res[:preset_labels] = @presets return res end res[:preset_labels].merge!(**@presets) res end |
#check_identifier!(id) ⇒ Object
Internal: Validates whether the given identifier might override one of the class methods. In a positive case, raises CollidingNameError.
303 304 305 |
# File 'lib/emrb/instruments/instruments.rb', line 303 def check_identifier!(id) raise Instruments::CollidingNameError, id if FORBIDDEN_IDENTIFIERS.include? id end |
#counter(identifier, docs = "...") ⇒ Object
Initializes a new Prometheus counter using the provided identifier, documentation, and either optional keyword arguments or a block that returns the keyword arguments. The block takes precedence when supplied.
identifier - The counter identifier. docs - The instrument docstring. Defaults to “…”
Usage example:
class MyApp
class Metrics
include Emrb::Instruments
counter :visits, "Number of visits the app has received"
end
def handle_visits
Metrics.visits.inc
...
end
end
For a complete list of options and functionalities for creating and utilizing a Counter, refer to the Prometheus client documentation: github.com/prometheus/client_ruby?tab=readme-ov-file#counter
41 42 43 44 45 46 47 |
# File 'lib/emrb/instruments/instruments.rb', line 41 def counter(identifier, docs = "...", **, &) check_identifier!(identifier) opts = block_opts(**, &) State.counter(id_for(identifier), docs, **opts).tap do |c| define_singleton_method(identifier) { c } end end |
#gauge(identifier, docs = "...") ⇒ Object
Initializes a new Prometheus gauge using the provided identifier, documentation, and either optional keyword arguments or a block that returns the keyword arguments. The block takes precedence when supplied.
identifier - The counter identifier. docs - The instrument docstring. Defaults to “…”
Usage example:
class Thermometer
class Metrics
include Emrb::Instruments
gauge :current_temperature, "current temperature"
end
def set_current_temp
temp = < ... >
Metrics.current_temperature.set(temp)
end
end
For a full list of options and functionalities for creating and utilizing a Gauge, refer to the Prometheus client documentation: github.com/prometheus/client_ruby?tab=readme-ov-file#gauge
73 74 75 76 77 78 79 |
# File 'lib/emrb/instruments/instruments.rb', line 73 def gauge(identifier, docs = "...", **, &) check_identifier!(identifier) opts = block_opts(**, &) State.gauge(id_for(identifier), docs, **opts).tap do |g| define_singleton_method(identifier) { g } end end |
#histogram(identifier, docs = "...") ⇒ Object
Initializes a new Prometheus histogram using the provided identifier, documentation, and either optional keyword arguments or a block that returns the keyword arguments. The block takes precedence when supplied.
identifier - The counter identifier. docs - The instrument docstring. Defaults to “…”
Usage example:
class MyApp
class Metrics
include Emrb::Instruments
histogram :request_duration, "Duration of requests" do
{ labels: [:path, :method], buckets: [0.1, 0.2] }
end
end
def measure_request_duration
labels = { path: request.path, method: request.env["REQUEST_METHOD"].downcase } #
Metrics.request_duration.observe(Benchmark.realtime { yield }, labels: )
end
get "/" do
measure_request_duration { [200, "OK"] }
end
end
For all available options and functionalities for creating and utilizing a Histogram, refer to the Prometheus client documentation: github.com/prometheus/client_ruby?tab=readme-ov-file#histogram
111 112 113 114 115 116 117 |
# File 'lib/emrb/instruments/instruments.rb', line 111 def histogram(identifier, docs = "...", **, &) check_identifier!(identifier) opts = block_opts(**, &) State.histogram(id_for(identifier), docs, **opts).tap do |h| define_singleton_method(identifier) { h } end end |
#id_for(identifier) ⇒ Object
Internal: validates whether to concatenate the given identifier with a pre-existing susbsystem name.
277 278 279 280 281 |
# File 'lib/emrb/instruments/instruments.rb', line 277 def id_for(identifier) return identifier unless @subsystem :"#{@subsystem}_#{identifier}" end |
#push(job) ⇒ Object
push the current registry state to a Pushgateway. It receives an obligatory job identifier, and optionally all supported keyword arguments of a Prometheus::Client::Push.
job - Job identifier
Usage example:
class MyJob
class Metrics
include Emrb::Instruments
counter :processed_tasks
end
def do_the_things
begin
tasks.each do |t|
< ... >
Metrics.processed_tasks.inc
end
rescue
< ... >
ensure
Metrics.push("job_name")
end
end
end
177 |
# File 'lib/emrb/instruments/instruments.rb', line 177 def push(job, **) = State.push(job, **) |
#push_periodically(job, frequency = 10) ⇒ Object
Periodically invokes #push in a given frequency.
job - Job identifier frequency - Frequency, in seconds, in which #push will be called.
Returns nothing.
185 186 187 188 189 190 |
# File 'lib/emrb/instruments/instruments.rb', line 185 def push_periodically(job, frequency = 10, **) Thread.new do sleep(frequency) push(job, **) end end |
#subsystem(prefix, inherit_presets: false, **presets) ⇒ Object
Provides a way to compose metrics for different subsystems. All instruments created within a subsystem will have their identifiers prefixed with the prefix param.
prefix - determines the prefix of all instruments declared
within the subsystem and how to access those instruments
within the implementation.
inherit_presets - determines whether or not to inherit presets from
the parent. Defaults to false.
presets - preset of labels to be used by all Instruments
of a given subsystem.
Usage example:
class Metrics
subsystem :http do
histogram :request_duration, "duration of requests" do
{ labels: [:method, :path] }
end
end
subsystem :postgres do
subsystem :master, op: "write" do
counter :op_count
end
subsystem :replica, op: "read" do
counter :op_count
end
end
end
# Acessing instruments: Metrics.http.request_duration Metrics.postgres.master.op_count Metrics.postgres.replica.op_count rubocop:disable Metrics/MethodLength
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/emrb/instruments/instruments.rb', line 257 def subsystem(prefix, inherit_presets: false, **presets, &) raise LocalJumpError, "no block given" unless block_given? s_prefix = prefix.to_s s_prefix.delete_suffix! "_" if s_prefix.end_with? "_" subsystem = id_for(s_prefix.to_sym) presets.merge! @presets if inherit_presets && !@presets.nil? s = Class.new s.include(Instruments) s.instance_variable_set(:@subsystem, subsystem) s.instance_variable_set(:@presets, presets) s.instance_eval(&) define_singleton_method(prefix) { s } end |
#summary(identifier, docs = "...") ⇒ Object
def do_a_call
Metrics.call_duration.observe(Benchmark.realtime { < ... > })
end
end
For a complete list of options and functionalities for creating and utilizing a Summary, refer to the Prometheus client documentation: github.com/prometheus/client_ruby?tab=readme-ov-file#summary
142 143 144 145 146 147 148 |
# File 'lib/emrb/instruments/instruments.rb', line 142 def summary(identifier, docs = "...", **, &) check_identifier!(identifier) opts = block_opts(**, &) State.summary(id_for(identifier), docs, **opts).tap do |s| define_singleton_method(identifier) { s } end end |
#with_presets(**labels) ⇒ Object
Allows instruments to be declared with preset labels.
labels - A hash containing the preset labels and values
Usage example:
class Metrics
include Emrb::Instruments
with_presets my: "label", other: "label" do
counter :my_counter, "a counter"
end
end
Metrics.my_counter.labels => [:my, :other] Metrics.my_counter.preset_labels => { my: “label”, other: “label” }
207 208 209 210 211 212 213 214 215 216 |
# File 'lib/emrb/instruments/instruments.rb', line 207 def with_presets(**labels, &) raise LocalJumpError, "no block given" unless block_given? raise ArgumentError, "labels are empty" if labels.nil? || labels.empty? old = (@presets ||= {}) current = old.merge labels @presets = current instance_eval(&) @presets = old end |