sidekiq-prometheus-exporter 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/Appraisals +6 -3
- data/Gemfile +1 -1
- data/README.md +6 -2
- data/Rakefile +14 -1
- data/lib/sidekiq/prometheus/exporter/standard.rb +73 -21
- data/lib/sidekiq/prometheus/exporter/templates/standard.erb +37 -8
- data/lib/sidekiq/prometheus/exporter/version.rb +1 -1
- data/sidekiq-prometheus-exporter.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 992a82a14617db8daeecd9c7b100f0a96f1503ada37ad80a509121ce940a6e38
|
4
|
+
data.tar.gz: 06c79dfc4a3652acccd1bffdecff30d46987dfc0a728058b6a8d692e70b59904
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bf9f6c91f5f5596d27bce500312545ae92366b71b0efff62b57883fabf12aa3b02557357b7cff2faa9fec890756722df842471d425b0219df1920cf3ea37490
|
7
|
+
data.tar.gz: e464afd62399b31b5a3970881a8e6ea73a5f0cca4544429689ba699a275b3b5a18e95fdd7093053a85a946c8e555e06603d7ab71f999d72771a93754451ad0d3
|
data/.rubocop.yml
CHANGED
data/Appraisals
CHANGED
@@ -15,16 +15,19 @@ appraise 'sidekiq-5.x' do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
appraise 'sidekiq-6.x' do
|
18
|
+
gem 'base64'
|
18
19
|
gem 'redis', '~> 4.1'
|
19
20
|
gem 'sidekiq', '~> 6.0'
|
20
21
|
end
|
21
22
|
|
22
23
|
appraise 'sidekiq-7.x' do
|
23
|
-
gem 'redis', '~> 5.0'
|
24
24
|
gem 'sidekiq', '~> 7.0'
|
25
25
|
end
|
26
26
|
|
27
|
+
appraise 'sidekiq-8.x' do
|
28
|
+
gem 'sidekiq', '~> 8.0'
|
29
|
+
end
|
30
|
+
|
27
31
|
appraise 'sidekiq-latest' do
|
28
|
-
gem '
|
29
|
-
gem 'sidekiq', '>= 7', github: 'mperham/sidekiq'
|
32
|
+
gem 'sidekiq', '>= 8', github: 'mperham/sidekiq'
|
30
33
|
end
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|

