gitlab-exporter 16.0.0 → 16.2.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: 9238e8cac6cf2f3ef7988d072cd7a2e2398e0304af9920fa66200965f1c4b98c
4
- data.tar.gz: 6a99535403821e1b5acd5a1b9d46be11a6e97f2b6f8e1c99682faacb733ea847
3
+ metadata.gz: 60e275e1cea2b8841c1c8471f44d851a49b552ede909c91aca462ad60efcd3ab
4
+ data.tar.gz: 59c1f60fc4caed54da0048db13c3dd1566fd70bbb744f3260c16cca78012c018
5
5
  SHA512:
6
- metadata.gz: 9adc56ffd8bb27659d37145b55a96eac0f8a905057ef938568054426c68f7d9693dd38915cd50467d6dd4d58e97c25210630fa2ce1e491096b07ed01e7ef6523
7
- data.tar.gz: ea57211fc8eb131f13b30db56bf014363440effecd9d5ccd21e9e298116b7ee9e90ea7c1c08f91aa53198599840daa99a0b57261d926fa1ce5e28538be18c84e
6
+ metadata.gz: e790d3ec4ebb7e07546d5565dc14fdc62f1131b3b23cf367c502eb12e7d7ed55051dd79fed6e8c865af464d1b120eaf2fe6f4f72f3a6a581915adc342b446ad2
7
+ data.tar.gz: 829b42af76274c5ff4b25c9094545ea42491fc41f16bae2dec96cd3a76450beb7cca40496bbc10f926f75b0bcaa509fb9a4001a3f83b2e7dc3f1031b7554d0d3
data/.gitlab-ci.yml CHANGED
@@ -7,7 +7,7 @@ include:
7
7
  - template: Security/Dependency-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
8
8
 
9
9
  variables:
10
- RUBY_VERSION: "3.0"
10
+ RUBY_VERSION: "3.3"
11
11
 
12
12
  stages:
13
13
  - test
@@ -17,6 +17,7 @@ stages:
17
17
  default:
18
18
  image: ruby:${RUBY_VERSION}
19
19
  cache:
20
+ key: ruby-${RUBY_VERSION}
20
21
  paths:
21
22
  - vendor
22
23
  tags:
@@ -26,6 +27,15 @@ default:
26
27
  - git config --global user.email "bot@gitlab.com"
27
28
  - git config --global user.name "Bot User"
28
29
  - bundle config set --local deployment true
30
+ - |
31
+ # Bundler 2.7.1 and up require Ruby 3.2 and up, so
32
+ # to avoid https://github.com/rubygems/rubygems/issues/5380 use an
33
+ # older Bundler version.
34
+ case ${RUBY_VERSION} in
35
+ "3.0"|"3.1")
36
+ export BUNDLER_VERSION="2.4.20"
37
+ ;;
38
+ esac
29
39
  - bundle install -j $(nproc)
30
40
 
31
41
  workflow:
@@ -52,7 +62,7 @@ rspec_integration:
52
62
  services:
53
63
  - name: redis:${REDIS_VERSION}
54
64
  alias: redis-master
55
- - name: bitnami/redis-sentinel:${REDIS_SENTINEL_VERSION}
65
+ - name: bitnamilegacy/redis-sentinel:${REDIS_SENTINEL_VERSION}
56
66
  alias: redis-sentinel
57
67
  command:
58
68
  - /bin/sh
data/.rubocop_todo.yml CHANGED
@@ -1,19 +1,14 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2021-01-11 12:24:03 UTC using RuboCop version 0.93.1.
3
+ # on 2025-08-06 20:59:18 UTC using RuboCop version 1.79.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 1
10
- # Configuration parameters: Include.
11
- # Include: **/*.gemspec
12
- Gemspec/RequiredRubyVersion:
13
- Exclude:
14
- - 'gitlab-exporter.gemspec'
15
-
16
9
  # Offense count: 3
10
+ # This cop supports safe autocorrection (--autocorrect).
11
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
17
12
  Lint/AmbiguousBlockAssociation:
18
13
  Exclude:
19
14
  - 'spec/git_spec.rb'
@@ -26,38 +21,32 @@ Lint/MissingCopEnableDirective:
26
21
  - 'spec/database/ci_builds_spec.rb'
27
22
  - 'spec/git_process_proper_spec.rb'
28
23
 
29
- # Offense count: 1
30
- # Cop supports --auto-correct.
31
- Lint/NonDeterministicRequireOrder:
32
- Exclude:
33
- - 'spec/spec_helper.rb'
34
-
35
- # Offense count: 16
36
- # Configuration parameters: CountComments, CountAsOne, ExcludedMethods.
37
- # ExcludedMethods: refine
24
+ # Offense count: 24
25
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
26
+ # AllowedMethods: refine
38
27
  Metrics/BlockLength:
39
- Max: 349
28
+ Max: 297
40
29
 
