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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce8ca39488a8899bf54a56909d58d146630d65b42e15125abe04b71b195184a0
4
- data.tar.gz: 964aa5174ccc4741d8aec5d4f04113fe3300308be52df082b7d3822a3b9486a3
3
+ metadata.gz: c199d67a010ca81ea54be6868ef3224c15633ae3a96f93c796d5388e979fda02
4
+ data.tar.gz: 57c2b7b3cff080ebb2b271781620fcf909374947baa2e427919abc2d4d912faf
5
5
  SHA512:
6
- metadata.gz: cbade2952b3dcec413afad922cd0d092e8a37be8096f520ef3d46a94d129a76e9d2d3e48f5ba97c8c9fb855fe0f707c5ea0ec4c18cb2a9aa2059c069d1e24598
7
- data.tar.gz: bbc7876726057eff433549331304a604160f5a377f7e4185d91b7d1c066196ac14791a24cf67e203e7cfd87b6cda4e70da5264c27b14d82ef356d1b1fa03510b
6
+ metadata.gz: b84c5bf72aeddf20385b464c489bd347ed0f74888b68ed2a573437d8a6dc79ef642d50b7726c067392dedf295c3a7ada74417a2dba79ff8434e93ac4814cc18b
7
+ data.tar.gz: cb981b9dd8f5fe66f1f6bf5a0331a94c79365ca772b274497434aa1401c920fbca197c1cb8218191189eef9bd724794c7a57bfa82e395b03bd828239ab5e7a0f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-exporter (15.2.0)
4
+ gitlab-exporter (15.3.0)
5
5
  connection_pool (= 2.2.5)
6
6
  deep_merge (~> 1.2.2)
7
7
  faraday (>= 1.8.0, <= 2.8.1)
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`
@@ -78,6 +78,9 @@ probes:
78
78
  <<: *db_common_opts
79
79
  project_ids:
80
80
  - 1
81
+ zoekt:
82
+ class_name: Database::ZoektProber
83
+ <<: *db_common
81
84
 
82
85
  process: &process
83
86
  methods:
@@ -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] || {}).map { |label, value| "#{label}=\"#{value}\"" }.join(",")
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
@@ -1,5 +1,5 @@
1
1
  module GitLab
2
2
  module Exporter
3
- VERSION = "15.2.0".freeze
3
+ VERSION = "15.3.0".freeze
4
4
  end
5
5
  end
@@ -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.2.0
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