|
2
2
|
[](https://codeclimate.com/github/Strech/sidekiq-prometheus-exporter/maintainability)
|
3
3
|
|
4
|
+
[Sidekiq Enterprise]: https://sidekiq.org/products/enterprise.html
|
5
|
+
|
4
6
|
# Sidekiq Prometheus Exporter
|
5
7
|
|
6
8
|
> — Hey! Sidekiq dashboard stats looks like a Prometheus metrics!?
|
@@ -31,6 +33,7 @@ _(starting Sidekiq `v4.1.0`)_
|
|
31
33
|
| sidekiq_workers | gauge | The number of workers across all the processes |
|
32
34
|
| sidekiq_processes | gauge | The number of processes |
|
33
35
|
| sidekiq_host_processes | gauge | The number of processes running on the host (labels: `host`, `quiet`) |
|
36
|
+
| sidekiq_host_processes_memory_usage_bytes | gauge | The amount of real memory (resident set) used by the processes running on the host (labels: `host`) |
|
34
37
|
| sidekiq_busy_workers | gauge | The number of workers performing the job |
|
35
38
|
| sidekiq_enqueued_jobs | gauge | The number of enqueued jobs |
|
36
39
|
| sidekiq_scheduled_jobs | gauge | The number of jobs scheduled for a future execution |
|
@@ -42,6 +45,7 @@ _(starting Sidekiq `v4.1.0`)_
|
|
42
45
|
| sidekiq_queue_workers | gauge | The number of workers serving the queue (labels: `name`) |
|
43
46
|
| sidekiq_queue_processes | gauge | The number of processes serving the queue (labels: `name`) |
|
44
47
|
| sidekiq_queue_busy_workers | gauge | The number of workers performing the job for the queue (labels: `name`) |
|
48
|
+
| sidekiq_leader_lifetime_seconds | gauge | The number of seconds since cluster leader has been created (available only on [Sidekiq Enterprise]) |
|
45
49
|
|
46
50
|
<details>
|
47
51
|
<summary>Click to expand for all available contribs</summary>
|
@@ -67,7 +71,7 @@ _(starting Sidekiq `v4.1.0`)_
|
|
67
71
|
Add this line to your application's Gemfile:
|
68
72
|
|
69
73
|
```ruby
|
70
|
-
gem 'sidekiq-prometheus-exporter', '~> 0.
|
74
|
+
gem 'sidekiq-prometheus-exporter', '~> 0.3'
|
71
75
|
```
|
72
76
|
|
73
77
|
And then execute:
|
@@ -79,7 +83,7 @@ $ bundle
|
|
79
83
|
Or install it yourself as:
|
80
84
|
|
81
85
|
```console
|
82
|
-
$ gem install sidekiq-prometheus-exporter -v '~> 0.
|
86
|
+
$ gem install sidekiq-prometheus-exporter -v '~> 0.3'
|
83
87
|
```
|
84
88
|
|
85
89
|
## Rack application
|
data/Rakefile
CHANGED
@@ -1,7 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bundler/gem_tasks'
|
2
4
|
require 'rspec/core/rake_task'
|
3
5
|
|
4
|
-
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |t, args|
|
7
|
+
require 'sidekiq/version'
|
8
|
+
directory =
|
9
|
+
case Gem::Version.new(Sidekiq::VERSION).segments[0]
|
10
|
+
when 7 then 'sidekiq-7.x'
|
11
|
+
when 8 then 'sidekiq-8.x'
|
12
|
+
else 'sidekiq'
|
13
|
+
end
|
14
|
+
|
15
|
+
t.pattern = "spec/#{directory}/**/*_spec.rb"
|
16
|
+
t.rspec_opts = args.to_a.join(' ')
|
17
|
+
end
|
5
18
|
|
6
19
|
task default: :spec
|
7
20
|
|
@@ -7,17 +7,31 @@ module Sidekiq
|
|
7
7
|
module Prometheus
|
8
8
|
module Exporter
|
9
9
|
class Standard
|
10
|
-
|
10
|
+
UNKNOWN_IDENTITY = 'unknown-identity'.freeze
|
11
|
+
BYTES_IN_KILOBYTE = 1024
|
12
|
+
OMIT_NEWLINES_MODE = '<>'.freeze
|
13
|
+
TEMPLATE = ERB.new(
|
14
|
+
File.read(File.expand_path('templates/standard.erb', __dir__)),
|
15
|
+
trim_mode: OMIT_NEWLINES_MODE
|
16
|
+
)
|
11
17
|
|
12
|
-
|
13
|
-
|
14
|
-
|
18
|
+
HostStats = Struct.new(:memory_usage, :by_quiet, keyword_init: true)
|
19
|
+
QueueStats = Struct.new(:name, :size, :latency, keyword_init: true)
|
20
|
+
QueueWorkersStats = Struct.new(
|
21
|
+
:total_workers, :busy_workers, :processes, keyword_init: true
|
22
|
+
)
|
23
|
+
WorkersStats = Struct.new(
|
24
|
+
:total_workers, :by_queue, :by_host, :leader_lifetime, keyword_init: true
|
25
|
+
)
|
15
26
|
|
16
27
|
def self.available?
|
17
28
|
true
|
18
29
|
end
|
19
30
|
|
20
31
|
def initialize
|
32
|
+
# Version dependent metrics
|
33
|
+
@show_memory_usage = false
|
34
|
+
|
21
35
|
@overview_stats = Sidekiq::Stats.new
|
22
36
|
@queues_stats = queues_stats
|
23
37
|
@workers_stats = workers_stats
|
@@ -25,46 +39,84 @@ module Sidekiq
|
|
25
39
|
end
|
26
40
|
|
27
41
|
def to_s
|
28
|
-
TEMPLATE.result(binding)
|
42
|
+
TEMPLATE.result(binding)
|
29
43
|
end
|
30
44
|
|
31
45
|
private
|
32
46
|
|
33
47
|
def queues_stats
|
34
48
|
Sidekiq::Queue.all.map do |queue|
|
35
|
-
QueueStats.new(queue.name, queue.size, queue.latency)
|
49
|
+
QueueStats.new(name: queue.name, size: queue.size, latency: queue.latency)
|
36
50
|
end
|
37
51
|
end
|
38
52
|
|
39
53
|
def workers_stats
|
40
|
-
|
54
|
+
processes = Sidekiq::ProcessSet.new
|
55
|
+
workers_stats = WorkersStats.new(total_workers: 0, by_queue: {}, by_host: {})
|
41
56
|
|
42
|
-
|
43
|
-
|
57
|
+
# NOTE: available only on enterprise starting v5.0.1
|
58
|
+
leader_identity =
|
59
|
+
processes.respond_to?(:leader) ? processes.leader : UNKNOWN_IDENTITY
|
44
60
|
|
45
|
-
|
46
|
-
stats.
|
61
|
+
processes.each_with_object(workers_stats) do |process, stats|
|
62
|
+
stats.total_workers += process['concurrency'].to_i
|
47
63
|
|
48
|
-
process['
|
49
|
-
stats.
|
50
|
-
stats.by_queue[queue].processes += 1
|
51
|
-
stats.by_queue[queue].busy_workers += process['busy'].to_i
|
52
|
-
stats.by_queue[queue].total_workers += process['concurrency'].to_i
|
64
|
+
if process['identity'] == leader_identity
|
65
|
+
stats.leader_lifetime = Time.now.utc.to_i - process['started_at']
|
53
66
|
end
|
67
|
+
|
68
|
+
collect_process_stats_by_host(process, stats.by_host)
|
69
|
+
collect_process_stats_by_queue(process, stats.by_queue)
|
54
70
|
end
|
55
71
|
end
|
56
72
|
|
73
|
+
def collect_process_stats_by_host(process, stats)
|
74
|
+
stats[process['hostname']] ||= HostStats.new(memory_usage: 0, by_quiet: Hash.new(0))
|
75
|
+
stats[process['hostname']].by_quiet[process['quiet']] += 1
|
76
|
+
# NOTE: available only starting v6.2.0
|
77
|
+
@show_memory_usage ||= true if process['rss']
|
78
|
+
stats[process['hostname']].memory_usage += kilobytes_to_bytes(process['rss'].to_i)
|
79
|
+
end
|
80
|
+
|
81
|
+
def collect_process_stats_by_queue(process, stats)
|
82
|
+
process['queues'].each do |queue|
|
83
|
+
stats[queue] ||= QueueWorkersStats.new(
|
84
|
+
total_workers: 0, busy_workers: 0, processes: 0
|
85
|
+
)
|
86
|
+
|
87
|
+
stats[queue].processes += 1
|
88
|
+
stats[queue].busy_workers += process['busy'].to_i
|
89
|
+
stats[queue].total_workers += process['concurrency'].to_i
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def kilobytes_to_bytes(kilobytes)
|
94
|
+
kilobytes * BYTES_IN_KILOBYTE
|
95
|
+
end
|
96
|
+
|
57
97
|
def max_processing_times
|
98
|
+
return new_max_processing_times if Sidekiq.const_defined?(:Work)
|
99
|
+
|
58
100
|
now = Time.now.to_i
|
59
101
|
|
60
102
|
Sidekiq::Workers.new
|
61
|
-
.
|
62
|
-
.
|
63
|
-
|
64
|
-
|
65
|
-
memo[queue] = now - oldest_execution['run_at']
|
103
|
+
.each_with_object({}) { |(_, _, work), memo| (memo[work['queue']] ||= []).push(work) }
|
104
|
+
.transform_values! do |works|
|
105
|
+
oldest_work = works.min_by { |work| work['run_at'] }
|
106
|
+
now - oldest_work['run_at']
|
66
107
|
end
|
67
108
|
end
|
109
|
+
|
110
|
+
# TODO: Internally Sidekiq::Work stores `run_at` as a timestamp.
|
111
|
+
# It would be great to use it instead of invoking `Time.at` call.
|
112
|
+
# See: https://github.com/sidekiq/sidekiq/blob/v8.0.0/lib/sidekiq/api.rb#L1253-L1255
|
113
|
+
def new_max_processing_times
|
114
|
+
now = Time.now
|
115
|
+
|
116
|
+
Sidekiq::Workers.new
|
117
|
+
.each_with_object({}) { |(_, _, work), memo| (memo[work.queue] ||= []).push(work) }
|
118
|
+
.transform_values! { |works| now - works.min_by(&:run_at).run_at }
|
119
|
+
end
|
68
120
|
end
|
69
121
|
end
|
70
122
|
end
|
@@ -16,8 +16,20 @@ sidekiq_processes <%= format('%d', @overview_stats.processes_size) %>
|
|
16
16
|
|
17
17
|
# HELP sidekiq_host_processes The number of processes running on the host.
|
18
18
|
# TYPE sidekiq_host_processes gauge
|
19
|
-
<% @workers_stats.by_host.each do |host, stats|
|
20
|
-
<%
|
19
|
+
<% @workers_stats.by_host.each do |host, stats| %>
|
20
|
+
<% stats.by_quiet.each do |quiet, count| %>
|
21
|
+
sidekiq_host_processes{host="<%= host %>",quiet="<%= quiet %>"} <%= format('%i', count) %>
|
22
|
+
<% end %>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<% if @show_memory_usage %>
|
26
|
+
# HELP sidekiq_host_processes_memory_usage_bytes The real memory (resident set) size of the processes running on the host.
|
27
|
+
# TYPE sidekiq_host_processes_memory_usage_bytes gauge
|
28
|
+
<% @workers_stats.by_host.each do |host, stats| %>
|
29
|
+
sidekiq_host_processes_memory_usage_bytes{host="<%= host %>"} <%= format('%i', stats.memory_usage) %>
|
30
|
+
<% end %>
|
31
|
+
|
32
|
+
<% end %>
|
21
33
|
# HELP sidekiq_busy_workers The number of workers performing the job.
|
22
34
|
# TYPE sidekiq_busy_workers gauge
|
23
35
|
sidekiq_busy_workers <%= format('%d', @overview_stats.workers_size) %>
|
@@ -40,25 +52,42 @@ sidekiq_dead_jobs <%= format('%d', @overview_stats.dead_size) %>
|
|
40
52
|
|
41
53
|
# HELP sidekiq_queue_latency_seconds The number of seconds between oldest job being pushed to the queue and current time.
|
42
54
|
# TYPE sidekiq_queue_latency_seconds gauge
|
43
|
-
<% @queues_stats.each do |queue| %>
|
55
|
+
<% @queues_stats.each do |queue| %>
|
56
|
+
sidekiq_queue_latency_seconds{name="<%= queue.name %>"} <%= format('%.3f', queue.latency) %>
|
44
57
|
<% end %>
|
58
|
+
|
45
59
|
# HELP sidekiq_queue_enqueued_jobs The number of enqueued jobs in the queue.
|
46
60
|
# TYPE sidekiq_queue_enqueued_jobs gauge
|
47
|
-
<% @queues_stats.each do |queue| %>
|
61
|
+
<% @queues_stats.each do |queue| %>
|
62
|
+
sidekiq_queue_enqueued_jobs{name="<%= queue.name %>"} <%= format('%d', queue.size) %>
|
48
63
|
<% end %>
|
64
|
+
|
49
65
|
# HELP sidekiq_queue_max_processing_time_seconds The number of seconds between oldest job of the queue being executed and current time.
|
50
66
|
# TYPE sidekiq_queue_max_processing_time_seconds gauge
|
51
|
-
<% @max_processing_times.each do |queue, max_processing_time| %>
|
67
|
+
<% @max_processing_times.each do |queue, max_processing_time| %>
|
68
|
+
sidekiq_queue_max_processing_time_seconds{name="<%= queue %>"} <%= format('%i', max_processing_time) %>
|
52
69
|
<% end %>
|
70
|
+
|
53
71
|
# HELP sidekiq_queue_workers The number of workers serving the queue.
|
54
72
|
# TYPE sidekiq_queue_workers gauge
|
55
|
-
<% @workers_stats.by_queue.each do |queue, stats| %>
|
73
|
+
<% @workers_stats.by_queue.each do |queue, stats| %>
|
74
|
+
sidekiq_queue_workers{name="<%= queue %>"} <%= format('%i', stats.total_workers) %>
|
56
75
|
<% end %>
|
76
|
+
|
57
77
|
# HELP sidekiq_queue_processes The number of processes serving the queue.
|
58
78
|
# TYPE sidekiq_queue_processes gauge
|
59
|
-
<% @workers_stats.by_queue.each do |queue, stats| %>
|
79
|
+
<% @workers_stats.by_queue.each do |queue, stats| %>
|
80
|
+
sidekiq_queue_processes{name="<%= queue %>"} <%= format('%i', stats.processes) %>
|
60
81
|
<% end %>
|
82
|
+
|
61
83
|
# HELP sidekiq_queue_busy_workers The number of workers performing the job for the queue.
|
62
84
|
# TYPE sidekiq_queue_busy_workers gauge
|
63
|
-
<% @workers_stats.by_queue.each do |queue, stats| %>
|
85
|
+
<% @workers_stats.by_queue.each do |queue, stats| %>
|
86
|
+
sidekiq_queue_busy_workers{name="<%= queue %>"} <%= format('%i', stats.busy_workers) %>
|
87
|
+
<% end %>
|
88
|
+
<% if @workers_stats.leader_lifetime %>
|
89
|
+
|
90
|
+
# HELP sidekiq_leader_lifetime_seconds The number of seconds since the leader process has started.
|
91
|
+
# TYPE sidekiq_leader_lifetime_seconds gauge
|
92
|
+
sidekiq_leader_lifetime_seconds <%= format('%d', @workers_stats.leader_lifetime) %>
|
64
93
|
<% end %>
|
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.executables = spec.files.grep(%r{^exe/}) { |file| File.basename(file) }
|
30
30
|
spec.require_paths = %w(lib)
|
31
31
|
|
32
|
-
spec.required_ruby_version = '>= 2.
|
32
|
+
spec.required_ruby_version = '>= 2.5'
|
33
33
|
spec.add_dependency 'rack', '>= 1.6.0'
|
34
34
|
spec.add_dependency 'sidekiq', '>= 4.1.0'
|
35
35
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-prometheus-exporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergey Fedorov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -78,14 +78,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
79
79
|
- - ">="
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '2.
|
81
|
+
version: '2.5'
|
82
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
83
|
requirements:
|
84
84
|
- - ">="
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: '0'
|
87
87
|
requirements: []
|
88
|
-
rubygems_version: 3.3
|
88
|
+
rubygems_version: 3.5.3
|
89
89
|
signing_key:
|
90
90
|
specification_version: 4
|
91
91
|
summary: Prometheus exporter for the Sidekiq
|