41
- # Offense count: 1
42
- # Configuration parameters: IgnoredMethods.
30
+ # Offense count: 2
31
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
43
32
  Metrics/CyclomaticComplexity:
44
33
  Max: 8
45
34
 
46
35
  # Offense count: 1
47
- # Configuration parameters: IgnoredMethods.
36
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
48
37
  Metrics/PerceivedComplexity:
49
38
  Max: 9
50
39
 
51
40
  # Offense count: 1
52
- # Configuration parameters: EnforcedStyle, AllowModifiersOnSymbols.
53
- # SupportedStyles: inline, group
54
- Style/AccessModifierDeclarations:
41
+ # Configuration parameters: AllowedMethods.
42
+ # AllowedMethods: respond_to_missing?
43
+ Style/OptionalBooleanParameter:
55
44
  Exclude:
56
- - 'lib/gitlab_exporter/util.rb'
45
+ - 'lib/gitlab_exporter/prometheus.rb'
57
46
 
58
- # Offense count: 2
59
- # Cop supports --auto-correct.
60
- # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods.
47
+ # Offense count: 3
48
+ # This cop supports unsafe autocorrection (--autocorrect-all).
49
+ # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength.
61
50
  # AllowedMethods: present?, blank?, presence, try, try!
62
51
  Style/SafeNavigation:
63
52
  Exclude:
data/Gemfile CHANGED
@@ -3,6 +3,5 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem "rspec", "~>3.12"
7
- gem "rubocop", "~>0.42"
6
+ gem "rubocop", "~>1.0"
8
7
  end
data/Gemfile.lock CHANGED
@@ -1,15 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-exporter (16.0.0)
5
- connection_pool (= 2.5.3)
4
+ gitlab-exporter (16.2.0)
5
+ connection_pool (= 2.5.4)
6
6
  deep_merge (~> 1.2.2)
7
- faraday (= 2.13.3)
8
- pg (= 1.5.9)
9
- puma (= 6.6.0)
7
+ faraday (= 2.14.0)
8
+ pg (= 1.6.2)
9
+ puma (= 6.6.1)
10
10
  quantile (= 0.2.1)
11
- redis (= 4.5.0)
12
- redis-namespace (= 1.9.0)
11
+ redis (= 4.8.1)
12
+ redis-namespace (= 1.11.0)
13
13
  sidekiq (= 6.5.12)
14
14
  sinatra (~> 3.2.0)
15
15
  webrick (~> 1.9)
@@ -17,38 +17,42 @@ PATH
17
17
  GEM
18
18
  remote: https://rubygems.org/
19
19
  specs:
20
- ast (2.4.1)
20
+ ast (2.4.3)
21
21
  base64 (0.2.0)
22
- connection_pool (2.5.3)
22
+ connection_pool (2.5.4)
23
23
  deep_merge (1.2.2)
24
24
  diff-lcs (1.5.0)
25
- faraday (2.13.3)
25
+ faraday (2.14.0)
26
26
  faraday-net_http (>= 2.0, < 3.5)
27
27
  json
28
28
  logger
29
29
  faraday-net_http (3.0.2)
30
30
  json (2.13.2)
31
+ language_server-protocol (3.17.0.5)
32
+ lint_roller (1.1.0)
31
33
  logger (1.7.0)
32
34
  mustermann (3.0.3)
33
35
  ruby2_keywords (~> 0.0.1)
34
36
  nio4r (2.7.4)
35
- parallel (1.20.1)
36
- parser (3.0.0.0)
37
+ parallel (1.27.0)
38
+ parser (3.3.9.0)
37
39
  ast (~> 2.4.1)
38
- pg (1.5.9)
39
- puma (6.6.0)
40
+ racc
41
+ pg (1.6.2)
42
+ prism (1.4.0)
43
+ puma (6.6.1)
40
44
  nio4r (~> 2.0)
41
45
  quantile (0.2.1)
46
+ racc (1.8.1)
42
47
  rack (2.2.15)
43
48
  rack-protection (3.2.0)
44
49
  base64 (>= 0.1.0)
45
50
  rack (~> 2.2, >= 2.2.4)
46
- rainbow (3.0.0)
47
- redis (4.5.0)
48
- redis-namespace (1.9.0)
51
+ rainbow (3.1.1)
52
+ redis (4.8.1)
53
+ redis-namespace (1.11.0)
49
54
  redis (>= 4)
50
- regexp_parser (2.0.3)
51
- rexml (3.2.4)
55
+ regexp_parser (2.11.0)
52
56
  rspec (3.12.0)
53
57
  rspec-core (~> 3.12.0)
54
58
  rspec-expectations (~> 3.12.0)
@@ -62,18 +66,21 @@ GEM
62
66
  diff-lcs (>= 1.2.0, < 2.0)
63
67
  rspec-support (~> 3.12.0)
64
68
  rspec-support (3.12.0)
65
- rubocop (0.93.1)
69
+ rubocop (1.81.1)
70
+ json (~> 2.3)
71
+ language_server-protocol (~> 3.17.0.2)
72
+ lint_roller (~> 1.1.0)
66
73
  parallel (~> 1.10)
