prometheus_exporter 0.8.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +36 -25
  3. data/CHANGELOG +51 -26
  4. data/README.md +151 -52
  5. data/bin/prometheus_exporter +19 -6
  6. data/lib/prometheus_exporter/client.rb +13 -6
  7. data/lib/prometheus_exporter/instrumentation/active_record.rb +5 -5
  8. data/lib/prometheus_exporter/instrumentation/process.rb +1 -1
  9. data/lib/prometheus_exporter/instrumentation/puma.rb +12 -12
  10. data/lib/prometheus_exporter/instrumentation/resque.rb +7 -7
  11. data/lib/prometheus_exporter/instrumentation/sidekiq.rb +27 -7
  12. data/lib/prometheus_exporter/instrumentation/sidekiq_process.rb +58 -0
  13. data/lib/prometheus_exporter/instrumentation/sidekiq_queue.rb +27 -13
  14. data/lib/prometheus_exporter/instrumentation/sidekiq_stats.rb +43 -0
  15. data/lib/prometheus_exporter/instrumentation/unicorn.rb +4 -4
  16. data/lib/prometheus_exporter/instrumentation.rb +2 -0
  17. data/lib/prometheus_exporter/metric/base.rb +11 -9
  18. data/lib/prometheus_exporter/metric/gauge.rb +4 -0
  19. data/lib/prometheus_exporter/metric/histogram.rb +13 -1
  20. data/lib/prometheus_exporter/middleware.rb +8 -4
  21. data/lib/prometheus_exporter/server/collector.rb +2 -0
  22. data/lib/prometheus_exporter/server/delayed_job_collector.rb +17 -18
  23. data/lib/prometheus_exporter/server/puma_collector.rb +7 -7
  24. data/lib/prometheus_exporter/server/resque_collector.rb +6 -6
  25. data/lib/prometheus_exporter/server/runner.rb +11 -2
  26. data/lib/prometheus_exporter/server/sidekiq_collector.rb +1 -1
  27. data/lib/prometheus_exporter/server/sidekiq_process_collector.rb +46 -0
  28. data/lib/prometheus_exporter/server/sidekiq_queue_collector.rb +1 -1
  29. data/lib/prometheus_exporter/server/sidekiq_stats_collector.rb +46 -0
  30. data/lib/prometheus_exporter/server/unicorn_collector.rb +3 -3
  31. data/lib/prometheus_exporter/server/web_collector.rb +17 -17
  32. data/lib/prometheus_exporter/server/web_server.rb +6 -8
  33. data/lib/prometheus_exporter/server.rb +2 -0
  34. data/lib/prometheus_exporter/version.rb +1 -1
  35. data/prometheus_exporter.gemspec +1 -1
  36. metadata +10 -6
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'socket'
4
4
  require 'thread'
5
+ require 'logger'
5
6
 
6
7
  module PrometheusExporter
7
8
  class Client
@@ -53,14 +54,20 @@ module PrometheusExporter
53
54
  MAX_SOCKET_AGE = 25
54
55
  MAX_QUEUE_SIZE = 10_000
55
56
 
57
+ attr_reader :logger
58
+
56
59
  def initialize(
57
60
  host: ENV.fetch('PROMETHEUS_EXPORTER_HOST', 'localhost'),
58
61
  port: ENV.fetch('PROMETHEUS_EXPORTER_PORT', PrometheusExporter::DEFAULT_PORT),
59
62
  max_queue_size: nil,
60
63
  thread_sleep: 0.5,
61
64
  json_serializer: nil,
62
- custom_labels: nil
65
+ custom_labels: nil,
66
+ logger: Logger.new(STDERR),
67
+ log_level: Logger::WARN
63
68
  )
69
+ @logger = logger
70
+ @logger.level = log_level
64
71
  @metrics = []
65
72
 
66
73
  @queue = Queue.new
@@ -72,7 +79,7 @@ module PrometheusExporter
72
79
  max_queue_size ||= MAX_QUEUE_SIZE
73
80
  max_queue_size = max_queue_size.to_i
74
81
 
75
- if max_queue_size.to_i <= 0
82
+ if max_queue_size <= 0
76
83
  raise ArgumentError, "max_queue_size must be larger than 0"
77
84
  end
78
85
 
