diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b449fc7..1752f8a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['3.1', '3.2', '3.3'] + ruby: ["3.1", "3.2", "3.3"] activerecord: [61, 70, 71] steps: @@ -42,6 +42,9 @@ jobs: - name: Rubocop run: bundle exec rubocop + - name: Syntax tree + run: bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake') $(git ls-files '*.thor') + - name: Run tests run: bundle exec rake diff --git a/.streerc b/.streerc new file mode 100644 index 00000000..cc0be494 --- /dev/null +++ b/.streerc @@ -0,0 +1,2 @@ +--print-width=100 +--plugins=plugin/trailing_comma,disable_ternary diff --git a/bench/bench.rb b/bench/bench.rb index 7f9e9cdb..26a9fbe5 100644 --- a/bench/bench.rb +++ b/bench/bench.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative '../lib/prometheus_exporter' -require_relative '../lib/prometheus_exporter/client' -require_relative '../lib/prometheus_exporter/server' +require_relative "../lib/prometheus_exporter" +require_relative "../lib/prometheus_exporter/client" +require_relative "../lib/prometheus_exporter/server" # test how long it takes a custom collector to process 10k messages @@ -26,18 +26,19 @@ def prometheus_metrics_text @client = nil @runs = 1000 -done = lambda do - puts "Elapsed for 10k messages is #{Time.now - @start}" - if (@runs -= 1) > 0 - @start = Time.now - 10_000.times { @client.send_json(hello: "world") } +done = + lambda do + puts "Elapsed for 10k messages is #{Time.now - @start}" + if (@runs -= 1) > 0 + @start = Time.now + 10_000.times { @client.send_json(hello: "world") } + end end -end collector = Collector.new(done) -server = PrometheusExporter::Server::WebServer.new port: 12349, collector: collector +server = PrometheusExporter::Server::WebServer.new port: 12_349, collector: collector server.start -@client = PrometheusExporter::Client.new port: 12349, max_queue_size: 100_000 +@client = PrometheusExporter::Client.new port: 12_349, max_queue_size: 100_000 @start = Time.now 10_000.times { @client.send_json(hello: "world") } diff --git a/examples/custom_collector.rb b/examples/custom_collector.rb index 21191bef..cd897d39 100644 --- a/examples/custom_collector.rb +++ b/examples/custom_collector.rb @@ -20,8 +20,6 @@ def process(obj) end def prometheus_metrics_text - @mutex.synchronize do - "#{@gauge1.to_prometheus_text}\n#{@gauge2.to_prometheus_text}" - end + @mutex.synchronize { "#{@gauge1.to_prometheus_text}\n#{@gauge2.to_prometheus_text}" } end end diff --git a/lib/prometheus_exporter/client.rb b/lib/prometheus_exporter/client.rb index 2302bd4c..f9e0cbf9 100644 --- a/lib/prometheus_exporter/client.rb +++ b/lib/prometheus_exporter/client.rb @@ -17,13 +17,7 @@ def initialize(name:, help:, type:, client:, opts: nil) end def standard_values(value, keys, prometheus_exporter_action = nil) - values = { - type: @type, - help: @help, - name: @name, - keys: keys, - value: value - } + values = { type: @type, help: @help, name: @name, keys: keys, value: value } values[ :prometheus_exporter_action ] = prometheus_exporter_action if prometheus_exporter_action @@ -59,10 +53,7 @@ def self.default=(client) def initialize( host: ENV.fetch("PROMETHEUS_EXPORTER_HOST", "localhost"), - port: ENV.fetch( - "PROMETHEUS_EXPORTER_PORT", - PrometheusExporter::DEFAULT_PORT - ), + port: ENV.fetch("PROMETHEUS_EXPORTER_PORT", PrometheusExporter::DEFAULT_PORT), max_queue_size: nil, thread_sleep: 0.5, json_serializer: nil, @@ -83,9 +74,7 @@ def initialize( max_queue_size ||= MAX_QUEUE_SIZE max_queue_size = max_queue_size.to_i - if max_queue_size <= 0 - raise ArgumentError, "max_queue_size must be larger than 0" - end + raise ArgumentError, "max_queue_size must be larger than 0" if max_queue_size <= 0 @max_queue_size = max_queue_size @host = host @@ -94,8 +83,7 @@ def initialize( @mutex = Mutex.new @thread_sleep = thread_sleep - @json_serializer = - json_serializer == :oj ? PrometheusExporter::OjCompat : JSON + @json_serializer = json_serializer == :oj ? PrometheusExporter::OjCompat : JSON @custom_labels = custom_labels end @@ -105,14 +93,7 @@ def custom_labels=(custom_labels) end def register(type, name, help, opts = nil) - metric = - RemoteMetric.new( - type: type, - name: name, - help: help, - client: self, - opts: opts - ) + metric = RemoteMetric.new(type: type, name: name, help: help, client: self, opts: opts) @metrics << metric metric end @@ -262,10 +243,7 @@ def ensure_socket! def wait_for_empty_queue_with_timeout(timeout_seconds) start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) while @queue.length > 0 - if start_time + timeout_seconds < - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - break - end + break if start_time + timeout_seconds < ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) sleep(0.05) end end diff --git a/lib/prometheus_exporter/instrumentation/active_record.rb b/lib/prometheus_exporter/instrumentation/active_record.rb index 8e474a12..4f363833 100644 --- a/lib/prometheus_exporter/instrumentation/active_record.rb +++ b/lib/prometheus_exporter/instrumentation/active_record.rb @@ -3,14 +3,16 @@ # collects stats from currently running process module PrometheusExporter::Instrumentation class ActiveRecord < PeriodicStats - ALLOWED_CONFIG_LABELS = %i(database username host port) + ALLOWED_CONFIG_LABELS = %i[database username host port] def self.start(client: nil, frequency: 30, custom_labels: {}, config_labels: []) client ||= PrometheusExporter::Client.default # Not all rails versions support connection pool stats unless ::ActiveRecord::Base.connection_pool.respond_to?(:stat) - client.logger.error("ActiveRecord connection pool stats not supported in your rails version") + client.logger.error( + "ActiveRecord connection pool stats not supported in your rails version", + ) return end @@ -29,7 +31,9 @@ def self.start(client: nil, frequency: 30, custom_labels: {}, config_labels: []) def self.validate_config_labels(config_labels) return if config_labels.size == 0 - raise "Invalid Config Labels, available options #{ALLOWED_CONFIG_LABELS}" if (config_labels - ALLOWED_CONFIG_LABELS).size > 0 + if (config_labels - ALLOWED_CONFIG_LABELS).size > 0 + raise "Invalid Config Labels, available options #{ALLOWED_CONFIG_LABELS}" + end end def initialize(metric_labels, config_labels) @@ -55,7 +59,7 @@ def collect_active_record_pool_stats(metrics) pid: pid, type: "active_record", hostname: ::PrometheusExporter.hostname, - metric_labels: labels(pool) + metric_labels: labels(pool), } metric.merge!(pool.stat) metrics << metric @@ -66,12 +70,20 @@ def collect_active_record_pool_stats(metrics) def labels(pool) if ::ActiveRecord.version < Gem::Version.new("6.1.0.rc1") - @metric_labels.merge(pool_name: pool.spec.name).merge(pool.spec.config - .select { |k, v| @config_labels.include? k } - .map { |k, v| [k.to_s.dup.prepend("dbconfig_"), v] }.to_h) + @metric_labels.merge(pool_name: pool.spec.name).merge( + pool + .spec + .config + .select { |k, v| @config_labels.include? k } + .map { |k, v| [k.to_s.dup.prepend("dbconfig_"), v] } + .to_h, + ) else @metric_labels.merge(pool_name: pool.db_config.name).merge( - @config_labels.each_with_object({}) { |l, acc| acc["dbconfig_#{l}"] = pool.db_config.public_send(l) }) + @config_labels.each_with_object({}) do |l, acc| + acc["dbconfig_#{l}"] = pool.db_config.public_send(l) + end, + ) end end end diff --git a/lib/prometheus_exporter/instrumentation/delayed_job.rb b/lib/prometheus_exporter/instrumentation/delayed_job.rb index 254fb0db..9978affa 100644 --- a/lib/prometheus_exporter/instrumentation/delayed_job.rb +++ b/lib/prometheus_exporter/instrumentation/delayed_job.rb @@ -2,24 +2,33 @@ module PrometheusExporter::Instrumentation class DelayedJob - JOB_CLASS_REGEXP = %r{job_class: ((\w+:{0,2})+)}.freeze + JOB_CLASS_REGEXP = /job_class: ((\w+:{0,2})+)/.freeze class << self def register_plugin(client: nil, include_module_name: false) instrumenter = self.new(client: client) return unless defined?(Delayed::Plugin) - plugin = Class.new(Delayed::Plugin) do - callbacks do |lifecycle| - lifecycle.around(:invoke_job) do |job, *args, &block| - max_attempts = Delayed::Worker.max_attempts - enqueued_count = Delayed::Job.where(queue: job.queue).count - pending_count = Delayed::Job.where(attempts: 0, locked_at: nil, queue: job.queue).count - instrumenter.call(job, max_attempts, enqueued_count, pending_count, include_module_name, - *args, &block) + plugin = + Class.new(Delayed::Plugin) do + callbacks do |lifecycle| + lifecycle.around(:invoke_job) do |job, *args, &block| + max_attempts = Delayed::Worker.max_attempts + enqueued_count = Delayed::Job.where(queue: job.queue).count + pending_count = + Delayed::Job.where(attempts: 0, locked_at: nil, queue: job.queue).count + instrumenter.call( + job, + max_attempts, + enqueued_count, + pending_count, + include_module_name, + *args, + &block + ) + end end end - end Delayed::Worker.plugins << plugin end @@ -50,7 +59,7 @@ def call(job, max_attempts, enqueued_count, pending_count, include_module_name, attempts: attempts, max_attempts: max_attempts, enqueued: enqueued_count, - pending: pending_count + pending: pending_count, ) end end diff --git a/lib/prometheus_exporter/instrumentation/good_job.rb b/lib/prometheus_exporter/instrumentation/good_job.rb index 03881d0c..6342c340 100644 --- a/lib/prometheus_exporter/instrumentation/good_job.rb +++ b/lib/prometheus_exporter/instrumentation/good_job.rb @@ -7,9 +7,7 @@ def self.start(client: nil, frequency: 30) good_job_collector = new client ||= PrometheusExporter::Client.default - worker_loop do - client.send_json(good_job_collector.collect) - end + worker_loop { client.send_json(good_job_collector.collect) } super end @@ -23,7 +21,7 @@ def collect running: ::GoodJob::Job.running.size, finished: ::GoodJob::Job.finished.size, succeeded: ::GoodJob::Job.succeeded.size, - discarded: ::GoodJob::Job.discarded.size + discarded: ::GoodJob::Job.discarded.size, } end end diff --git a/lib/prometheus_exporter/instrumentation/hutch.rb b/lib/prometheus_exporter/instrumentation/hutch.rb index 8f8240fb..8287f477 100644 --- a/lib/prometheus_exporter/instrumentation/hutch.rb +++ b/lib/prometheus_exporter/instrumentation/hutch.rb @@ -19,7 +19,7 @@ def handle(message) type: "hutch", name: @klass.class.to_s, success: success, - duration: duration + duration: duration, ) end end diff --git a/lib/prometheus_exporter/instrumentation/method_profiler.rb b/lib/prometheus_exporter/instrumentation/method_profiler.rb index 045a77f9..5270bc0c 100644 --- a/lib/prometheus_exporter/instrumentation/method_profiler.rb +++ b/lib/prometheus_exporter/instrumentation/method_profiler.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true # see https://samsaffron.com/archive/2017/10/18/fastest-way-to-profile-a-method-in-ruby -module PrometheusExporter::Instrumentation; end +module PrometheusExporter::Instrumentation +end class PrometheusExporter::Instrumentation::MethodProfiler def self.patch(klass, methods, name, instrument:) @@ -21,9 +22,8 @@ def self.transfer end def self.start(transfer = nil) - Thread.current[:_method_profiler] = transfer || { - __start: Process.clock_gettime(Process::CLOCK_MONOTONIC) - } + Thread.current[:_method_profiler] = transfer || + { __start: Process.clock_gettime(Process::CLOCK_MONOTONIC) } end def self.clear @@ -42,8 +42,8 @@ def self.stop def self.define_methods_on_module(klass, methods, name) patch_source_line = __LINE__ + 3 - patches = methods.map do |method_name| - <<~RUBY + + patches = methods.map { |method_name| <<~RUBY }.join("\n") def #{method_name}(...) unless prof = Thread.current[:_method_profiler] return super @@ -58,9 +58,8 @@ def #{method_name}(...) end end RUBY - end.join("\n") - klass.module_eval patches, __FILE__, patch_source_line + klass.module_eval(patches, __FILE__, patch_source_line) end def self.patch_using_prepend(klass, methods, name) @@ -71,14 +70,16 @@ def self.patch_using_prepend(klass, methods, name) def self.patch_using_alias_method(klass, methods, name) patch_source_line = __LINE__ + 3 - patches = methods.map do |method_name| - <<~RUBY + + patches = methods.map { |method_name| <<~RUBY }.join("\n") unless defined?(#{method_name}__mp_unpatched) alias_method :#{method_name}__mp_unpatched, :#{method_name} + def #{method_name}(...) unless prof = Thread.current[:_method_profiler] return #{method_name}__mp_unpatched(...) end + begin start = Process.clock_gettime(Process::CLOCK_MONOTONIC) #{method_name}__mp_unpatched(...) @@ -90,8 +91,7 @@ def #{method_name}(...) end end RUBY - end.join("\n") - klass.class_eval patches, __FILE__, patch_source_line + klass.class_eval(patches, __FILE__, patch_source_line) end end diff --git a/lib/prometheus_exporter/instrumentation/periodic_stats.rb b/lib/prometheus_exporter/instrumentation/periodic_stats.rb index 44893308..4b9dade9 100644 --- a/lib/prometheus_exporter/instrumentation/periodic_stats.rb +++ b/lib/prometheus_exporter/instrumentation/periodic_stats.rb @@ -2,21 +2,14 @@ module PrometheusExporter::Instrumentation class PeriodicStats - def self.start(*args, frequency:, client: nil, **kwargs) client ||= PrometheusExporter::Client.default - if !(Numeric === frequency) - raise ArgumentError.new("Expected frequency to be a number") - end + raise ArgumentError.new("Expected frequency to be a number") if !(Numeric === frequency) - if frequency < 0 - raise ArgumentError.new("Expected frequency to be a positive number") - end + raise ArgumentError.new("Expected frequency to be a positive number") if frequency < 0 - if !@worker_loop - raise ArgumentError.new("Worker loop was not set") - end + raise ArgumentError.new("Worker loop was not set") if !@worker_loop klass = self @@ -24,18 +17,18 @@ def self.start(*args, frequency:, client: nil, **kwargs) @stop_thread = false - @thread = Thread.new do - while !@stop_thread - begin - @worker_loop.call - rescue => e - client.logger.error("#{klass} Prometheus Exporter Failed To Collect Stats #{e}") - ensure - sleep frequency + @thread = + Thread.new do + while !@stop_thread + begin + @worker_loop.call + rescue => e + client.logger.error("#{klass} Prometheus Exporter Failed To Collect Stats #{e}") + ensure + sleep frequency + end end end - end - end def self.started? @@ -57,6 +50,5 @@ def self.stop end @thread = nil end - end end diff --git a/lib/prometheus_exporter/instrumentation/process.rb b/lib/prometheus_exporter/instrumentation/process.rb index 69624488..3129dde9 100644 --- a/lib/prometheus_exporter/instrumentation/process.rb +++ b/lib/prometheus_exporter/instrumentation/process.rb @@ -3,9 +3,7 @@ # collects stats from currently running process module PrometheusExporter::Instrumentation class Process < PeriodicStats - def self.start(client: nil, type: "ruby", frequency: 30, labels: nil) - metric_labels = if labels && type labels.merge(type: type) @@ -46,14 +44,22 @@ def pid end def rss - @pagesize ||= `getconf PAGESIZE`.to_i rescue 4096 - File.read("/proc/#{pid}/statm").split(' ')[1].to_i * @pagesize rescue 0 + @pagesize ||= + begin + `getconf PAGESIZE`.to_i + rescue StandardError + 4096 + end + begin + File.read("/proc/#{pid}/statm").split(" ")[1].to_i * @pagesize + rescue StandardError + 0 + end end def collect_process_stats(metric) metric[:pid] = pid metric[:rss] = rss - end def collect_gc_stats(metric) @@ -68,7 +74,7 @@ def collect_gc_stats(metric) end def collect_v8_stats(metric) - return if !defined? MiniRacer + return if !defined?(MiniRacer) metric[:v8_heap_count] = metric[:v8_heap_size] = 0 metric[:v8_heap_size] = metric[:v8_physical_size] = 0 diff --git a/lib/prometheus_exporter/instrumentation/puma.rb b/lib/prometheus_exporter/instrumentation/puma.rb index a5c931dc..c03b4ea8 100644 --- a/lib/prometheus_exporter/instrumentation/puma.rb +++ b/lib/prometheus_exporter/instrumentation/puma.rb @@ -26,7 +26,7 @@ def collect pid: pid, type: "puma", hostname: ::PrometheusExporter.hostname, - metric_labels: @metric_labels + metric_labels: @metric_labels, } collect_puma_stats(metric) metric diff --git a/lib/prometheus_exporter/instrumentation/resque.rb b/lib/prometheus_exporter/instrumentation/resque.rb index d0c158b6..38bf4893 100644 --- a/lib/prometheus_exporter/instrumentation/resque.rb +++ b/lib/prometheus_exporter/instrumentation/resque.rb @@ -7,9 +7,7 @@ def self.start(client: nil, frequency: 30) resque_collector = new client ||= PrometheusExporter::Client.default - worker_loop do - client.send_json(resque_collector.collect) - end + worker_loop { client.send_json(resque_collector.collect) } super end diff --git a/lib/prometheus_exporter/instrumentation/shoryuken.rb b/lib/prometheus_exporter/instrumentation/shoryuken.rb index 40d9e809..c9d433e3 100644 --- a/lib/prometheus_exporter/instrumentation/shoryuken.rb +++ b/lib/prometheus_exporter/instrumentation/shoryuken.rb @@ -2,7 +2,6 @@ module PrometheusExporter::Instrumentation class Shoryuken - def initialize(client: nil) @client = client || PrometheusExporter::Client.default end @@ -19,12 +18,12 @@ def call(worker, queue, msg, body) ensure duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start @client.send_json( - type: "shoryuken", - queue: queue, - name: worker.class.name, - success: success, - shutdown: shutdown, - duration: duration + type: "shoryuken", + queue: queue, + name: worker.class.name, + success: success, + shutdown: shutdown, + duration: duration, ) end end diff --git a/lib/prometheus_exporter/instrumentation/sidekiq.rb b/lib/prometheus_exporter/instrumentation/sidekiq.rb index e00c3266..ef4ff487 100644 --- a/lib/prometheus_exporter/instrumentation/sidekiq.rb +++ b/lib/prometheus_exporter/instrumentation/sidekiq.rb @@ -3,8 +3,7 @@ require "yaml" module PrometheusExporter::Instrumentation - JOB_WRAPPER_CLASS_NAME = - "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper" + JOB_WRAPPER_CLASS_NAME = "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper" DELAYED_CLASS_NAMES = %w[ Sidekiq::Extensions::DelayedClass Sidekiq::Extensions::DelayedModel @@ -24,7 +23,7 @@ def self.death_handler type: "sidekiq", name: get_name(job["class"], job), dead: true, - custom_labels: worker_custom_labels + custom_labels: worker_custom_labels, ) end end @@ -44,8 +43,7 @@ def self.get_worker_custom_labels(worker_class, msg) end def initialize(options = { client: nil }) - @client = - options.fetch(:client, nil) || PrometheusExporter::Client.default + @client = options.fetch(:client, nil) || PrometheusExporter::Client.default end def call(worker, msg, queue) @@ -67,7 +65,7 @@ def call(worker, msg, queue) success: success, shutdown: shutdown, duration: duration, - custom_labels: self.class.get_worker_custom_labels(worker.class, msg) + custom_labels: self.class.get_worker_custom_labels(worker.class, msg), ) end diff --git a/lib/prometheus_exporter/instrumentation/sidekiq_process.rb b/lib/prometheus_exporter/instrumentation/sidekiq_process.rb index bb96934e..b56af4cd 100644 --- a/lib/prometheus_exporter/instrumentation/sidekiq_process.rb +++ b/lib/prometheus_exporter/instrumentation/sidekiq_process.rb @@ -6,9 +6,7 @@ def self.start(client: nil, frequency: 30) client ||= PrometheusExporter::Client.default sidekiq_process_collector = new - worker_loop do - client.send_json(sidekiq_process_collector.collect) - end + worker_loop { client.send_json(sidekiq_process_collector.collect) } super end @@ -19,10 +17,7 @@ def initialize end def collect - { - type: 'sidekiq_process', - process: collect_stats - } + { type: "sidekiq_process", process: collect_stats } end def collect_stats @@ -30,23 +25,21 @@ def collect_stats return {} unless process { - busy: process['busy'], - concurrency: process['concurrency'], + busy: process["busy"], + concurrency: process["concurrency"], labels: { - labels: process['labels'].sort.join(','), - queues: process['queues'].sort.join(','), - quiet: process['quiet'], - tag: process['tag'], - hostname: process['hostname'], - identity: process['identity'], - } + labels: process["labels"].sort.join(","), + queues: process["queues"].sort.join(","), + quiet: process["quiet"], + tag: process["tag"], + hostname: process["hostname"], + identity: process["identity"], + }, } end def current_process - ::Sidekiq::ProcessSet.new.find do |sp| - sp['hostname'] == @hostname && sp['pid'] == @pid - end + ::Sidekiq::ProcessSet.new.find { |sp| sp["hostname"] == @hostname && sp["pid"] == @pid } end end end diff --git a/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb b/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb index 9f2b0608..046f828a 100644 --- a/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb +++ b/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb @@ -6,9 +6,7 @@ def self.start(client: nil, frequency: 30, all_queues: false) client ||= PrometheusExporter::Client.default sidekiq_queue_collector = new(all_queues: all_queues) - worker_loop do - client.send_json(sidekiq_queue_collector.collect) - end + worker_loop { client.send_json(sidekiq_queue_collector.collect) } super end @@ -20,10 +18,7 @@ def initialize(all_queues: false) end def collect - { - type: 'sidekiq_queue', - queues: collect_queue_stats - } + { type: "sidekiq_queue", queues: collect_queue_stats } end def collect_queue_stats @@ -34,13 +29,17 @@ def collect_queue_stats sidekiq_queues.select! { |sidekiq_queue| queues.include?(sidekiq_queue.name) } end - sidekiq_queues.map do |queue| - { - backlog: queue.size, - latency_seconds: queue.latency.to_i, - labels: { queue: queue.name } - } - end.compact + sidekiq_queues + .map do |queue| + { + backlog: queue.size, + latency_seconds: queue.latency.to_i, + labels: { + queue: queue.name, + }, + } + end + .compact end private @@ -48,11 +47,9 @@ def collect_queue_stats def collect_current_process_queues ps = ::Sidekiq::ProcessSet.new - process = ps.find do |sp| - sp['hostname'] == @hostname && sp['pid'] == @pid - end + process = ps.find { |sp| sp["hostname"] == @hostname && sp["pid"] == @pid } - process.nil? ? [] : process['queues'] + process.nil? ? [] : process["queues"] end end end diff --git a/lib/prometheus_exporter/instrumentation/sidekiq_stats.rb b/lib/prometheus_exporter/instrumentation/sidekiq_stats.rb index 5e30b825..33501961 100644 --- a/lib/prometheus_exporter/instrumentation/sidekiq_stats.rb +++ b/lib/prometheus_exporter/instrumentation/sidekiq_stats.rb @@ -6,31 +6,26 @@ def self.start(client: nil, frequency: 30) client ||= PrometheusExporter::Client.default sidekiq_stats_collector = new - worker_loop do - client.send_json(sidekiq_stats_collector.collect) - end + worker_loop { client.send_json(sidekiq_stats_collector.collect) } super end def collect - { - type: 'sidekiq_stats', - stats: collect_stats - } + { type: "sidekiq_stats", stats: collect_stats } end def collect_stats stats = ::Sidekiq::Stats.new { - 'dead_size' => stats.dead_size, - 'enqueued' => stats.enqueued, - 'failed' => stats.failed, - 'processed' => stats.processed, - 'processes_size' => stats.processes_size, - 'retry_size' => stats.retry_size, - 'scheduled_size' => stats.scheduled_size, - 'workers_size' => stats.workers_size, + "dead_size" => stats.dead_size, + "enqueued" => stats.enqueued, + "failed" => stats.failed, + "processed" => stats.processed, + "processes_size" => stats.processes_size, + "retry_size" => stats.retry_size, + "scheduled_size" => stats.scheduled_size, + "workers_size" => stats.workers_size, } end end diff --git a/lib/prometheus_exporter/instrumentation/unicorn.rb b/lib/prometheus_exporter/instrumentation/unicorn.rb index eb9cd4e0..49e1276c 100644 --- a/lib/prometheus_exporter/instrumentation/unicorn.rb +++ b/lib/prometheus_exporter/instrumentation/unicorn.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true begin - require 'raindrops' + require "raindrops" rescue LoadError # No raindrops available, dont do anything end @@ -29,7 +29,7 @@ def initialize(pid_file:, listener_address:) def collect metric = {} - metric[:type] = 'unicorn' + metric[:type] = "unicorn" collect_unicorn_stats(metric) metric end diff --git a/lib/prometheus_exporter/metric/base.rb b/lib/prometheus_exporter/metric/base.rb index d47ea375..76fecb4a 100644 --- a/lib/prometheus_exporter/metric/base.rb +++ b/lib/prometheus_exporter/metric/base.rb @@ -2,7 +2,6 @@ module PrometheusExporter::Metric class Base - @default_prefix = nil if !defined?(@default_prefix) @default_labels = nil if !defined?(@default_labels) @default_aggregation = nil if !defined?(@default_aggregation) @@ -77,11 +76,14 @@ def prefix(name) def labels_text(labels) labels = Base.default_labels.merge(labels || {}) if labels && labels.length > 0 - s = labels.map do |key, value| - value = value.to_s - value = escape_value(value) if needs_escape?(value) - "#{key}=\"#{value}\"" - end.join(",") + s = + labels + .map do |key, value| + value = value.to_s + value = escape_value(value) if needs_escape?(value) + "#{key}=\"#{value}\"" + end + .join(",") "{#{s}}" end end @@ -109,6 +111,5 @@ def escape_value(str) def needs_escape?(str) str.match?(/[\n"\\]/m) end - end end diff --git a/lib/prometheus_exporter/metric/counter.rb b/lib/prometheus_exporter/metric/counter.rb index 68efcc0c..4b30a61b 100644 --- a/lib/prometheus_exporter/metric/counter.rb +++ b/lib/prometheus_exporter/metric/counter.rb @@ -18,9 +18,7 @@ def reset! end def metric_text - @data.map do |labels, value| - "#{prefix(@name)}#{labels_text(labels)} #{value}" - end.join("\n") + @data.map { |labels, value| "#{prefix(@name)}#{labels_text(labels)} #{value}" }.join("\n") end def to_h diff --git a/lib/prometheus_exporter/metric/gauge.rb b/lib/prometheus_exporter/metric/gauge.rb index 91d999f1..15aacd0f 100644 --- a/lib/prometheus_exporter/metric/gauge.rb +++ b/lib/prometheus_exporter/metric/gauge.rb @@ -18,9 +18,7 @@ def type end def metric_text - @data.map do |labels, value| - "#{prefix(@name)}#{labels_text(labels)} #{value}" - end.join("\n") + @data.map { |labels, value| "#{prefix(@name)}#{labels_text(labels)} #{value}" }.join("\n") end def reset! @@ -39,9 +37,7 @@ def observe(value, labels = {}) if value.nil? data.delete(labels) else - if !(Numeric === value) - raise ArgumentError, 'value must be a number' - end + raise ArgumentError, "value must be a number" if !(Numeric === value) @data[labels] = value end end diff --git a/lib/prometheus_exporter/metric/histogram.rb b/lib/prometheus_exporter/metric/histogram.rb index 7d72b781..79f5a2c9 100644 --- a/lib/prometheus_exporter/metric/histogram.rb +++ b/lib/prometheus_exporter/metric/histogram.rb @@ -2,7 +2,6 @@ module PrometheusExporter::Metric class Histogram < Base - DEFAULT_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5.0, 10.0].freeze @default_buckets = nil if !defined?(@default_buckets) @@ -100,6 +99,5 @@ def fill_buckets(value, buckets) def with_bucket(labels, bucket) labels.merge("le" => bucket) end - end end diff --git a/lib/prometheus_exporter/metric/summary.rb b/lib/prometheus_exporter/metric/summary.rb index 180087ba..e4ad3048 100644 --- a/lib/prometheus_exporter/metric/summary.rb +++ b/lib/prometheus_exporter/metric/summary.rb @@ -2,7 +2,6 @@ module PrometheusExporter::Metric class Summary < Base - DEFAULT_QUANTILES = [0.99, 0.9, 0.5, 0.1, 0.01] ROTATE_AGE = 120 @@ -49,9 +48,7 @@ def calculate_quantiles(raw_data) result = {} if length > 0 - @quantiles.each do |quantile| - result[quantile] = sorted[(length * quantile).ceil - 1] - end + @quantiles.each { |quantile| result[quantile] = sorted[(length * quantile).ceil - 1] } end result @@ -61,12 +58,9 @@ def calculate_all_quantiles buffer = @buffers[@current_buffer] result = {} - buffer.each do |labels, raw_data| - result[labels] = calculate_quantiles(raw_data) - end + buffer.each { |labels, raw_data| result[labels] = calculate_quantiles(raw_data) } result - end def metric_text @@ -87,8 +81,8 @@ def metric_text # makes sure we have storage def ensure_summary(labels) - @buffers[0][labels] ||= [] - @buffers[1][labels] ||= [] + @buffers[0][labels] ||= [] + @buffers[1][labels] ||= [] @sums[labels] ||= 0.0 @counts[labels] ||= 0 nil @@ -97,9 +91,7 @@ def ensure_summary(labels) def rotate_if_needed if (now = Process.clock_gettime(Process::CLOCK_MONOTONIC)) > (@last_rotated + ROTATE_AGE) @last_rotated = now - @buffers[@current_buffer].each do |labels, raw| - raw.clear - end + @buffers[@current_buffer].each { |labels, raw| raw.clear } @current_buffer = @current_buffer == 0 ? 1 : 0 end nil @@ -116,6 +108,5 @@ def observe(value, labels = nil) @sums[labels] += value @counts[labels] += 1 end - end end diff --git a/lib/prometheus_exporter/middleware.rb b/lib/prometheus_exporter/middleware.rb index 35950506..19642282 100644 --- a/lib/prometheus_exporter/middleware.rb +++ b/lib/prometheus_exporter/middleware.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'prometheus_exporter/instrumentation/method_profiler' -require 'prometheus_exporter/client' +require "prometheus_exporter/instrumentation/method_profiler" +require "prometheus_exporter/client" class PrometheusExporter::Middleware MethodProfiler = PrometheusExporter::Instrumentation::MethodProfiler @@ -11,28 +11,41 @@ def initialize(app, config = { instrument: :alias_method, client: nil }) @client = config[:client] || PrometheusExporter::Client.default if config[:instrument] - if defined?(RedisClient) - apply_redis_client_middleware! - end - if defined?(Redis::VERSION) && (Gem::Version.new(Redis::VERSION) >= Gem::Version.new('5.0.0')) + apply_redis_client_middleware! if defined?(RedisClient) + + if defined?(Redis::VERSION) && (Gem::Version.new(Redis::VERSION) >= Gem::Version.new("5.0.0")) # redis 5 support handled via RedisClient - elsif defined? Redis::Client - MethodProfiler.patch(Redis::Client, [ - :call, :call_pipeline - ], :redis, instrument: config[:instrument]) + elsif defined?(Redis::Client) + MethodProfiler.patch( + Redis::Client, + %i[call call_pipeline], + :redis, + instrument: config[:instrument], + ) end - if defined? PG::Connection - MethodProfiler.patch(PG::Connection, [ - :exec, :async_exec, :exec_prepared, :exec_params, :send_query_prepared, :query - ], :sql, instrument: config[:instrument]) + + if defined?(PG::Connection) + MethodProfiler.patch( + PG::Connection, + %i[exec async_exec exec_prepared exec_params send_query_prepared query], + :sql, + instrument: config[:instrument], + ) end - if defined? Mysql2::Client + + if defined?(Mysql2::Client) MethodProfiler.patch(Mysql2::Client, [:query], :sql, instrument: config[:instrument]) MethodProfiler.patch(Mysql2::Statement, [:execute], :sql, instrument: config[:instrument]) MethodProfiler.patch(Mysql2::Result, [:each], :sql, instrument: config[:instrument]) end - if defined? Dalli::Client - MethodProfiler.patch(Dalli::Client, %i[delete fetch get add set], :memcache, instrument: config[:instrument]) + + if defined?(Dalli::Client) + MethodProfiler.patch( + Dalli::Client, + %i[delete fetch get add set], + :memcache, + instrument: config[:instrument], + ) end end end @@ -52,12 +65,10 @@ def call(env) timings: info, queue_time: queue_time, status: status, - default_labels: default_labels(env, result) + default_labels: default_labels(env, result), } labels = custom_labels(env) - if labels - obj = obj.merge(custom_labels: labels) - end + obj = obj.merge(custom_labels: labels) if labels @client.send_json(obj) end @@ -75,10 +86,7 @@ def default_labels(env, result) controller = "preflight" end - { - action: action || "other", - controller: controller || "other" - } + { action: action || "other", controller: controller || "other" } end # allows subclasses to add custom labels based on env @@ -106,32 +114,29 @@ def request_start # determine queue start from well-known trace headers def queue_start(env) - # get the content of the x-queue-start or x-request-start header - value = env['HTTP_X_REQUEST_START'] || env['HTTP_X_QUEUE_START'] - unless value.nil? || value == '' + value = env["HTTP_X_REQUEST_START"] || env["HTTP_X_QUEUE_START"] + unless value.nil? || value == "" # nginx returns time as milliseconds with 3 decimal places # apache returns time as microseconds without decimal places # this method takes care to convert both into a proper second + fractions timestamp - value = value.to_s.gsub(/t=|\./, '') + value = value.to_s.gsub(/t=|\./, "") return "#{value[0, 10]}.#{value[10, 13]}".to_f end # get the content of the x-amzn-trace-id header # see also: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-request-tracing.html - value = env['HTTP_X_AMZN_TRACE_ID'] - value&.split('Root=')&.last&.split('-')&.fetch(1)&.to_i(16) - + value = env["HTTP_X_AMZN_TRACE_ID"] + value&.split("Root=")&.last&.split("-")&.fetch(1)&.to_i(16) end private module RedisInstrumenter - MethodProfiler.define_methods_on_module(self, ["call", "call_pipelined"], "redis") + MethodProfiler.define_methods_on_module(self, %w[call call_pipelined], "redis") end def apply_redis_client_middleware! RedisClient.register(RedisInstrumenter) end - end diff --git a/lib/prometheus_exporter/server/active_record_collector.rb b/lib/prometheus_exporter/server/active_record_collector.rb index 7df958e3..3b97c69d 100644 --- a/lib/prometheus_exporter/server/active_record_collector.rb +++ b/lib/prometheus_exporter/server/active_record_collector.rb @@ -10,15 +10,15 @@ class ActiveRecordCollector < TypeCollector dead: "Dead connections in pool", idle: "Idle connections in pool", waiting: "Connection requests waiting", - size: "Maximum allowed connection pool size" + size: "Maximum allowed connection pool size", } def initialize @active_record_metrics = MetricsContainer.new(ttl: MAX_METRIC_AGE) - @active_record_metrics.filter = -> (new_metric, old_metric) do + @active_record_metrics.filter = ->(new_metric, old_metric) do new_metric["pid"] == old_metric["pid"] && - new_metric["hostname"] == old_metric["hostname"] && - new_metric["metric_labels"]["pool_name"] == old_metric["metric_labels"]["pool_name"] + new_metric["hostname"] == old_metric["hostname"] && + new_metric["metric_labels"]["pool_name"] == old_metric["metric_labels"]["pool_name"] end end @@ -32,13 +32,18 @@ def metrics metrics = {} @active_record_metrics.map do |m| - metric_key = (m["metric_labels"] || {}).merge("pid" => m["pid"], "hostname" => m["hostname"]) + metric_key = + (m["metric_labels"] || {}).merge("pid" => m["pid"], "hostname" => m["hostname"]) metric_key.merge!(m["custom_labels"]) if m["custom_labels"] ACTIVE_RECORD_GAUGES.map do |k, help| k = k.to_s if v = m[k] - g = metrics[k] ||= PrometheusExporter::Metric::Gauge.new("active_record_connection_pool_#{k}", help) + g = + metrics[k] ||= PrometheusExporter::Metric::Gauge.new( + "active_record_connection_pool_#{k}", + help, + ) g.observe(v, metric_key) end end diff --git a/lib/prometheus_exporter/server/collector.rb b/lib/prometheus_exporter/server/collector.rb index 5a642430..5396ade8 100644 --- a/lib/prometheus_exporter/server/collector.rb +++ b/lib/prometheus_exporter/server/collector.rb @@ -1,9 +1,7 @@ # frozen_string_literal: true module PrometheusExporter::Server - class Collector < CollectorBase - def initialize(json_serializer: nil) @process_metrics = [] @metrics = {} @@ -40,19 +38,15 @@ def process_hash(obj) collector.collect(obj) else metric = @metrics[obj["name"]] - if !metric - metric = register_metric_unsafe(obj) - end + metric = register_metric_unsafe(obj) if !metric keys = obj["keys"] || {} - if obj["custom_labels"] - keys = obj["custom_labels"].merge(keys) - end + keys = obj["custom_labels"].merge(keys) if obj["custom_labels"] case obj["prometheus_exporter_action"] - when 'increment' + when "increment" metric.increment(keys, obj["value"]) - when 'decrement' + when "decrement" metric.decrement(keys, obj["value"]) else metric.observe(obj["value"], keys) @@ -63,15 +57,14 @@ def process_hash(obj) def prometheus_metrics_text @mutex.synchronize do - (@metrics.values + @collectors.values.map(&:metrics).flatten) - .map(&:to_prometheus_text).join("\n") + (@metrics.values + @collectors.values.map(&:metrics).flatten).map( + &:to_prometheus_text + ).join("\n") end end def register_metric(metric) - @mutex.synchronize do - @metrics[metric.name] = metric - end + @mutex.synchronize { @metrics[metric.name] = metric } end protected @@ -101,7 +94,10 @@ def register_metric_unsafe(obj) end def symbolize_keys(hash) - hash.inject({}) { |memo, k| memo[k.first.to_sym] = k.last; memo } + hash.inject({}) do |memo, k| + memo[k.first.to_sym] = k.last + memo + end end end end diff --git a/lib/prometheus_exporter/server/collector_base.rb b/lib/prometheus_exporter/server/collector_base.rb index 6f4b6dca..6497f6c6 100644 --- a/lib/prometheus_exporter/server/collector_base.rb +++ b/lib/prometheus_exporter/server/collector_base.rb @@ -1,10 +1,8 @@ # frozen_string_literal: true module PrometheusExporter::Server - # minimal interface to implement a customer collector class CollectorBase - # called each time a string is delivered from the web def process(str) end diff --git a/lib/prometheus_exporter/server/delayed_job_collector.rb b/lib/prometheus_exporter/server/delayed_job_collector.rb index f9c21732..85bc1721 100644 --- a/lib/prometheus_exporter/server/delayed_job_collector.rb +++ b/lib/prometheus_exporter/server/delayed_job_collector.rb @@ -20,19 +20,31 @@ def type end def collect(obj) - custom_labels = obj['custom_labels'] || {} - gauge_labels = { queue_name: obj['queue_name'] }.merge(custom_labels) - counter_labels = gauge_labels.merge(job_name: obj['name']) + custom_labels = obj["custom_labels"] || {} + gauge_labels = { queue_name: obj["queue_name"] }.merge(custom_labels) + counter_labels = gauge_labels.merge(job_name: obj["name"]) ensure_delayed_job_metrics @delayed_job_duration_seconds.observe(obj["duration"], counter_labels) @delayed_job_latency_seconds_total.observe(obj["latency"], counter_labels) @delayed_jobs_total.observe(1, counter_labels) @delayed_failed_jobs_total.observe(1, counter_labels) if !obj["success"] - @delayed_jobs_max_attempts_reached_total.observe(1, counter_labels) if obj["attempts"] >= obj["max_attempts"] + if obj["attempts"] >= obj["max_attempts"] + @delayed_jobs_max_attempts_reached_total.observe(1, counter_labels) + end @delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels) - @delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels.merge(status: "success")) if obj["success"] - @delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels.merge(status: "failed")) if !obj["success"] + if obj["success"] + @delayed_job_duration_seconds_summary.observe( + obj["duration"], + counter_labels.merge(status: "success"), + ) + end + if !obj["success"] + @delayed_job_duration_seconds_summary.observe( + obj["duration"], + counter_labels.merge(status: "failed"), + ) + end @delayed_job_attempts_summary.observe(obj["attempts"], counter_labels) if obj["success"] @delayed_jobs_enqueued.observe(obj["enqueued"], gauge_labels) @delayed_jobs_pending.observe(obj["pending"], gauge_labels) @@ -40,9 +52,17 @@ def collect(obj) def metrics if @delayed_jobs_total - [@delayed_job_duration_seconds, @delayed_job_latency_seconds_total, @delayed_jobs_total, @delayed_failed_jobs_total, - @delayed_jobs_max_attempts_reached_total, @delayed_job_duration_seconds_summary, @delayed_job_attempts_summary, - @delayed_jobs_enqueued, @delayed_jobs_pending] + [ + @delayed_job_duration_seconds, + @delayed_job_latency_seconds_total, + @delayed_jobs_total, + @delayed_failed_jobs_total, + @delayed_jobs_max_attempts_reached_total, + @delayed_job_duration_seconds_summary, + @delayed_job_attempts_summary, + @delayed_jobs_enqueued, + @delayed_jobs_pending, + ] else [] end @@ -52,42 +72,59 @@ def metrics def ensure_delayed_job_metrics if !@delayed_jobs_total - @delayed_job_duration_seconds = - PrometheusExporter::Metric::Counter.new( - "delayed_job_duration_seconds", "Total time spent in delayed jobs.") + PrometheusExporter::Metric::Counter.new( + "delayed_job_duration_seconds", + "Total time spent in delayed jobs.", + ) @delayed_job_latency_seconds_total = - PrometheusExporter::Metric::Counter.new( - "delayed_job_latency_seconds_total", "Total delayed jobs latency.") + PrometheusExporter::Metric::Counter.new( + "delayed_job_latency_seconds_total", + "Total delayed jobs latency.", + ) @delayed_jobs_total = - PrometheusExporter::Metric::Counter.new( - "delayed_jobs_total", "Total number of delayed jobs executed.") + PrometheusExporter::Metric::Counter.new( + "delayed_jobs_total", + "Total number of delayed jobs executed.", + ) @delayed_jobs_enqueued = - PrometheusExporter::Metric::Gauge.new( - "delayed_jobs_enqueued", "Number of enqueued delayed jobs.") + PrometheusExporter::Metric::Gauge.new( + "delayed_jobs_enqueued", + "Number of enqueued delayed jobs.", + ) @delayed_jobs_pending = - PrometheusExporter::Metric::Gauge.new( - "delayed_jobs_pending", "Number of pending delayed jobs.") + PrometheusExporter::Metric::Gauge.new( + "delayed_jobs_pending", + "Number of pending delayed jobs.", + ) @delayed_failed_jobs_total = - PrometheusExporter::Metric::Counter.new( - "delayed_failed_jobs_total", "Total number failed delayed jobs executed.") + PrometheusExporter::Metric::Counter.new( + "delayed_failed_jobs_total", + "Total number failed delayed jobs executed.", + ) @delayed_jobs_max_attempts_reached_total = - PrometheusExporter::Metric::Counter.new( - "delayed_jobs_max_attempts_reached_total", "Total number of delayed jobs that reached max attempts.") + PrometheusExporter::Metric::Counter.new( + "delayed_jobs_max_attempts_reached_total", + "Total number of delayed jobs that reached max attempts.", + ) @delayed_job_duration_seconds_summary = - PrometheusExporter::Metric::Base.default_aggregation.new("delayed_job_duration_seconds_summary", - "Summary of the time it takes jobs to execute.") + PrometheusExporter::Metric::Base.default_aggregation.new( + "delayed_job_duration_seconds_summary", + "Summary of the time it takes jobs to execute.", + ) @delayed_job_attempts_summary = - PrometheusExporter::Metric::Base.default_aggregation.new("delayed_job_attempts_summary", - "Summary of the amount of attempts it takes delayed jobs to succeed.") + PrometheusExporter::Metric::Base.default_aggregation.new( + "delayed_job_attempts_summary", + "Summary of the amount of attempts it takes delayed jobs to succeed.", + ) end end end diff --git a/lib/prometheus_exporter/server/good_job_collector.rb b/lib/prometheus_exporter/server/good_job_collector.rb index 5a6ee37e..e2fc4186 100644 --- a/lib/prometheus_exporter/server/good_job_collector.rb +++ b/lib/prometheus_exporter/server/good_job_collector.rb @@ -10,7 +10,7 @@ class GoodJobCollector < TypeCollector running: "Total number of running GoodJob jobs.", finished: "Total number of finished GoodJob jobs.", succeeded: "Total number of succeeded GoodJob jobs.", - discarded: "Total number of discarded GoodJob jobs." + discarded: "Total number of discarded GoodJob jobs.", } def initialize diff --git a/lib/prometheus_exporter/server/hutch_collector.rb b/lib/prometheus_exporter/server/hutch_collector.rb index 6607fa61..e05ac615 100644 --- a/lib/prometheus_exporter/server/hutch_collector.rb +++ b/lib/prometheus_exporter/server/hutch_collector.rb @@ -14,8 +14,8 @@ def type end def collect(obj) - default_labels = { job_name: obj['name'] } - custom_labels = obj['custom_labels'] + default_labels = { job_name: obj["name"] } + custom_labels = obj["custom_labels"] labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels) ensure_hutch_metrics @@ -36,15 +36,23 @@ def metrics def ensure_hutch_metrics if !@hutch_jobs_total - - @hutch_job_duration_seconds = PrometheusExporter::Metric::Counter.new( - "hutch_job_duration_seconds", "Total time spent in hutch jobs.") - - @hutch_jobs_total = PrometheusExporter::Metric::Counter.new( - "hutch_jobs_total", "Total number of hutch jobs executed.") - - @hutch_failed_jobs_total = PrometheusExporter::Metric::Counter.new( - "hutch_failed_jobs_total", "Total number failed hutch jobs executed.") + @hutch_job_duration_seconds = + PrometheusExporter::Metric::Counter.new( + "hutch_job_duration_seconds", + "Total time spent in hutch jobs.", + ) + + @hutch_jobs_total = + PrometheusExporter::Metric::Counter.new( + "hutch_jobs_total", + "Total number of hutch jobs executed.", + ) + + @hutch_failed_jobs_total = + PrometheusExporter::Metric::Counter.new( + "hutch_failed_jobs_total", + "Total number failed hutch jobs executed.", + ) end end end diff --git a/lib/prometheus_exporter/server/metrics_container.rb b/lib/prometheus_exporter/server/metrics_container.rb index ea46a4f6..1e0f2ddf 100644 --- a/lib/prometheus_exporter/server/metrics_container.rb +++ b/lib/prometheus_exporter/server/metrics_container.rb @@ -9,10 +9,10 @@ class MetricsContainer attr_accessor :filter def initialize(ttl: METRIC_MAX_AGE, expire_attr: METRIC_EXPIRE_ATTR, filter: nil) - @data = [] - @ttl = ttl - @expire_attr = expire_attr - @filter = filter + @data = [] + @ttl = ttl + @expire_attr = expire_attr + @filter = filter end def <<(obj) diff --git a/lib/prometheus_exporter/server/process_collector.rb b/lib/prometheus_exporter/server/process_collector.rb index baccd4d7..bf1ae876 100644 --- a/lib/prometheus_exporter/server/process_collector.rb +++ b/lib/prometheus_exporter/server/process_collector.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true module PrometheusExporter::Server - class ProcessCollector < TypeCollector MAX_METRIC_AGE = 60 @@ -13,8 +12,10 @@ class ProcessCollector < TypeCollector v8_physical_size: "Physical size consumed by V8 heaps.", v8_heap_count: "Number of V8 contexts running.", rss: "Total RSS used by process.", - malloc_increase_bytes_limit: 'Limit before Ruby triggers a GC against current objects (bytes).', - oldmalloc_increase_bytes_limit: 'Limit before Ruby triggers a major GC against old objects (bytes).' + malloc_increase_bytes_limit: + "Limit before Ruby triggers a GC against current objects (bytes).", + oldmalloc_increase_bytes_limit: + "Limit before Ruby triggers a major GC against old objects (bytes).", } PROCESS_COUNTERS = { @@ -25,7 +26,7 @@ class ProcessCollector < TypeCollector def initialize @process_metrics = MetricsContainer.new(ttl: MAX_METRIC_AGE) - @process_metrics.filter = -> (new_metric, old_metric) do + @process_metrics.filter = ->(new_metric, old_metric) do new_metric["pid"] == old_metric["pid"] && new_metric["hostname"] == old_metric["hostname"] end end @@ -40,7 +41,8 @@ def metrics metrics = {} @process_metrics.map do |m| - metric_key = (m["metric_labels"] || {}).merge("pid" => m["pid"], "hostname" => m["hostname"]) + metric_key = + (m["metric_labels"] || {}).merge("pid" => m["pid"], "hostname" => m["hostname"]) metric_key.merge!(m["custom_labels"]) if m["custom_labels"] PROCESS_GAUGES.map do |k, help| diff --git a/lib/prometheus_exporter/server/puma_collector.rb b/lib/prometheus_exporter/server/puma_collector.rb index 67e04bd2..016dd04a 100644 --- a/lib/prometheus_exporter/server/puma_collector.rb +++ b/lib/prometheus_exporter/server/puma_collector.rb @@ -15,7 +15,7 @@ class PumaCollector < TypeCollector def initialize @puma_metrics = MetricsContainer.new(ttl: MAX_PUMA_METRIC_AGE) - @puma_metrics.filter = -> (new_metric, old_metric) do + @puma_metrics.filter = ->(new_metric, old_metric) do new_metric["pid"] == old_metric["pid"] && new_metric["hostname"] == old_metric["hostname"] end end @@ -31,15 +31,9 @@ def metrics @puma_metrics.map do |m| labels = {} - if m["phase"] - labels.merge!(phase: m["phase"]) - end - if m["custom_labels"] - labels.merge!(m["custom_labels"]) - end - if m["metric_labels"] - labels.merge!(m["metric_labels"]) - end + labels.merge!(phase: m["phase"]) if m["phase"] + labels.merge!(m["custom_labels"]) if m["custom_labels"] + labels.merge!(m["metric_labels"]) if m["metric_labels"] PUMA_GAUGES.map do |k, help| k = k.to_s diff --git a/lib/prometheus_exporter/server/resque_collector.rb b/lib/prometheus_exporter/server/resque_collector.rb index 4058d72b..17adada3 100644 --- a/lib/prometheus_exporter/server/resque_collector.rb +++ b/lib/prometheus_exporter/server/resque_collector.rb @@ -9,7 +9,7 @@ class ResqueCollector < TypeCollector pending_jobs: "Total number of pending Resque jobs.", queues: "Total number of Resque queues.", workers: "Total number of Resque workers running.", - working: "Total number of Resque workers working." + working: "Total number of Resque workers working.", } def initialize diff --git a/lib/prometheus_exporter/server/runner.rb b/lib/prometheus_exporter/server/runner.rb index 006de520..7b61d203 100644 --- a/lib/prometheus_exporter/server/runner.rb +++ b/lib/prometheus_exporter/server/runner.rb @@ -1,10 +1,13 @@ # frozen_string_literal: true -require_relative '../client' +require_relative "../client" module PrometheusExporter::Server - class RunnerException < StandardError; end - class WrongInheritance < RunnerException; end + class RunnerException < StandardError + end + + class WrongInheritance < RunnerException + end class Runner def initialize(options = {}) @@ -18,9 +21,7 @@ def initialize(options = {}) @realm = nil @histogram = nil - options.each do |k, v| - send("#{k}=", v) if self.class.method_defined?("#{k}=") - end + options.each { |k, v| send("#{k}=", v) if self.class.method_defined?("#{k}=") } end def start @@ -34,27 +35,47 @@ def start register_type_collectors unless collector.is_a?(PrometheusExporter::Server::CollectorBase) - raise WrongInheritance, 'Collector class must be inherited from PrometheusExporter::Server::CollectorBase' + raise WrongInheritance, + "Collector class must be inherited from PrometheusExporter::Server::CollectorBase" end if unicorn_listen_address && unicorn_pid_file - - require_relative '../instrumentation' + require_relative "../instrumentation" local_client = PrometheusExporter::LocalClient.new(collector: collector) PrometheusExporter::Instrumentation::Unicorn.start( pid_file: unicorn_pid_file, listener_address: unicorn_listen_address, - client: local_client + client: local_client, ) end - server = server_class.new(port: port, bind: bind, collector: collector, timeout: timeout, verbose: verbose, auth: auth, realm: realm) + server = + server_class.new( + port: port, + bind: bind, + collector: collector, + timeout: timeout, + verbose: verbose, + auth: auth, + realm: realm, + ) server.start end attr_accessor :unicorn_listen_address, :unicorn_pid_file - attr_writer :prefix, :port, :bind, :collector_class, :type_collectors, :timeout, :verbose, :server_class, :label, :auth, :realm, :histogram + attr_writer :prefix, + :port, + :bind, + :collector_class, + :type_collectors, + :timeout, + :verbose, + :server_class, + :label, + :auth, + :realm, + :histogram def auth @auth || nil @@ -89,7 +110,7 @@ def timeout end def verbose - return @verbose if defined? @verbose + return @verbose if defined?(@verbose) false end diff --git a/lib/prometheus_exporter/server/shoryuken_collector.rb b/lib/prometheus_exporter/server/shoryuken_collector.rb index 487a22ad..379a9470 100644 --- a/lib/prometheus_exporter/server/shoryuken_collector.rb +++ b/lib/prometheus_exporter/server/shoryuken_collector.rb @@ -2,7 +2,6 @@ module PrometheusExporter::Server class ShoryukenCollector < TypeCollector - def initialize @shoryuken_jobs_total = nil @shoryuken_job_duration_seconds = nil @@ -16,8 +15,8 @@ def type end def collect(obj) - default_labels = { job_name: obj['name'] , queue_name: obj['queue'] } - custom_labels = obj['custom_labels'] + default_labels = { job_name: obj["name"], queue_name: obj["queue"] } + custom_labels = obj["custom_labels"] labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels) ensure_shoryuken_metrics @@ -30,10 +29,10 @@ def collect(obj) def metrics if @shoryuken_jobs_total [ - @shoryuken_job_duration_seconds, - @shoryuken_jobs_total, - @shoryuken_restarted_jobs_total, - @shoryuken_failed_jobs_total, + @shoryuken_job_duration_seconds, + @shoryuken_jobs_total, + @shoryuken_restarted_jobs_total, + @shoryuken_failed_jobs_total, ] else [] @@ -44,23 +43,29 @@ def metrics def ensure_shoryuken_metrics if !@shoryuken_jobs_total - @shoryuken_job_duration_seconds = - PrometheusExporter::Metric::Counter.new( - "shoryuken_job_duration_seconds", "Total time spent in shoryuken jobs.") + PrometheusExporter::Metric::Counter.new( + "shoryuken_job_duration_seconds", + "Total time spent in shoryuken jobs.", + ) @shoryuken_jobs_total = - PrometheusExporter::Metric::Counter.new( - "shoryuken_jobs_total", "Total number of shoryuken jobs executed.") + PrometheusExporter::Metric::Counter.new( + "shoryuken_jobs_total", + "Total number of shoryuken jobs executed.", + ) @shoryuken_restarted_jobs_total = - PrometheusExporter::Metric::Counter.new( - "shoryuken_restarted_jobs_total", "Total number of shoryuken jobs that we restarted because of a shoryuken shutdown.") + PrometheusExporter::Metric::Counter.new( + "shoryuken_restarted_jobs_total", + "Total number of shoryuken jobs that we restarted because of a shoryuken shutdown.", + ) @shoryuken_failed_jobs_total = - PrometheusExporter::Metric::Counter.new( - "shoryuken_failed_jobs_total", "Total number of failed shoryuken jobs.") - + PrometheusExporter::Metric::Counter.new( + "shoryuken_failed_jobs_total", + "Total number of failed shoryuken jobs.", + ) end end end diff --git a/lib/prometheus_exporter/server/sidekiq_collector.rb b/lib/prometheus_exporter/server/sidekiq_collector.rb index 11494443..49821c18 100644 --- a/lib/prometheus_exporter/server/sidekiq_collector.rb +++ b/lib/prometheus_exporter/server/sidekiq_collector.rb @@ -2,7 +2,6 @@ module PrometheusExporter::Server class SidekiqCollector < TypeCollector - def initialize @sidekiq_jobs_total = nil @sidekiq_job_duration_seconds = nil @@ -17,8 +16,8 @@ def type end def collect(obj) - default_labels = { job_name: obj['name'], queue: obj['queue'] } - custom_labels = obj['custom_labels'] + default_labels = { job_name: obj["name"], queue: obj["queue"] } + custom_labels = obj["custom_labels"] labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels) ensure_sidekiq_metrics @@ -50,26 +49,35 @@ def metrics def ensure_sidekiq_metrics if !@sidekiq_jobs_total - @sidekiq_job_duration_seconds = - PrometheusExporter::Metric::Base.default_aggregation.new( - "sidekiq_job_duration_seconds", "Total time spent in sidekiq jobs.") + PrometheusExporter::Metric::Base.default_aggregation.new( + "sidekiq_job_duration_seconds", + "Total time spent in sidekiq jobs.", + ) @sidekiq_jobs_total = - PrometheusExporter::Metric::Counter.new( - "sidekiq_jobs_total", "Total number of sidekiq jobs executed.") + PrometheusExporter::Metric::Counter.new( + "sidekiq_jobs_total", + "Total number of sidekiq jobs executed.", + ) @sidekiq_restarted_jobs_total = - PrometheusExporter::Metric::Counter.new( - "sidekiq_restarted_jobs_total", "Total number of sidekiq jobs that we restarted because of a sidekiq shutdown.") + PrometheusExporter::Metric::Counter.new( + "sidekiq_restarted_jobs_total", + "Total number of sidekiq jobs that we restarted because of a sidekiq shutdown.", + ) @sidekiq_failed_jobs_total = - PrometheusExporter::Metric::Counter.new( - "sidekiq_failed_jobs_total", "Total number of failed sidekiq jobs.") + PrometheusExporter::Metric::Counter.new( + "sidekiq_failed_jobs_total", + "Total number of failed sidekiq jobs.", + ) @sidekiq_dead_jobs_total = - PrometheusExporter::Metric::Counter.new( - "sidekiq_dead_jobs_total", "Total number of dead sidekiq jobs.") + PrometheusExporter::Metric::Counter.new( + "sidekiq_dead_jobs_total", + "Total number of dead sidekiq jobs.", + ) end end end diff --git a/lib/prometheus_exporter/server/sidekiq_process_collector.rb b/lib/prometheus_exporter/server/sidekiq_process_collector.rb index 6cb4996b..388eb9f1 100644 --- a/lib/prometheus_exporter/server/sidekiq_process_collector.rb +++ b/lib/prometheus_exporter/server/sidekiq_process_collector.rb @@ -5,8 +5,8 @@ class SidekiqProcessCollector < PrometheusExporter::Server::TypeCollector MAX_METRIC_AGE = 60 SIDEKIQ_PROCESS_GAUGES = { - 'busy' => 'Number of running jobs', - 'concurrency' => 'Maximum concurrency', + "busy" => "Number of running jobs", + "concurrency" => "Maximum concurrency", }.freeze attr_reader :sidekiq_metrics, :gauges @@ -17,17 +17,21 @@ def initialize end def type - 'sidekiq_process' + "sidekiq_process" end def metrics SIDEKIQ_PROCESS_GAUGES.each_key { |name| gauges[name]&.reset! } sidekiq_metrics.map do |metric| - labels = metric.fetch('labels', {}) + labels = metric.fetch("labels", {}) SIDEKIQ_PROCESS_GAUGES.map do |name, help| if (value = metric[name]) - gauge = gauges[name] ||= PrometheusExporter::Metric::Gauge.new("sidekiq_process_#{name}", help) + gauge = + gauges[name] ||= PrometheusExporter::Metric::Gauge.new( + "sidekiq_process_#{name}", + help, + ) gauge.observe(value, labels) end end diff --git a/lib/prometheus_exporter/server/sidekiq_queue_collector.rb b/lib/prometheus_exporter/server/sidekiq_queue_collector.rb index 935476a6..224c0157 100644 --- a/lib/prometheus_exporter/server/sidekiq_queue_collector.rb +++ b/lib/prometheus_exporter/server/sidekiq_queue_collector.rb @@ -4,8 +4,8 @@ class SidekiqQueueCollector < TypeCollector MAX_METRIC_AGE = 60 SIDEKIQ_QUEUE_GAUGES = { - 'backlog' => 'Size of the sidekiq queue.', - 'latency_seconds' => 'Latency of the sidekiq queue.', + "backlog" => "Size of the sidekiq queue.", + "latency_seconds" => "Latency of the sidekiq queue.", }.freeze attr_reader :sidekiq_metrics, :gauges @@ -16,7 +16,7 @@ def initialize end def type - 'sidekiq_queue' + "sidekiq_queue" end def metrics @@ -26,7 +26,8 @@ def metrics labels = metric.fetch("labels", {}) SIDEKIQ_QUEUE_GAUGES.map do |name, help| if (value = metric[name]) - gauge = gauges[name] ||= PrometheusExporter::Metric::Gauge.new("sidekiq_queue_#{name}", help) + gauge = + gauges[name] ||= PrometheusExporter::Metric::Gauge.new("sidekiq_queue_#{name}", help) gauge.observe(value, labels) end end @@ -36,8 +37,8 @@ def metrics end def collect(object) - object['queues'].each do |queue| - queue["labels"].merge!(object['custom_labels']) if object['custom_labels'] + object["queues"].each do |queue| + queue["labels"].merge!(object["custom_labels"]) if object["custom_labels"] @sidekiq_metrics << queue end end diff --git a/lib/prometheus_exporter/server/sidekiq_stats_collector.rb b/lib/prometheus_exporter/server/sidekiq_stats_collector.rb index 27f52d99..05877725 100644 --- a/lib/prometheus_exporter/server/sidekiq_stats_collector.rb +++ b/lib/prometheus_exporter/server/sidekiq_stats_collector.rb @@ -5,14 +5,14 @@ class SidekiqStatsCollector < TypeCollector MAX_METRIC_AGE = 60 SIDEKIQ_STATS_GAUGES = { - 'dead_size' => 'Size of dead the queue', - 'enqueued' => 'Number of enqueued jobs', - 'failed' => 'Number of failed jobs', - 'processed' => 'Total number of processed jobs', - 'processes_size' => 'Number of processes', - 'retry_size' => 'Size of the retries queue', - 'scheduled_size' => 'Size of the scheduled queue', - 'workers_size' => 'Number of jobs actively being processed', + "dead_size" => "Size of dead the queue", + "enqueued" => "Number of enqueued jobs", + "failed" => "Number of failed jobs", + "processed" => "Total number of processed jobs", + "processes_size" => "Number of processes", + "retry_size" => "Size of the retries queue", + "scheduled_size" => "Size of the scheduled queue", + "workers_size" => "Number of jobs actively being processed", }.freeze attr_reader :sidekiq_metrics, :gauges @@ -23,7 +23,7 @@ def initialize end def type - 'sidekiq_stats' + "sidekiq_stats" end def metrics @@ -31,8 +31,9 @@ def metrics sidekiq_metrics.map do |metric| SIDEKIQ_STATS_GAUGES.map do |name, help| - if (value = metric['stats'][name]) - gauge = gauges[name] ||= PrometheusExporter::Metric::Gauge.new("sidekiq_stats_#{name}", help) + if (value = metric["stats"][name]) + gauge = + gauges[name] ||= PrometheusExporter::Metric::Gauge.new("sidekiq_stats_#{name}", help) gauge.observe(value) end end diff --git a/lib/prometheus_exporter/server/unicorn_collector.rb b/lib/prometheus_exporter/server/unicorn_collector.rb index 840887f5..bdaa373b 100644 --- a/lib/prometheus_exporter/server/unicorn_collector.rb +++ b/lib/prometheus_exporter/server/unicorn_collector.rb @@ -7,9 +7,9 @@ class UnicornCollector < PrometheusExporter::Server::TypeCollector MAX_METRIC_AGE = 60 UNICORN_GAUGES = { - workers: 'Number of unicorn workers.', - active_workers: 'Number of active unicorn workers', - request_backlog: 'Number of requests waiting to be processed by a unicorn worker.' + workers: "Number of unicorn workers.", + active_workers: "Number of active unicorn workers", + request_backlog: "Number of requests waiting to be processed by a unicorn worker.", }.freeze def initialize @@ -17,7 +17,7 @@ def initialize end def type - 'unicorn' + "unicorn" end def metrics diff --git a/lib/prometheus_exporter/server/web_collector.rb b/lib/prometheus_exporter/server/web_collector.rb index cb3b0ffa..61575241 100644 --- a/lib/prometheus_exporter/server/web_collector.rb +++ b/lib/prometheus_exporter/server/web_collector.rb @@ -29,41 +29,49 @@ def metrics def ensure_metrics unless @http_requests_total - @metrics["http_requests_total"] = @http_requests_total = PrometheusExporter::Metric::Counter.new( - "http_requests_total", - "Total HTTP requests from web app." - ) + @metrics["http_requests_total"] = @http_requests_total = + PrometheusExporter::Metric::Counter.new( + "http_requests_total", + "Total HTTP requests from web app.", + ) - @metrics["http_request_duration_seconds"] = @http_request_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new( - "http_request_duration_seconds", - "Time spent in HTTP reqs in seconds." - ) + @metrics["http_request_duration_seconds"] = @http_request_duration_seconds = + PrometheusExporter::Metric::Base.default_aggregation.new( + "http_request_duration_seconds", + "Time spent in HTTP reqs in seconds.", + ) - @metrics["http_request_redis_duration_seconds"] = @http_request_redis_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new( - "http_request_redis_duration_seconds", - "Time spent in HTTP reqs in Redis, in seconds." - ) + @metrics["http_request_redis_duration_seconds"] = @http_request_redis_duration_seconds = + PrometheusExporter::Metric::Base.default_aggregation.new( + "http_request_redis_duration_seconds", + "Time spent in HTTP reqs in Redis, in seconds.", + ) - @metrics["http_request_sql_duration_seconds"] = @http_request_sql_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new( - "http_request_sql_duration_seconds", - "Time spent in HTTP reqs in SQL in seconds." - ) + @metrics["http_request_sql_duration_seconds"] = @http_request_sql_duration_seconds = + PrometheusExporter::Metric::Base.default_aggregation.new( + "http_request_sql_duration_seconds", + "Time spent in HTTP reqs in SQL in seconds.", + ) - @metrics["http_request_memcache_duration_seconds"] = @http_request_memcache_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new( - "http_request_memcache_duration_seconds", - "Time spent in HTTP reqs in Memcache in seconds." - ) + @metrics[ + "http_request_memcache_duration_seconds" + ] = @http_request_memcache_duration_seconds = + PrometheusExporter::Metric::Base.default_aggregation.new( + "http_request_memcache_duration_seconds", + "Time spent in HTTP reqs in Memcache in seconds.", + ) - @metrics["http_request_queue_duration_seconds"] = @http_request_queue_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new( - "http_request_queue_duration_seconds", - "Time spent queueing the request in load balancer in seconds." - ) + @metrics["http_request_queue_duration_seconds"] = @http_request_queue_duration_seconds = + PrometheusExporter::Metric::Base.default_aggregation.new( + "http_request_queue_duration_seconds", + "Time spent queueing the request in load balancer in seconds.", + ) end end def observe(obj) - default_labels = obj['default_labels'] - custom_labels = obj['custom_labels'] + default_labels = obj["default_labels"] + custom_labels = obj["custom_labels"] labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels) @http_requests_total.observe(1, labels.merge("status" => obj["status"])) diff --git a/lib/prometheus_exporter/server/web_server.rb b/lib/prometheus_exporter/server/web_server.rb index d6baf963..7c23450e 100644 --- a/lib/prometheus_exporter/server/web_server.rb +++ b/lib/prometheus_exporter/server/web_server.rb @@ -21,19 +21,19 @@ def initialize(opts) @metrics_total = PrometheusExporter::Metric::Counter.new( "collector_metrics_total", - "Total metrics processed by exporter web." + "Total metrics processed by exporter web.", ) @sessions_total = PrometheusExporter::Metric::Counter.new( "collector_sessions_total", - "Total send_metric sessions processed by exporter web." + "Total send_metric sessions processed by exporter web.", ) @bad_metrics_total = PrometheusExporter::Metric::Counter.new( "collector_bad_metrics_total", - "Total mis-handled metrics by collector." + "Total mis-handled metrics by collector.", ) @metrics_total.observe(0) @@ -46,7 +46,7 @@ def initialize(opts) if @verbose @access_log = [ [$stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT], - [$stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT] + [$stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT], ] @logger = WEBrick::Log.new(log_target || $stderr) else @@ -54,9 +54,7 @@ def initialize(opts) @logger = WEBrick::Log.new(log_target || "/dev/null") end - if @verbose && @auth - @logger.info "Using Basic Authentication via #{@auth}" - end + @logger.info "Using Basic Authentication via #{@auth}" if @verbose && @auth if %w[ALL ANY].include?(@bind) @logger.info "Listening on both 0.0.0.0/:: network interfaces" @@ -68,7 +66,7 @@ def initialize(opts) Port: @port, BindAddress: @bind, Logger: @logger, - AccessLog: @access_log + AccessLog: @access_log, ) @server.mount_proc "/" do |req, res| @@ -140,9 +138,7 @@ def stop def metrics metric_text = nil begin - Timeout.timeout(@timeout) do - metric_text = @collector.prometheus_metrics_text - end + Timeout.timeout(@timeout) { metric_text = @collector.prometheus_metrics_text } rescue Timeout::Error # we timed out ... bummer @logger.error "Generating Prometheus metrics text timed out" @@ -153,14 +149,10 @@ def metrics metrics << add_gauge( "collector_working", "Is the master process collector able to collect metrics", - metric_text && metric_text.length > 0 ? 1 : 0 + metric_text && metric_text.length > 0 ? 1 : 0, ) - metrics << add_gauge( - "collector_rss", - "total memory used by collector process", - get_rss - ) + metrics << add_gauge("collector_rss", "total memory used by collector process", get_rss) metrics << @metrics_total metrics << @sessions_total @@ -196,9 +188,7 @@ def add_gauge(name, help, value) def authenticate(req, res) htpasswd = WEBrick::HTTPAuth::Htpasswd.new(@auth) basic_auth = - WEBrick::HTTPAuth::BasicAuth.new( - { Realm: @realm, UserDB: htpasswd, Logger: @logger } - ) + WEBrick::HTTPAuth::BasicAuth.new({ Realm: @realm, UserDB: htpasswd, Logger: @logger }) basic_auth.authenticate(req, res) end diff --git a/prometheus_exporter.gemspec b/prometheus_exporter.gemspec index e1ee5448..386b2359 100644 --- a/prometheus_exporter.gemspec +++ b/prometheus_exporter.gemspec @@ -5,22 +5,20 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require "prometheus_exporter/version" Gem::Specification.new do |spec| - spec.name = "prometheus_exporter" - spec.version = PrometheusExporter::VERSION - spec.authors = ["Sam Saffron"] - spec.email = ["sam.saffron@gmail.com"] + spec.name = "prometheus_exporter" + spec.version = PrometheusExporter::VERSION + spec.authors = ["Sam Saffron"] + spec.email = ["sam.saffron@gmail.com"] - spec.summary = %q{Prometheus Exporter} - spec.description = %q{Prometheus metric collector and exporter for Ruby} - spec.homepage = "https://github.com/discourse/prometheus_exporter" - spec.license = "MIT" + spec.summary = "Prometheus Exporter" + spec.description = "Prometheus metric collector and exporter for Ruby" + spec.homepage = "https://github.com/discourse/prometheus_exporter" + spec.license = "MIT" - spec.files = `git ls-files -z`.split("\x0").reject do |f| - f.match(%r{^(test|spec|features|bin)/}) - end - spec.bindir = "bin" - spec.executables = ["prometheus_exporter"] - spec.require_paths = ["lib"] + spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|bin)/}) } + spec.bindir = "bin" + spec.executables = ["prometheus_exporter"] + spec.require_paths = ["lib"] spec.add_dependency "webrick" @@ -39,8 +37,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency "activerecord", "~> 6.0.0" spec.add_development_dependency "redis", "> 5" spec.add_development_dependency "m" - if !RUBY_ENGINE == 'jruby' - spec.add_development_dependency "raindrops", "~> 0.19" - end - spec.required_ruby_version = '>= 3.0.0' + spec.add_development_dependency "syntax_tree" + spec.add_development_dependency "syntax_tree-disable_ternary" + spec.add_development_dependency "raindrops", "~> 0.19" if !RUBY_ENGINE == "jruby" + spec.required_ruby_version = ">= 3.0.0" end diff --git a/test/client_test.rb b/test/client_test.rb index 55051140..aa780a7c 100644 --- a/test/client_test.rb +++ b/test/client_test.rb @@ -8,53 +8,52 @@ def test_find_the_correct_registered_metric client = PrometheusExporter::Client.new # register a metrics for testing - counter_metric = client.register(:counter, 'counter_metric', 'helping') + counter_metric = client.register(:counter, "counter_metric", "helping") # when the given name doesn't match any existing metric, it returns nil - result = client.find_registered_metric('not_registered') + result = client.find_registered_metric("not_registered") assert_nil(result) # when the given name matches an existing metric, it returns this metric - result = client.find_registered_metric('counter_metric') + result = client.find_registered_metric("counter_metric") assert_equal(counter_metric, result) # when the given name matches an existing metric, but the given type doesn't, it returns nil - result = client.find_registered_metric('counter_metric', type: :gauge) + result = client.find_registered_metric("counter_metric", type: :gauge) assert_nil(result) # when the given name and type match an existing metric, it returns the metric - result = client.find_registered_metric('counter_metric', type: :counter) + result = client.find_registered_metric("counter_metric", type: :counter) assert_equal(counter_metric, result) # when the given name matches an existing metric, but the given help doesn't, it returns nil - result = client.find_registered_metric('counter_metric', help: 'not helping') + result = client.find_registered_metric("counter_metric", help: "not helping") assert_nil(result) # when the given name and help match an existing metric, it returns the metric - result = client.find_registered_metric('counter_metric', help: 'helping') + result = client.find_registered_metric("counter_metric", help: "helping") assert_equal(counter_metric, result) # when the given name matches an existing metric, but the given help and type don't, it returns nil - result = client.find_registered_metric('counter_metric', type: :gauge, help: 'not helping') + result = client.find_registered_metric("counter_metric", type: :gauge, help: "not helping") assert_nil(result) # when the given name, type, and help all match an existing metric, it returns the metric - result = client.find_registered_metric('counter_metric', type: :counter, help: 'helping') + result = client.find_registered_metric("counter_metric", type: :counter, help: "helping") assert_equal(counter_metric, result) end def test_standard_values client = PrometheusExporter::Client.new - counter_metric = client.register(:counter, 'counter_metric', 'helping') - assert_equal(false, counter_metric.standard_values('value', 'key').has_key?(:opts)) + counter_metric = client.register(:counter, "counter_metric", "helping") + assert_equal(false, counter_metric.standard_values("value", "key").has_key?(:opts)) expected_quantiles = { quantiles: [0.99, 9] } - summary_metric = client.register(:summary, 'summary_metric', 'helping', expected_quantiles) - assert_equal(expected_quantiles, summary_metric.standard_values('value', 'key')[:opts]) + summary_metric = client.register(:summary, "summary_metric", "helping", expected_quantiles) + assert_equal(expected_quantiles, summary_metric.standard_values("value", "key")[:opts]) end def test_overriding_logger - logs = StringIO.new logger = Logger.new(logs) logger.level = :warn diff --git a/test/instrumentation/active_record_test.rb b/test/instrumentation/active_record_test.rb index cff90160..8dc59676 100644 --- a/test/instrumentation/active_record_test.rb +++ b/test/instrumentation/active_record_test.rb @@ -1,22 +1,22 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/instrumentation' -require 'active_record' +require_relative "../test_helper" +require "prometheus_exporter/instrumentation" +require "active_record" class PrometheusInstrumentationActiveRecordTest < Minitest::Test - def setup super # With this trick this variable with be accessible with ::ObjectSpace - @pool = if active_record_version >= Gem::Version.create('6.1.0.rc1') - active_record61_pool - elsif active_record_version >= Gem::Version.create('6.0.0') - active_record60_pool - else - raise 'unsupported active_record version' - end + @pool = + if active_record_version >= Gem::Version.create("6.1.0.rc1") + active_record61_pool + elsif active_record_version >= Gem::Version.create("6.0.0") + active_record60_pool + else + raise "unsupported active_record version" + end end def metric_labels @@ -28,7 +28,8 @@ def config_labels end def collector - @collector ||= PrometheusExporter::Instrumentation::ActiveRecord.new(metric_labels, config_labels) + @collector ||= + PrometheusExporter::Instrumentation::ActiveRecord.new(metric_labels, config_labels) end %i[size connections busy dead idle waiting checkout_timeout type metric_labels].each do |key| @@ -42,7 +43,7 @@ def test_metrics_labels end def test_type - assert_equal collector.collect.first[:type], 'active_record' + assert_equal collector.collect.first[:type], "active_record" end private @@ -57,6 +58,7 @@ def active_record60_pool def active_record61_pool ::ActiveRecord::ConnectionAdapters::ConnectionPool.new( - OpenStruct.new(db_config: OpenStruct.new(checkout_timeout: 0, idle_timeout: 0, pool: 5))) + OpenStruct.new(db_config: OpenStruct.new(checkout_timeout: 0, idle_timeout: 0, pool: 5)), + ) end end diff --git a/test/instrumentation/method_profiler_test.rb b/test/instrumentation/method_profiler_test.rb index d57c5e62..45d9651b 100644 --- a/test/instrumentation/method_profiler_test.rb +++ b/test/instrumentation/method_profiler_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "prometheus_exporter/instrumentation" class PrometheusInstrumentationMethodProfilerTest < Minitest::Test class SomeClassPatchedUsingAliasMethod @@ -16,8 +16,19 @@ def some_method end end - PrometheusExporter::Instrumentation::MethodProfiler.patch SomeClassPatchedUsingAliasMethod, [:some_method], :test, instrument: :alias_method - PrometheusExporter::Instrumentation::MethodProfiler.patch SomeClassPatchedUsingPrepend, [:some_method], :test, instrument: :prepend + PrometheusExporter::Instrumentation::MethodProfiler.patch( + SomeClassPatchedUsingAliasMethod, + [:some_method], + :test, + instrument: :alias_method, + ) + + PrometheusExporter::Instrumentation::MethodProfiler.patch( + SomeClassPatchedUsingPrepend, + [:some_method], + :test, + instrument: :prepend, + ) def test_alias_method_source_location file, line = SomeClassPatchedUsingAliasMethod.instance_method(:some_method).source_location @@ -26,7 +37,7 @@ def test_alias_method_source_location end def test_alias_method_preserves_behavior - assert_equal 'Hello, world', SomeClassPatchedUsingAliasMethod.new.some_method + assert_equal "Hello, world", SomeClassPatchedUsingAliasMethod.new.some_method end def test_prepend_source_location @@ -36,6 +47,6 @@ def test_prepend_source_location end def test_prepend_preserves_behavior - assert_equal 'Hello, world', SomeClassPatchedUsingPrepend.new.some_method + assert_equal "Hello, world", SomeClassPatchedUsingPrepend.new.some_method end end diff --git a/test/metric/base_test.rb b/test/metric/base_test.rb index febdb78e..29455361 100644 --- a/test/metric/base_test.rb +++ b/test/metric/base_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/metric' +require_relative "../test_helper" +require "prometheus_exporter/metric" module PrometheusExporter::Metric describe Base do @@ -9,20 +9,20 @@ module PrometheusExporter::Metric Counter.new("a_counter", "my amazing counter") end - before do - Base.default_prefix = '' + before do + Base.default_prefix = "" Base.default_labels = {} Base.default_aggregation = nil end after do - Base.default_prefix = '' + Base.default_prefix = "" Base.default_labels = {} Base.default_aggregation = nil end it "supports a dynamic prefix" do - Base.default_prefix = 'web_' + Base.default_prefix = "web_" counter.observe text = <<~TEXT @@ -67,7 +67,6 @@ module PrometheusExporter::Metric end it "supports reset! for Gauge" do - gauge = Gauge.new("test", "test") gauge.observe(999) @@ -83,7 +82,6 @@ module PrometheusExporter::Metric end it "supports reset! for Counter" do - counter = Counter.new("test", "test") counter.observe(999) @@ -99,7 +97,6 @@ module PrometheusExporter::Metric end it "supports reset! for Histogram" do - histogram = Histogram.new("test", "test") histogram.observe(999) @@ -115,7 +112,6 @@ module PrometheusExporter::Metric end it "supports reset! for Summary" do - summary = Summary.new("test", "test") summary.observe(999) diff --git a/test/metric/counter_test.rb b/test/metric/counter_test.rb index fd2b672d..1dc10b1c 100644 --- a/test/metric/counter_test.rb +++ b/test/metric/counter_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/metric' +require_relative "../test_helper" +require "prometheus_exporter/metric" module PrometheusExporter::Metric describe Counter do @@ -9,12 +9,10 @@ module PrometheusExporter::Metric Counter.new("a_counter", "my amazing counter") end - before do - Base.default_prefix = '' - end + before { Base.default_prefix = "" } it "supports a dynamic prefix" do - Base.default_prefix = 'web_' + Base.default_prefix = "web_" counter.observe text = <<~TEXT @@ -24,7 +22,7 @@ module PrometheusExporter::Metric TEXT assert_equal(counter.to_prometheus_text, text) - Base.default_prefix = '' + Base.default_prefix = "" end it "can correctly increment counters with labels" do @@ -70,7 +68,6 @@ module PrometheusExporter::Metric end it "can correctly log multiple increments" do - counter.observe counter.observe counter.observe diff --git a/test/metric/gauge_test.rb b/test/metric/gauge_test.rb index f6b4b1d8..b10619ae 100644 --- a/test/metric/gauge_test.rb +++ b/test/metric/gauge_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/metric' +require_relative "../test_helper" +require "prometheus_exporter/metric" module PrometheusExporter::Metric describe Gauge do @@ -13,14 +13,10 @@ module PrometheusExporter::Metric Gauge.new("a_gauge_total", "my amazing gauge") end - before do - Base.default_prefix = '' - end + before { Base.default_prefix = "" } it "should not allow observe to corrupt data" do - assert_raises do - gauge.observe("hello") - end + assert_raises { gauge.observe("hello") } # going to special case nil here instead of adding a new API # observing nil should set to nothing @@ -41,7 +37,7 @@ module PrometheusExporter::Metric end it "supports a dynamic prefix" do - Base.default_prefix = 'web_' + Base.default_prefix = "web_" gauge.observe(400.11) text = <<~TEXT @@ -52,7 +48,7 @@ module PrometheusExporter::Metric assert_equal(gauge.to_prometheus_text, text) - Base.default_prefix = '' + Base.default_prefix = "" end it "can correctly set gauges with labels" do @@ -72,7 +68,6 @@ module PrometheusExporter::Metric end it "can correctly reset on change" do - gauge.observe(10) gauge.observe(11) @@ -86,7 +81,6 @@ module PrometheusExporter::Metric end it "can use the set on alias" do - gauge.set(10) gauge.set(11) diff --git a/test/metric/histogram_test.rb b/test/metric/histogram_test.rb index 59af51b4..91115639 100644 --- a/test/metric/histogram_test.rb +++ b/test/metric/histogram_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/metric' +require_relative "../test_helper" +require "prometheus_exporter/metric" module PrometheusExporter::Metric describe Histogram do @@ -9,9 +9,7 @@ module PrometheusExporter::Metric Histogram.new("a_histogram", "my amazing histogram") end - before do - Base.default_prefix = '' - end + before { Base.default_prefix = "" } it "can correctly gather a histogram" do histogram.observe(0.1) @@ -45,7 +43,6 @@ module PrometheusExporter::Metric end it "can correctly gather a histogram over multiple labels" do - histogram.observe(0.1, nil) histogram.observe(0.2) histogram.observe(0.610001) @@ -146,12 +143,15 @@ module PrometheusExporter::Metric assert_equal(histogram.to_h, key => val) end - it 'supports default buckets' do - assert_equal(Histogram::DEFAULT_BUCKETS, [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5.0, 10.0]) + it "supports default buckets" do + assert_equal( + Histogram::DEFAULT_BUCKETS, + [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5.0, 10.0], + ) assert_equal(Histogram::DEFAULT_BUCKETS, Histogram.default_buckets) end - it 'allows to change default buckets' do + it "allows to change default buckets" do custom_buckets = [0.005, 0.1, 1, 2, 5, 10] Histogram.default_buckets = custom_buckets @@ -160,11 +160,11 @@ module PrometheusExporter::Metric Histogram.default_buckets = Histogram::DEFAULT_BUCKETS end - it 'uses the default buckets for instance' do + it "uses the default buckets for instance" do assert_equal(histogram.buckets, Histogram::DEFAULT_BUCKETS) end - it 'uses the the custom default buckets for instance' do + it "uses the the custom default buckets for instance" do custom_buckets = [0.005, 0.1, 1, 2, 5, 10] Histogram.default_buckets = custom_buckets @@ -173,9 +173,9 @@ module PrometheusExporter::Metric Histogram.default_buckets = Histogram::DEFAULT_BUCKETS end - it 'uses the specified buckets' do + it "uses the specified buckets" do buckets = [0.1, 0.2, 0.3] - histogram = Histogram.new('test_bucktets', 'I have specified buckets', buckets: buckets) + histogram = Histogram.new("test_bucktets", "I have specified buckets", buckets: buckets) assert_equal(histogram.buckets, buckets) end diff --git a/test/metric/summary_test.rb b/test/metric/summary_test.rb index 310f93ce..3c0e41df 100644 --- a/test/metric/summary_test.rb +++ b/test/metric/summary_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/metric' +require_relative "../test_helper" +require "prometheus_exporter/metric" module PrometheusExporter::Metric describe Summary do @@ -9,16 +9,12 @@ module PrometheusExporter::Metric Summary.new("a_summary", "my amazing summary") end - before do - Base.default_prefix = '' - end + before { Base.default_prefix = "" } it "can correctly gather a summary with custom quantiles" do summary = Summary.new("custom", "custom summary", quantiles: [0.4, 0.6]) - (1..10).each do |i| - summary.observe(i) - end + (1..10).each { |i| summary.observe(i) } expected = <<~TEXT # HELP custom custom summary @@ -33,7 +29,6 @@ module PrometheusExporter::Metric end it "can correctly gather a summary over multiple labels" do - summary.observe(0.1, nil) summary.observe(0.2) summary.observe(0.610001) @@ -90,16 +85,13 @@ module PrometheusExporter::Metric end it "can correctly rotate quantiles" do - Process.stub(:clock_gettime, 1.0) do summary.observe(0.1) summary.observe(0.2) summary.observe(0.6) end - Process.stub(:clock_gettime, 1.0 + Summary::ROTATE_AGE + 1.0) do - summary.observe(300) - end + Process.stub(:clock_gettime, 1.0 + Summary::ROTATE_AGE + 1.0) { summary.observe(300) } Process.stub(:clock_gettime, 1.0 + (Summary::ROTATE_AGE * 2) + 1.1) do summary.observe(100) diff --git a/test/middleware_test.rb b/test/middleware_test.rb index 734a6085..72314d97 100644 --- a/test/middleware_test.rb +++ b/test/middleware_test.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -require 'minitest/stub_const' -require_relative 'test_helper' -require 'rack/test' -require 'prometheus_exporter/middleware' +require "minitest/stub_const" +require_relative "test_helper" +require "rack/test" +require "prometheus_exporter/middleware" class PrometheusExporterMiddlewareTest < Minitest::Test include Rack::Test::Methods @@ -23,9 +23,7 @@ def client end def inner_app - Proc.new do |env| - [200, {}, "OK"] - end + Proc.new { |env| [200, {}, "OK"] } end def now @@ -42,7 +40,7 @@ def @app.request_start def assert_valid_headers_response(delta = 0.5) configure_middleware - get '/' + get "/" assert last_response.ok? refute_nil client.last_send refute_nil client.last_send[:queue_time] @@ -51,7 +49,7 @@ def assert_valid_headers_response(delta = 0.5) def assert_invalid_headers_response configure_middleware - get '/' + get "/" assert last_response.ok? refute_nil client.last_send assert_nil client.last_send[:queue_time] @@ -59,34 +57,34 @@ def assert_invalid_headers_response def test_converting_apache_request_start configure_middleware - now_microsec = '1234567890123456' - header 'X-Request-Start', "t=#{now_microsec}" + now_microsec = "1234567890123456" + header "X-Request-Start", "t=#{now_microsec}" assert_valid_headers_response end def test_converting_nginx_request_start configure_middleware - now = '1234567890.123' - header 'X-Request-Start', "t=#{now}" + now = "1234567890.123" + header "X-Request-Start", "t=#{now}" assert_valid_headers_response end def test_request_start_in_wrong_format configure_middleware - header 'X-Request-Start', "" + header "X-Request-Start", "" assert_invalid_headers_response end def test_converting_amzn_trace_id_start configure_middleware - now = '1234567890' - header 'X-Amzn-Trace-Id', "Root=1-#{now.to_i.to_s(16)}-abc123" + now = "1234567890" + header "X-Amzn-Trace-Id", "Root=1-#{now.to_i.to_s(16)}-abc123" assert_valid_headers_response end def test_amzn_trace_id_in_wrong_format configure_middleware - header 'X-Amzn-Trace-Id', "" + header "X-Amzn-Trace-Id", "" assert_invalid_headers_response end @@ -180,7 +178,7 @@ def test_patch_called_with_prepend_instrument def test_patch_called_with_alias_method_instrument Object.stub_const(:Redis, Module) do # must be less than version 5 for this instrumentation - ::Redis.stub_const(:VERSION, '4.0.4') do + ::Redis.stub_const(:VERSION, "4.0.4") do ::Redis.stub_const(:Client) do mock = Minitest::Mock.new mock.expect :call, nil, [Redis::Client, Array, :redis], instrument: :alias_method diff --git a/test/server/active_record_collector_test.rb b/test/server/active_record_collector_test.rb index 94c983c9..09459930 100644 --- a/test/server/active_record_collector_test.rb +++ b/test/server/active_record_collector_test.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'mini_racer' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "mini_racer" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusActiveRecordCollectorTest < Minitest::Test include CollectorHelper @@ -22,7 +22,7 @@ def test_collecting_metrics "dead" => 10, "idle" => 20, "waiting" => 0, - "size" => 120 + "size" => 120, ) metrics = collector.metrics assert_equal 6, metrics.size @@ -40,13 +40,17 @@ def test_collecting_metrics_with_custom_labels "waiting" => 0, "size" => 120, "metric_labels" => { - "service" => "service1" - } + "service" => "service1", + }, ) metrics = collector.metrics assert_equal 6, metrics.size - assert(metrics.first.metric_text.include?('active_record_connection_pool_connections{service="service1",pid="1000",hostname="localhost"} 50')) + assert( + metrics.first.metric_text.include?( + 'active_record_connection_pool_connections{service="service1",pid="1000",hostname="localhost"} 50', + ), + ) end def test_collecting_metrics_with_client_default_labels @@ -61,16 +65,20 @@ def test_collecting_metrics_with_client_default_labels "waiting" => 0, "size" => 120, "metric_labels" => { - "service" => "service1" + "service" => "service1", }, "custom_labels" => { - "environment" => "test" - } + "environment" => "test", + }, ) metrics = collector.metrics assert_equal 6, metrics.size - assert(metrics.first.metric_text.include?('active_record_connection_pool_connections{service="service1",pid="1000",hostname="localhost",environment="test"} 50')) + assert( + metrics.first.metric_text.include?( + 'active_record_connection_pool_connections{service="service1",pid="1000",hostname="localhost",environment="test"} 50', + ), + ) end def test_collecting_metrics_for_multiple_pools @@ -85,8 +93,8 @@ def test_collecting_metrics_for_multiple_pools "waiting" => 0, "size" => 120, "metric_labels" => { - "pool_name" => "primary" - } + "pool_name" => "primary", + }, ) collector.collect( "type" => "active_record", @@ -99,22 +107,32 @@ def test_collecting_metrics_for_multiple_pools "waiting" => 0, "size" => 12, "metric_labels" => { - "pool_name" => "other" - } + "pool_name" => "other", + }, ) metrics = collector.metrics assert_equal 6, metrics.size - assert(metrics.first.metric_text.include?('active_record_connection_pool_connections{pool_name="primary",pid="1000",hostname="localhost"} 50')) - assert(metrics.first.metric_text.include?('active_record_connection_pool_connections{pool_name="other",pid="1000",hostname="localhost"} 5')) + assert( + metrics.first.metric_text.include?( + 'active_record_connection_pool_connections{pool_name="primary",pid="1000",hostname="localhost"} 50', + ), + ) + assert( + metrics.first.metric_text.include?( + 'active_record_connection_pool_connections{pool_name="other",pid="1000",hostname="localhost"} 5', + ), + ) end def test_metrics_deduplication data = { "pid" => "1000", "hostname" => "localhost", - "metric_labels" => { "pool_name" => "primary" }, - "connections" => 100 + "metric_labels" => { + "pool_name" => "primary", + }, + "connections" => 100, } collector.collect(data) @@ -128,11 +146,12 @@ def test_metrics_deduplication assert_equal 1, metrics.size assert_equal [ - 'active_record_connection_pool_connections{pool_name="primary",pid="1000",hostname="localhost"} 200', - 'active_record_connection_pool_connections{pool_name="primary",pid="2000",hostname="localhost"} 300', - 'active_record_connection_pool_connections{pool_name="primary",pid="3000",hostname="localhost"} 400', - 'active_record_connection_pool_connections{pool_name="primary",pid="2000",hostname="localhost2"} 500' - ], metrics_lines + 'active_record_connection_pool_connections{pool_name="primary",pid="1000",hostname="localhost"} 200', + 'active_record_connection_pool_connections{pool_name="primary",pid="2000",hostname="localhost"} 300', + 'active_record_connection_pool_connections{pool_name="primary",pid="3000",hostname="localhost"} 400', + 'active_record_connection_pool_connections{pool_name="primary",pid="2000",hostname="localhost2"} 500', + ], + metrics_lines end def test_metrics_expiration @@ -146,8 +165,8 @@ def test_metrics_expiration "waiting" => 0, "size" => 120, "metric_labels" => { - "pool_name" => "primary" - } + "pool_name" => "primary", + }, } stub_monotonic_clock(0) do @@ -156,8 +175,6 @@ def test_metrics_expiration assert_equal 6, collector.metrics.size end - stub_monotonic_clock(max_metric_age + 1) do - assert_equal 0, collector.metrics.size - end + stub_monotonic_clock(max_metric_age + 1) { assert_equal 0, collector.metrics.size } end end diff --git a/test/server/collector_test.rb b/test/server/collector_test.rb index f46873f4..36464610 100644 --- a/test/server/collector_test.rb +++ b/test/server/collector_test.rb @@ -1,16 +1,15 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'mini_racer' -require 'prometheus_exporter/server' -require 'prometheus_exporter/client' -require 'prometheus_exporter/instrumentation' -require 'active_record' +require_relative "../test_helper" +require "mini_racer" +require "prometheus_exporter/server" +require "prometheus_exporter/client" +require "prometheus_exporter/instrumentation" +require "active_record" class PrometheusCollectorTest < Minitest::Test - def setup - PrometheusExporter::Metric::Base.default_prefix = '' + PrometheusExporter::Metric::Base.default_prefix = "" PrometheusExporter::Metric::Base.default_aggregation = nil end @@ -32,10 +31,11 @@ def send_json(obj) class WorkerWithCustomLabels def self.custom_labels - { test_label: 'one', other_label: 'two' } + { test_label: "one", other_label: "two" } end - def perform; end + def perform + end end class WorkerWithCustomLabelsFromJob @@ -43,22 +43,30 @@ def self.custom_labels(job) { first_job_arg: job["args"].first } end - def perform; end + def perform + end end class DelayedAction - def foo; end + def foo + end end class DelayedModel < ::ActiveRecord::Base - def foo; end + def foo + end end def test_local_metric collector = PrometheusExporter::Server::Collector.new client = PrometheusExporter::LocalClient.new(collector: collector) - PrometheusExporter::Instrumentation::Process.start(client: client, labels: { hello: "custom label" }) + PrometheusExporter::Instrumentation::Process.start( + client: client, + labels: { + hello: "custom label", + }, + ) metrics_text = "" TestHelper.wait_for(2) do @@ -93,8 +101,8 @@ def test_register_metric end def test_it_can_increment_gauge_when_specified - name = 'test_name' - help = 'test_help' + name = "test_name" + help = "test_help" collector = PrometheusExporter::Server::Collector.new metric = PrometheusExporter::Metric::Gauge.new(name, help) collector.register_metric(metric) @@ -102,9 +110,11 @@ def test_it_can_increment_gauge_when_specified type: :gauge, help: help, name: name, - keys: { key1: 'test1' }, + keys: { + key1: "test1", + }, prometheus_exporter_action: :increment, - value: 1 + value: 1, }.to_json collector.process(json) @@ -119,8 +129,8 @@ def test_it_can_increment_gauge_when_specified end def test_it_can_decrement_gauge_when_specified - name = 'test_name' - help = 'test_help' + name = "test_name" + help = "test_help" collector = PrometheusExporter::Server::Collector.new metric = PrometheusExporter::Metric::Gauge.new(name, help) collector.register_metric(metric) @@ -128,9 +138,11 @@ def test_it_can_decrement_gauge_when_specified type: :gauge, help: help, name: name, - keys: { key1: 'test1' }, + keys: { + key1: "test1", + }, prometheus_exporter_action: :decrement, - value: 5 + value: 5, }.to_json collector.process(json) @@ -145,16 +157,10 @@ def test_it_can_decrement_gauge_when_specified end def test_it_can_export_summary_stats - name = 'test_name' - help = 'test_help' + name = "test_name" + help = "test_help" collector = PrometheusExporter::Server::Collector.new - json = { - type: :summary, - help: help, - name: name, - keys: { key1: 'test1' }, - value: 0.6 - }.to_json + json = { type: :summary, help: help, name: name, keys: { key1: "test1" }, value: 0.6 }.to_json collector.process(json) collector.process(json) @@ -174,16 +180,20 @@ def test_it_can_export_summary_stats end def test_it_can_pass_options_to_summary - name = 'test_name' - help = 'test_help' + name = "test_name" + help = "test_help" collector = PrometheusExporter::Server::Collector.new json = { type: :summary, help: help, name: name, - keys: { key1: 'test1' }, - opts: { quantiles: [0.75, 0.5, 0.25] }, - value: 8 + keys: { + key1: "test1", + }, + opts: { + quantiles: [0.75, 0.5, 0.25], + }, + value: 8, } collector.process(json.to_json) @@ -207,16 +217,10 @@ def test_it_can_pass_options_to_summary end def test_it_can_export_histogram_stats - name = 'test_name' - help = 'test_help' + name = "test_name" + help = "test_help" collector = PrometheusExporter::Server::Collector.new - json = { - type: :histogram, - help: help, - name: name, - keys: { key1: 'test1' }, - value: 6 - }.to_json + json = { type: :histogram, help: help, name: name, keys: { key1: "test1" }, value: 6 }.to_json collector.process(json) collector.process(json) @@ -243,16 +247,20 @@ def test_it_can_export_histogram_stats end def test_it_can_pass_options_to_histogram - name = 'test_name' - help = 'test_help' + name = "test_name" + help = "test_help" collector = PrometheusExporter::Server::Collector.new json = { type: :histogram, help: help, name: name, - keys: { key1: 'test1' }, - opts: { buckets: [5, 6, 7] }, - value: 6 + keys: { + key1: "test1", + }, + opts: { + buckets: [5, 6, 7], + }, + value: 6, }.to_json collector.process(json) @@ -282,23 +290,27 @@ def test_it_can_collect_sidekiq_metrics end begin - instrument.call(false, nil, "default") do - boom - end - rescue + instrument.call(false, nil, "default") { boom } + rescue StandardError end result = collector.prometheus_metrics_text - assert(result.include?("sidekiq_failed_jobs_total{job_name=\"FalseClass\",queue=\"default\"} 1"), "has failed job") + assert( + result.include?("sidekiq_failed_jobs_total{job_name=\"FalseClass\",queue=\"default\"} 1"), + "has failed job", + ) - assert(result.include?("sidekiq_jobs_total{job_name=\"String\",queue=\"default\"} 1"), "has working job") + assert( + result.include?("sidekiq_jobs_total{job_name=\"String\",queue=\"default\"} 1"), + "has working job", + ) assert(result.include?("sidekiq_job_duration_seconds"), "has duration") end def test_it_can_collect_sidekiq_metrics_with_custom_labels collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) instrument = PrometheusExporter::Instrumentation::Sidekiq.new(client: client) @@ -307,67 +319,129 @@ def test_it_can_collect_sidekiq_metrics_with_custom_labels end begin - instrument.call(false, nil, "default") do - boom - end - rescue + instrument.call(false, nil, "default") { boom } + rescue StandardError end active_job_worker = {} active_job_worker.stub(:class, "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper") do - instrument.call(active_job_worker, { 'wrapped' => 'WrappedClass' }, "default") do + instrument.call(active_job_worker, { "wrapped" => "WrappedClass" }, "default") do # nothing end end delayed_worker = {} delayed_worker.stub(:class, "Sidekiq::Extensions::DelayedClass") do - instrument.call(delayed_worker, { 'args' => [ "---\n- !ruby/class 'DelayedAction'\n- :foo\n- -" ] }, "default") do + instrument.call( + delayed_worker, + { "args" => ["---\n- !ruby/class 'DelayedAction'\n- :foo\n- -"] }, + "default", + ) do # nothing end end delayed_worker.stub(:class, "Sidekiq::Extensions::DelayedModel") do - instrument.call(delayed_worker, { 'args' => [ "---\n- !ruby/class 'DelayedModel'\n- :foo\n- -" ] }, "default") do + instrument.call( + delayed_worker, + { "args" => ["---\n- !ruby/class 'DelayedModel'\n- :foo\n- -"] }, + "default", + ) do # nothing end end delayed_worker.stub(:class, "Sidekiq::Extensions::DelayedClass") do - instrument.call(delayed_worker, { 'args' => [ 1 ] }, "default") do + instrument.call(delayed_worker, { "args" => [1] }, "default") do # nothing end end result = collector.prometheus_metrics_text - assert(result.include?('sidekiq_failed_jobs_total{job_name="FalseClass",queue="default",service="service1"} 1'), "has failed job") - assert(result.include?('sidekiq_jobs_total{job_name="String",queue="default",service="service1"} 1'), "has working job") - assert(result.include?('sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.99"}'), "has duration quantile 0.99") - assert(result.include?('sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.9"}'), "has duration quantile 0.9") - assert(result.include?('sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.5"}'), "has duration quantile 0.5") - assert(result.include?('sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.1"}'), "has duration quantile 0.1") - assert(result.include?('sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.01"}'), "has duration quantile 0.01") - assert(result.include?('sidekiq_jobs_total{job_name="WrappedClass",queue="default",service="service1"} 1'), "has sidekiq working job from ActiveJob") - assert(result.include?('sidekiq_jobs_total{job_name="DelayedAction#foo",queue="default",service="service1"} 1'), "has sidekiq delayed class") - assert(result.include?('sidekiq_jobs_total{job_name="DelayedModel#foo",queue="default",service="service1"} 1'), "has sidekiq delayed class") - assert(result.include?('sidekiq_jobs_total{job_name="Sidekiq::Extensions::DelayedClass",queue="default",service="service1"} 1'), "has sidekiq delayed class") + assert( + result.include?( + 'sidekiq_failed_jobs_total{job_name="FalseClass",queue="default",service="service1"} 1', + ), + "has failed job", + ) + assert( + result.include?('sidekiq_jobs_total{job_name="String",queue="default",service="service1"} 1'), + "has working job", + ) + assert( + result.include?( + 'sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.99"}', + ), + "has duration quantile 0.99", + ) + assert( + result.include?( + 'sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.9"}', + ), + "has duration quantile 0.9", + ) + assert( + result.include?( + 'sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.5"}', + ), + "has duration quantile 0.5", + ) + assert( + result.include?( + 'sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.1"}', + ), + "has duration quantile 0.1", + ) + assert( + result.include?( + 'sidekiq_job_duration_seconds{job_name="FalseClass",queue="default",service="service1",quantile="0.01"}', + ), + "has duration quantile 0.01", + ) + assert( + result.include?( + 'sidekiq_jobs_total{job_name="WrappedClass",queue="default",service="service1"} 1', + ), + "has sidekiq working job from ActiveJob", + ) + assert( + result.include?( + 'sidekiq_jobs_total{job_name="DelayedAction#foo",queue="default",service="service1"} 1', + ), + "has sidekiq delayed class", + ) + assert( + result.include?( + 'sidekiq_jobs_total{job_name="DelayedModel#foo",queue="default",service="service1"} 1', + ), + "has sidekiq delayed class", + ) + assert( + result.include?( + 'sidekiq_jobs_total{job_name="Sidekiq::Extensions::DelayedClass",queue="default",service="service1"} 1', + ), + "has sidekiq delayed class", + ) end def test_it_can_collect_sidekiq_metrics_with_custom_labels_from_worker_class - worker_class = 'WorkerWithCustomLabels' - msg = { 'wrapped' => worker_class } + worker_class = "WorkerWithCustomLabels" + msg = { "wrapped" => worker_class } queue = "default" client = Minitest::Mock.new - client.expect(:send_json, '', [], + client.expect( + :send_json, + "", + [], type: "sidekiq", name: "PrometheusCollectorTest::#{worker_class}", queue: queue, success: true, shutdown: false, duration: 0, - custom_labels: WorkerWithCustomLabels.custom_labels + custom_labels: WorkerWithCustomLabels.custom_labels, ) ::Process.stub(:clock_gettime, 1, ::Process::CLOCK_MONOTONIC) do @@ -381,19 +455,24 @@ def test_it_can_collect_sidekiq_metrics_with_custom_labels_from_worker_class end def test_it_can_collect_sidekiq_metrics_with_custom_labels_from_job - worker_class = 'WorkerWithCustomLabelsFromJob' - msg = { 'wrapped' => worker_class, 'args' => ['arg_one'] } + worker_class = "WorkerWithCustomLabelsFromJob" + msg = { "wrapped" => worker_class, "args" => ["arg_one"] } queue = "default" client = Minitest::Mock.new - client.expect(:send_json, '', [], + client.expect( + :send_json, + "", + [], type: "sidekiq", name: "PrometheusCollectorTest::#{worker_class}", queue: queue, success: true, shutdown: false, duration: 0, - custom_labels: { first_job_arg: 'arg_one' } + custom_labels: { + first_job_arg: "arg_one", + }, ) ::Process.stub(:clock_gettime, 1, ::Process::CLOCK_MONOTONIC) do @@ -407,25 +486,29 @@ def test_it_can_collect_sidekiq_metrics_with_custom_labels_from_job end def test_it_can_collect_sidekiq_metrics_on_job_death - job = { - "dead" => true, - "retry" => true, - "class" => "TestWorker" - } + job = { "dead" => true, "retry" => true, "class" => "TestWorker" } worker = Minitest::Mock.new client = Minitest::Mock.new - client.expect(:send_json, '', [], + custom_labels = {} + + client.expect( + :send_json, + "", + [], type: "sidekiq", name: job["class"], dead: true, - custom_labels: {} + custom_labels: custom_labels, ) - Object.stub(:const_get, worker, [job['class']]) do + Object.stub(:const_get, worker, [job["class"]]) do PrometheusExporter::Client.stub(:default, client) do - PrometheusExporter::Instrumentation::Sidekiq.death_handler.call(job, RuntimeError.new('bang')) + PrometheusExporter::Instrumentation::Sidekiq.death_handler.call( + job, + RuntimeError.new("bang"), + ) end end @@ -438,22 +521,29 @@ def test_it_can_collect_sidekiq_metrics_on_job_death_for_delayed "dead" => true, "retry" => true, "class" => "Sidekiq::Extensions::DelayedClass", - "args" => [ "---\n- !ruby/class 'DelayedAction'\n- :foo\n- -" ] + "args" => ["---\n- !ruby/class 'DelayedAction'\n- :foo\n- -"], } worker = Minitest::Mock.new client = Minitest::Mock.new - client.expect(:send_json, '', [], + custom_labels = {} + client.expect( + :send_json, + "", + [], type: "sidekiq", name: "DelayedAction#foo", dead: true, - custom_labels: {} + custom_labels: custom_labels, ) - Object.stub(:const_get, worker, [job['class']]) do + Object.stub(:const_get, worker, [job["class"]]) do PrometheusExporter::Client.stub(:default, client) do - PrometheusExporter::Instrumentation::Sidekiq.death_handler.call(job, RuntimeError.new('bang')) + PrometheusExporter::Instrumentation::Sidekiq.death_handler.call( + job, + RuntimeError.new("bang"), + ) end end @@ -462,23 +552,25 @@ def test_it_can_collect_sidekiq_metrics_on_job_death_for_delayed end def test_it_can_collect_sidekiq_metrics_on_job_death_with_custom_labels_from_worker_class - job = { - "dead" => true, - "retry" => true, - "class" => "WorkerWithCustomLabels" - } + job = { "dead" => true, "retry" => true, "class" => "WorkerWithCustomLabels" } client = Minitest::Mock.new - client.expect(:send_json, '', [], + client.expect( + :send_json, + "", + [], type: "sidekiq", name: job["class"], dead: true, - custom_labels: WorkerWithCustomLabels.custom_labels + custom_labels: WorkerWithCustomLabels.custom_labels, ) - Object.stub(:const_get, WorkerWithCustomLabels, [job['class']]) do + Object.stub(:const_get, WorkerWithCustomLabels, [job["class"]]) do PrometheusExporter::Client.stub(:default, client) do - PrometheusExporter::Instrumentation::Sidekiq.death_handler.call(job, RuntimeError.new('bang')) + PrometheusExporter::Instrumentation::Sidekiq.death_handler.call( + job, + RuntimeError.new("bang"), + ) end end @@ -486,39 +578,39 @@ def test_it_can_collect_sidekiq_metrics_on_job_death_with_custom_labels_from_wor end def test_it_does_not_collect_sidekiq_metrics_on_fire_forget_job_death - job = { - "dead" => false, - "retry" => false, - "class" => "WorkerWithCustomLabels" - } + job = { "dead" => false, "retry" => false, "class" => "WorkerWithCustomLabels" } client = Minitest::Mock.new - Object.stub(:const_get, WorkerWithCustomLabels, [job['class']]) do + Object.stub(:const_get, WorkerWithCustomLabels, [job["class"]]) do PrometheusExporter::Client.stub(:default, client) do - PrometheusExporter::Instrumentation::Sidekiq.death_handler.call(job, RuntimeError.new('bang')) + PrometheusExporter::Instrumentation::Sidekiq.death_handler.call( + job, + RuntimeError.new("bang"), + ) end end end def test_it_can_collect_sidekiq_queue_metrics_for_all_queues collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) instrument = PrometheusExporter::Instrumentation::SidekiqQueue.new(all_queues: true) - mocks_for_sidekiq_que_all = 2.times.map do |i| - mock = Minitest::Mock.new - mock.expect(:name, "que_#{i}") - mock.expect(:size, 10 + i) - mock.expect(:latency, 1.to_f + i) - end + mocks_for_sidekiq_que_all = + 2.times.map do |i| + mock = Minitest::Mock.new + mock.expect(:name, "que_#{i}") + mock.expect(:size, 10 + i) + mock.expect(:latency, 1.to_f + i) + end mock_sidekiq_que = Minitest::Mock.new mock_sidekiq_que.expect(:all, mocks_for_sidekiq_que_all) Object.stub_const(:Sidekiq, Module) do ::Sidekiq.stub_const(:Queue, mock_sidekiq_que) do - instrument.stub(:collect_current_process_queues, ["que_0", "que_1"]) do + instrument.stub(:collect_current_process_queues, %w[que_0 que_1]) do metric = instrument.collect client.send_json metric end @@ -526,26 +618,39 @@ def test_it_can_collect_sidekiq_queue_metrics_for_all_queues end result = collector.prometheus_metrics_text - assert(result.include?('sidekiq_queue_backlog{queue="que_0",service="service1"} 10'), "has number of backlog") - assert(result.include?('sidekiq_queue_backlog{queue="que_1",service="service1"} 11'), "has number of backlog") - assert(result.include?('sidekiq_queue_latency_seconds{queue="que_0",service="service1"} 1'), "has latency") - assert(result.include?('sidekiq_queue_latency_seconds{queue="que_1",service="service1"} 2'), "has latency") + assert( + result.include?('sidekiq_queue_backlog{queue="que_0",service="service1"} 10'), + "has number of backlog", + ) + assert( + result.include?('sidekiq_queue_backlog{queue="que_1",service="service1"} 11'), + "has number of backlog", + ) + assert( + result.include?('sidekiq_queue_latency_seconds{queue="que_0",service="service1"} 1'), + "has latency", + ) + assert( + result.include?('sidekiq_queue_latency_seconds{queue="que_1",service="service1"} 2'), + "has latency", + ) mocks_for_sidekiq_que_all.each(&:verify) mock_sidekiq_que.verify end def test_it_can_collect_sidekiq_queue_metrics_for_own_queues collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) instrument = PrometheusExporter::Instrumentation::SidekiqQueue.new(all_queues: false) - mocks_for_sidekiq_que_all = 2.times.map do |i| - mock = Minitest::Mock.new - mock.expect(:name, "que_#{i}") - mock.expect(:size, 10 + i) - mock.expect(:latency, 1.to_f + i) - mock.expect(:name, "que_#{i}") - end + mocks_for_sidekiq_que_all = + 2.times.map do |i| + mock = Minitest::Mock.new + mock.expect(:name, "que_#{i}") + mock.expect(:size, 10 + i) + mock.expect(:latency, 1.to_f + i) + mock.expect(:name, "que_#{i}") + end mock_sidekiq_que = Minitest::Mock.new mock_sidekiq_que.expect(:all, mocks_for_sidekiq_que_all) @@ -560,35 +665,47 @@ def test_it_can_collect_sidekiq_queue_metrics_for_own_queues end result = collector.prometheus_metrics_text - assert(result.include?('sidekiq_queue_backlog{queue="que_0",service="service1"} 10'), "has number of backlog") - refute(result.include?('sidekiq_queue_backlog{queue="que_1",service="service1"} 11'), "has number of backlog") - assert(result.include?('sidekiq_queue_latency_seconds{queue="que_0",service="service1"} 1'), "has latency") - refute(result.include?('sidekiq_queue_latency_seconds{queue="que_1",service="service1"} 2'), "has latency") + assert( + result.include?('sidekiq_queue_backlog{queue="que_0",service="service1"} 10'), + "has number of backlog", + ) + refute( + result.include?('sidekiq_queue_backlog{queue="que_1",service="service1"} 11'), + "has number of backlog", + ) + assert( + result.include?('sidekiq_queue_latency_seconds{queue="que_0",service="service1"} 1'), + "has latency", + ) + refute( + result.include?('sidekiq_queue_latency_seconds{queue="que_1",service="service1"} 2'), + "has latency", + ) mocks_for_sidekiq_que_all.each(&:verify) mock_sidekiq_que.verify end def test_it_can_collect_sidekiq_process_metrics collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) instrument = PrometheusExporter::Instrumentation::SidekiqProcess.new mock_sidekiq_process = Minitest::Mock.new mock_sidekiq_process.expect( :new, - 2.times.map { |i| + 2.times.map do |i| { - 'busy' => 1, - 'concurrency' => 2, - 'hostname' => PrometheusExporter.hostname, - 'identity' => "hostname:#{i}", - 'labels' => ['lab_2', 'lab_1'], - 'pid' => Process.pid + i, - 'queues' => ['queue_2', 'queue_1'], - 'quiet' => false, - 'tag' => 'default' + "busy" => 1, + "concurrency" => 2, + "hostname" => PrometheusExporter.hostname, + "identity" => "hostname:#{i}", + "labels" => %w[lab_2 lab_1], + "pid" => Process.pid + i, + "queues" => %w[queue_2 queue_1], + "quiet" => false, + "tag" => "default", } - } + end, ) Object.stub_const(:Sidekiq, Module) do @@ -599,14 +716,24 @@ def test_it_can_collect_sidekiq_process_metrics end result = collector.prometheus_metrics_text - assert(result.include?(%Q[sidekiq_process_busy{labels="lab_1,lab_2",queues="queue_1,queue_2",quiet="false",tag="default",hostname="#{PrometheusExporter.hostname}",identity="hostname:0"} 1]), "has number of busy") - assert(result.include?(%Q[sidekiq_process_concurrency{labels="lab_1,lab_2",queues="queue_1,queue_2",quiet="false",tag="default",hostname="#{PrometheusExporter.hostname}",identity="hostname:0"} 2]), "has number of concurrency") + assert( + result.include?( + %Q[sidekiq_process_busy{labels="lab_1,lab_2",queues="queue_1,queue_2",quiet="false",tag="default",hostname="#{PrometheusExporter.hostname}",identity="hostname:0"} 1], + ), + "has number of busy", + ) + assert( + result.include?( + %Q[sidekiq_process_concurrency{labels="lab_1,lab_2",queues="queue_1,queue_2",quiet="false",tag="default",hostname="#{PrometheusExporter.hostname}",identity="hostname:0"} 2], + ), + "has number of concurrency", + ) mock_sidekiq_process.verify end def test_it_can_collect_sidekiq_stats_metrics collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) instrument = PrometheusExporter::Instrumentation::SidekiqStats.new mock_sidekiq_stats_new = Minitest::Mock.new @@ -654,10 +781,8 @@ def test_it_can_collect_sidekiq_metrics_in_histogram_mode end begin - instrument.call(false, nil, "default") do - boom - end - rescue + instrument.call(false, nil, "default") { boom } + rescue StandardError end result = collector.prometheus_metrics_text @@ -667,29 +792,41 @@ def test_it_can_collect_sidekiq_metrics_in_histogram_mode def test_it_can_collect_shoryuken_metrics_with_custom_lables collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) instrument = PrometheusExporter::Instrumentation::Shoryuken.new(client: client) - instrument.call("hello", nil, "default", "body") do - end + instrument.call("hello", nil, "default", "body") {} begin - instrument.call(false, nil, "default", "body") do - boom - end - rescue + instrument.call(false, nil, "default", "body") { boom } + rescue StandardError end result = collector.prometheus_metrics_text - assert(result.include?("shoryuken_failed_jobs_total{job_name=\"FalseClass\",queue_name=\"\",service=\"service1\"} 1"), "has failed job") - assert(result.include?("shoryuken_jobs_total{job_name=\"String\",queue_name=\"\",service=\"service1\"} 1"), "has working job") - assert(result.include?("shoryuken_job_duration_seconds{job_name=\"String\",queue_name=\"\",service=\"service1\"} "), "has duration") + assert( + result.include?( + "shoryuken_failed_jobs_total{job_name=\"FalseClass\",queue_name=\"\",service=\"service1\"} 1", + ), + "has failed job", + ) + assert( + result.include?( + "shoryuken_jobs_total{job_name=\"String\",queue_name=\"\",service=\"service1\"} 1", + ), + "has working job", + ) + assert( + result.include?( + "shoryuken_job_duration_seconds{job_name=\"String\",queue_name=\"\",service=\"service1\"} ", + ), + "has duration", + ) end def test_it_merges_custom_labels_for_generic_metrics - name = 'test_name' - help = 'test_help' + name = "test_name" + help = "test_help" collector = PrometheusExporter::Server::Collector.new metric = PrometheusExporter::Metric::Gauge.new(name, help) collector.register_metric(metric) @@ -697,9 +834,13 @@ def test_it_merges_custom_labels_for_generic_metrics type: :gauge, help: help, name: name, - custom_labels: { host: "example.com" }, - keys: { key1: 'test1' }, - value: 5 + custom_labels: { + host: "example.com", + }, + keys: { + key1: "test1", + }, + value: 5, }.to_json collector.process(json) @@ -727,7 +868,8 @@ def test_it_can_collect_process_metrics text = collector.prometheus_metrics_text - v8_str = "v8_heap_count{type=\"web\",pid=\"#{collected[:pid]}\",hostname=\"#{PrometheusExporter.hostname}\"} #{collected[:v8_heap_count]}" + v8_str = + "v8_heap_count{type=\"web\",pid=\"#{collected[:pid]}\",hostname=\"#{PrometheusExporter.hostname}\"} #{collected[:v8_heap_count]}" assert(text.include?(v8_str), "must include v8 metric") assert(text.include?("minor_gc_ops_total"), "must include counters") @@ -759,19 +901,38 @@ def test_it_can_collect_delayed_job_metrics failed_job.expect(:run_at, 30.seconds.ago) begin - instrument.call(failed_job, 25, 10, 0, false, nil, "default") do - boom - end - rescue + instrument.call(failed_job, 25, 10, 0, false, nil, "default") { boom } + rescue StandardError end result = collector.prometheus_metrics_text - assert(result.include?("delayed_failed_jobs_total{queue_name=\"my_queue\",job_name=\"Object\"} 1"), "has failed job") - assert(result.include?("delayed_jobs_total{queue_name=\"my_queue\",job_name=\"SomeModule::Class\"} 1"), "has working job") - assert(result.include?("delayed_job_duration_seconds{queue_name=\"my_queue\",job_name=\"SomeModule::Class\"}"), "has duration") - assert(result.include?("delayed_job_latency_seconds_total{queue_name=\"my_queue\",job_name=\"SomeModule::Class\"}"), "has latency") - assert(result.include?("delayed_jobs_enqueued{queue_name=\"my_queue\"} 10"), "has enqueued count") + assert( + result.include?("delayed_failed_jobs_total{queue_name=\"my_queue\",job_name=\"Object\"} 1"), + "has failed job", + ) + assert( + result.include?( + "delayed_jobs_total{queue_name=\"my_queue\",job_name=\"SomeModule::Class\"} 1", + ), + "has working job", + ) + assert( + result.include?( + "delayed_job_duration_seconds{queue_name=\"my_queue\",job_name=\"SomeModule::Class\"}", + ), + "has duration", + ) + assert( + result.include?( + "delayed_job_latency_seconds_total{queue_name=\"my_queue\",job_name=\"SomeModule::Class\"}", + ), + "has latency", + ) + assert( + result.include?("delayed_jobs_enqueued{queue_name=\"my_queue\"} 10"), + "has enqueued count", + ) assert(result.include?("delayed_jobs_pending{queue_name=\"my_queue\"} 0"), "has pending count") job.verify failed_job.verify @@ -779,7 +940,7 @@ def test_it_can_collect_delayed_job_metrics def test_it_can_collect_delayed_job_metrics_with_custom_labels collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) instrument = PrometheusExporter::Instrumentation::DelayedJob.new(client: client) @@ -802,20 +963,44 @@ def test_it_can_collect_delayed_job_metrics_with_custom_labels failed_job.expect(:run_at, 30.seconds.ago) begin - instrument.call(failed_job, 25, 10, 0, false, nil, "default") do - boom - end - rescue + instrument.call(failed_job, 25, 10, 0, false, nil, "default") { boom } + rescue StandardError end result = collector.prometheus_metrics_text - assert(result.include?('delayed_failed_jobs_total{queue_name="my_queue",service="service1",job_name="Object"} 1'), "has failed job") - assert(result.include?('delayed_jobs_total{queue_name="my_queue",service="service1",job_name="Class"} 1'), "has working job") - assert(result.include?('delayed_job_duration_seconds{queue_name="my_queue",service="service1",job_name="Class"}'), "has duration") - assert(result.include?('delayed_job_latency_seconds_total{queue_name="my_queue",service="service1",job_name="Class"} 10.0'), "has latency") - assert(result.include?('delayed_jobs_enqueued{queue_name="my_queue",service="service1"} 10'), "has enqueued count") - assert(result.include?('delayed_jobs_pending{queue_name="my_queue",service="service1"} 0'), "has pending count") + assert( + result.include?( + 'delayed_failed_jobs_total{queue_name="my_queue",service="service1",job_name="Object"} 1', + ), + "has failed job", + ) + assert( + result.include?( + 'delayed_jobs_total{queue_name="my_queue",service="service1",job_name="Class"} 1', + ), + "has working job", + ) + assert( + result.include?( + 'delayed_job_duration_seconds{queue_name="my_queue",service="service1",job_name="Class"}', + ), + "has duration", + ) + assert( + result.include?( + 'delayed_job_latency_seconds_total{queue_name="my_queue",service="service1",job_name="Class"} 10.0', + ), + "has latency", + ) + assert( + result.include?('delayed_jobs_enqueued{queue_name="my_queue",service="service1"} 10'), + "has enqueued count", + ) + assert( + result.include?('delayed_jobs_pending{queue_name="my_queue",service="service1"} 0'), + "has pending count", + ) job.verify failed_job.verify end @@ -844,16 +1029,16 @@ def test_it_can_collect_delayed_job_metrics_in_histogram_mode job.verify end - require 'minitest/stub_const' + require "minitest/stub_const" def test_it_can_collect_puma_metrics collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) mock_puma = Minitest::Mock.new mock_puma.expect( :stats, - '{ "workers": 1, "phase": 0, "booted_workers": 1, "old_workers": 0, "worker_status": [{ "pid": 87819, "index": 0, "phase": 0, "booted": true, "last_checkin": "2018-10-16T11:50:31Z", "last_status": { "backlog":0, "running":8, "pool_capacity":32, "max_threads": 32 } }] }' + '{ "workers": 1, "phase": 0, "booted_workers": 1, "old_workers": 0, "worker_status": [{ "pid": 87819, "index": 0, "phase": 0, "booted": true, "last_checkin": "2018-10-16T11:50:31Z", "last_status": { "backlog":0, "running":8, "pool_capacity":32, "max_threads": 32 } }] }', ) instrument = PrometheusExporter::Instrumentation::Puma.new @@ -864,23 +1049,32 @@ def test_it_can_collect_puma_metrics end result = collector.prometheus_metrics_text - assert(result.include?('puma_booted_workers{phase="0",service="service1"} 1'), "has booted workers") - assert(result.include?('puma_request_backlog{phase="0",service="service1"} 0'), "has total backlog") - assert(result.include?('puma_thread_pool_capacity{phase="0",service="service1"} 32'), "has pool capacity") + assert( + result.include?('puma_booted_workers{phase="0",service="service1"} 1'), + "has booted workers", + ) + assert( + result.include?('puma_request_backlog{phase="0",service="service1"} 0'), + "has total backlog", + ) + assert( + result.include?('puma_thread_pool_capacity{phase="0",service="service1"} 32'), + "has pool capacity", + ) mock_puma.verify end def test_it_can_collect_puma_metrics_with_metric_labels collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) mock_puma = Minitest::Mock.new mock_puma.expect( :stats, - '{ "workers": 1, "phase": 0, "booted_workers": 1, "old_workers": 0, "worker_status": [{ "pid": 87819, "index": 0, "phase": 0, "booted": true, "last_checkin": "2018-10-16T11:50:31Z", "last_status": { "backlog":0, "running":8, "pool_capacity":32, "max_threads": 32 } }] }' + '{ "workers": 1, "phase": 0, "booted_workers": 1, "old_workers": 0, "worker_status": [{ "pid": 87819, "index": 0, "phase": 0, "booted": true, "last_checkin": "2018-10-16T11:50:31Z", "last_status": { "backlog":0, "running":8, "pool_capacity":32, "max_threads": 32 } }] }', ) - instrument = PrometheusExporter::Instrumentation::Puma.new({ foo: 'bar' }) + instrument = PrometheusExporter::Instrumentation::Puma.new({ foo: "bar" }) Object.stub_const(:Puma, mock_puma) do metric = instrument.collect @@ -888,20 +1082,29 @@ def test_it_can_collect_puma_metrics_with_metric_labels end result = collector.prometheus_metrics_text - assert(result.include?('puma_booted_workers{phase="0",service="service1",foo="bar"} 1'), "has booted workers") - assert(result.include?('puma_request_backlog{phase="0",service="service1",foo="bar"} 0'), "has total backlog") - assert(result.include?('puma_thread_pool_capacity{phase="0",service="service1",foo="bar"} 32'), "has pool capacity") + assert( + result.include?('puma_booted_workers{phase="0",service="service1",foo="bar"} 1'), + "has booted workers", + ) + assert( + result.include?('puma_request_backlog{phase="0",service="service1",foo="bar"} 0'), + "has total backlog", + ) + assert( + result.include?('puma_thread_pool_capacity{phase="0",service="service1",foo="bar"} 32'), + "has pool capacity", + ) mock_puma.verify end def test_it_can_collect_resque_metrics collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) mock_resque = Minitest::Mock.new mock_resque.expect( :info, - { processed: 12, failed: 2, pending: 42, queues: 2, workers: 1, working: 1 } + { processed: 12, failed: 2, pending: 42, queues: 2, workers: 1, working: 1 }, ) instrument = PrometheusExporter::Instrumentation::Resque.new @@ -920,16 +1123,17 @@ def test_it_can_collect_resque_metrics def test_it_can_collect_unicorn_metrics collector = PrometheusExporter::Server::Collector.new - client = PipedClient.new(collector, custom_labels: { service: 'service1' }) + client = PipedClient.new(collector, custom_labels: { service: "service1" }) mock_unicorn_listener_address_stats = Minitest::Mock.new mock_unicorn_listener_address_stats.expect(:active, 2) mock_unicorn_listener_address_stats.expect(:queued, 10) - instrument = PrometheusExporter::Instrumentation::Unicorn.new( - pid_file: "/tmp/foo.pid", - listener_address: "localhost:22222", - ) + instrument = + PrometheusExporter::Instrumentation::Unicorn.new( + pid_file: "/tmp/foo.pid", + listener_address: "localhost:22222", + ) instrument.stub(:worker_process_count, 4) do instrument.stub(:listener_address_stats, mock_unicorn_listener_address_stats) do @@ -940,8 +1144,14 @@ def test_it_can_collect_unicorn_metrics result = collector.prometheus_metrics_text assert(result.include?('unicorn_workers{service="service1"} 4'), "has the number of workers") - assert(result.include?('unicorn_active_workers{service="service1"} 2'), "has number of active workers") - assert(result.include?('unicorn_request_backlog{service="service1"} 10'), "has number of request baklogs") + assert( + result.include?('unicorn_active_workers{service="service1"} 2'), + "has number of active workers", + ) + assert( + result.include?('unicorn_request_backlog{service="service1"} 10'), + "has number of request baklogs", + ) mock_unicorn_listener_address_stats.verify end end diff --git a/test/server/good_job_collector_test.rb b/test/server/good_job_collector_test.rb index 1bf7d0aa..6ee4dcf1 100644 --- a/test/server/good_job_collector_test.rb +++ b/test/server/good_job_collector_test.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusGoodJobCollectorTest < Minitest::Test include CollectorHelper @@ -20,8 +20,8 @@ def test_collecting_metrics "running" => 5, "finished" => 100, "succeeded" => 2000, - "discarded" => 9 - } + "discarded" => 9, + }, ) metrics = collector.metrics @@ -33,7 +33,7 @@ def test_collecting_metrics "good_job_running 5", "good_job_finished 100", "good_job_succeeded 2000", - "good_job_discarded 9" + "good_job_discarded 9", ] assert_equal expected, metrics.map(&:metric_text) end @@ -48,9 +48,9 @@ def test_collecting_metrics_with_custom_labels "finished" => 100, "succeeded" => 2000, "discarded" => 9, - 'custom_labels' => { - 'hostname' => 'good_job_host' - } + "custom_labels" => { + "hostname" => "good_job_host", + }, ) metrics = collector.metrics @@ -59,20 +59,13 @@ def test_collecting_metrics_with_custom_labels end def test_metrics_expiration - data = { - "type" => "good_job", - "scheduled" => 3, - "retried" => 4, - "queued" => 0 - } + data = { "type" => "good_job", "scheduled" => 3, "retried" => 4, "queued" => 0 } stub_monotonic_clock(0) do collector.collect(data) assert_equal 3, collector.metrics.size end - stub_monotonic_clock(max_metric_age + 1) do - assert_equal 0, collector.metrics.size - end + stub_monotonic_clock(max_metric_age + 1) { assert_equal 0, collector.metrics.size } end end diff --git a/test/server/metrics_container_test.rb b/test/server/metrics_container_test.rb index 46ab1662..b67469f2 100644 --- a/test/server/metrics_container_test.rb +++ b/test/server/metrics_container_test.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' -require 'prometheus_exporter/server/metrics_container' +require_relative "../test_helper" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" +require "prometheus_exporter/server/metrics_container" class PrometheusMetricsContainerTest < Minitest::Test def metrics @@ -20,7 +20,7 @@ def test_container_with_expiration stub_monotonic_clock(61.0) do metrics << { key: "value2" } assert_equal 2, metrics.size - assert_equal ["value", "value2"], metrics.map { |v| v[:key] } + assert_equal %w[value value2], metrics.map { |v| v[:key] } assert_equal 61.0, metrics[0]["_expire_at"] assert_equal 121.0, metrics[1]["_expire_at"] end @@ -28,7 +28,7 @@ def test_container_with_expiration stub_monotonic_clock(62.0) do metrics << { key: "value3" } assert_equal 2, metrics.size - assert_equal ["value2", "value3"], metrics.map { |v| v[:key] } + assert_equal %w[value2 value3], metrics.map { |v| v[:key] } assert_equal 121.0, metrics[0]["_expire_at"] assert_equal 122.0, metrics[1]["_expire_at"] end @@ -45,9 +45,7 @@ def test_container_with_expiration end def test_container_with_filter - metrics.filter = -> (new_metric, old_metric) do - new_metric[:hostname] == old_metric[:hostname] - end + metrics.filter = ->(new_metric, old_metric) { new_metric[:hostname] == old_metric[:hostname] } stub_monotonic_clock(1.0) do metrics << { hostname: "host1", value: 100 } diff --git a/test/server/process_collector_test.rb b/test/server/process_collector_test.rb index 1a6aa640..db4732aa 100644 --- a/test/server/process_collector_test.rb +++ b/test/server/process_collector_test.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'mini_racer' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "mini_racer" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class ProcessCollectorTest < Minitest::Test include CollectorHelper @@ -26,7 +26,7 @@ def base_data "rss" => 3000, "major_gc_ops_total" => 4000, "minor_gc_ops_total" => 4001, - "allocated_objects_total" => 4002 + "allocated_objects_total" => 4002, } end @@ -35,17 +35,18 @@ def test_metrics_collection assert_equal 10, collector.metrics.size assert_equal [ - 'heap_free_slots{pid="1000",hostname="localhost"} 1000', - 'heap_live_slots{pid="1000",hostname="localhost"} 1001', - 'v8_heap_size{pid="1000",hostname="localhost"} 2000', - 'v8_used_heap_size{pid="1000",hostname="localhost"} 2001', - 'v8_physical_size{pid="1000",hostname="localhost"} 2003', - 'v8_heap_count{pid="1000",hostname="localhost"} 2004', - 'rss{pid="1000",hostname="localhost"} 3000', - 'major_gc_ops_total{pid="1000",hostname="localhost"} 4000', - 'minor_gc_ops_total{pid="1000",hostname="localhost"} 4001', - 'allocated_objects_total{pid="1000",hostname="localhost"} 4002' - ], collector_metric_lines + 'heap_free_slots{pid="1000",hostname="localhost"} 1000', + 'heap_live_slots{pid="1000",hostname="localhost"} 1001', + 'v8_heap_size{pid="1000",hostname="localhost"} 2000', + 'v8_used_heap_size{pid="1000",hostname="localhost"} 2001', + 'v8_physical_size{pid="1000",hostname="localhost"} 2003', + 'v8_heap_count{pid="1000",hostname="localhost"} 2004', + 'rss{pid="1000",hostname="localhost"} 3000', + 'major_gc_ops_total{pid="1000",hostname="localhost"} 4000', + 'minor_gc_ops_total{pid="1000",hostname="localhost"} 4001', + 'allocated_objects_total{pid="1000",hostname="localhost"} 4002', + ], + collector_metric_lines end def test_metrics_deduplication @@ -68,8 +69,6 @@ def test_metrics_expiration assert_equal 10, collector.metrics.size end - stub_monotonic_clock(max_metric_age + 1) do - assert_equal 0, collector.metrics.size - end + stub_monotonic_clock(max_metric_age + 1) { assert_equal 0, collector.metrics.size } end end diff --git a/test/server/puma_collector_test.rb b/test/server/puma_collector_test.rb index d6c6d3ac..4591254f 100644 --- a/test/server/puma_collector_test.rb +++ b/test/server/puma_collector_test.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'mini_racer' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "mini_racer" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusPumaCollectorTest < Minitest::Test include CollectorHelper @@ -24,7 +24,7 @@ def test_collecting_metrics_for_different_hosts_without_custom_labels "request_backlog" => 0, "running_threads" => 4, "thread_pool_capacity" => 10, - "max_threads" => 10 + "max_threads" => 10, ) collector.collect( @@ -38,7 +38,7 @@ def test_collecting_metrics_for_different_hosts_without_custom_labels "request_backlog" => 1, "running_threads" => 9, "thread_pool_capacity" => 10, - "max_threads" => 10 + "max_threads" => 10, ) # overwriting previous metrics from first host @@ -53,13 +53,12 @@ def test_collecting_metrics_for_different_hosts_without_custom_labels "request_backlog" => 2, "running_threads" => 8, "thread_pool_capacity" => 10, - "max_threads" => 10 + "max_threads" => 10, ) metrics = collector.metrics assert_equal 7, metrics.size - assert_equal "puma_workers{phase=\"0\"} 3", - metrics.first.metric_text + assert_equal "puma_workers{phase=\"0\"} 3", metrics.first.metric_text end def test_collecting_metrics_for_different_hosts_with_custom_labels @@ -76,8 +75,8 @@ def test_collecting_metrics_for_different_hosts_with_custom_labels "thread_pool_capacity" => 10, "max_threads" => 10, "custom_labels" => { - "hostname" => "test1.example.com" - } + "hostname" => "test1.example.com", + }, ) collector.collect( @@ -93,8 +92,8 @@ def test_collecting_metrics_for_different_hosts_with_custom_labels "thread_pool_capacity" => 10, "max_threads" => 10, "custom_labels" => { - "hostname" => "test2.example.com" - } + "hostname" => "test2.example.com", + }, ) # overwriting previous metrics from first host @@ -111,14 +110,14 @@ def test_collecting_metrics_for_different_hosts_with_custom_labels "thread_pool_capacity" => 10, "max_threads" => 10, "custom_labels" => { - "hostname" => "test1.example.com" - } + "hostname" => "test1.example.com", + }, ) metrics = collector.metrics assert_equal 7, metrics.size assert_equal "puma_workers{phase=\"0\",hostname=\"test2.example.com\"} 4\n" \ - "puma_workers{phase=\"0\",hostname=\"test1.example.com\"} 3", + "puma_workers{phase=\"0\",hostname=\"test1.example.com\"} 3", metrics.first.metric_text end end diff --git a/test/server/resque_collector_test.rb b/test/server/resque_collector_test.rb index 44cc4d72..8f2faf86 100644 --- a/test/server/resque_collector_test.rb +++ b/test/server/resque_collector_test.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusResqueCollectorTest < Minitest::Test include CollectorHelper @@ -12,31 +12,23 @@ def collector end def test_collecting_metrics - collector.collect( - 'pending_jobs' => 4, - 'processed_jobs' => 7, - 'failed_jobs' => 1 - ) + collector.collect("pending_jobs" => 4, "processed_jobs" => 7, "failed_jobs" => 1) metrics = collector.metrics - expected = [ - 'resque_processed_jobs 7', - 'resque_failed_jobs 1', - 'resque_pending_jobs 4' - ] + expected = ["resque_processed_jobs 7", "resque_failed_jobs 1", "resque_pending_jobs 4"] assert_equal expected, metrics.map(&:metric_text) end def test_collecting_metrics_with_custom_labels collector.collect( - 'type' => 'resque', - 'pending_jobs' => 1, - 'processed_jobs' => 2, - 'failed_jobs' => 3, - 'custom_labels' => { - 'hostname' => 'a323d2f681e2' - } + "type" => "resque", + "pending_jobs" => 1, + "processed_jobs" => 2, + "failed_jobs" => 3, + "custom_labels" => { + "hostname" => "a323d2f681e2", + }, ) metrics = collector.metrics @@ -44,20 +36,13 @@ def test_collecting_metrics_with_custom_labels end def test_metrics_expiration - data = { - 'type' => 'resque', - 'pending_jobs' => 1, - 'processed_jobs' => 2, - 'failed_jobs' => 3 - } + data = { "type" => "resque", "pending_jobs" => 1, "processed_jobs" => 2, "failed_jobs" => 3 } stub_monotonic_clock(0) do collector.collect(data) assert_equal 3, collector.metrics.size end - stub_monotonic_clock(max_metric_age + 1) do - assert_equal 0, collector.metrics.size - end + stub_monotonic_clock(max_metric_age + 1) { assert_equal 0, collector.metrics.size } end end diff --git a/test/server/runner_test.rb b/test/server/runner_test.rb index 9b667455..b133e82c 100644 --- a/test/server/runner_test.rb +++ b/test/server/runner_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/server' +require_relative "../test_helper" +require "prometheus_exporter/server" class PrometheusRunnerTest < Minitest::Test class MockerWebServer < OpenStruct @@ -29,7 +29,7 @@ class WrongCollectorMock class TypeCollectorMock < PrometheusExporter::Server::TypeCollector def type - 'test' + "test" end def collect(_) @@ -48,7 +48,7 @@ def teardown def test_runner_defaults runner = PrometheusExporter::Server::Runner.new - assert_equal(runner.prefix, 'ruby_') + assert_equal(runner.prefix, "ruby_") assert_equal(runner.port, 9394) assert_equal(runner.timeout, 2) assert_equal(runner.collector_class, PrometheusExporter::Server::Collector) @@ -56,69 +56,80 @@ def test_runner_defaults assert_equal(runner.verbose, false) assert_empty(runner.label) assert_nil(runner.auth) - assert_equal(runner.realm, 'Prometheus Exporter') + assert_equal(runner.realm, "Prometheus Exporter") end def test_runner_custom_options - runner = PrometheusExporter::Server::Runner.new( - prefix: 'new_', - port: 1234, - timeout: 1, - collector_class: CollectorMock, - type_collectors: [TypeCollectorMock], - verbose: true, - label: { environment: 'integration' }, - auth: 'my_htpasswd_file', - realm: 'test realm', - histogram: true - ) - - assert_equal(runner.prefix, 'new_') + runner = + PrometheusExporter::Server::Runner.new( + prefix: "new_", + port: 1234, + timeout: 1, + collector_class: CollectorMock, + type_collectors: [TypeCollectorMock], + verbose: true, + label: { + environment: "integration", + }, + auth: "my_htpasswd_file", + realm: "test realm", + histogram: true, + ) + + assert_equal(runner.prefix, "new_") assert_equal(runner.port, 1234) assert_equal(runner.timeout, 1) assert_equal(runner.collector_class, CollectorMock) assert_equal(runner.type_collectors, [TypeCollectorMock]) assert_equal(runner.verbose, true) - assert_equal(runner.label, { environment: 'integration' }) - assert_equal(runner.auth, 'my_htpasswd_file') - assert_equal(runner.realm, 'test realm') + assert_equal(runner.label, { environment: "integration" }) + assert_equal(runner.auth, "my_htpasswd_file") + assert_equal(runner.realm, "test realm") assert_equal(runner.histogram, true) reset_base_metric_label end def test_runner_start - runner = PrometheusExporter::Server::Runner.new(server_class: MockerWebServer, label: { environment: 'integration' }) + runner = + PrometheusExporter::Server::Runner.new( + server_class: MockerWebServer, + label: { + environment: "integration", + }, + ) result = runner.start assert_equal(result, true) - assert_equal(PrometheusExporter::Metric::Base.default_prefix, 'ruby_') + assert_equal(PrometheusExporter::Metric::Base.default_prefix, "ruby_") assert_equal(runner.port, 9394) assert_equal(runner.timeout, 2) assert_equal(runner.verbose, false) assert_nil(runner.auth) - assert_equal(runner.realm, 'Prometheus Exporter') - assert_equal(PrometheusExporter::Metric::Base.default_labels, { environment: 'integration' }) + assert_equal(runner.realm, "Prometheus Exporter") + assert_equal(PrometheusExporter::Metric::Base.default_labels, { environment: "integration" }) assert_instance_of(PrometheusExporter::Server::Collector, runner.collector) reset_base_metric_label end def test_runner_custom_collector - runner = PrometheusExporter::Server::Runner.new( - server_class: MockerWebServer, - collector_class: CollectorMock - ) + runner = + PrometheusExporter::Server::Runner.new( + server_class: MockerWebServer, + collector_class: CollectorMock, + ) runner.start assert_equal(runner.collector_class, CollectorMock) end def test_runner_wrong_collector - runner = PrometheusExporter::Server::Runner.new( - server_class: MockerWebServer, - collector_class: WrongCollectorMock - ) + runner = + PrometheusExporter::Server::Runner.new( + server_class: MockerWebServer, + collector_class: WrongCollectorMock, + ) assert_raises PrometheusExporter::Server::WrongInheritance do runner.start @@ -126,11 +137,12 @@ def test_runner_wrong_collector end def test_runner_custom_collector_types - runner = PrometheusExporter::Server::Runner.new( - server_class: MockerWebServer, - collector_class: CollectorMock, - type_collectors: [TypeCollectorMock] - ) + runner = + PrometheusExporter::Server::Runner.new( + server_class: MockerWebServer, + collector_class: CollectorMock, + type_collectors: [TypeCollectorMock], + ) runner.start custom_collectors = runner.collector.collectors @@ -140,13 +152,13 @@ def test_runner_custom_collector_types end def test_runner_histogram_mode - runner = PrometheusExporter::Server::Runner.new( - server_class: MockerWebServer, - histogram: true - ) + runner = PrometheusExporter::Server::Runner.new(server_class: MockerWebServer, histogram: true) runner.start - assert_equal(PrometheusExporter::Metric::Base.default_aggregation, PrometheusExporter::Metric::Histogram) + assert_equal( + PrometheusExporter::Metric::Base.default_aggregation, + PrometheusExporter::Metric::Histogram, + ) end def reset_base_metric_label diff --git a/test/server/sidekiq_process_collector_test.rb b/test/server/sidekiq_process_collector_test.rb index 40a00b73..c3a1d8be 100644 --- a/test/server/sidekiq_process_collector_test.rb +++ b/test/server/sidekiq_process_collector_test.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusSidekiqProcessCollectorTest < Minitest::Test include CollectorHelper @@ -13,18 +13,18 @@ def collector def test_collecting_metrics collector.collect( - 'process' => { - 'busy' => 1, - 'concurrency' => 2, - 'labels' => { - 'labels' => 'lab_1,lab_2', - 'queues' => 'default,reliable', - 'quiet' => 'false', - 'tag' => 'default', - 'hostname' => 'sidekiq-1234', - 'identity' => 'sidekiq-1234:1', - } - } + "process" => { + "busy" => 1, + "concurrency" => 2, + "labels" => { + "labels" => "lab_1,lab_2", + "queues" => "default,reliable", + "quiet" => "false", + "tag" => "default", + "hostname" => "sidekiq-1234", + "identity" => "sidekiq-1234:1", + }, + }, ) metrics = collector.metrics @@ -38,41 +38,41 @@ def test_collecting_metrics def test_only_fresh_metrics_are_collected stub_monotonic_clock(1.0) do collector.collect( - 'process' => { - 'busy' => 1, - 'concurrency' => 2, - 'labels' => { - 'labels' => 'lab_1,lab_2', - 'queues' => 'default,reliable', - 'quiet' => 'false', - 'tag' => 'default', - 'hostname' => 'sidekiq-1234', - 'identity' => 'sidekiq-1234:1', - } - } + "process" => { + "busy" => 1, + "concurrency" => 2, + "labels" => { + "labels" => "lab_1,lab_2", + "queues" => "default,reliable", + "quiet" => "false", + "tag" => "default", + "hostname" => "sidekiq-1234", + "identity" => "sidekiq-1234:1", + }, + }, ) end stub_monotonic_clock(2.0, advance: max_metric_age) do collector.collect( - 'process' => { - 'busy' => 2, - 'concurrency' => 2, - 'labels' => { - 'labels' => 'other_label', - 'queues' => 'default,reliable', - 'quiet' => 'true', - 'tag' => 'default', - 'hostname' => 'sidekiq-1234', - 'identity' => 'sidekiq-1234:1', - } - } + "process" => { + "busy" => 2, + "concurrency" => 2, + "labels" => { + "labels" => "other_label", + "queues" => "default,reliable", + "quiet" => "true", + "tag" => "default", + "hostname" => "sidekiq-1234", + "identity" => "sidekiq-1234:1", + }, + }, ) metrics = collector.metrics expected = [ 'sidekiq_process_busy{labels="other_label",queues="default,reliable",quiet="true",tag="default",hostname="sidekiq-1234",identity="sidekiq-1234:1"} 2', - 'sidekiq_process_concurrency{labels="other_label",queues="default,reliable",quiet="true",tag="default",hostname="sidekiq-1234",identity="sidekiq-1234:1"} 2' + 'sidekiq_process_concurrency{labels="other_label",queues="default,reliable",quiet="true",tag="default",hostname="sidekiq-1234",identity="sidekiq-1234:1"} 2', ] assert_equal expected, metrics.map(&:metric_text) end diff --git a/test/server/sidekiq_queue_collector_test.rb b/test/server/sidekiq_queue_collector_test.rb index 5da41239..301e369f 100644 --- a/test/server/sidekiq_queue_collector_test.rb +++ b/test/server/sidekiq_queue_collector_test.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusSidekiqQueueCollectorTest < Minitest::Test include CollectorHelper @@ -13,11 +13,7 @@ def collector def test_collecting_metrics collector.collect( - 'queues' => [ - 'backlog' => 16, - 'latency_seconds' => 7, - 'labels' => { 'queue' => 'default' } - ] + "queues" => ["backlog" => 16, "latency_seconds" => 7, "labels" => { "queue" => "default" }], ) metrics = collector.metrics @@ -31,14 +27,10 @@ def test_collecting_metrics def test_collecting_metrics_with_client_default_labels collector.collect( - 'queues' => [ - 'backlog' => 16, - 'latency_seconds' => 7, - 'labels' => { 'queue' => 'default' } - ], - 'custom_labels' => { - 'environment' => 'test' - } + "queues" => ["backlog" => 16, "latency_seconds" => 7, "labels" => { "queue" => "default" }], + "custom_labels" => { + "environment" => "test", + }, ) metrics = collector.metrics @@ -52,27 +44,15 @@ def test_collecting_metrics_with_client_default_labels def test_only_fresh_metrics_are_collected stub_monotonic_clock(1.0) do - collector.collect( - 'queues' => [ - 'backlog' => 1, - 'labels' => { 'queue' => 'default' } - ] - ) + collector.collect("queues" => ["backlog" => 1, "labels" => { "queue" => "default" }]) end stub_monotonic_clock(2.0, advance: max_metric_age) do - collector.collect( - 'queues' => [ - 'latency_seconds' => 1, - 'labels' => { 'queue' => 'default' } - ] - ) + collector.collect("queues" => ["latency_seconds" => 1, "labels" => { "queue" => "default" }]) metrics = collector.metrics - expected = [ - 'sidekiq_queue_latency_seconds{queue="default"} 1', - ] + expected = ['sidekiq_queue_latency_seconds{queue="default"} 1'] assert_equal expected, metrics.map(&:metric_text) end end diff --git a/test/server/sidekiq_stats_collector_test.rb b/test/server/sidekiq_stats_collector_test.rb index 64906705..060af83f 100644 --- a/test/server/sidekiq_stats_collector_test.rb +++ b/test/server/sidekiq_stats_collector_test.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusSidekiqStatsCollectorTest < Minitest::Test include CollectorHelper @@ -13,16 +13,16 @@ def collector def test_collecting_metrics collector.collect( - 'stats' => { - 'dead_size' => 1, - 'enqueued' => 2, - 'failed' => 3, - 'processed' => 4, - 'processes_size' => 5, - 'retry_size' => 6, - 'scheduled_size' => 7, - 'workers_size' => 8, - } + "stats" => { + "dead_size" => 1, + "enqueued" => 2, + "failed" => 3, + "processed" => 4, + "processes_size" => 5, + "retry_size" => 6, + "scheduled_size" => 7, + "workers_size" => 8, + }, ) metrics = collector.metrics @@ -34,7 +34,7 @@ def test_collecting_metrics "sidekiq_stats_processes_size 5", "sidekiq_stats_retry_size 6", "sidekiq_stats_scheduled_size 7", - "sidekiq_stats_workers_size 8" + "sidekiq_stats_workers_size 8", ] assert_equal expected, metrics.map(&:metric_text) end @@ -42,31 +42,31 @@ def test_collecting_metrics def test_only_fresh_metrics_are_collected stub_monotonic_clock(1.0) do collector.collect( - 'stats' => { - 'dead_size' => 1, - 'enqueued' => 2, - 'failed' => 3, - 'processed' => 4, - 'processes_size' => 5, - 'retry_size' => 6, - 'scheduled_size' => 7, - 'workers_size' => 8, - } + "stats" => { + "dead_size" => 1, + "enqueued" => 2, + "failed" => 3, + "processed" => 4, + "processes_size" => 5, + "retry_size" => 6, + "scheduled_size" => 7, + "workers_size" => 8, + }, ) end stub_monotonic_clock(2.0, advance: max_metric_age) do collector.collect( - 'stats' => { - 'dead_size' => 2, - 'enqueued' => 3, - 'failed' => 4, - 'processed' => 5, - 'processes_size' => 6, - 'retry_size' => 7, - 'scheduled_size' => 8, - 'workers_size' => 9, - } + "stats" => { + "dead_size" => 2, + "enqueued" => 3, + "failed" => 4, + "processed" => 5, + "processes_size" => 6, + "retry_size" => 7, + "scheduled_size" => 8, + "workers_size" => 9, + }, ) metrics = collector.metrics @@ -78,7 +78,7 @@ def test_only_fresh_metrics_are_collected "sidekiq_stats_processes_size 6", "sidekiq_stats_retry_size 7", "sidekiq_stats_scheduled_size 8", - "sidekiq_stats_workers_size 9" + "sidekiq_stats_workers_size 9", ] assert_equal expected, metrics.map(&:metric_text) diff --git a/test/server/unicorn_collector_test.rb b/test/server/unicorn_collector_test.rb index 28fbecdc..7907214e 100644 --- a/test/server/unicorn_collector_test.rb +++ b/test/server/unicorn_collector_test.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'mini_racer' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "mini_racer" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusUnicornCollectorTest < Minitest::Test include CollectorHelper @@ -13,28 +13,24 @@ def collector end def test_collecting_metrics - collector.collect( - 'workers' => 4, - 'active_workers' => 3, - 'request_backlog' => 0 - ) + collector.collect("workers" => 4, "active_workers" => 3, "request_backlog" => 0) assert_collector_metric_lines [ - 'unicorn_workers 4', - 'unicorn_active_workers 3', - 'unicorn_request_backlog 0' - ] + "unicorn_workers 4", + "unicorn_active_workers 3", + "unicorn_request_backlog 0", + ] end def test_collecting_metrics_with_custom_labels collector.collect( - 'type' => 'unicorn', - 'workers' => 2, - 'active_workers' => 0, - 'request_backlog' => 0, - 'custom_labels' => { - 'hostname' => 'a323d2f681e2' - } + "type" => "unicorn", + "workers" => 2, + "active_workers" => 0, + "request_backlog" => 0, + "custom_labels" => { + "hostname" => "a323d2f681e2", + }, ) metrics = collector.metrics @@ -43,20 +39,23 @@ def test_collecting_metrics_with_custom_labels end def test_metrics_deduplication - collector.collect('workers' => 4, 'active_workers' => 3, 'request_backlog' => 0) - collector.collect('workers' => 4, 'active_workers' => 3, 'request_backlog' => 0) - collector.collect('workers' => 4, 'active_workers' => 3, 'request_backlog' => 0, 'hostname' => 'localhost2') + collector.collect("workers" => 4, "active_workers" => 3, "request_backlog" => 0) + collector.collect("workers" => 4, "active_workers" => 3, "request_backlog" => 0) + collector.collect( + "workers" => 4, + "active_workers" => 3, + "request_backlog" => 0, + "hostname" => "localhost2", + ) assert_equal 3, collector_metric_lines.size end def test_metrics_expiration stub_monotonic_clock(0) do - collector.collect('workers' => 4, 'active_workers' => 3, 'request_backlog' => 0) + collector.collect("workers" => 4, "active_workers" => 3, "request_backlog" => 0) assert_equal 3, collector.metrics.size end - stub_monotonic_clock(max_metric_age + 1) do - assert_equal 0, collector.metrics.size - end + stub_monotonic_clock(max_metric_age + 1) { assert_equal 0, collector.metrics.size } end end diff --git a/test/server/web_collector_test.rb b/test/server/web_collector_test.rb index 1d20f0d6..bd82ba73 100644 --- a/test/server/web_collector_test.rb +++ b/test/server/web_collector_test.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'mini_racer' -require 'prometheus_exporter/server' -require 'prometheus_exporter/instrumentation' +require_relative "../test_helper" +require "mini_racer" +require "prometheus_exporter/server" +require "prometheus_exporter/instrumentation" class PrometheusWebCollectorTest < Minitest::Test def setup - PrometheusExporter::Metric::Base.default_prefix = '' + PrometheusExporter::Metric::Base.default_prefix = "" PrometheusExporter::Metric::Base.default_aggregation = nil end @@ -24,9 +24,9 @@ def test_collecting_metrics_without_specific_timings "type" => "web", "timings" => nil, "default_labels" => { - "action" => 'index', - "controller" => 'home', - "status": 200 + "action" => "index", + "controller" => "home", + :"status" => 200, }, ) @@ -41,23 +41,23 @@ def test_collecting_metrics "timings" => { "sql" => { duration: 0.5, - count: 40 + count: 40, }, "redis" => { duration: 0.03, - count: 4 + count: 4, }, "memcache" => { duration: 0.02, - count: 1 + count: 1, }, "queue" => 0.03, - "total_duration" => 1.0 + "total_duration" => 1.0, }, - 'default_labels' => { - 'action' => 'index', - 'controller' => 'home', - "status" => 200 + "default_labels" => { + "action" => "index", + "controller" => "home", + "status" => 200, }, ) @@ -67,81 +67,95 @@ def test_collecting_metrics def test_collecting_metrics_with_custom_labels collector.collect( - 'type' => 'web', - 'timings' => nil, - 'status' => 200, - 'default_labels' => { - 'controller' => 'home', - 'action' => 'index' + "type" => "web", + "timings" => nil, + "status" => 200, + "default_labels" => { + "controller" => "home", + "action" => "index", + }, + "custom_labels" => { + "service" => "service1", }, - 'custom_labels' => { - 'service' => 'service1' - } ) metrics = collector.metrics assert_equal 6, metrics.size - assert(metrics.first.metric_text.include?('http_requests_total{controller="home",action="index",service="service1",status="200"} 1')) + assert( + metrics.first.metric_text.include?( + 'http_requests_total{controller="home",action="index",service="service1",status="200"} 1', + ), + ) end def test_collecting_metrics_merging_custom_labels_and_status collector.collect( - 'type' => 'web', - 'timings' => nil, - 'status' => 200, - 'default_labels' => { - 'controller' => 'home', - 'action' => 'index' + "type" => "web", + "timings" => nil, + "status" => 200, + "default_labels" => { + "controller" => "home", + "action" => "index", + }, + "custom_labels" => { + "service" => "service1", + "status" => 200, }, - 'custom_labels' => { - 'service' => 'service1', - 'status' => 200 - } ) metrics = collector.metrics assert_equal 6, metrics.size - assert(metrics.first.metric_text.include?('http_requests_total{controller="home",action="index",service="service1",status="200"} 1')) + assert( + metrics.first.metric_text.include?( + 'http_requests_total{controller="home",action="index",service="service1",status="200"} 1', + ), + ) end def test_collecting_metrics_in_histogram_mode PrometheusExporter::Metric::Base.default_aggregation = PrometheusExporter::Metric::Histogram collector.collect( - 'type' => 'web', - 'status' => 200, + "type" => "web", + "status" => 200, "timings" => { "sql" => { duration: 0.5, - count: 40 + count: 40, }, "redis" => { duration: 0.03, - count: 4 + count: 4, }, "memcache" => { duration: 0.02, - count: 1 + count: 1, }, "queue" => 0.03, "total_duration" => 1.0, }, - 'default_labels' => { - 'controller' => 'home', - 'action' => 'index' + "default_labels" => { + "controller" => "home", + "action" => "index", + }, + "custom_labels" => { + "service" => "service1", }, - 'custom_labels' => { - 'service' => 'service1' - } ) metrics = collector.metrics metrics_lines = metrics.map(&:metric_text).flat_map(&:lines) assert_equal 6, metrics.size - assert_includes(metrics_lines, "http_requests_total{controller=\"home\",action=\"index\",service=\"service1\",status=\"200\"} 1") - assert_includes(metrics_lines, "http_request_duration_seconds_bucket{controller=\"home\",action=\"index\",service=\"service1\",le=\"+Inf\"} 1\n") + assert_includes( + metrics_lines, + "http_requests_total{controller=\"home\",action=\"index\",service=\"service1\",status=\"200\"} 1", + ) + assert_includes( + metrics_lines, + "http_request_duration_seconds_bucket{controller=\"home\",action=\"index\",service=\"service1\",le=\"+Inf\"} 1\n", + ) end end diff --git a/test/server/web_server_test.rb b/test/server/web_server_test.rb index ee88d2b5..4e2ad163 100644 --- a/test/server/web_server_test.rb +++ b/test/server/web_server_test.rb @@ -1,39 +1,34 @@ # frozen_string_literal: true -require_relative '../test_helper' -require 'prometheus_exporter/server' -require 'prometheus_exporter/client' -require 'net/http' +require_relative "../test_helper" +require "prometheus_exporter/server" +require "prometheus_exporter/client" +require "net/http" class DemoCollector - def initialize @gauge = PrometheusExporter::Metric::Gauge.new "memory", "amount of memory" end def process(str) obj = JSON.parse(str) - if obj["type"] == "mem metric" - @gauge.observe(obj["value"]) - end + @gauge.observe(obj["value"]) if obj["type"] == "mem metric" end def prometheus_metrics_text @gauge.to_prometheus_text end - end class PrometheusExporterTest < Minitest::Test - def setup - PrometheusExporter::Metric::Base.default_prefix = '' + PrometheusExporter::Metric::Base.default_prefix = "" @auth_config = { - file: 'test/server/my_htpasswd_file', - realm: 'Prometheus Exporter', - user: 'test_user', - passwd: 'test_password', + file: "test/server/my_htpasswd_file", + realm: "Prometheus Exporter", + user: "test_user", + passwd: "test_password", } # Create an htpasswd file for basic auth @@ -49,7 +44,7 @@ def teardown end def find_free_port - port = 12437 + port = 12_437 while port < 13_000 begin TCPSocket.new("localhost", port).close @@ -90,7 +85,6 @@ def test_it_can_collect_with_and_without_oj assert(text =~ /7/) assert(text =~ /8/) assert(text =~ /9/) - end def test_it_can_collect_over_ipv6 @@ -105,9 +99,7 @@ def test_it_can_collect_over_ipv6 gauge = client.register(:gauge, "my_gauge", "some gauge") gauge.observe(99) - TestHelper.wait_for(2) do - server.collector.prometheus_metrics_text =~ /99/ - end + TestHelper.wait_for(2) { server.collector.prometheus_metrics_text =~ /99/ } expected = <<~TEXT # HELP my_gauge some gauge @@ -116,8 +108,16 @@ def test_it_can_collect_over_ipv6 TEXT assert_equal(expected, collector.prometheus_metrics_text) ensure - client.stop rescue nil - server.stop rescue nil + begin + client.stop + rescue StandardError + nil + end + begin + server.stop + rescue StandardError + nil + end end def test_it_can_collect_metrics_from_standard @@ -137,9 +137,7 @@ def test_it_can_collect_metrics_from_standard counter.observe(3) gauge.observe(92, abcd: 1) - TestHelper.wait_for(2) do - server.collector.prometheus_metrics_text =~ /92/ - end + TestHelper.wait_for(2) { server.collector.prometheus_metrics_text =~ /92/ } expected = <<~TEXT # HELP my_gauge some gauge @@ -151,10 +149,17 @@ def test_it_can_collect_metrics_from_standard my_counter 4 TEXT assert_equal(expected, collector.prometheus_metrics_text) - ensure - client.stop rescue nil - server.stop rescue nil + begin + client.stop + rescue StandardError + nil + end + begin + server.stop + rescue StandardError + nil + end end def test_it_can_collect_metrics_from_custom @@ -168,92 +173,121 @@ def test_it_can_collect_metrics_from_custom client.send_json "type" => "mem metric", "value" => 150 client.send_json "type" => "mem metric", "value" => 199 - TestHelper.wait_for(2) do - collector.prometheus_metrics_text =~ /199/ - end + TestHelper.wait_for(2) { collector.prometheus_metrics_text =~ /199/ } assert_match(/199/, collector.prometheus_metrics_text) body = nil - Net::HTTP.new("localhost", port).start do |http| - request = Net::HTTP::Get.new "/metrics" + Net::HTTP + .new("localhost", port) + .start do |http| + request = Net::HTTP::Get.new "/metrics" - http.request(request) do |response| - assert_equal(["gzip"], response.to_hash["content-encoding"]) - body = response.body + http.request(request) do |response| + assert_equal(["gzip"], response.to_hash["content-encoding"]) + body = response.body + end end - end assert_match(/199/, body) one_minute = Time.now + 60 Time.stub(:now, one_minute) do client.send_json "type" => "mem metric", "value" => 200.1 - TestHelper.wait_for(2) do - collector.prometheus_metrics_text =~ /200.1/ - end + TestHelper.wait_for(2) { collector.prometheus_metrics_text =~ /200.1/ } assert_match(/200.1/, collector.prometheus_metrics_text) end - ensure - client.stop rescue nil - server.stop rescue nil + begin + client.stop + rescue StandardError + nil + end + begin + server.stop + rescue StandardError + nil + end end def test_it_can_collect_metrics_with_basic_auth collector = DemoCollector.new port = find_free_port - server = PrometheusExporter::Server::WebServer.new port: port, collector: collector, auth: @auth_config[:file], realm: @auth_config[:realm] + server = + PrometheusExporter::Server::WebServer.new port: port, + collector: collector, + auth: @auth_config[:file], + realm: @auth_config[:realm] server.start client = PrometheusExporter::Client.new host: "localhost", port: port, thread_sleep: 0.001 client.send_json "type" => "mem metric", "value" => 150 client.send_json "type" => "mem metric", "value" => 199 - TestHelper.wait_for(2) do - collector.prometheus_metrics_text =~ /199/ - end + TestHelper.wait_for(2) { collector.prometheus_metrics_text =~ /199/ } assert_match(/199/, collector.prometheus_metrics_text) - Net::HTTP.new("localhost", port).start do |http| - request = Net::HTTP::Get.new "/metrics" - request.basic_auth @auth_config[:user], @auth_config[:passwd] - - http.request(request) do |response| - assert_equal("200", response.code) - assert_equal(["gzip"], response.to_hash["content-encoding"]) - assert_match(/199/, response.body) + Net::HTTP + .new("localhost", port) + .start do |http| + request = Net::HTTP::Get.new "/metrics" + request.basic_auth @auth_config[:user], @auth_config[:passwd] + + http.request(request) do |response| + assert_equal("200", response.code) + assert_equal(["gzip"], response.to_hash["content-encoding"]) + assert_match(/199/, response.body) + end end - end - ensure - client.stop rescue nil - server.stop rescue nil + begin + client.stop + rescue StandardError + nil + end + begin + server.stop + rescue StandardError + nil + end end def test_it_fails_with_invalid_auth collector = DemoCollector.new port = find_free_port - server = PrometheusExporter::Server::WebServer.new port: port, collector: collector, auth: @auth_config[:file], realm: @auth_config[:realm] + server = + PrometheusExporter::Server::WebServer.new port: port, + collector: collector, + auth: @auth_config[:file], + realm: @auth_config[:realm] server.start - Net::HTTP.new("localhost", port).start do |http| - request = Net::HTTP::Get.new "/metrics" + Net::HTTP + .new("localhost", port) + .start do |http| + request = Net::HTTP::Get.new "/metrics" - http.request(request) do |response| - assert_equal("401", response.code) - assert_match(/Unauthorized/, response.body) + http.request(request) do |response| + assert_equal("401", response.code) + assert_match(/Unauthorized/, response.body) + end end - end - ensure - client.stop rescue nil - server.stop rescue nil + begin + client.stop + rescue StandardError + nil + end + begin + server.stop + rescue StandardError + nil + end end def test_it_responds_to_ping @@ -265,17 +299,26 @@ def test_it_responds_to_ping client = PrometheusExporter::Client.new host: "localhost", port: port, thread_sleep: 0.001 - Net::HTTP.new("localhost", port).start do |http| - request = Net::HTTP::Get.new "/ping" + Net::HTTP + .new("localhost", port) + .start do |http| + request = Net::HTTP::Get.new "/ping" - http.request(request) do |response| - assert_equal("200", response.code) - assert_match(/PONG/, response.body) + http.request(request) do |response| + assert_equal("200", response.code) + assert_match(/PONG/, response.body) + end end - end - ensure - client.stop rescue nil - server.stop rescue nil + begin + client.stop + rescue StandardError + nil + end + begin + server.stop + rescue StandardError + nil + end end end diff --git a/test/sidekiq_middleware_test.rb b/test/sidekiq_middleware_test.rb index e984845e..6c41154b 100644 --- a/test/sidekiq_middleware_test.rb +++ b/test/sidekiq_middleware_test.rb @@ -1,11 +1,10 @@ # frozen_string_literal: true -require 'minitest/stub_const' -require_relative 'test_helper' -require 'prometheus_exporter/instrumentation/sidekiq' +require "minitest/stub_const" +require_relative "test_helper" +require "prometheus_exporter/instrumentation/sidekiq" class PrometheusExporterSidekiqMiddlewareTest < Minitest::Test - class FakeClient end @@ -27,9 +26,11 @@ def make_new end def test_initiating_middlware - middleware_entry = FakeSidekiqMiddlewareChainEntry.new( - PrometheusExporter::Instrumentation::Sidekiq, { client: client }) + middleware_entry = + FakeSidekiqMiddlewareChainEntry.new( + PrometheusExporter::Instrumentation::Sidekiq, + { client: client }, + ) assert_instance_of PrometheusExporter::Instrumentation::Sidekiq, middleware_entry.make_new end - end diff --git a/test/test_helper.rb b/test/test_helper.rb index 027c65e0..35ff85b4 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -76,12 +76,7 @@ def self.wait_for(time, &blk) module ClockHelper def stub_monotonic_clock(at = 0.0, advance: nil, &blk) - Process.stub( - :clock_gettime, - at + advance.to_f, - Process::CLOCK_MONOTONIC, - &blk - ) + Process.stub(:clock_gettime, at + advance.to_f, Process::CLOCK_MONOTONIC, &blk) end end