67
- parser (>= 2.7.1.5)
74
+ parser (>= 3.3.0.2)
68
75
  rainbow (>= 2.2.2, < 4.0)
69
- regexp_parser (>= 1.8)
70
- rexml
71
- rubocop-ast (>= 0.6.0)
76
+ regexp_parser (>= 2.9.3, < 3.0)
77
+ rubocop-ast (>= 1.47.1, < 2.0)
72
78
  ruby-progressbar (~> 1.7)
73
- unicode-display_width (>= 1.4.0, < 2.0)
74
- rubocop-ast (1.4.0)
75
- parser (>= 2.7.1.5)
76
- ruby-progressbar (1.11.0)
79
+ unicode-display_width (>= 2.4.0, < 4.0)
80
+ rubocop-ast (1.47.1)
81
+ parser (>= 3.3.7.2)
82
+ prism (~> 1.4)
83
+ ruby-progressbar (1.13.0)
77
84
  ruby2_keywords (0.0.5)
78
85
  sidekiq (6.5.12)
79
86
  connection_pool (>= 2.2.5, < 3)
@@ -85,7 +92,9 @@ GEM
85
92
  rack-protection (= 3.2.0)
86
93
  tilt (~> 2.0)
87
94
  tilt (2.6.0)
88
- unicode-display_width (1.7.0)
95
+ unicode-display_width (3.1.4)
96
+ unicode-emoji (~> 4.0, >= 4.0.4)
97
+ unicode-emoji (4.0.4)
89
98
  webrick (1.9.1)
90
99
 
91
100
  PLATFORMS
@@ -93,9 +102,9 @@ PLATFORMS
93
102
 
94
103
  DEPENDENCIES
95
104
  gitlab-exporter!
96
- rspec (~> 3.12)
105
+ rspec (~> 3.12.0)
97
106
  rspec-expectations (~> 3.12.0)
98
- rubocop (~> 0.42)
107
+ rubocop (~> 1.0)
99
108
 
100
109
  BUNDLED WITH
101
- 2.4.20
110
+ 2.7.1
@@ -22,14 +22,14 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.required_ruby_version = Gem::Requirement.new(">= 3.0")
24
24
 
25
- s.add_runtime_dependency "connection_pool", "2.5.3"
25
+ s.add_runtime_dependency "connection_pool", "2.5.4"
26
26
  s.add_runtime_dependency "deep_merge", "~> 1.2.2"
27
- s.add_runtime_dependency "faraday", "2.13.3"
28
- s.add_runtime_dependency "pg", "1.5.9"
29
- s.add_runtime_dependency "puma", "6.6.0"
27
+ s.add_runtime_dependency "faraday", "2.14.0"
28
+ s.add_runtime_dependency "pg", "1.6.2"
29
+ s.add_runtime_dependency "puma", "6.6.1"
30
30
  s.add_runtime_dependency "quantile", "0.2.1"
31
- s.add_runtime_dependency "redis", "4.5.0"
32
- s.add_runtime_dependency "redis-namespace", "1.9.0"
31
+ s.add_runtime_dependency "redis", "4.8.1"
32
+ s.add_runtime_dependency "redis-namespace", "1.11.0"
33
33
  s.add_runtime_dependency "sidekiq", "6.5.12"
34
34
  s.add_runtime_dependency "sinatra", "~> 3.2.0"
35
35
  s.add_runtime_dependency "webrick", "~> 1.9"
@@ -44,7 +44,7 @@ module GitLab
44
44
  @options = options(args)
45
45
  args = @options.parse!
46
46
  @source = args.shift
47
- @target = args.shift || STDOUT
47
+ @target = args.shift || $stdout
48
48
  @labels ||= {}
49
49
  end
50
50
 
@@ -79,7 +79,7 @@ module GitLab
79
79
 
80
80
  # Database tuple stats runner.
81
81
  #
82
- # It will take a database connection string and print results to STDOUT
82
+ # It will take a database connection string and print results to $stdout
83
83
  class DatabaseTupleStats
84
84
  COMMAND_NAME = "db-tuple-stats".freeze
85
85
 
@@ -87,7 +87,7 @@ module GitLab
87
87
  @options = options(args)
88
88
  @options.parse!
89
89
 
90
- @target = args.shift || STDOUT
90
+ @target = args.shift || $stdout
91
91
  @target = File.open(@target, "a") if @target.is_a?(String)
92
92
  end
93
93
 
@@ -121,7 +121,7 @@ module GitLab
121
121
 
122
122
  # Database row counts query runner.
123
123
  #
124
- # This will take the database connection and print the result to STDOUT
124
+ # This will take the database connection and print the result to $stdout
125
125
  class DatabaseRowCounts
126
126
  COMMAND_NAME = "row-counts".freeze
127
127
 
@@ -129,7 +129,7 @@ module GitLab
129
129
  @options = options(args)