@@ -125,7 +132,7 @@ module PrometheusExporter
125
132
  def send(str)
126
133
  @queue << str
127
134
  if @queue.length > @max_queue_size
128
- STDERR.puts "Prometheus Exporter client is dropping message cause queue is full"
135
+ logger.warn "Prometheus Exporter client is dropping message cause queue is full"
129
136
  @queue.pop
130
137
  end
131
138
 
@@ -143,7 +150,7 @@ module PrometheusExporter
143
150
  @socket.write(message)
144
151
  @socket.write("\r\n")
145
152
  rescue => e
146
- STDERR.puts "Prometheus Exporter is dropping a message: #{e}"
153
+ logger.warn "Prometheus Exporter is dropping a message: #{e}"
147
154
  @socket = nil
148
155
  raise
149
156
  end
@@ -168,7 +175,7 @@ module PrometheusExporter
168
175
  close_socket_if_old!
169
176
  process_queue
170
177
  rescue => e
171
- STDERR.puts "Prometheus Exporter, failed to send message #{e}"
178
+ logger.error "Prometheus Exporter, failed to send message #{e}"
172
179
  end
173
180
 
174
181
  def ensure_worker_thread!
@@ -186,7 +193,7 @@ module PrometheusExporter
186
193
  end
187
194
  rescue ThreadError => e
188
195
  raise unless e.message =~ /can't alloc thread/
189
- STDERR.puts "Prometheus Exporter, failed to send message ThreadError #{e}"
196
+ logger.error "Prometheus Exporter, failed to send message ThreadError #{e}"
190
197
  end
191
198
 
192
199
  def close_socket!
@@ -7,9 +7,11 @@ module PrometheusExporter::Instrumentation
7
7
 
8
8
  def self.start(client: nil, frequency: 30, custom_labels: {}, config_labels: [])
9
9
 
10
- # Not all rails versions support coonection pool stats
10
+ client ||= PrometheusExporter::Client.default
11
+
12
+ # Not all rails versions support connection pool stats
11
13
  unless ::ActiveRecord::Base.connection_pool.respond_to?(:stat)
12
- STDERR.puts("ActiveRecord connection pool stats not supported in your rails version")
14
+ client.logger.error("ActiveRecord connection pool stats not supported in your rails version")
13
15
  return
14
16
  end
15
17
 
@@ -18,8 +20,6 @@ module PrometheusExporter::Instrumentation
18
20
 
19
21
  active_record_collector = new(custom_labels, config_labels)
20
22
 
21
- client ||= PrometheusExporter::Client.default
22
-
23
23
  stop if @thread
24
24
 
25
25
  @thread = Thread.new do
@@ -28,7 +28,7 @@ module PrometheusExporter::Instrumentation
28
28
  metrics = active_record_collector.collect
29
29
  metrics.each { |metric| client.send_json metric }
30
30
  rescue => e
31
- STDERR.puts("Prometheus Exporter Failed To Collect Process Stats #{e}")
31
+ client.logger.error("Prometheus Exporter Failed To Collect Process Stats #{e}")
32
32
  ensure
33
33
  sleep frequency
34
34
  end
@@ -27,7 +27,7 @@ module PrometheusExporter::Instrumentation
27
27
  metric = process_collector.collect
28
28
  client.send_json metric
29
29
  rescue => e
30
- STDERR.puts("Prometheus Exporter Failed To Collect Process Stats #{e}")
30
+ client.logger.error("Prometheus Exporter Failed To Collect Process Stats #{e}")
31
31
  ensure
32
32
  sleep frequency
33
33
  end
@@ -14,7 +14,7 @@ module PrometheusExporter::Instrumentation
14
14
  metric = puma_collector.collect
15
15
  client.send_json metric
16
16
  rescue => e
17
- STDERR.puts("Prometheus Exporter Failed To Collect Puma Stats #{e}")
17
+ client.logger.error("Prometheus Exporter Failed To Collect Puma Stats #{e}")
18
18
  ensure
19
19
  sleep frequency
20
20
  end
@@ -46,9 +46,9 @@ module PrometheusExporter::Instrumentation
46
46
 
47
47
  if stats.key?("workers")
48
48
  metric[:phase] = stats["phase"]
