gitlab-exporter 15.2.0 → 15.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/Gemfile.lock +1 -1
- data/README.md +2 -0
- data/config/gitlab-exporter.yml.example +3 -0
- data/lib/gitlab_exporter/database/zoekt.rb +98 -0
- data/lib/gitlab_exporter/database.rb +1 -0
- data/lib/gitlab_exporter/prometheus.rb +14 -2
- data/lib/gitlab_exporter/version.rb +1 -1
- data/spec/database/zoekt_spec.rb +137 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c199d67a010ca81ea54be6868ef3224c15633ae3a96f93c796d5388e979fda02
|
4
|
+
data.tar.gz: 57c2b7b3cff080ebb2b271781620fcf909374947baa2e427919abc2d4d912faf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b84c5bf72aeddf20385b464c489bd347ed0f74888b68ed2a573437d8a6dc79ef642d50b7726c067392dedf295c3a7ada74417a2dba79ff8434e93ac4814cc18b
|
7
|
+
data.tar.gz: cb981b9dd8f5fe66f1f6bf5a0331a94c79365ca772b274497434aa1401c920fbca197c1cb8218191189eef9bd724794c7a57bfa82e395b03bd828239ab5e7a0f
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -31,6 +31,8 @@ metrics.
|
|
31
31
|
(table bloat) and keys `bloat_ratio bloat_size extra_size real_size` (see below)
|
32
32
|
* [Remote mirrors](lib/gitlab_exporter/database/remote_mirrors.rb) --
|
33
33
|
`project_remote_mirror_last_successful_update_time_seconds`, `project_remote_mirror_last_update_time_seconds`
|
34
|
+
* [Zoekt](lib/gitlab_exporter/database/zoekt.rb) --
|
35
|
+
`search_zoekt_task_processing_queue_size`
|
34
36
|
1. Git
|
35
37
|
* [git pull/push timings](lib/gitlab_exporter/git.rb) --
|
36
38
|
`git_pull_time_milliseconds`, `git_push_time_milliseconds`
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module GitLab
|
2
|
+
module Exporter
|
3
|
+
module Database
|
4
|
+
# A helper class to collect zoekt metrics.
|
5
|
+
class ZoektCollector < Base
|
6
|
+
QUERY = <<~SQL.freeze
|
7
|
+
WITH task_counts AS (
|
8
|
+
SELECT
|
9
|
+
zoekt_node_id,
|
10
|
+
COUNT(*) AS count
|
11
|
+
FROM
|
12
|
+
zoekt_tasks
|
13
|
+
WHERE
|
14
|
+
perform_at <= $1
|
15
|
+
AND state IN (0, 1)
|
16
|
+
GROUP BY
|
17
|
+
zoekt_node_id
|
18
|
+
)
|
19
|
+
SELECT
|
20
|
+
n.id AS node_id,
|
21
|
+
n.metadata ->> 'name' AS node_name,
|
22
|
+
COALESCE(tc.count, 0) AS task_count
|
23
|
+
FROM
|
24
|
+
zoekt_nodes n
|
25
|
+
LEFT JOIN
|
26
|
+
task_counts tc ON n.id = tc.zoekt_node_id
|
27
|
+
SQL
|
28
|
+
|
29
|
+
ZOEKT_ENABLED_QUERY = <<~SQL.freeze
|
30
|
+
SELECT
|
31
|
+
zoekt_settings ->> 'zoekt_indexing_enabled' AS zoekt_indexing_enabled
|
32
|
+
FROM application_settings
|
33
|
+
ORDER BY ID DESC
|
34
|
+
LIMIT 1
|
35
|
+
SQL
|
36
|
+
|
37
|
+
def run
|
38
|
+
return unless zoekt_indexing_enabled?
|
39
|
+
|
40
|
+
execute(QUERY, [Time.now.utc])
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def zoekt_indexing_enabled?
|
46
|
+
@zoekt_indexing_enabled ||=
|
47
|
+
begin
|
48
|
+
with_connection_pool do |conn|
|
49
|
+
conn.exec(ZOEKT_ENABLED_QUERY).first["zoekt_indexing_enabled"] == "true"
|
50
|
+
end
|
51
|
+
rescue PG::UndefinedColumn
|
52
|
+
false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def execute(query, params)
|
57
|
+
with_connection_pool do |conn|
|
58
|
+
conn.exec_params(query, params)
|
59
|
+
end
|
60
|
+
rescue PG::UndefinedTable, PG::UndefinedColumn
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# The prober which is called when gathering metrics
|
66
|
+
class ZoektProber
|
67
|
+
PrometheusMetrics.describe("search_zoekt_task_processing_queue_size",
|
68
|
+
"Number of tasks waiting to be processed by Zoekt",
|
69
|
+
"gauge")
|
70
|
+
|
71
|
+
def initialize(metrics: PrometheusMetrics.new, **opts)
|
72
|
+
@metrics = metrics
|
73
|
+
@collector = opts[:collector] || ZoektCollector.new(**opts)
|
74
|
+
end
|
75
|
+
|
76
|
+
def probe_db
|
77
|
+
results = @collector.run
|
78
|
+
results.to_a.each do |row|
|
79
|
+
@metrics.add(
|
80
|
+
"search_zoekt_task_processing_queue_size",
|
81
|
+
row["task_count"].to_i,
|
82
|
+
node_name: row["node_name"],
|
83
|
+
node_id: row["node_id"]
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
self
|
88
|
+
rescue PG::ConnectionBad
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
def write_to(target)
|
93
|
+
target.write(@metrics.to_s)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -9,6 +9,7 @@ module GitLab
|
|
9
9
|
autoload :BloatProber, "gitlab_exporter/database/bloat"
|
10
10
|
autoload :RemoteMirrorsProber, "gitlab_exporter/database/remote_mirrors"
|
11
11
|
autoload :PgSequencesProber, "gitlab_exporter/database/pg_sequences"
|
12
|
+
autoload :ZoektProber, "gitlab_exporter/database/zoekt"
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
@@ -16,17 +16,24 @@ module GitLab
|
|
16
16
|
end
|
17
17
|
|
18
18
|
class << self
|
19
|
-
def describe(name, description)
|
19
|
+
def describe(name, description, metric_type = nil)
|
20
20
|
@metric_descriptions ||= {}
|
21
21
|
@metric_descriptions[name] = description
|
22
|
+
@metric_types ||= {}
|
23
|
+
@metric_types[name] = metric_type
|
22
24
|
end
|
23
25
|
|
24
26
|
def description(name)
|
25
27
|
@metric_descriptions && @metric_descriptions[name]
|
26
28
|
end
|
27
29
|
|
30
|
+
def metric_type(name)
|
31
|
+
@metric_types && @metric_types[name]
|
32
|
+
end
|
33
|
+
|
28
34
|
def clear_descriptions
|
29
35
|
@metric_descriptions = {}
|
36
|
+
@metric_types = {}
|
30
37
|
end
|
31
38
|
end
|
32
39
|
|
@@ -48,10 +55,11 @@ module GitLab
|
|
48
55
|
buffer = ""
|
49
56
|
@metrics.each do |name, measurements|
|
50
57
|
buffer << "# HELP #{name} #{self.class.description(name)}\n" if self.class.description(name)
|
58
|
+
buffer << "# TYPE #{name} #{self.class.metric_type(name)}\n" if self.class.metric_type(name)
|
51
59
|
|
52
60
|
measurements.each do |measurement|
|
53
61
|
buffer << name.to_s
|
54
|
-
labels = (measurement[:labels]
|
62
|
+
labels = labels(measurement[:labels])
|
55
63
|
buffer << "{#{labels}}" unless labels.empty?
|
56
64
|
buffer << " #{measurement[:value]}"
|
57
65
|
buffer << " #{measurement[:timestamp]}" if @include_timestamp
|
@@ -63,6 +71,10 @@ module GitLab
|
|
63
71
|
|
64
72
|
private
|
65
73
|
|
74
|
+
def labels(measurement_labels = {})
|
75
|
+
measurement_labels.map { |label, value| "#{label}=\"#{value}\"" }.join(",")
|
76
|
+
end
|
77
|
+
|
66
78
|
def add_quantiles_to_metrics
|
67
79
|
@quantiles.each do |data, measurements|
|
68
80
|
estimator = Quantile::Estimator.new
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "gitlab_exporter/database/zoekt"
|
3
|
+
|
4
|
+
describe GitLab::Exporter::Database::ZoektCollector do
|
5
|
+
let(:connection_pool) { double("connection pool") }
|
6
|
+
let(:connection) { double("connection") }
|
7
|
+
let(:query) { described_class::QUERY }
|
8
|
+
let(:zoekt_enabled_query) { described_class::ZOEKT_ENABLED_QUERY }
|
9
|
+
|
10
|
+
subject(:collector) { described_class.new(connection_string: "host=localhost") }
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(collector).to receive(:connection_pool).and_return(connection_pool)
|
14
|
+
allow(connection_pool).to receive(:with).and_yield(connection)
|
15
|
+
# allow(Time).to receive(:now).and_return(time_now)
|
16
|
+
end
|
17
|
+
|
18
|
+
def stub_zoekt_enabled
|
19
|
+
allow(connection).to receive(:exec).with(zoekt_enabled_query).and_return([{ "zoekt_indexing_enabled" => "true" }])
|
20
|
+
end
|
21
|
+
|
22
|
+
def stub_zoekt_not_enabled
|
23
|
+
allow(connection).to receive(:exec).with(zoekt_enabled_query).and_return([{ "zoekt_indexing_enabled" => "false" }])
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#run" do
|
27
|
+
let(:zoekt_enabled_results) {}
|
28
|
+
let(:frozen_time) { Time.new(2023, 1, 1, 0, 0, 0, 0) }
|
29
|
+
let(:query_results) do
|
30
|
+
[
|
31
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "task_count" => "5" },
|
32
|
+
{ "node_id" => "2", "node_name" => "zoekt-2", "task_count" => "10" }
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
before do
|
37
|
+
allow(Time).to receive(:now).and_return(frozen_time)
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when zoekt is not enabled" do
|
41
|
+
before do
|
42
|
+
stub_zoekt_not_enabled
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns nil" do
|
46
|
+
allow(connection).to receive(:exec_params).with(query, frozen_time).and_raise(PG::UndefinedTable)
|
47
|
+
|
48
|
+
expect(collector.run).to be_nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when zoekt is enabled" do
|
53
|
+
before do
|
54
|
+
stub_zoekt_enabled
|
55
|
+
end
|
56
|
+
|
57
|
+
it "executes the query with the current time" do
|
58
|
+
expect(connection).to receive(:exec_params).with(query, [frozen_time]).and_return(query_results)
|
59
|
+
|
60
|
+
expect(collector.run).to eq(query_results)
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when PG::UndefinedTable is raised" do
|
64
|
+
it "returns nil" do
|
65
|
+
allow(connection).to receive(:exec_params).with(query, [frozen_time]).and_raise(PG::UndefinedTable)
|
66
|
+
|
67
|
+
expect(collector.run).to be_nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when PG::UndefinedColumn is raised" do
|
72
|
+
it "returns nil" do
|
73
|
+
allow(connection).to receive(:exec_params).with(query, [frozen_time]).and_raise(PG::UndefinedColumn)
|
74
|
+
|
75
|
+
expect(collector.run).to be_nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#zoekt_indexing_enabled?" do
|
82
|
+
it "returns true when zoekt is enabled" do
|
83
|
+
expect(connection).to receive(:exec)
|
84
|
+
.with(zoekt_enabled_query).and_return([{ "zoekt_indexing_enabled" => "true" }])
|
85
|
+
|
86
|
+
expect(subject.send(:zoekt_indexing_enabled?)).to eq(true)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "returns false when PG::UndefinedColumn is raised" do
|
90
|
+
expect(connection).to receive(:exec).with(zoekt_enabled_query).and_raise(PG::UndefinedColumn)
|
91
|
+
|
92
|
+
expect(subject.send(:zoekt_indexing_enabled?)).to eq(false)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe GitLab::Exporter::Database::ZoektProber do
|
98
|
+
let(:opts) { { connection_string: "host=localhost" } }
|
99
|
+
let(:metrics) { double("PrometheusMetrics", add: nil) }
|
100
|
+
let(:collector) { double(GitLab::Exporter::Database::ZoektCollector, run: data) }
|
101
|
+
let(:data) do
|
102
|
+
[
|
103
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "task_count" => "5" },
|
104
|
+
{ "node_id" => "2", "node_name" => "zoekt-2", "task_count" => "10" }
|
105
|
+
]
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#probe_db" do
|
109
|
+
before do
|
110
|
+
allow(collector).to receive(:connected?).and_return(true)
|
111
|
+
end
|
112
|
+
|
113
|
+
subject(:probe_db) do
|
114
|
+
described_class.new(metrics: metrics, collector: collector, **opts).probe_db
|
115
|
+
end
|
116
|
+
|
117
|
+
it "invokes the collector" do
|
118
|
+
expect(collector).to receive(:run)
|
119
|
+
|
120
|
+
probe_db
|
121
|
+
end
|
122
|
+
|
123
|
+
it "adds metrics for each node" do
|
124
|
+
expect(collector).to receive(:run).and_return(data)
|
125
|
+
|
126
|
+
data.each do |node_data|
|
127
|
+
expect(metrics).to receive(:add)
|
128
|
+
.with("search_zoekt_task_processing_queue_size",
|
129
|
+
node_data["task_count"].to_i,
|
130
|
+
node_name: node_data["node_name"],
|
131
|
+
node_id: node_data["node_id"])
|
132
|
+
end
|
133
|
+
|
134
|
+
probe_db
|
135
|
+
end
|
136
|
+
end
|
137
|
+
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: 15.
|
4
|
+
version: 15.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pablo Carranza
|
@@ -231,6 +231,7 @@ files:
|
|
231
231
|
- lib/gitlab_exporter/database/remote_mirrors.rb
|
232
232
|
- lib/gitlab_exporter/database/row_count.rb
|
233
233
|
- lib/gitlab_exporter/database/tuple_stats.rb
|
234
|
+
- lib/gitlab_exporter/database/zoekt.rb
|
234
235
|
- lib/gitlab_exporter/elasticsearch.rb
|
235
236
|
- lib/gitlab_exporter/git.rb
|
236
237
|
- lib/gitlab_exporter/memstats.rb
|
@@ -250,6 +251,7 @@ files:
|
|
250
251
|
- spec/database/ci_builds_spec.rb
|
251
252
|
- spec/database/pg_sequences_spec.rb
|
252
253
|
- spec/database/row_count_spec.rb
|
254
|
+
- spec/database/zoekt_spec.rb
|
253
255
|
- spec/elasticsearch_spec.rb
|
254
256
|
- spec/fixtures/config.yml
|
255
257
|
- spec/fixtures/smaps/sample.txt
|
@@ -290,6 +292,7 @@ test_files:
|
|
290
292
|
- spec/database/ci_builds_spec.rb
|
291
293
|
- spec/database/pg_sequences_spec.rb
|
292
294
|
- spec/database/row_count_spec.rb
|
295
|
+
- spec/database/zoekt_spec.rb
|
293
296
|
- spec/elasticsearch_spec.rb
|
294
297
|
- spec/fixtures/config.yml
|
295
298
|
- spec/fixtures/smaps/sample.txt
|