130
130
  @options.parse!
131
131
 
132
- @target = args.shift || STDOUT
132
+ @target = args.shift || $stdout
133
133
  @target = File.open(@target, "a") if @target.is_a?(String)
134
134
  end
135
135
 
@@ -234,7 +234,7 @@ module GitLab
234
234
  @options = options(args)
235
235
  @options.parse!
236
236
 
237
- @target = args.shift || STDOUT
237
+ @target = args.shift || $stdout
238
238
  @target = File.open(@target, "a") if @target.is_a?(String)
239
239
  end
240
240
 
@@ -271,7 +271,7 @@ module GitLab
271
271
 
272
272
  # Sidekiq runner.
273
273
  #
274
- # It will take a Redis connection URL and print results to STDOUT
274
+ # It will take a Redis connection URL and print results to $stdout
275
275
  class SidekiqRunner
276
276
  COMMAND_NAME = "sidekiq".freeze
277
277
 
@@ -279,7 +279,7 @@ module GitLab
279
279
  @options = options(args)
280
280
  @options.parse!
281
281
 
282
- @target = args.shift || STDOUT
282
+ @target = args.shift || $stdout
283
283
  @target = File.open(@target, "a") if @target.is_a?(String)
284
284
  end
285
285
 
@@ -315,7 +315,7 @@ module GitLab
315
315
  redis_sentinels: @redis_sentinels,
316
316
  redis_sentinel_username: @redis_sentinel_username,
317
317
  redis_sentinel_password: @redis_sentinel_password,
318
- logger: Logger.new(STDERR))
318
+ logger: Logger.new($stderr))
319
319
 
320
320
  prober
321
321
  .probe_stats
@@ -343,7 +343,7 @@ module GitLab
343
343
  @options = options(args)
344
344
  @options.parse!
345
345
 
346
- @target = args.shift || STDOUT
346
+ @target = args.shift || $stdout
347
347
  @target = File.open(@target, "a") if @target.is_a?(String)
348
348
  end
349
349
 
@@ -191,7 +191,7 @@ module GitLab
191
191
  results = []
192
192
 
193
193
  query = ee? ? BUILDS_QUERY_EE : BUILDS_QUERY_CE
194
- query = query % [status] # rubocop:disable Style/FormatString
194
+ query %= [status]
195
195
  exec_query_with_custom_random_page_cost(query).each do |row|
196
196
  results << transform_builds_row_to_values(row)
197
197
  end
@@ -202,7 +202,7 @@ module GitLab
202
202
 
203
203
  result.map do |row|
204
204
  labels = {}
205
- (query_hash[:fields] || []).each do |key, _| labels[key] = row[key.to_s] end
205
+ (query_hash[:fields] || {}).each_key do |key| labels[key] = row[key.to_s] end
206
206
  { "count": row["count"], "labels": labels }
207
207
  end
208
208
  end
@@ -233,7 +233,7 @@ module GitLab
233
233
  query_string << " FROM #{query[:select]}"
234
234
  query_string << " #{query[:joins]}" if query[:joins]
235
235
  query_string << " WHERE #{query[:where]}" if query[:where]
236
- query_string << " GROUP BY " + query[:fields].keys.join(", ") if query[:fields]
236
+ query_string << " GROUP BY #{query[:fields].keys.join(', ')}" if query[:fields]
237
237
  query_string << ";"
238
238
  end
239
239
  end
@@ -3,45 +3,100 @@ module GitLab
3
3
  module Database
4
4
  # A helper class to collect zoekt metrics.
5
5
  class ZoektCollector < Base
6
- QUERY = <<~SQL.freeze
6
+ # Query to get processing zoekt_tasks distribution by zoekt_node_id
7
+ ZOEKT_TASKS_PROCESSING_QUERY = <<~SQL.freeze
7
8
  WITH task_counts AS (
8
- SELECT
9
+ SELECT
9
10
  zoekt_node_id,
10
11
  COUNT(*) AS count
11
- FROM
12
+ FROM
12
13
  zoekt_tasks
13
- WHERE
14
+ WHERE
14
15
  perform_at <= $1
15
16
  AND state IN (0, 1)
16
- GROUP BY
17
+ GROUP BY
17
18
  zoekt_node_id
18
19
  )
19
- SELECT
20
+ SELECT
20
21
  n.id AS node_id,
21
22
  n.metadata ->> 'name' AS node_name,
22
23
  COALESCE(tc.count, 0) AS task_count
23
- FROM
24
+ FROM
24
25
  zoekt_nodes n
25
- LEFT JOIN
26
+ LEFT JOIN
26
27
  task_counts tc ON n.id = tc.zoekt_node_id
27
28
  SQL
28
29
 
