gitlab-exporter 13.5.0 → 14.0.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/Gemfile.lock +2 -2
- data/config/gitlab-exporter.yml.example +0 -2
- data/lib/gitlab_exporter/sidekiq.rb +83 -122
- data/lib/gitlab_exporter/version.rb +1 -1
- metadata +1 -3
- data/spec/sidekiq_spec.rb +0 -64
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6420230ed0ec27d530fa71e46c0776ea2cb21b036a198335229fc304dcdfe3e0
|
4
|
+
data.tar.gz: 91205ee62a32b2e00f7978f9fc7ec063be203d593cade97ea481f85ee1388bbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3be9966a1abe20b42169a4a85e20815649c87e46a31f853002dd5fb0eaff6437a692f5904334d42172fb1950627b0d3bba31a67c6992e5533051f367ed74144f
|
7
|
+
data.tar.gz: 20aefc5c04ee63033feeb80e986e6f239a711d9d88197859c154fe4e429573344d52d5c58ca9d9e611dace90804da5fba8341ed45ed5f592e33a5df8c3c6cc7e
|
data/Gemfile.lock
CHANGED
@@ -7,7 +7,6 @@ module GitLab
|
|
7
7
|
# A prober for Sidekiq queues
|
8
8
|
#
|
9
9
|
# It takes the Redis URL Sidekiq is connected to
|
10
|
-
# rubocop:disable Metrics/ClassLength
|
11
10
|
class SidekiqProber
|
12
11
|
# The maximum depth (from the head) of each queue to probe. Probing the
|
13
12
|
# entirety of a very large queue will take longer and run the risk of
|
@@ -41,24 +40,35 @@ module GitLab
|
|
41
40
|
@opts = opts
|
42
41
|
@metrics = metrics
|
43
42
|
@logger = logger
|
44
|
-
|
45
|
-
@probe_namespaced = !!opts[:probe_namespaced] # rubocop:disable Style/DoubleNegation
|
46
|
-
@probe_non_namespaced = !!opts[:probe_non_namespaced] # rubocop:disable Style/DoubleNegation
|
47
|
-
|
48
|
-
# to maintain backward compatibility if the config is missing values
|
49
|
-
@probe_namespaced = true if opts[:probe_namespaced].nil? && opts[:probe_non_namespaced].nil?
|
50
43
|
end
|
51
44
|
|
52
45
|
def probe_stats
|
53
|
-
with_sidekiq
|
54
|
-
|
46
|
+
with_sidekiq do
|
47
|
+
stats = Sidekiq::Stats.new
|
48
|
+
|
49
|
+
@metrics.add("sidekiq_jobs_processed_total", stats.processed)
|
50
|
+
@metrics.add("sidekiq_jobs_failed_total", stats.failed)
|
51
|
+
@metrics.add("sidekiq_jobs_enqueued_size", stats.enqueued)
|
52
|
+
@metrics.add("sidekiq_jobs_scheduled_size", stats.scheduled_size)
|
53
|
+
@metrics.add("sidekiq_jobs_retry_size", stats.retry_size)
|
54
|
+
@metrics.add("sidekiq_jobs_dead_size", stats.dead_size)
|
55
|
+
|
56
|
+
@metrics.add("sidekiq_default_queue_latency_seconds", stats.default_queue_latency)
|
57
|
+
@metrics.add("sidekiq_processes_size", stats.processes_size)
|
58
|
+
@metrics.add("sidekiq_workers_size", stats.workers_size)
|
59
|
+
end
|
55
60
|
|
56
61
|
self
|
57
62
|
end
|
58
63
|
|
59
64
|
def probe_queues
|
60
|
-
with_sidekiq
|
61
|
-
|
65
|
+
with_sidekiq do
|
66
|
+
Sidekiq::Queue.all.each do |queue|
|
67
|
+
@metrics.add("sidekiq_queue_size", queue.size, name: queue.name)
|
68
|
+
@metrics.add("sidekiq_queue_latency_seconds", queue.latency, name: queue.name)
|
69
|
+
@metrics.add("sidekiq_queue_paused", queue.paused? ? 1 : 0, name: queue.name)
|
70
|
+
end
|
71
|
+
end
|
62
72
|
|
63
73
|
self
|
64
74
|
end
|
@@ -71,8 +81,24 @@ module GitLab
|
|
71
81
|
end
|
72
82
|
|
73
83
|
def probe_future_sets
|
74
|
-
|
75
|
-
with_sidekiq
|
84
|
+
now = Time.now.to_f
|
85
|
+
with_sidekiq do
|
86
|
+
Sidekiq.redis do |conn|
|
87
|
+
Sidekiq::Scheduled::SETS.each do |set|
|
88
|
+
# Default to 0; if all jobs are due in the future, there is no "negative" delay.
|
89
|
+
delay = 0
|
90
|
+
|
91
|
+
_job, timestamp = conn.zrangebyscore(set, "-inf", now.to_s, limit: [0, 1], withscores: true).first
|
92
|
+
delay = now - timestamp if timestamp
|
93
|
+
|
94
|
+
@metrics.add("sidekiq_#{set}_set_processing_delay_seconds", delay)
|
95
|
+
|
96
|
+
# zcount is O(log(N)) (prob. binary search), so is still quick even with large sets
|
97
|
+
@metrics.add("sidekiq_#{set}_set_backlog_count",
|
98
|
+
conn.zcount(set, "-inf", now.to_s))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
76
102
|
end
|
77
103
|
|
78
104
|
# Count worker classes present in Sidekiq queues. This only looks at the
|
@@ -82,22 +108,57 @@ module GitLab
|
|
82
108
|
# will not have completely accurate statistics, but the probe performance
|
83
109
|
# will also not degrade as the queue gets larger.
|
84
110
|
def probe_jobs_limit
|
85
|
-
with_sidekiq
|
86
|
-
|
111
|
+
with_sidekiq do
|
112
|
+
job_stats = Hash.new(0)
|
113
|
+
|
114
|
+
Sidekiq::Queue.all.each do |queue|
|
115
|
+
Sidekiq.redis do |conn|
|
116
|
+
conn.lrange("queue:#{queue.name}", 0, PROBE_JOBS_LIMIT).each do |job|
|
117
|
+
job_class = Sidekiq.load_json(job)["class"]
|
118
|
+
|
119
|
+
job_stats[job_class] += 1
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
job_stats.each do |class_name, count|
|
125
|
+
@metrics.add("sidekiq_enqueued_jobs", count, name: class_name)
|
126
|
+
end
|
127
|
+
end
|
87
128
|
|
88
129
|
self
|
89
130
|
end
|
90
131
|
|
91
132
|
def probe_workers
|
92
|
-
with_sidekiq
|
93
|
-
|
133
|
+
with_sidekiq do
|
134
|
+
worker_stats = Hash.new(0)
|
135
|
+
|
136
|
+
Sidekiq::Workers.new.map do |_pid, _tid, work|
|
137
|
+
job_klass = work["payload"]["class"]
|
138
|
+
|
139
|
+
worker_stats[job_klass] += 1
|
140
|
+
end
|
141
|
+
|
142
|
+
worker_stats.each do |class_name, count|
|
143
|
+
@metrics.add("sidekiq_running_jobs", count, name: class_name)
|
144
|
+
end
|
145
|
+
end
|
94
146
|
|
95
147
|
self
|
96
148
|
end
|
97
149
|
|
98
150
|
def probe_retries
|
99
|
-
with_sidekiq
|
100
|
-
|
151
|
+
with_sidekiq do
|
152
|
+
retry_stats = Hash.new(0)
|
153
|
+
|
154
|
+
Sidekiq::RetrySet.new.map do |job|
|
155
|
+
retry_stats[job.klass] += 1
|
156
|
+
end
|
157
|
+
|
158
|
+
retry_stats.each do |class_name, count|
|
159
|
+
@metrics.add("sidekiq_to_be_retried_jobs", count, name: class_name)
|
160
|
+
end
|
161
|
+
end
|
101
162
|
|
102
163
|
self
|
103
164
|
end
|
@@ -119,104 +180,10 @@ module GitLab
|
|
119
180
|
|
120
181
|
private
|
121
182
|
|
122
|
-
def
|
123
|
-
labels = add_namespace_labels? ? { namespaced: namespace } : {}
|
124
|
-
worker_stats = Hash.new(0)
|
125
|
-
|
126
|
-
Sidekiq::Workers.new.map do |_pid, _tid, work|
|
127
|
-
job_klass = work["payload"]["class"]
|
128
|
-
|
129
|
-
worker_stats[job_klass] += 1
|
130
|
-
end
|
131
|
-
|
132
|
-
worker_stats.each do |class_name, count|
|
133
|
-
@metrics.add("sidekiq_running_jobs", count, **labels.merge({ name: class_name }))
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def _probe_future_sets(namespace = true)
|
138
|
-
labels = add_namespace_labels? ? { namespaced: namespace } : {}
|
139
|
-
now = Time.now.to_f
|
140
|
-
Sidekiq.redis do |conn|
|
141
|
-
Sidekiq::Scheduled::SETS.each do |set|
|
142
|
-
# Default to 0; if all jobs are due in the future, there is no "negative" delay.
|
143
|
-
delay = 0
|
144
|
-
|
145
|
-
_job, timestamp = conn.zrangebyscore(set, "-inf", now.to_s, limit: [0, 1], withscores: true).first
|
146
|
-
delay = now - timestamp if timestamp
|
147
|
-
|
148
|
-
@metrics.add("sidekiq_#{set}_set_processing_delay_seconds", delay, **labels)
|
149
|
-
|
150
|
-
# zcount is O(log(N)) (prob. binary search), so is still quick even with large sets
|
151
|
-
@metrics.add("sidekiq_#{set}_set_backlog_count",
|
152
|
-
conn.zcount(set, "-inf", now.to_s), **labels)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def _probe_stats(namespace = true)
|
158
|
-
stats = Sidekiq::Stats.new
|
159
|
-
labels = add_namespace_labels? ? { namespaced: namespace } : {}
|
160
|
-
|
161
|
-
@metrics.add("sidekiq_jobs_processed_total", stats.processed, **labels)
|
162
|
-
@metrics.add("sidekiq_jobs_failed_total", stats.failed, **labels)
|
163
|
-
@metrics.add("sidekiq_jobs_enqueued_size", stats.enqueued, **labels)
|
164
|
-
@metrics.add("sidekiq_jobs_scheduled_size", stats.scheduled_size, **labels)
|
165
|
-
@metrics.add("sidekiq_jobs_retry_size", stats.retry_size, **labels)
|
166
|
-
@metrics.add("sidekiq_jobs_dead_size", stats.dead_size, **labels)
|
167
|
-
|
168
|
-
@metrics.add("sidekiq_default_queue_latency_seconds", stats.default_queue_latency, **labels)
|
169
|
-
@metrics.add("sidekiq_processes_size", stats.processes_size, **labels)
|
170
|
-
@metrics.add("sidekiq_workers_size", stats.workers_size, **labels)
|
171
|
-
end
|
172
|
-
|
173
|
-
def _probe_queues(namespace = true)
|
174
|
-
Sidekiq::Queue.all.each do |queue|
|
175
|
-
labels = { name: queue.name }
|
176
|
-
labels[:namespaced] = namespace if add_namespace_labels?
|
177
|
-
|
178
|
-
@metrics.add("sidekiq_queue_size", queue.size, **labels)
|
179
|
-
@metrics.add("sidekiq_queue_latency_seconds", queue.latency, **labels)
|
180
|
-
@metrics.add("sidekiq_queue_paused", queue.paused? ? 1 : 0, **labels)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
def _probe_jobs_limit(namespace = true)
|
185
|
-
labels = add_namespace_labels? ? { namespaced: namespace } : {}
|
186
|
-
job_stats = Hash.new(0)
|
187
|
-
|
188
|
-
Sidekiq::Queue.all.each do |queue|
|
189
|
-
Sidekiq.redis do |conn|
|
190
|
-
conn.lrange("queue:#{queue.name}", 0, PROBE_JOBS_LIMIT).each do |job|
|
191
|
-
job_class = Sidekiq.load_json(job)["class"]
|
192
|
-
|
193
|
-
job_stats[job_class] += 1
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
job_stats.each do |class_name, count|
|
199
|
-
@metrics.add("sidekiq_enqueued_jobs", count, **labels.merge({ name: class_name }))
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def _probe_retries(namespace = true)
|
204
|
-
labels = add_namespace_labels? ? { namespaced: namespace } : {}
|
205
|
-
retry_stats = Hash.new(0)
|
206
|
-
|
207
|
-
Sidekiq::RetrySet.new.map do |job|
|
208
|
-
retry_stats[job.klass] += 1
|
209
|
-
end
|
210
|
-
|
211
|
-
retry_stats.each do |class_name, count|
|
212
|
-
@metrics.add("sidekiq_to_be_retried_jobs", count, **labels.merge({ name: class_name }))
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def with_sidekiq(namespaced = true)
|
183
|
+
def with_sidekiq
|
217
184
|
SIDEKIQ_REDIS_LOCK.synchronize {
|
218
185
|
Sidekiq.configure_client do |config|
|
219
|
-
config.redis = self.class.connection_pool[redis_options
|
186
|
+
config.redis = self.class.connection_pool[redis_options]
|
220
187
|
end
|
221
188
|
|
222
189
|
return unless connected?
|
@@ -225,14 +192,13 @@ module GitLab
|
|
225
192
|
}
|
226
193
|
end
|
227
194
|
|
228
|
-
def redis_options
|
195
|
+
def redis_options
|
229
196
|
options = {
|
230
197
|
url: @opts[:redis_url],
|
231
198
|
connect_timeout: 1,
|
232
199
|
reconnect_attempts: 0
|
233
200
|
}
|
234
201
|
|
235
|
-
options[:namespace] = "resque:gitlab" if namespaced
|
236
202
|
options[:id] = nil unless redis_enable_client?
|
237
203
|
options
|
238
204
|
end
|
@@ -253,11 +219,6 @@ module GitLab
|
|
253
219
|
@logger&.error "Error connecting to the Redis: #{e}"
|
254
220
|
@connected = false
|
255
221
|
end
|
256
|
-
|
257
|
-
def add_namespace_labels?
|
258
|
-
@probe_namespaced && @probe_non_namespaced
|
259
|
-
end
|
260
222
|
end
|
261
|
-
# rubocop:enable Metrics/ClassLength
|
262
223
|
end
|
263
224
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitlab-exporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 14.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pablo Carranza
|
@@ -236,7 +236,6 @@ files:
|
|
236
236
|
- spec/memstats_spec.rb
|
237
237
|
- spec/prometheus_metrics_spec.rb
|
238
238
|
- spec/ruby_spec.rb
|
239
|
-
- spec/sidekiq_spec.rb
|
240
239
|
- spec/spec_helper.rb
|
241
240
|
- spec/util_spec.rb
|
242
241
|
homepage: https://gitlab.com/gitlab-org/ruby/gems/gitlab-exporter
|
@@ -275,6 +274,5 @@ test_files:
|
|
275
274
|
- spec/memstats_spec.rb
|
276
275
|
- spec/prometheus_metrics_spec.rb
|
277
276
|
- spec/ruby_spec.rb
|
278
|
-
- spec/sidekiq_spec.rb
|
279
277
|
- spec/spec_helper.rb
|
280
278
|
- spec/util_spec.rb
|
data/spec/sidekiq_spec.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "gitlab_exporter/sidekiq"
|
3
|
-
|
4
|
-
describe GitLab::Exporter::SidekiqProber do
|
5
|
-
let(:probe_list) { %w[probe_stats probe_queues probe_future_sets probe_jobs_limit probe_workers probe_retries] }
|
6
|
-
let(:opt) { {} }
|
7
|
-
let(:probe) { described_class.new(**opt) }
|
8
|
-
|
9
|
-
before do
|
10
|
-
# stub connection as we want check if the probe methods are called
|
11
|
-
# with the right namespace argument
|
12
|
-
allow(probe).to receive(:connected?).and_return(true)
|
13
|
-
end
|
14
|
-
|
15
|
-
context "when no namespace options are defined" do
|
16
|
-
it "defaults to probing non-namespaced keys only" do
|
17
|
-
probe_list.each do |probe_type|
|
18
|
-
expect(probe).not_to receive("_#{probe_type}".to_sym).with(false)
|
19
|
-
expect(probe).to receive("_#{probe_type}".to_sym).with(no_args)
|
20
|
-
|
21
|
-
probe.send(probe_type)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context "when probing both namespaces" do
|
27
|
-
let(:opt) { { probe_non_namespaced: true, probe_namespaced: true } }
|
28
|
-
|
29
|
-
it "probes both namespaces" do
|
30
|
-
probe_list.each do |probe_type|
|
31
|
-
expect(probe).to receive("_#{probe_type}".to_sym).with(false)
|
32
|
-
expect(probe).to receive("_#{probe_type}".to_sym).with(no_args)
|
33
|
-
|
34
|
-
probe.send(probe_type)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
context "when probing non-namespaced only" do
|
40
|
-
let(:opt) { { probe_non_namespaced: true } }
|
41
|
-
|
42
|
-
it "probes non-namespaced only" do
|
43
|
-
probe_list.each do |probe_type|
|
44
|
-
expect(probe).to receive("_#{probe_type}".to_sym).with(false)
|
45
|
-
expect(probe).not_to receive("_#{probe_type}".to_sym).with(no_args)
|
46
|
-
|
47
|
-
probe.send(probe_type)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context "when probing namespace only" do
|
53
|
-
let(:opt) { { probe_namespaced: true } }
|
54
|
-
|
55
|
-
it "probes namespaced only" do
|
56
|
-
probe_list.each do |probe_type|
|
57
|
-
expect(probe).not_to receive("_#{probe_type}".to_sym).with(false)
|
58
|
-
expect(probe).to receive("_#{probe_type}".to_sym).with(no_args)
|
59
|
-
|
60
|
-
probe.send(probe_type)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|