49
- metric[:workers_total] = stats["workers"]
50
- metric[:booted_workers_total] = stats["booted_workers"]
51
- metric[:old_workers_total] = stats["old_workers"]
49
+ metric[:workers] = stats["workers"]
50
+ metric[:booted_workers] = stats["booted_workers"]
51
+ metric[:old_workers] = stats["old_workers"]
52
52
 
53
53
  stats["worker_status"].each do |worker|
54
54
  next if worker["last_status"].empty?
@@ -62,15 +62,15 @@ module PrometheusExporter::Instrumentation
62
62
  private
63
63
 
64
64
  def collect_worker_status(metric, status)
65
- metric[:request_backlog_total] ||= 0
66
- metric[:running_threads_total] ||= 0
67
- metric[:thread_pool_capacity_total] ||= 0
68
- metric[:max_threads_total] ||= 0
65
+ metric[:request_backlog] ||= 0
66
+ metric[:running_threads] ||= 0
67
+ metric[:thread_pool_capacity] ||= 0
68
+ metric[:max_threads] ||= 0
69
69
 
70
- metric[:request_backlog_total] += status["backlog"]
71
- metric[:running_threads_total] += status["running"]
72
- metric[:thread_pool_capacity_total] += status["pool_capacity"]
73
- metric[:max_threads_total] += status["max_threads"]
70
+ metric[:request_backlog] += status["backlog"]
71
+ metric[:running_threads] += status["running"]
72
+ metric[:thread_pool_capacity] += status["pool_capacity"]
73
+ metric[:max_threads] += status["max_threads"]
74
74
  end
75
75
  end
76
76
  end
@@ -11,7 +11,7 @@ module PrometheusExporter::Instrumentation
11
11
  begin
12
12
  client.send_json(resque_collector.collect)
13
13
  rescue => e
14
- STDERR.puts("Prometheus Exporter Failed To Collect Resque Stats #{e}")
14
+ client.logger.error("Prometheus Exporter Failed To Collect Resque Stats #{e}")
15
15
  ensure
16
16
  sleep frequency
17
17
  end
@@ -29,12 +29,12 @@ module PrometheusExporter::Instrumentation
29
29
  def collect_resque_stats(metric)
30
30
  info = ::Resque.info
31
31
 
32
- metric[:processed_jobs_total] = info[:processed]
33
- metric[:failed_jobs_total] = info[:failed]
34
- metric[:pending_jobs_total] = info[:pending]
35
- metric[:queues_total] = info[:queues]
36
- metric[:worker_total] = info[:workers]
37
- metric[:working_total] = info[:working]
32
+ metric[:processed_jobs] = info[:processed]
33
+ metric[:failed_jobs] = info[:failed]
34
+ metric[:pending_jobs] = info[:pending]
35
+ metric[:queues] = info[:queues]
36
+ metric[:worker] = info[:workers]
37
+ metric[:working] = info[:working]
38
38
  end
39
39
  end
40
40
  end
@@ -15,16 +15,24 @@ module PrometheusExporter::Instrumentation
15
15
  -> (job, ex) do
16
16
  job_is_fire_and_forget = job["retry"] == false
17
17
 
18
+ worker_class = Object.const_get(job["class"])
19
+ worker_custom_labels = self.get_worker_custom_labels(worker_class)
20
+
18
21
  unless job_is_fire_and_forget
19
22
  PrometheusExporter::Client.default.send_json(
20
23
  type: "sidekiq",
21
24
  name: job["class"],
22
25
  dead: true,
26
+ custom_labels: worker_custom_labels
23
27
  )
24
28
  end
25
29
  end
26
30
  end
27
31
 
32
+ def self.get_worker_custom_labels(worker_class)
33
+ worker_class.respond_to?(:custom_labels) ? worker_class.custom_labels : {}
34
+ end
35
+
28
36
  def initialize(client: nil)
29
37
  @client = client || PrometheusExporter::Client.default
30
38
  end
@@ -47,7 +55,8 @@ module PrometheusExporter::Instrumentation
47
55
  queue: queue,
48
56
  success: success,
49
57
  shutdown: shutdown,
50
- duration: duration
58
+ duration: duration,
59
+ custom_labels: self.class.get_worker_custom_labels(worker.class)
51
60
  )