30
+ ZOEKT_NODES_QUERY = <<~SQL.freeze
31
+ SELECT schema_version, id FROM zoekt_nodes
32
+ SQL
33
+
34
+ ZOEKT_REPOSITORY_SCHEMA_VERSION_QUERY = <<~SQL.freeze
35
+ SELECT
36
+ COUNT(*)
37
+ FROM
38
+ zoekt_repositories
39
+ INNER JOIN
40
+ zoekt_indices
41
+ ON zoekt_repositories.zoekt_index_id = zoekt_indices.id
42
+ WHERE
43
+ zoekt_indices.zoekt_node_id = $1
44
+ AND zoekt_repositories.schema_version < $2
45
+ AND zoekt_repositories.state = 10;
46
+ SQL
47
+
29
48
  ZOEKT_ENABLED_QUERY = <<~SQL.freeze
30
49
  SELECT
31
- zoekt_settings ->> 'zoekt_indexing_enabled' AS zoekt_indexing_enabled
50
+ zoekt_settings ->> 'zoekt_indexing_enabled' AS zoekt_indexing_enabled
32
51
  FROM application_settings
33
52
  ORDER BY ID DESC
34
53
  LIMIT 1
35
54
  SQL
36
55
 
37
56
  def run
38
- return unless zoekt_indexing_enabled?
57
+ return {} unless zoekt_indexing_enabled?
39
58
 
40
- execute(QUERY, [Time.now.utc])
59
+ {
60
+ task_processing_query_result: execute(ZOEKT_TASKS_PROCESSING_QUERY, [Time.now.utc]),
61
+ repositories_schema_version_query_result: repositories_schema_version_query_result
62
+ }.compact
41
63
  end
42
64
 
43
65
  private
44
66
 
67
+ def repositories_schema_version_query_result
68
+ hash = zoekt_node_schema_version_hash
69
+ return if hash.nil?
70
+
71
+ zoekt_repository_schema_version_result(hash)
72
+ end
73
+
74
+ def zoekt_node_schema_version_hash
75
+ zoekt_nodes = execute(ZOEKT_NODES_QUERY)
76
+ return if zoekt_nodes.nil?
77
+
78
+ hash = {}
79
+ zoekt_nodes.each do |row|
80
+ hash[row["id"]] = row["schema_version"]
81
+ end
82
+ hash
83
+ end
84
+
85
+ def zoekt_repository_schema_version_result(hash)
86
+ result = Set.new
87
+ hash.each do |id, schema_version|
88
+ query_result = execute(ZOEKT_REPOSITORY_SCHEMA_VERSION_QUERY, [id, schema_version])
89
+ if query_result.nil?
90
+ result = nil
91
+ break
92
+ end
93
+
94
+ count = query_result[0]["count"].to_i
95
+ result.add({ target_schema_version: schema_version, zoekt_node_id: id, unfinished_repository_count: count })
96
+ end
97
+ result
98
+ end
99
+
45
100
  def zoekt_indexing_enabled?
46
101
  @zoekt_indexing_enabled ||=
47
102
  begin
@@ -53,7 +108,7 @@ module GitLab
53
108
  end
54
109
  end
55
110
 
56
- def execute(query, params)
111
+ def execute(query, params = [])
57
112
  with_connection_pool do |conn|
58
113
  conn.exec_params(query, params)
59
114
  end
@@ -68,6 +123,10 @@ module GitLab
68
123
  "Number of tasks waiting to be processed by Zoekt",
69
124
  "gauge")
70
125
 
126
+ PrometheusMetrics.describe("search_zoekt_repositories_schema_version_count",
127
+ "Number of zoekt_repositories which do not have the latest schema version",
128
+ "gauge")
129
+
71
130
  def initialize(metrics: PrometheusMetrics.new, **opts)
72
131
  @metrics = metrics
73
132
  @collector = opts[:collector] || ZoektCollector.new(**opts)
@@ -75,13 +134,11 @@ module GitLab
75
134
 
76
135
  def probe_db
77
136
  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
- )
137
+ results[:task_processing_query_result].to_a.each do |row|
138
+ add_processing_zoekt_tasks_to_metric(row)
139
+ end
140
+ results[:repositories_schema_version_query_result]&.each do |row|
141
+ add_zoekt_repositories_by_schema_version_to_metric(row)
85
142
  end
86
143
 
87
144
  self
@@ -89,6 +146,24 @@ module GitLab
89
146
  self
90
147
  end
91
148
 
149
+ def add_processing_zoekt_tasks_to_metric(row)
150
+ @metrics.add(
151
+ "search_zoekt_task_processing_queue_size",
152
+ row["task_count"].to_i,
153
+ node_name: row["node_name"],
154
+ node_id: row["node_id"]
155
+ )
156
+ end
157
+
158
+ def add_zoekt_repositories_by_schema_version_to_metric(row)
159
+ @metrics.add(
160
+ "search_zoekt_repositories_schema_version_count",
161
+ row[:unfinished_repository_count].to_i,
162
+ target_schema_version: row[:target_schema_version],
163
+ zoekt_node_id: row[:zoekt_node_id]
164
+ )
165
+ end
166
+
92
167
  def write_to(target)
