gitlab-exporter 10.4.0 → 10.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +4 -0
- data/Gemfile.lock +1 -1
- data/config/gitlab-exporter.yml.example +0 -2
- data/lib/gitlab_exporter/cli.rb +1 -1
- data/lib/gitlab_exporter/prometheus.rb +17 -0
- data/lib/gitlab_exporter/sidekiq.rb +49 -0
- data/lib/gitlab_exporter/version.rb +1 -1
- data/spec/prometheus_metrics_spec.rb +17 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c392268186f090b025d290c818f821120f5160a9a59f2e3ba228f26da0b8505
|
4
|
+
data.tar.gz: 3771d5912cb2a310183a1f78a8e24d191eb502d20c2beab3c327994243ae7077
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9ee25b554e51484e4cba96070677c90e3cbad17da49eef2e2f649ad4d4ff125e8e2982cfb6e952444436d7ead6f603f6173ba1270b7112b3de75126cb57b318
|
7
|
+
data.tar.gz: e6038eff74531eb7c0561437cb676336853d9a597b588d07a9561a4561ef165a3ad2f528711b3a2f5d61ebfc8df341ef93ec4d15274fb7efcc88859abc1bc6c3
|
data/.gitlab-ci.yml
CHANGED
@@ -6,6 +6,10 @@ include:
|
|
6
6
|
- template: Security/SAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
|
7
7
|
- template: Security/Secret-Detection.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
|
8
8
|
|
9
|
+
stages:
|
10
|
+
- test
|
11
|
+
- dast
|
12
|
+
|
9
13
|
default:
|
10
14
|
image: ruby:2.7
|
11
15
|
cache:
|
data/Gemfile.lock
CHANGED
data/lib/gitlab_exporter/cli.rb
CHANGED
@@ -217,7 +217,7 @@ module GitLab
|
|
217
217
|
opts.on("--pid=123", "Process ID") do |val|
|
218
218
|
@pid = val
|
219
219
|
end
|
220
|
-
opts.on("--pattern=
|
220
|
+
opts.on("--pattern=worker", "Process command pattern") do |val|
|
221
221
|
@pattern = val
|
222
222
|
end
|
223
223
|
opts.on("--name=NAME", "Process name to be used in metrics") do |val|
|
@@ -15,6 +15,21 @@ module GitLab
|
|
15
15
|
@include_timestamp = include_timestamp
|
16
16
|
end
|
17
17
|
|
18
|
+
class << self
|
19
|
+
def describe(name, description)
|
20
|
+
@metric_descriptions ||= {}
|
21
|
+
@metric_descriptions[name] = description
|
22
|
+
end
|
23
|
+
|
24
|
+
def description(name)
|
25
|
+
@metric_descriptions && @metric_descriptions[name]
|
26
|
+
end
|
27
|
+
|
28
|
+
def clear_descriptions
|
29
|
+
@metric_descriptions = {}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
18
33
|
def add(name, value, quantile = false, **labels)
|
19
34
|
fail "value '#{value}' must be a number" unless value.is_a?(Numeric)
|
20
35
|
|
@@ -32,6 +47,8 @@ module GitLab
|
|
32
47
|
|
33
48
|
buffer = ""
|
34
49
|
@metrics.each do |name, measurements|
|
50
|
+
buffer << "# HELP #{name} #{self.class.description(name)}\n" if self.class.description(name)
|
51
|
+
|
35
52
|
measurements.each do |measurement|
|
36
53
|
buffer << name.to_s
|
37
54
|
labels = (measurement[:labels] || {}).map { |label, value| "#{label}=\"#{value}\"" }.join(",")
|
@@ -10,6 +10,13 @@ module GitLab
|
|
10
10
|
QUEUE_JOB_STATS_SCRIPT = File.read(File.expand_path("#{__FILE__}/../sidekiq_queue_job_stats.lua")).freeze
|
11
11
|
QUEUE_JOB_STATS_SHA = Digest::SHA1.hexdigest(QUEUE_JOB_STATS_SCRIPT).freeze
|
12
12
|
|
13
|
+
# The maximum depth (from the head) of each queue to probe. Probing the
|
14
|
+
# entirety of a very large queue will take longer and run the risk of
|
15
|
+
# timing out. But when we have a very large queue, we are most in need of
|
16
|
+
# reliable metrics. This trades off completeness for predictability by
|
17
|
+
# only taking a limited amount of items from the head of the queue.
|
18
|
+
PROBE_JOBS_LIMIT = 1_000
|
19
|
+
|
13
20
|
POOL_SIZE = 3
|
14
21
|
|
15
22
|
# This timeout is configured to higher interval than scrapping
|
@@ -17,6 +24,9 @@ module GitLab
|
|
17
24
|
# needed to be re-initialized
|
18
25
|
POOL_TIMEOUT = 90
|
19
26
|
|
27
|
+
PrometheusMetrics.describe("sidekiq_enqueued_jobs",
|
28
|
+
"Total number of jobs enqueued by class name. Only inspects the first #{PROBE_JOBS_LIMIT} jobs per queue.") # rubocop:disable Layout/LineLength
|
29
|
+
|
20
30
|
def self.connection_pool
|
21
31
|
@@connection_pool ||= Hash.new do |h, connection_hash| # rubocop:disable Style/ClassVars
|
22
32
|
config = connection_hash.merge(pool_timeout: POOL_TIMEOUT, size: POOL_SIZE)
|
@@ -62,6 +72,13 @@ module GitLab
|
|
62
72
|
self
|
63
73
|
end
|
64
74
|
|
75
|
+
# Count worker classes present in Sidekiq queues. This uses a Lua
|
76
|
+
# script to find all jobs in all queues. That script will block
|
77
|
+
# all other Redis commands:
|
78
|
+
# https://redis.io/commands/eval#atomicity-of-scripts
|
79
|
+
#
|
80
|
+
# The script is generally fast, but may be slower with very large
|
81
|
+
# queues, which is why this is not enabled by default.
|
65
82
|
def probe_jobs
|
66
83
|
with_sidekiq do
|
67
84
|
job_stats = {}
|
@@ -84,6 +101,38 @@ module GitLab
|
|
84
101
|
self
|
85
102
|
end
|
86
103
|
|
104
|
+
# This does the same as #probe_jobs, but only looks at the first
|
105
|
+
# PROBE_JOBS_LIMIT jobs in each queue. This means that we run a
|
106
|
+
# single LRANGE command for each queue, which does not block other
|
107
|
+
# commands. For queues over PROBE_JOBS_LIMIT in size, this means
|
108
|
+
# that we will not have completely accurate statistics, but the
|
109
|
+
# probe performance will also not degrade as the queue gets
|
110
|
+
# larger.
|
111
|
+
#
|
112
|
+
# DO NOT USE this and probe_jobs together, as they export the same
|
113
|
+
# metric (sidekiq_enqueued_jobs).
|
114
|
+
def probe_jobs_limit
|
115
|
+
with_sidekiq do
|
116
|
+
job_stats = Hash.new(0)
|
117
|
+
|
118
|
+
Sidekiq::Queue.all.each do |queue|
|
119
|
+
Sidekiq.redis do |conn|
|
120
|
+
conn.lrange("queue:#{queue.name}", 0, PROBE_JOBS_LIMIT).each do |job|
|
121
|
+
job_class = Sidekiq.load_json(job)["class"]
|
122
|
+
|
123
|
+
job_stats[job_class] += 1
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
job_stats.each do |class_name, count|
|
129
|
+
@metrics.add("sidekiq_enqueued_jobs", count, name: class_name)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
self
|
134
|
+
end
|
135
|
+
|
87
136
|
def probe_workers
|
88
137
|
with_sidekiq do
|
89
138
|
worker_stats = Hash.new(0)
|
@@ -23,4 +23,21 @@ describe GitLab::Exporter::PrometheusMetrics do
|
|
23
23
|
subject.add("mymetric", "invalid", mylabel: "x", myotherlabel: "y").to_s
|
24
24
|
}.to raise_error(RuntimeError)
|
25
25
|
end
|
26
|
+
|
27
|
+
it "supports described metrics" do
|
28
|
+
time = Time.now
|
29
|
+
|
30
|
+
allow(Time).to receive(:now).and_return(time)
|
31
|
+
|
32
|
+
described_class.describe("mymetric", "description")
|
33
|
+
described_class.describe("missingmetric", "otherdescription")
|
34
|
+
subject.add("mymetric", 1.3, mylabel: "x", myotherlabel: "y")
|
35
|
+
|
36
|
+
expect(subject.to_s).to eq(<<~METRICS)
|
37
|
+
# HELP mymetric description
|
38
|
+
mymetric{mylabel="x",myotherlabel="y"} 1.3 #{(time.to_f * 1000).to_i}
|
39
|
+
METRICS
|
40
|
+
|
41
|
+
described_class.clear_descriptions
|
42
|
+
end
|
26
43
|
end
|