52
61
  end
53
62
 
@@ -69,19 +78,30 @@ module PrometheusExporter::Instrumentation
69
78
  end
70
79
 
71
80
  def get_delayed_name(msg, class_name)
72
- # fallback to class_name since we're relying on the internal implementation
73
- # of the delayed extensions
74
- # https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/extensions/class_methods.rb
75
81
  begin
76
- (target, method_name, _args) = YAML.load(msg['args'].first)
82
+ # fallback to class_name since we're relying on the internal implementation
83
+ # of the delayed extensions
84
+ # https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/extensions/class_methods.rb
85
+ (target, method_name, _args) = YAML.load(msg['args'].first) # rubocop:disable Security/YAMLLoad
77
86
  if target.class == Class
78
87
  "#{target.name}##{method_name}"
79
88
  else
80
89
  "#{target.class.name}##{method_name}"
81
90
  end
82
- rescue
83
- class_name
91
+ rescue Psych::DisallowedClass, ArgumentError
92
+ parsed = Psych.parse(msg['args'].first)
93
+ children = parsed.root.children
94
+ target = (children[0].value || children[0].tag).sub('!', '')
95
+ method_name = (children[1].value || children[1].tag).sub(':', '')
96
+
97
+ if target && method_name
98
+ "#{target}##{method_name}"
99
+ else
100
+ class_name
101
+ end
84
102
  end
103
+ rescue
104
+ class_name
85
105
  end
86
106
  end
87
107
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrometheusExporter::Instrumentation
4
+ class SidekiqProcess
5
+ def self.start(client: nil, frequency: 30)
6
+ client ||= PrometheusExporter::Client.default
7
+ sidekiq_process_collector = new
8
+
9
+ Thread.new do
10
+ loop do
11
+ begin
12
+ client.send_json(sidekiq_process_collector.collect)
13
+ rescue StandardError => e
14
+ STDERR.puts("Prometheus Exporter Failed To Collect Sidekiq Processes metrics #{e}")
15
+ ensure
16
+ sleep frequency
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def initialize
23
+ @pid = ::Process.pid
24
+ @hostname = Socket.gethostname
25
+ end
26
+
27
+ def collect
28
+ {
29
+ type: 'sidekiq_process',
30
+ process: collect_stats
31
+ }
32
+ end
33
+
34
+ def collect_stats
35
+ process = current_process
36
+ return {} unless process
37
+
38
+ {
39
+ busy: process['busy'],
40
+ concurrency: process['concurrency'],
41
+ labels: {
42
+ labels: process['labels'].sort.join(','),
43
+ queues: process['queues'].sort.join(','),
44
+ quiet: process['quiet'],
45
+ tag: process['tag'],
46
+ hostname: process['hostname'],
47
+ identity: process['identity'],
48
+ }
49
+ }
50
+ end
51
+
52
+ def current_process
53
+ ::Sidekiq::ProcessSet.new.find do |sp|
54
+ sp['hostname'] == @hostname && sp['pid'] == @pid
55
+ end
56
+ end
57
+ end
58
+ end
@@ -2,16 +2,16 @@
2
2
 
3
3
  module PrometheusExporter::Instrumentation
4
4
  class SidekiqQueue
5
- def self.start(client: nil, frequency: 30)
5
+ def self.start(client: nil, frequency: 30, all_queues: false)
6
6
  client ||= PrometheusExporter::Client.default
7
- sidekiq_queue_collector = new
7
+ sidekiq_queue_collector = new(all_queues: all_queues)
8
8
 
9
9
  Thread.new do
10
10
  loop do
11
11
  begin
12
12
  client.send_json(sidekiq_queue_collector.collect)
13
13
  rescue StandardError => e
14
- STDERR.puts("Prometheus Exporter Failed To Collect Sidekiq Queue metrics #{e}")
14
+ client.logger.error("Prometheus Exporter Failed To Collect Sidekiq Queue metrics #{e}")
15
15
  ensure
16
16
  sleep frequency
17
17
  end
@@ -19,6 +19,12 @@ module PrometheusExporter::Instrumentation
19
19
  end
20
20
  end
21
21
 
22
+ def initialize(all_queues: false)
23
+ @all_queues = all_queues
24
+ @pid = ::Process.pid
25
+ @hostname = Socket.gethostname
26
+ end
27
+
22
28
  def collect