93
168
  target.write(@metrics.to_s)
94
169
  end
@@ -101,10 +101,10 @@ module GitLab
101
101
 
102
102
  Utils.pgrep("^git ").each do |pid|
103
103
  process_cmd = begin
104
- File.read("/proc/#{pid}/cmdline")
105
- rescue StandardError
106
- "" # Process file is gone (race condition)
107
- end
104
+ File.read("/proc/#{pid}/cmdline")
105
+ rescue StandardError
106
+ "" # Process file is gone (race condition)
107
+ end
108
108
  subcommand = self.class.extract_subcommand(process_cmd)
109
109
  next unless subcommand # Unlikely, but just to be safe
110
110
 
@@ -142,7 +142,7 @@ module GitLab
142
142
 
143
143
  cmd_splitted.shift # Because it's "git"
144
144
  cmd_splitted.shift while cmd_splitted.first &&
145
- (cmd_splitted.first.empty? || cmd_splitted.first !~ /^[^-][a-z\-]*$/)
145
+ (cmd_splitted.first.empty? || cmd_splitted.first !~ /^[^-][a-z-]*$/)
146
146
 
147
147
  cmd_splitted[0]
148
148
  end
@@ -27,23 +27,9 @@ module GitLab
27
27
  class Mapping
28
28
  FIELDS = %w[size rss shared_clean shared_dirty private_clean private_dirty swap pss].freeze
29
29
 
30
- attr_reader :address_start
31
- attr_reader :address_end
32
- attr_reader :perms
33
- attr_reader :offset
34
- attr_reader :device_major
35
- attr_reader :device_minor
36
- attr_reader :inode
37
- attr_reader :region
30
+ attr_reader :address_start, :address_end, :perms, :offset, :device_major, :device_minor, :inode, :region
38
31
 
39
- attr_accessor :size
40
- attr_accessor :rss
41
- attr_accessor :shared_clean
42
- attr_accessor :shared_dirty
43
- attr_accessor :private_dirty
44
- attr_accessor :private_clean
45
- attr_accessor :swap
46
- attr_accessor :pss
32
+ attr_accessor :size, :rss, :shared_clean, :shared_dirty, :private_dirty, :private_clean, :swap, :pss
47
33
 
48
34
  def initialize(lines)
49
35
  FIELDS.each do |field|
@@ -11,7 +11,7 @@ module GitLab
11
11
  end
12
12
 
13
13
  def probe_all
14
- @prober_opts.each do |_probe_name, params|
14
+ @prober_opts.each_value do |params|
15
15
  Utils.wrap_in_array(params[:opts]).each do |opts|
16
16
  prober = params[:class].new(metrics: @metrics, logger: @logger, **opts)
17
17
  params[:methods].each do |meth|
@@ -1,6 +1,6 @@
1
1
  # Contains helper methods to generate TLS related configuration for web servers
2
2
  module TLSHelper
3
- CERT_REGEX = /-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/.freeze
3
+ CERT_REGEX = /-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/
4
4
 
5
5
  def validate_tls_config(config)
6
6
  %i[tls_cert_path tls_key_path].each do |key|
@@ -1,5 +1,5 @@
1
1
  module GitLab
2
2
  module Exporter
3
- VERSION = "16.0.0".freeze
3
+ VERSION = "16.2.0".freeze
4
4
  end
5
5
  end
@@ -43,10 +43,10 @@ describe GitLab::Exporter::Database::BloatProber do
43
43
  end
44
44
 
45
45
  describe "#probe_db" do
46
- subject { described_class.new(metrics: metrics, collector: collector, logger: STDOUT, **opts).probe_db }
46
+ subject { described_class.new(metrics: metrics, collector: collector, logger: $stdout, **opts).probe_db }
47
47
 
48
48
  before do
49
- expect(collector).to receive(:logger=).with(STDOUT)
49
+ expect(collector).to receive(:logger=).with($stdout)
50
50
  end
51
51
 
52
52
  it "invokes the collector for each bloat type" do
@@ -3,9 +3,9 @@ require "gitlab_exporter/database/row_count"
3
3
 
4
4
  describe GitLab::Exporter::Database::RowCountCollector do
5
5
  let(:query) {
6
- { project_1: { select: :projects, where: "id=1" },
7
- project_2: { select: :projects, where: "id=2" },
8
- project_3: { select: :projects, fields: { is_public: { definition: "visibility_level == 20" } } } }
6
+ { project1: { select: :projects, where: "id=1" },
7
+ project2: { select: :projects, where: "id=2" },
8
+ project3: { select: :projects, fields: { is_public: { definition: "visibility_level == 20" } } } }
9
9
  }
10
10
  let(:collector) { described_class.new(connection_string: "host=localhost") }
11
11
 
@@ -26,29 +26,29 @@ describe GitLab::Exporter::Database::RowCountCollector do
26
26
 
27
27
  it "executes all the queries" do
28
28
  expect(collector.run).to eq(
29
- project_1: [{ count: 0, labels: {} }],
30
- project_2: [{ count: 6, labels: {} }],
31
- project_3: [{ count: 3, labels: { is_public: true } },
32
- { count: 6, labels: { is_public: false } }]
29
+ project1: [{ count: 0, labels: {} }],
30
+ project2: [{ count: 6, labels: {} }],
31
+ project3: [{ count: 3, labels: { is_public: true } },
32
+ { count: 6, labels: { is_public: false } }]
33
33
  )
34
34
  end
35
35
 
36
36
  context "when selected_queries is passed" do
37
- let(:collector) { described_class.new(connection_string: "host=localhost", selected_queries: ["project_2"]) }
37
+ let(:collector) { described_class.new(connection_string: "host=localhost", selected_queries: ["project2"]) }
38
38
 
39
39
  it "executes the selected queries" do
40
- expect(collector.run).to eq(project_2: [{ count: 6, labels: {} }])
40
+ expect(collector.run).to eq(project2: [{ count: 6, labels: {} }])
41
41
  end
42
42
  end
43
43
  end
44
44
 
45
45
  describe "#construct_query" do
46
46
  it "accepts a table and where clause" do
47
- expect(collector.send(:construct_query, query[:project_1])).to eq "SELECT COUNT(*) FROM projects WHERE id=1;"
47
+ expect(collector.send(:construct_query, query[:project1])).to eq "SELECT COUNT(*) FROM projects WHERE id=1;"
48
48
  end
49
49
 
50
50
  it "accepts a table and group (field) clause" do
51
- expect(collector.send(:construct_query, query[:project_3])).to eq \
51
+ expect(collector.send(:construct_query, query[:project3])).to eq \
52
52
  "SELECT COUNT(*), (visibility_level == 20) AS is_public FROM projects GROUP BY is_public;"
53
53
  end
54
54
  end
@@ -4,8 +4,13 @@ require "gitlab_exporter/database/zoekt"
4
4
  describe GitLab::Exporter::Database::ZoektCollector do
5
5
  let(:connection_pool) { double("connection pool") }
6
6
  let(:connection) { double("connection") }
7
- let(:query) { described_class::QUERY }
7
+ let(:zoekt_tasks_processing_query) { described_class::ZOEKT_TASKS_PROCESSING_QUERY }
8
+ let(:zoekt_nodes_query) { described_class::ZOEKT_NODES_QUERY }
9
+ let(:zoekt_nodes_query_results) { [{ "id" => "1", "schema_version" => "2302" }] }
8
10
  let(:zoekt_enabled_query) { described_class::ZOEKT_ENABLED_QUERY }
11
+ let(:zoekt_repository_schema_version_query) { described_class::ZOEKT_REPOSITORY_SCHEMA_VERSION_QUERY }
12
+
13
+ let(:zoekt_repository_schema_version_query_results) { [{ "count" => "1" }] }
9
14
 
10
15
  subject(:collector) { described_class.new(connection_string: "host=localhost") }
11
16
 
@@ -26,13 +31,24 @@ describe GitLab::Exporter::Database::ZoektCollector do
26
31
  describe "#run" do
27
32
  let(:zoekt_enabled_results) {}
28
33
  let(:frozen_time) { Time.new(2023, 1, 1, 0, 0, 0, 0) }
29
- let(:query_results) do
34
+ let(:zoekt_tasks_processing_query_results) do
30
35
  [
31
36
  { "node_id" => "1", "node_name" => "zoekt-1", "task_count" => "5" },
32
37
  { "node_id" => "2", "node_name" => "zoekt-2", "task_count" => "10" }
33
38
  ]
34
39
  end
35
40
 
41
+ let(:zoekt_repositories_schema_version_query_results) do
42
+ Set.new([{ target_schema_version: "2302", zoekt_node_id: "1", unfinished_repository_count: 1 }])
43
+ end
44
+
45
+ let(:result) do
46
+ {
47
+ repositories_schema_version_query_result: zoekt_repositories_schema_version_query_results,
48
+ task_processing_query_result: zoekt_tasks_processing_query_results
49
+ }
50
+ end
51
+
36
52
  before do
37
53
  allow(Time).to receive(:now).and_return(frozen_time)
38
54
  end
@@ -42,10 +58,8 @@ describe GitLab::Exporter::Database::ZoektCollector do
42
58
  stub_zoekt_not_enabled
43
59
  end
44
60
 
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
61
+ it "returns {}" do
62
+ expect(collector.run).to eq({})
49
63
  end
50
64
  end
51
65
 
@@ -54,25 +68,38 @@ describe GitLab::Exporter::Database::ZoektCollector do
54
68
  stub_zoekt_enabled
55
69
  end