23
29
  {
24
30
  type: 'sidekiq_queue',
@@ -27,24 +33,32 @@ module PrometheusExporter::Instrumentation
27
33
  end
28
34
 
29
35
  def collect_queue_stats
30
- hostname = Socket.gethostname
31
- pid = ::Process.pid
32
- ps = ::Sidekiq::ProcessSet.new
36
+ sidekiq_queues = ::Sidekiq::Queue.all
33
37
 
34
- process = ps.find do |sp|
35
- sp['hostname'] == hostname && sp['pid'] == pid
38
+ unless @all_queues
39
+ queues = collect_current_process_queues
40
+ sidekiq_queues.select! { |sidekiq_queue| queues.include?(sidekiq_queue.name) }
36
41
  end
37
42
 
38
- queues = process.nil? ? [] : process['queues']
39
-
40
- ::Sidekiq::Queue.all.map do |queue|
41
- next unless queues.include? queue.name
43
+ sidekiq_queues.map do |queue|
42
44
  {
43
- backlog_total: queue.size,
45
+ backlog: queue.size,
44
46
  latency_seconds: queue.latency.to_i,
45
47
  labels: { queue: queue.name }
46
48
  }
47
49
  end.compact
48
50
  end
51
+
52
+ private
53
+
54
+ def collect_current_process_queues
55
+ ps = ::Sidekiq::ProcessSet.new
56
+
57
+ process = ps.find do |sp|
58
+ sp['hostname'] == @hostname && sp['pid'] == @pid
59
+ end
60
+
61
+ process.nil? ? [] : process['queues']
62
+ end
49
63
  end
50
64
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrometheusExporter::Instrumentation
4
+ class SidekiqStats
5
+ def self.start(client: nil, frequency: 30)
6
+ client ||= PrometheusExporter::Client.default
7
+ sidekiq_stats_collector = new
8
+
9
+ Thread.new do
10
+ loop do
11
+ begin
12
+ client.send_json(sidekiq_stats_collector.collect)
13
+ rescue StandardError => e
14
+ STDERR.puts("Prometheus Exporter Failed To Collect Sidekiq Stats metrics #{e}")
15
+ ensure
16
+ sleep frequency
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def collect
23
+ {
24
+ type: 'sidekiq_stats',
25
+ stats: collect_stats
26
+ }
27
+ end
28
+
29
+ def collect_stats
30
+ stats = ::Sidekiq::Stats.new
31
+ {
32
+ 'dead_size' => stats.dead_size,
33
+ 'enqueued' => stats.enqueued,
34
+ 'failed' => stats.failed,
35
+ 'processed' => stats.processed,
36
+ 'processes_size' => stats.processes_size,
37
+ 'retry_size' => stats.retry_size,
38
+ 'scheduled_size' => stats.scheduled_size,
39
+ 'workers_size' => stats.workers_size,
40
+ }
41
+ end
42
+ end
43
+ end
@@ -18,7 +18,7 @@ module PrometheusExporter::Instrumentation
18
18
  metric = unicorn_collector.collect
19
19
  client.send_json metric
20
20
  rescue StandardError => e
21
- STDERR.puts("Prometheus Exporter Failed To Collect Unicorn Stats #{e}")
21
+ client.logger.error("Prometheus Exporter Failed To Collect Unicorn Stats #{e}")
22
22
  ensure
23
23
  sleep frequency
24
24
  end
@@ -42,9 +42,9 @@ module PrometheusExporter::Instrumentation
42
42
  def collect_unicorn_stats(metric)
43
43
  stats = listener_address_stats
44
44
 
45
- metric[:active_workers_total] = stats.active
46
- metric[:request_backlog_total] = stats.queued
47
- metric[:workers_total] = worker_process_count
45
+ metric[:active_workers] = stats.active
46
+ metric[:request_backlog] = stats.queued
47
+ metric[:workers] = worker_process_count
48
48
  end
49
49
 
50
50
  private
@@ -5,6 +5,8 @@ require_relative "instrumentation/process"
5
5
  require_relative "instrumentation/method_profiler"
6
6
  require_relative "instrumentation/sidekiq"
7
7
  require_relative "instrumentation/sidekiq_queue"
8
+ require_relative "instrumentation/sidekiq_process"
9
+ require_relative "instrumentation/sidekiq_stats"
8
10
  require_relative "instrumentation/delayed_job"
9
11
  require_relative "instrumentation/puma"
10
12
  require_relative "instrumentation/hutch"
@@ -5,6 +5,7 @@ module PrometheusExporter::Metric
5
5
 
6
6
  @default_prefix = nil if !defined?(@default_prefix)
7
7
  @default_labels = nil if !defined?(@default_labels)
8
+ @default_aggregation = nil if !defined?(@default_aggregation)
8
9
 
9
10
  # prefix applied to all metrics
10
11
  def self.default_prefix=(name)
@@ -23,6 +24,14 @@ module PrometheusExporter::Metric
23
24
  @default_labels || {}
24
25
  end
25
26
 
27
+ def self.default_aggregation=(aggregation)
28
+ @default_aggregation = aggregation
29
+ end
30
+
31
+ def self.default_aggregation
32
+ @default_aggregation ||= Summary
33
+ end
34
+
26
35
  attr_accessor :help, :name, :data
27
36
 
28
37
  def initialize(name, help)
@@ -97,15 +106,8 @@ module PrometheusExporter::Metric
97
106
  end
98
107
  end
99
108
 
100
- # when we drop Ruby 2.3 we can drop this
101
- if "".respond_to? :match?
102
- def needs_escape?(str)
103
- str.match?(/[\n"\\]/m)
104
- end
105
- else
106
- def needs_escape?(str)
107
- !!str.match(/[\n"\\]/m)
108
- end
109
+ def needs_escape?(str)
110
+ str.match?(/[\n"\\]/m)
109
111
  end
110
112
 
111
113
  end
@@ -5,6 +5,10 @@ module PrometheusExporter::Metric
5
5
  attr_reader :data
6
6
 
7
7
  def initialize(name, help)
8
+ if name.end_with?("_total")
9
+ raise ArgumentError, "The metric name of gauge must not have _total suffix. Given: #{name}"
10
+ end
11
+
8
12
  super
9
13
  reset!
10
14
  end
@@ -5,9 +5,21 @@ module PrometheusExporter::Metric
5
5
 
6
6
  DEFAULT_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5.0, 10.0].freeze
7
7
 
8
+ @default_buckets = nil if !defined?(@default_buckets)
9
+
10
+ def self.default_buckets
11
+ @default_buckets || DEFAULT_BUCKETS
12
+ end
13
+
14
+ def self.default_buckets=(buckets)
15
+ @default_buckets = buckets
16
+ end
17
+
18
+ attr_reader :buckets
19
+
8
20
  def initialize(name, help, opts = {})
9
21
  super(name, help)
10
- @buckets = (opts[:buckets] || DEFAULT_BUCKETS).sort.reverse
22
+ @buckets = (opts[:buckets] || self.class.default_buckets).sort.reverse
11
23
  reset!
12
24
  end
13
25
 
@@ -36,11 +36,12 @@ class PrometheusExporter::Middleware
36
36
 
37
37
  result
38
38
  ensure
39
-
39
+ status = (result && result[0]) || -1
40
40
  obj = {
41
41
  type: "web",
42
42
  timings: info,
43
43
  queue_time: queue_time,
44
+ status: status,
44
45
  default_labels: default_labels(env, result)
45
46
  }
46
47
  labels = custom_labels(env)
@@ -52,18 +53,21 @@ class PrometheusExporter::Middleware
52
53
  end
53
54
 
54
55
  def default_labels(env, result)
55
- status = (result && result[0]) || -1
56
56
  params = env["action_dispatch.request.parameters"]
57
57
  action = controller = nil
58
58
  if params
59
59
  action = params["action"]
60
60
  controller = params["controller"]
61
+ elsif (cors = env["rack.cors"]) && cors.respond_to?(:preflight?) && cors.preflight?
62
+ # if the Rack CORS Middleware identifies the request as a preflight request,
63
+ # the stack doesn't get to the point where controllers/actions are defined
64
+ action = "preflight"
65
+ controller = "preflight"
61
66
  end
62
67
 
63
68
  {
64
69
  action: action || "other",
65
- controller: controller || "other",
66
- status: status
70
+ controller: controller || "other"
67
71
  }
68
72
  end
69
73
 
@@ -14,6 +14,8 @@ module PrometheusExporter::Server
14
14
  register_collector(ProcessCollector.new)
15
15
  register_collector(SidekiqCollector.new)
16
16
  register_collector(SidekiqQueueCollector.new)
17
+ register_collector(SidekiqProcessCollector.new)
18
+ register_collector(SidekiqStatsCollector.new)
17
19
  register_collector(DelayedJobCollector.new)
18
20
  register_collector(PumaCollector.new)
19
21
  register_collector(HutchCollector.new)
@@ -19,22 +19,21 @@ module PrometheusExporter::Server
19
19
  end
20
20
 
21
21
  def collect(obj)
22
- default_labels = { job_name: obj['name'], queue_name: obj['queue_name'] }
23
- custom_labels = obj['custom_labels']
24
-
25
- labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels)
22
+ custom_labels = obj['custom_labels'] || {}
23
+ gauge_labels = { queue_name: obj['queue_name'] }.merge(custom_labels)
24
+ counter_labels = gauge_labels.merge(job_name: obj['name'])
26
25
 
27
26
  ensure_delayed_job_metrics
28
- @delayed_job_duration_seconds.observe(obj["duration"], labels)
29
- @delayed_jobs_total.observe(1, labels)
30
- @delayed_failed_jobs_total.observe(1, labels) if !obj["success"]
31
- @delayed_jobs_max_attempts_reached_total.observe(1, labels) if obj["attempts"] >= obj["max_attempts"]
32
- @delayed_job_duration_seconds_summary.observe(obj["duration"], labels)
33
- @delayed_job_duration_seconds_summary.observe(obj["duration"], labels.merge(status: "success")) if obj["success"]
34
- @delayed_job_duration_seconds_summary.observe(obj["duration"], labels.merge(status: "failed")) if !obj["success"]
35
- @delayed_job_attempts_summary.observe(obj["attempts"], labels) if obj["success"]
36
- @delayed_jobs_enqueued.observe(obj["enqueued"], labels)
37
- @delayed_jobs_pending.observe(obj["pending"], labels)
27
+ @delayed_job_duration_seconds.observe(obj["duration"], counter_labels)
28
+ @delayed_jobs_total.observe(1, counter_labels)
29
+ @delayed_failed_jobs_total.observe(1, counter_labels) if !obj["success"]
30
+ @delayed_jobs_max_attempts_reached_total.observe(1, counter_labels) if obj["attempts"] >= obj["max_attempts"]
31
+ @delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels)
32
+ @delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels.merge(status: "success")) if obj["success"]
33
+ @delayed_job_duration_seconds_summary.observe(obj["duration"], counter_labels.merge(status: "failed")) if !obj["success"]
34
+ @delayed_job_attempts_summary.observe(obj["attempts"], counter_labels) if obj["success"]
35
+ @delayed_jobs_enqueued.observe(obj["enqueued"], gauge_labels)
36
+ @delayed_jobs_pending.observe(obj["pending"], gauge_labels)
38
37
  end
39
38
 
40
39
  def metrics
@@ -77,12 +76,12 @@ module PrometheusExporter::Server
77
76
  "delayed_jobs_max_attempts_reached_total", "Total number of delayed jobs that reached max attempts.")
78
77
 
79
78
  @delayed_job_duration_seconds_summary =
80
- PrometheusExporter::Metric::Summary.new("delayed_job_duration_seconds_summary",
81
- "Summary of the time it takes jobs to execute.")
79
+ PrometheusExporter::Metric::Base.default_aggregation.new("delayed_job_duration_seconds_summary",
80
+ "Summary of the time it takes jobs to execute.")
82
81
 
83
82
  @delayed_job_attempts_summary =
84
- PrometheusExporter::Metric::Summary.new("delayed_job_attempts_summary",
85
- "Summary of the amount of attempts it takes delayed jobs to succeed.")
83
+ PrometheusExporter::Metric::Base.default_aggregation.new("delayed_job_attempts_summary",
84
+ "Summary of the amount of attempts it takes delayed jobs to succeed.")
86
85
  end
87
86
  end
88
87
  end