56
70
 
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)
71
+ it "executes the query with correct params" do
72
+ expect(connection).to receive(:exec_params).with(zoekt_tasks_processing_query, [frozen_time])
73
+ .and_return(zoekt_tasks_processing_query_results)
74
+ expect(connection).to receive(:exec_params).with(zoekt_nodes_query, [])
75
+ .and_return(zoekt_nodes_query_results)
76
+ expect(connection).to receive(:exec_params).with(zoekt_repository_schema_version_query, %w[1 2302])
77
+ .and_return(zoekt_repository_schema_version_query_results)
59
78
 
60
- expect(collector.run).to eq(query_results)
79
+ expect(collector.run).to eq(result)
61
80
  end
62
81
 
63
82
  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)
83
+ it "does not includes the key which got the exception" do
84
+ allow(connection).to receive(:exec_params).with(zoekt_tasks_processing_query, [frozen_time])
85
+ .and_raise(PG::UndefinedTable)
86
+ allow(connection).to receive(:exec_params).with(zoekt_nodes_query, [])
87
+ .and_raise(PG::UndefinedTable)
66
88
 
67
- expect(collector.run).to be_nil
89
+ expect(collector.run).to eq({})
68
90
  end
69
91
  end
70
92
 
71
93
  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
94
+ it "does not includes the key which got the exception" do
95
+ allow(connection).to receive(:exec_params).with(zoekt_tasks_processing_query, [frozen_time])
96
+ .and_return(zoekt_tasks_processing_query_results)
97
+ expect(connection).to receive(:exec_params).with(zoekt_nodes_query, [])
98
+ .and_return(zoekt_nodes_query_results)
99
+ expect(connection).to receive(:exec_params).with(zoekt_repository_schema_version_query, %w[1 2302])
100
+ .and_raise(PG::UndefinedTable)
101
+
102
+ expect(collector.run).to eq({ task_processing_query_result: zoekt_tasks_processing_query_results })
76
103
  end
77
104
  end
78
105
  end
@@ -99,10 +126,15 @@ describe GitLab::Exporter::Database::ZoektProber do
99
126
  let(:metrics) { double("PrometheusMetrics", add: nil) }
100
127
  let(:collector) { double(GitLab::Exporter::Database::ZoektCollector, run: data) }
101
128
  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
- ]
129
+ {
130
+ repositories_schema_version_query_result: Set.new(
131
+ [{ target_schema_version: "2302", zoekt_node_id: "1", unfinished_repository_count: 1 }]
132
+ ),
133
+ task_processing_query_result: [
134
+ { "node_id" => "1", "node_name" => "zoekt-1", "task_count" => "5" },
135
+ { "node_id" => "2", "node_name" => "zoekt-2", "task_count" => "10" }
136
+ ]
137
+ }
106
138
  end
107
139
 
108
140
  describe "#probe_db" do
@@ -123,7 +155,7 @@ describe GitLab::Exporter::Database::ZoektProber do
123
155
  it "adds metrics for each node" do
124
156
  expect(collector).to receive(:run).and_return(data)
125
157
 
126
- data.each do |node_data|
158
+ data[:task_processing_query_result].each do |node_data|
127
159
  expect(metrics).to receive(:add)
128
160
  .with("search_zoekt_task_processing_queue_size",
129
161
  node_data["task_count"].to_i,
@@ -131,6 +163,16 @@ describe GitLab::Exporter::Database::ZoektProber do
131
163
  node_id: node_data["node_id"])
132
164
  end
133
165
 
166
+ data[:repositories_schema_version_query_result].each do |node_data|
167
+ expect(metrics).to receive(:add)
168
+ .with(
169
+ "search_zoekt_repositories_schema_version_count",
170
+ node_data[:unfinished_repository_count].to_i,
171
+ target_schema_version: node_data[:target_schema_version],
172
+ zoekt_node_id: node_data[:zoekt_node_id]
173
+ )
174
+ end
175
+
134
176
  probe_db
135
177
  end
136
178
  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: 16.0.0
4
+ version: 16.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pablo Carranza
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 2.5.3
19
+ version: 2.5.4
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 2.5.3
26
+ version: 2.5.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: deep_merge
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,42 +44,42 @@ dependencies:
44
44
  requirements:
45
45
  - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: 2.13.3
47
+ version: 2.14.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: 2.13.3
54
+ version: 2.14.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pg
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 1.5.9
61
+ version: 1.6.2
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 1.5.9
68
+ version: 1.6.2
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: puma
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 6.6.0
75
+ version: 6.6.1
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 6.6.0
82
+ version: 6.6.1
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: quantile
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,28 +100,28 @@ dependencies:
100
100
  requirements:
101
101
  - - '='
102
102
  - !ruby/object:Gem::Version
103
- version: 4.5.0
103
+ version: 4.8.1
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - '='
109
109
  - !ruby/object:Gem::Version
110
- version: 4.5.0
110
+ version: 4.8.1
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: redis-namespace
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - '='
116
116
  - !ruby/object:Gem::Version
117
- version: 1.9.0
117
+ version: 1.11.0
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
- version: 1.9.0
124
+ version: 1.11.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: sidekiq
127
127
  requirement: !ruby/object:Gem::Requirement