gitlab-exporter 16.7.0 → 16.9.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 +5 -5
- data/gitlab-exporter.gemspec +2 -2
- data/lib/gitlab_exporter/database/bloat_btree.sql +10 -4
- data/lib/gitlab_exporter/database/bloat_table.sql +10 -3
- data/lib/gitlab_exporter/database/zoekt.rb +124 -32
- data/lib/gitlab_exporter/version.rb +1 -1
- data/spec/database/zoekt_spec.rb +145 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 77bae663d5dff12133db411a27154cb55c100caf0bec1ecdd4dd4e8102c88994
|
|
4
|
+
data.tar.gz: d98c9128dc327d8757d4bb8d021cf863274f59588767ff877ce5ebe4c3274636
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff4b8dc86a0765ab98cf1e7ac97ee7016e09e1ec1e0a08db4366bdd9a66ae75dc34cb9d41ad5ed28668a6d279f641db780526ac3619b04b114f4c68aa29d8a74
|
|
7
|
+
data.tar.gz: a76a114f309436e969865d25cb3a0e7aa4b94d8239cb4d7f775958ef971d3a6747380d002adf8999d3a8be545ad3692980ae980dd5ed6e1a8533cc3f7bc87173
|
data/Gemfile.lock
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
gitlab-exporter (16.
|
|
4
|
+
gitlab-exporter (16.9.0)
|
|
5
5
|
connection_pool (= 2.5.5)
|
|
6
6
|
deep_merge (~> 1.2.2)
|
|
7
|
-
faraday (= 2.14.
|
|
7
|
+
faraday (= 2.14.3)
|
|
8
8
|
pg (= 1.6.3)
|
|
9
|
-
puma (=
|
|
9
|
+
puma (= 8.0.1)
|
|
10
10
|
quantile (= 0.2.1)
|
|
11
11
|
redis (= 4.8.1)
|
|
12
12
|
redis-namespace (= 1.11.0)
|
|
@@ -22,7 +22,7 @@ GEM
|
|
|
22
22
|
connection_pool (2.5.5)
|
|
23
23
|
deep_merge (1.2.2)
|
|
24
24
|
diff-lcs (1.5.0)
|
|
25
|
-
faraday (2.14.
|
|
25
|
+
faraday (2.14.3)
|
|
26
26
|
faraday-net_http (>= 2.0, < 3.5)
|
|
27
27
|
json
|
|
28
28
|
logger
|
|
@@ -40,7 +40,7 @@ GEM
|
|
|
40
40
|
racc
|
|
41
41
|
pg (1.6.3)
|
|
42
42
|
prism (1.9.0)
|
|
43
|
-
puma (
|
|
43
|
+
puma (8.0.1)
|
|
44
44
|
nio4r (~> 2.0)
|
|
45
45
|
quantile (0.2.1)
|
|
46
46
|
racc (1.8.1)
|
data/gitlab-exporter.gemspec
CHANGED
|
@@ -24,9 +24,9 @@ Gem::Specification.new do |s|
|
|
|
24
24
|
|
|
25
25
|
s.add_runtime_dependency "connection_pool", "2.5.5"
|
|
26
26
|
s.add_runtime_dependency "deep_merge", "~> 1.2.2"
|
|
27
|
-
s.add_runtime_dependency "faraday", "2.14.
|
|
27
|
+
s.add_runtime_dependency "faraday", "2.14.3"
|
|
28
28
|
s.add_runtime_dependency "pg", "1.6.3"
|
|
29
|
-
s.add_runtime_dependency "puma", "
|
|
29
|
+
s.add_runtime_dependency "puma", "8.0.1"
|
|
30
30
|
s.add_runtime_dependency "quantile", "0.2.1"
|
|
31
31
|
s.add_runtime_dependency "redis", "4.8.1"
|
|
32
32
|
s.add_runtime_dependency "redis-namespace", "1.11.0"
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
-- Originally from: https://github.com/ioguix/pgsql-bloat-estimation/blob/master/btree/btree_bloat.sql
|
|
2
2
|
-- WARNING: executed with a non-superuser role, the query inspect only index on tables you are granted to read.
|
|
3
3
|
-- WARNING: rows with is_na = 't' are known to have bad statistics ("name" type is not supported).
|
|
4
|
-
-- This query is compatible with PostgreSQL
|
|
4
|
+
-- This query is compatible with PostgreSQL 12 and after
|
|
5
|
+
-- pg_stats is materialized so the planner sees the true row count before planning the join,
|
|
6
|
+
-- avoiding a catastrophic cardinality underestimate on PostgreSQL 17.
|
|
7
|
+
WITH pg_stats_cached AS MATERIALIZED (
|
|
8
|
+
SELECT schemaname, tablename, attname, null_frac, avg_width
|
|
9
|
+
FROM pg_catalog.pg_stats
|
|
10
|
+
)
|
|
5
11
|
SELECT current_database(), nspname AS schemaname, tblname, idxname AS object_name, bs*(relpages)::bigint AS real_size,
|
|
6
12
|
bs*(relpages-est_pages)::bigint AS extra_size,
|
|
7
13
|
100 * (relpages-est_pages)::float / relpages AS extra_ratio,
|
|
@@ -91,9 +97,9 @@ FROM (
|
|
|
91
97
|
AND a2.attnum = ic.attpos
|
|
92
98
|
) i
|
|
93
99
|
JOIN pg_catalog.pg_namespace n ON n.oid = i.relnamespace
|
|
94
|
-
JOIN
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
JOIN pg_stats_cached s ON s.schemaname = n.nspname
|
|
101
|
+
AND s.tablename = i.attrelname
|
|
102
|
+
AND s.attname = i.attname
|
|
97
103
|
GROUP BY 1,2,3,4,5,6,7,8,9,10,11
|
|
98
104
|
) AS rows_data_stats
|
|
99
105
|
) AS rows_hdr_pdg_stats
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
-- Originally from: https://github.com/ioguix/pgsql-bloat-estimation/blob/master/table/table_bloat.sql
|
|
2
2
|
/* WARNING: executed with a non-superuser role, the query inspect only tables and materialized view (9.3+) you are granted to read.
|
|
3
|
-
* This query is compatible with PostgreSQL
|
|
3
|
+
* This query is compatible with PostgreSQL 12 and later
|
|
4
4
|
*/
|
|
5
|
+
-- pg_stats is materialized so the planner sees the true row count before planning the join,
|
|
6
|
+
-- avoiding a catastrophic cardinality underestimate on PostgreSQL 17.
|
|
7
|
+
WITH pg_stats_cached AS MATERIALIZED (
|
|
8
|
+
SELECT schemaname, tablename, attname, null_frac, avg_width
|
|
9
|
+
FROM pg_stats
|
|
10
|
+
WHERE inherited = false
|
|
11
|
+
)
|
|
5
12
|
SELECT current_database(), schemaname, tblname AS object_name, bs*tblpages AS real_size,
|
|
6
13
|
(tblpages-est_tblpages)*bs AS extra_size,
|
|
7
14
|
CASE WHEN tblpages - est_tblpages > 0
|
|
@@ -49,8 +56,8 @@ FROM (
|
|
|
49
56
|
FROM pg_attribute AS att
|
|
50
57
|
JOIN pg_class AS tbl ON att.attrelid = tbl.oid
|
|
51
58
|
JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace
|
|
52
|
-
LEFT JOIN
|
|
53
|
-
AND s.tablename = tbl.relname AND s.
|
|
59
|
+
LEFT JOIN pg_stats_cached AS s ON s.schemaname=ns.nspname
|
|
60
|
+
AND s.tablename = tbl.relname AND s.attname=att.attname
|
|
54
61
|
LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid
|
|
55
62
|
WHERE NOT att.attisdropped
|
|
56
63
|
AND tbl.relkind in ('r','m')
|
|
@@ -2,6 +2,7 @@ module GitLab
|
|
|
2
2
|
module Exporter
|
|
3
3
|
module Database
|
|
4
4
|
# A helper class to collect zoekt metrics.
|
|
5
|
+
# rubocop:disable Metrics/ClassLength
|
|
5
6
|
class ZoektCollector < Base
|
|
6
7
|
# Query to get processing zoekt_tasks distribution by zoekt_node_id
|
|
7
8
|
ZOEKT_TASKS_PROCESSING_QUERY = <<~SQL.freeze
|
|
@@ -62,13 +63,26 @@ module GitLab
|
|
|
62
63
|
LIMIT 1
|
|
63
64
|
SQL
|
|
64
65
|
|
|
66
|
+
# unclaimed_storage_bytes and storage_percent_used are not real columns on
|
|
67
|
+
# zoekt_nodes; they are derived in Search::Zoekt::Node. We compute them in SQL
|
|
68
|
+
# here to avoid loading every row through ActiveRecord.
|
|
65
69
|
ZOEKT_NODE_STORAGE_QUERY = <<~SQL.freeze
|
|
66
70
|
SELECT
|
|
67
|
-
id,
|
|
68
|
-
metadata ->> 'name' AS node_name,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
zn.id,
|
|
72
|
+
zn.metadata ->> 'name' AS node_name,
|
|
73
|
+
(zn.usable_storage_bytes - COALESCE(zi.reserved_total, 0))::bigint
|
|
74
|
+
AS unclaimed_storage_bytes,
|
|
75
|
+
CASE
|
|
76
|
+
WHEN zn.total_bytes > 0
|
|
77
|
+
THEN zn.used_bytes::float8 / zn.total_bytes::float8
|
|
78
|
+
ELSE 0
|
|
79
|
+
END AS storage_percent_used
|
|
80
|
+
FROM zoekt_nodes zn
|
|
81
|
+
LEFT JOIN (
|
|
82
|
+
SELECT zoekt_node_id, SUM(reserved_storage_bytes) AS reserved_total
|
|
83
|
+
FROM zoekt_indices
|
|
84
|
+
GROUP BY zoekt_node_id
|
|
85
|
+
) zi ON zi.zoekt_node_id = zn.id
|
|
72
86
|
SQL
|
|
73
87
|
|
|
74
88
|
ZOEKT_REPOSITORIES_STATE_QUERY = <<~SQL.freeze
|
|
@@ -95,6 +109,40 @@ module GitLab
|
|
|
95
109
|
zoekt_nodes ON zoekt_indices.zoekt_node_id = zoekt_nodes.id
|
|
96
110
|
SQL
|
|
97
111
|
|
|
112
|
+
ZOEKT_NODE_ENABLED_NAMESPACES_QUERY = <<~SQL.freeze
|
|
113
|
+
SELECT
|
|
114
|
+
zn.id AS node_id,
|
|
115
|
+
zn.metadata ->> 'name' AS node_name,
|
|
116
|
+
COUNT(DISTINCT zi.zoekt_enabled_namespace_id) AS count
|
|
117
|
+
FROM zoekt_nodes zn
|
|
118
|
+
LEFT JOIN zoekt_indices zi ON zi.zoekt_node_id = zn.id
|
|
119
|
+
GROUP BY zn.id, zn.metadata ->> 'name'
|
|
120
|
+
SQL
|
|
121
|
+
|
|
122
|
+
ZOEKT_NODE_TASKS_QUERY = <<~SQL.freeze
|
|
123
|
+
SELECT
|
|
124
|
+
zn.id AS node_id,
|
|
125
|
+
zn.metadata ->> 'name' AS node_name,
|
|
126
|
+
zt.state,
|
|
127
|
+
COUNT(*) AS count
|
|
128
|
+
FROM zoekt_nodes zn
|
|
129
|
+
LEFT JOIN zoekt_tasks zt ON zt.zoekt_node_id = zn.id
|
|
130
|
+
GROUP BY zn.id, zn.metadata ->> 'name', zt.state
|
|
131
|
+
SQL
|
|
132
|
+
|
|
133
|
+
ZOEKT_INDICES_STALE_USED_STORAGE_QUERY = <<~SQL.freeze
|
|
134
|
+
SELECT COUNT(*) AS count FROM zoekt_indices WHERE last_indexed_at >= used_storage_bytes_updated_at
|
|
135
|
+
SQL
|
|
136
|
+
|
|
137
|
+
ZOEKT_TASK_STATES = {
|
|
138
|
+
0 => "pending",
|
|
139
|
+
1 => "processing",
|
|
140
|
+
10 => "done",
|
|
141
|
+
250 => "skipped",
|
|
142
|
+
255 => "failed",
|
|
143
|
+
256 => "orphaned"
|
|
144
|
+
}.freeze
|
|
145
|
+
|
|
98
146
|
def run
|
|
99
147
|
return {} unless zoekt_indexing_enabled?
|
|
100
148
|
|
|
@@ -106,7 +154,10 @@ module GitLab
|
|
|
106
154
|
repositories_state_query_result: execute(ZOEKT_REPOSITORIES_STATE_QUERY),
|
|
107
155
|
indices_state_query_result: execute(ZOEKT_INDICES_STATE_QUERY),
|
|
108
156
|
indices_watermark_query_result: execute(ZOEKT_INDICES_WATERMARK_QUERY),
|
|
109
|
-
indices_storage_query_result: execute(ZOEKT_INDICES_STORAGE_QUERY)
|
|
157
|
+
indices_storage_query_result: execute(ZOEKT_INDICES_STORAGE_QUERY),
|
|
158
|
+
node_enabled_namespaces_query_result: execute(ZOEKT_NODE_ENABLED_NAMESPACES_QUERY),
|
|
159
|
+
node_tasks_query_result: execute(ZOEKT_NODE_TASKS_QUERY),
|
|
160
|
+
indices_stale_used_storage_query_result: execute(ZOEKT_INDICES_STALE_USED_STORAGE_QUERY)
|
|
110
161
|
}.compact
|
|
111
162
|
end
|
|
112
163
|
|
|
@@ -163,10 +214,12 @@ module GitLab
|
|
|
163
214
|
with_connection_pool do |conn|
|
|
164
215
|
conn.exec_params(query, params)
|
|
165
216
|
end
|
|
166
|
-
rescue PG::UndefinedTable, PG::UndefinedColumn
|
|
217
|
+
rescue PG::UndefinedTable, PG::UndefinedColumn => e
|
|
218
|
+
@logger&.warn("ZoektCollector query failed: #{e.class}: #{e.message.lines.first&.strip}")
|
|
167
219
|
nil
|
|
168
220
|
end
|
|
169
221
|
end
|
|
222
|
+
# rubocop:enable Metrics/ClassLength
|
|
170
223
|
|
|
171
224
|
# The prober which is called when gathering metrics
|
|
172
225
|
# rubocop:disable Metrics/ClassLength
|
|
@@ -231,6 +284,24 @@ module GitLab
|
|
|
231
284
|
"gauge"
|
|
232
285
|
)
|
|
233
286
|
|
|
287
|
+
PrometheusMetrics.describe(
|
|
288
|
+
"search_zoekt_node_enabled_namespaces",
|
|
289
|
+
"Number of enabled namespaces per Zoekt node",
|
|
290
|
+
"gauge"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
PrometheusMetrics.describe(
|
|
294
|
+
"search_zoekt_node_tasks",
|
|
295
|
+
"Number of Zoekt indexing tasks on a node, broken down by state",
|
|
296
|
+
"gauge"
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
PrometheusMetrics.describe(
|
|
300
|
+
"search_zoekt_indices_with_stale_used_storage_bytes",
|
|
301
|
+
"Number of Zoekt indices whose used_storage_bytes value has not been updated since the last index run",
|
|
302
|
+
"gauge"
|
|
303
|
+
)
|
|
304
|
+
|
|
234
305
|
def initialize(metrics: PrometheusMetrics.new, **opts)
|
|
235
306
|
@metrics = metrics
|
|
236
307
|
@collector = opts[:collector] || ZoektCollector.new(**opts)
|
|
@@ -255,6 +326,9 @@ module GitLab
|
|
|
255
326
|
process_indices_state_results(results[:indices_state_query_result])
|
|
256
327
|
process_indices_watermark_results(results[:indices_watermark_query_result])
|
|
257
328
|
process_indices_storage_results(results[:indices_storage_query_result])
|
|
329
|
+
process_node_enabled_namespaces_results(results[:node_enabled_namespaces_query_result])
|
|
330
|
+
process_node_tasks_results(results[:node_tasks_query_result])
|
|
331
|
+
process_indices_stale_used_storage_results(results[:indices_stale_used_storage_query_result])
|
|
258
332
|
end
|
|
259
333
|
|
|
260
334
|
def process_task_results(results)
|
|
@@ -349,23 +423,11 @@ module GitLab
|
|
|
349
423
|
end
|
|
350
424
|
|
|
351
425
|
def add_zoekt_repositories_state_to_metric(row)
|
|
352
|
-
@metrics.add(
|
|
353
|
-
"search_zoekt_repositories_states_total",
|
|
354
|
-
row["count"].to_i,
|
|
355
|
-
**{
|
|
356
|
-
state: row["state"]
|
|
357
|
-
}.compact
|
|
358
|
-
)
|
|
426
|
+
@metrics.add("search_zoekt_repositories_states_total", row["count"].to_i, **{ state: row["state"] }.compact)
|
|
359
427
|
end
|
|
360
428
|
|
|
361
429
|
def add_zoekt_indices_state_to_metric(row)
|
|
362
|
-
@metrics.add(
|
|
363
|
-
"search_zoekt_indices_states",
|
|
364
|
-
row["count"].to_i,
|
|
365
|
-
**{
|
|
366
|
-
state: row["state"]
|
|
367
|
-
}.compact
|
|
368
|
-
)
|
|
430
|
+
@metrics.add("search_zoekt_indices_states", row["count"].to_i, **{ state: row["state"] }.compact)
|
|
369
431
|
end
|
|
370
432
|
|
|
371
433
|
def add_zoekt_indices_watermark_to_metric(row)
|
|
@@ -378,26 +440,56 @@ module GitLab
|
|
|
378
440
|
)
|
|
379
441
|
end
|
|
380
442
|
|
|
381
|
-
|
|
382
|
-
|
|
443
|
+
def process_node_enabled_namespaces_results(results)
|
|
444
|
+
results&.each { |row| add_zoekt_node_enabled_namespaces_to_metric(row) }
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def process_node_tasks_results(results)
|
|
448
|
+
results&.each { |row| add_zoekt_node_tasks_to_metric(row) }
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def process_indices_stale_used_storage_results(results)
|
|
452
|
+
results&.each { |row| add_zoekt_indices_stale_used_storage_to_metric(row) }
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def add_zoekt_node_enabled_namespaces_to_metric(row)
|
|
383
456
|
@metrics.add(
|
|
384
|
-
"
|
|
385
|
-
row["
|
|
457
|
+
"search_zoekt_node_enabled_namespaces",
|
|
458
|
+
row["count"].to_i,
|
|
386
459
|
**{
|
|
387
|
-
|
|
388
|
-
|
|
460
|
+
node_id: row["node_id"],
|
|
461
|
+
node_name: row["node_name"]
|
|
389
462
|
}.compact
|
|
390
463
|
)
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
def add_zoekt_node_tasks_to_metric(row)
|
|
467
|
+
state_int = row["state"]&.to_i
|
|
468
|
+
return if row["state"].nil?
|
|
469
|
+
|
|
470
|
+
state_label = ZoektCollector::ZOEKT_TASK_STATES[state_int]
|
|
471
|
+
return if state_label.nil?
|
|
472
|
+
|
|
391
473
|
@metrics.add(
|
|
392
|
-
"
|
|
393
|
-
row["
|
|
474
|
+
"search_zoekt_node_tasks",
|
|
475
|
+
row["count"].to_i,
|
|
394
476
|
**{
|
|
395
|
-
|
|
396
|
-
|
|
477
|
+
node_id: row["node_id"],
|
|
478
|
+
node_name: row["node_name"],
|
|
479
|
+
state: state_label
|
|
397
480
|
}.compact
|
|
398
481
|
)
|
|
399
482
|
end
|
|
400
|
-
|
|
483
|
+
|
|
484
|
+
def add_zoekt_indices_stale_used_storage_to_metric(row)
|
|
485
|
+
@metrics.add("search_zoekt_indices_with_stale_used_storage_bytes", row["count"].to_i)
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def add_zoekt_indices_storage_to_metric(row)
|
|
489
|
+
payload = { zoekt_index_id: row["id"], zoekt_node_name: row["node_name"] }.compact
|
|
490
|
+
@metrics.add("search_zoekt_indices_reserved_storage_bytes", row["reserved_storage_bytes"].to_i, **payload)
|
|
491
|
+
@metrics.add("search_zoekt_indices_used_storage_bytes", row["used_storage_bytes"].to_i, **payload)
|
|
492
|
+
end
|
|
401
493
|
|
|
402
494
|
def write_to(target)
|
|
403
495
|
target.write(@metrics.to_s)
|
data/spec/database/zoekt_spec.rb
CHANGED
|
@@ -36,6 +36,23 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
|
36
36
|
"node_name" => "zoekt-2" }
|
|
37
37
|
]
|
|
38
38
|
end
|
|
39
|
+
let(:zoekt_node_enabled_namespaces_query) { described_class::ZOEKT_NODE_ENABLED_NAMESPACES_QUERY }
|
|
40
|
+
let(:zoekt_node_enabled_namespaces_query_results) do
|
|
41
|
+
[
|
|
42
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "count" => "3" },
|
|
43
|
+
{ "node_id" => "2", "node_name" => "zoekt-2", "count" => "5" }
|
|
44
|
+
]
|
|
45
|
+
end
|
|
46
|
+
let(:zoekt_node_tasks_query) { described_class::ZOEKT_NODE_TASKS_QUERY }
|
|
47
|
+
let(:zoekt_node_tasks_query_results) do
|
|
48
|
+
[
|
|
49
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "state" => "0", "count" => "4" },
|
|
50
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "state" => "1", "count" => "2" },
|
|
51
|
+
{ "node_id" => "2", "node_name" => "zoekt-2", "state" => "10", "count" => "7" }
|
|
52
|
+
]
|
|
53
|
+
end
|
|
54
|
+
let(:zoekt_indices_stale_used_storage_query) { described_class::ZOEKT_INDICES_STALE_USED_STORAGE_QUERY }
|
|
55
|
+
let(:zoekt_indices_stale_used_storage_query_results) { [{ "count" => "6" }] }
|
|
39
56
|
|
|
40
57
|
let(:zoekt_repository_schema_version_query_results) { [{ "count" => "1" }] }
|
|
41
58
|
|
|
@@ -80,7 +97,10 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
|
80
97
|
repositories_state_query_result: zoekt_repositories_state_query_results,
|
|
81
98
|
indices_state_query_result: zoekt_indices_state_query_results,
|
|
82
99
|
indices_watermark_query_result: zoekt_indices_watermark_query_results,
|
|
83
|
-
indices_storage_query_result: zoekt_indices_storage_query_results
|
|
100
|
+
indices_storage_query_result: zoekt_indices_storage_query_results,
|
|
101
|
+
node_enabled_namespaces_query_result: zoekt_node_enabled_namespaces_query_results,
|
|
102
|
+
node_tasks_query_result: zoekt_node_tasks_query_results,
|
|
103
|
+
indices_stale_used_storage_query_result: zoekt_indices_stale_used_storage_query_results
|
|
84
104
|
}
|
|
85
105
|
end
|
|
86
106
|
|
|
@@ -122,6 +142,12 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
|
122
142
|
.and_return(zoekt_indices_watermark_query_results)
|
|
123
143
|
expect(connection).to receive(:exec_params).with(zoekt_indices_storage_query, [])
|
|
124
144
|
.and_return(zoekt_indices_storage_query_results)
|
|
145
|
+
expect(connection).to receive(:exec_params).with(zoekt_node_enabled_namespaces_query, [])
|
|
146
|
+
.and_return(zoekt_node_enabled_namespaces_query_results)
|
|
147
|
+
expect(connection).to receive(:exec_params).with(zoekt_node_tasks_query, [])
|
|
148
|
+
.and_return(zoekt_node_tasks_query_results)
|
|
149
|
+
expect(connection).to receive(:exec_params).with(zoekt_indices_stale_used_storage_query, [])
|
|
150
|
+
.and_return(zoekt_indices_stale_used_storage_query_results)
|
|
125
151
|
|
|
126
152
|
expect(collector.run).to eq(result)
|
|
127
153
|
end
|
|
@@ -144,6 +170,12 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
|
144
170
|
.and_raise(PG::UndefinedTable)
|
|
145
171
|
allow(connection).to receive(:exec_params).with(zoekt_indices_storage_query, [])
|
|
146
172
|
.and_raise(PG::UndefinedTable)
|
|
173
|
+
allow(connection).to receive(:exec_params).with(zoekt_node_enabled_namespaces_query, [])
|
|
174
|
+
.and_raise(PG::UndefinedTable)
|
|
175
|
+
allow(connection).to receive(:exec_params).with(zoekt_node_tasks_query, [])
|
|
176
|
+
.and_raise(PG::UndefinedTable)
|
|
177
|
+
allow(connection).to receive(:exec_params).with(zoekt_indices_stale_used_storage_query, [])
|
|
178
|
+
.and_raise(PG::UndefinedTable)
|
|
147
179
|
|
|
148
180
|
expect(collector.run).to eq({})
|
|
149
181
|
end
|
|
@@ -167,6 +199,12 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
|
167
199
|
.and_raise(PG::UndefinedColumn)
|
|
168
200
|
expect(connection).to receive(:exec_params).with(zoekt_indices_storage_query, [])
|
|
169
201
|
.and_raise(PG::UndefinedColumn)
|
|
202
|
+
expect(connection).to receive(:exec_params).with(zoekt_node_enabled_namespaces_query, [])
|
|
203
|
+
.and_raise(PG::UndefinedColumn)
|
|
204
|
+
expect(connection).to receive(:exec_params).with(zoekt_node_tasks_query, [])
|
|
205
|
+
.and_raise(PG::UndefinedColumn)
|
|
206
|
+
expect(connection).to receive(:exec_params).with(zoekt_indices_stale_used_storage_query, [])
|
|
207
|
+
.and_raise(PG::UndefinedColumn)
|
|
170
208
|
|
|
171
209
|
expect(collector.run).to eq({ task_processing_query_result: zoekt_tasks_processing_query_results })
|
|
172
210
|
end
|
|
@@ -174,6 +212,33 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
|
174
212
|
end
|
|
175
213
|
end
|
|
176
214
|
|
|
215
|
+
describe "ZOEKT_NODE_STORAGE_QUERY" do
|
|
216
|
+
subject(:query) { described_class::ZOEKT_NODE_STORAGE_QUERY }
|
|
217
|
+
|
|
218
|
+
it "selects the unclaimed_storage_bytes and storage_percent_used aliases" do
|
|
219
|
+
expect(query).to match(/AS unclaimed_storage_bytes/)
|
|
220
|
+
expect(query).to match(/AS storage_percent_used/)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it "computes unclaimed_storage_bytes from real columns rather than referencing a non-existent column" do
|
|
224
|
+
# zoekt_nodes does not have an unclaimed_storage_bytes column; it must be derived
|
|
225
|
+
# from usable_storage_bytes minus the SUM of zoekt_indices.reserved_storage_bytes.
|
|
226
|
+
expect(query).to include("usable_storage_bytes")
|
|
227
|
+
expect(query).to include("reserved_storage_bytes")
|
|
228
|
+
expect(query).to include("zoekt_indices")
|
|
229
|
+
expect(query).not_to match(/^\s*unclaimed_storage_bytes\b/)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "computes storage_percent_used from used_bytes / total_bytes with a guard" do
|
|
233
|
+
# zoekt_nodes does not have a storage_percent_used column; it must be derived
|
|
234
|
+
# from used_bytes / total_bytes (with a divide-by-zero guard).
|
|
235
|
+
expect(query).to include("used_bytes")
|
|
236
|
+
expect(query).to include("total_bytes")
|
|
237
|
+
expect(query).to match(/total_bytes\s*>\s*0/)
|
|
238
|
+
expect(query).not_to match(/^\s*storage_percent_used\b/)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
177
242
|
describe "#zoekt_indexing_enabled?" do
|
|
178
243
|
it "returns true when zoekt is enabled" do
|
|
179
244
|
expect(connection).to receive(:exec)
|
|
@@ -230,6 +295,19 @@ describe GitLab::Exporter::Database::ZoektProber do
|
|
|
230
295
|
"node_name" => "zoekt-1" },
|
|
231
296
|
{ "id" => "2", "reserved_storage_bytes" => "2000000", "used_storage_bytes" => "1500000",
|
|
232
297
|
"node_name" => "zoekt-2" }
|
|
298
|
+
],
|
|
299
|
+
node_enabled_namespaces_query_result: [
|
|
300
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "count" => "3" },
|
|
301
|
+
{ "node_id" => "2", "node_name" => "zoekt-2", "count" => "5" }
|
|
302
|
+
],
|
|
303
|
+
node_tasks_query_result: [
|
|
304
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "state" => "0", "count" => "4" },
|
|
305
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "state" => "1", "count" => "2" },
|
|
306
|
+
{ "node_id" => "2", "node_name" => "zoekt-2", "state" => "10", "count" => "7" },
|
|
307
|
+
{ "node_id" => "2", "node_name" => "zoekt-2", "state" => nil, "count" => "1" }
|
|
308
|
+
],
|
|
309
|
+
indices_stale_used_storage_query_result: [
|
|
310
|
+
{ "count" => "6" }
|
|
233
311
|
]
|
|
234
312
|
}
|
|
235
313
|
end
|
|
@@ -334,7 +412,73 @@ describe GitLab::Exporter::Database::ZoektProber do
|
|
|
334
412
|
)
|
|
335
413
|
end
|
|
336
414
|
|
|
415
|
+
data[:node_enabled_namespaces_query_result].each do |ns_data|
|
|
416
|
+
expect(metrics).to receive(:add)
|
|
417
|
+
.with(
|
|
418
|
+
"search_zoekt_node_enabled_namespaces",
|
|
419
|
+
ns_data["count"].to_i,
|
|
420
|
+
node_id: ns_data["node_id"],
|
|
421
|
+
node_name: ns_data["node_name"]
|
|
422
|
+
)
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Only rows with a known state integer are emitted; the nil-state row is skipped.
|
|
426
|
+
task_state_map = GitLab::Exporter::Database::ZoektCollector::ZOEKT_TASK_STATES
|
|
427
|
+
data[:node_tasks_query_result].each do |task_data|
|
|
428
|
+
next if task_data["state"].nil?
|
|
429
|
+
|
|
430
|
+
state_label = task_state_map[task_data["state"].to_i]
|
|
431
|
+
next if state_label.nil?
|
|
432
|
+
|
|
433
|
+
expect(metrics).to receive(:add)
|
|
434
|
+
.with(
|
|
435
|
+
"search_zoekt_node_tasks",
|
|
436
|
+
task_data["count"].to_i,
|
|
437
|
+
node_id: task_data["node_id"],
|
|
438
|
+
node_name: task_data["node_name"],
|
|
439
|
+
state: state_label
|
|
440
|
+
)
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
data[:indices_stale_used_storage_query_result].each do |stale_data|
|
|
444
|
+
expect(metrics).to receive(:add)
|
|
445
|
+
.with(
|
|
446
|
+
"search_zoekt_indices_with_stale_used_storage_bytes",
|
|
447
|
+
stale_data["count"].to_i
|
|
448
|
+
)
|
|
449
|
+
end
|
|
450
|
+
|
|
337
451
|
probe_db
|
|
338
452
|
end
|
|
453
|
+
|
|
454
|
+
context "when node_tasks_query_result contains nil state rows" do
|
|
455
|
+
it "skips rows where state is nil" do
|
|
456
|
+
nil_state_data = data.merge(
|
|
457
|
+
node_tasks_query_result: [{ "node_id" => "1", "node_name" => "zoekt-1", "state" => nil, "count" => "3" }],
|
|
458
|
+
node_enabled_namespaces_query_result: [],
|
|
459
|
+
indices_stale_used_storage_query_result: []
|
|
460
|
+
)
|
|
461
|
+
allow(collector).to receive(:run).and_return(nil_state_data)
|
|
462
|
+
|
|
463
|
+
expect(metrics).not_to receive(:add).with("search_zoekt_node_tasks", anything, anything)
|
|
464
|
+
|
|
465
|
+
described_class.new(metrics: metrics, collector: collector, **opts).probe_db
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
context "when node_tasks_query_result contains an unknown state integer" do
|
|
470
|
+
it "skips rows where state integer is not in ZOEKT_TASK_STATES" do
|
|
471
|
+
unknown_state_data = data.merge(
|
|
472
|
+
node_tasks_query_result: [{ "node_id" => "1", "node_name" => "zoekt-1", "state" => "99", "count" => "2" }],
|
|
473
|
+
node_enabled_namespaces_query_result: [],
|
|
474
|
+
indices_stale_used_storage_query_result: []
|
|
475
|
+
)
|
|
476
|
+
allow(collector).to receive(:run).and_return(unknown_state_data)
|
|
477
|
+
|
|
478
|
+
expect(metrics).not_to receive(:add).with("search_zoekt_node_tasks", anything, anything)
|
|
479
|
+
|
|
480
|
+
described_class.new(metrics: metrics, collector: collector, **opts).probe_db
|
|
481
|
+
end
|
|
482
|
+
end
|
|
339
483
|
end
|
|
340
484
|
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.
|
|
4
|
+
version: 16.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pablo Carranza
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - '='
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 2.14.
|
|
47
|
+
version: 2.14.3
|
|
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.14.
|
|
54
|
+
version: 2.14.3
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: pg
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,14 +72,14 @@ dependencies:
|
|
|
72
72
|
requirements:
|
|
73
73
|
- - '='
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
75
|
+
version: 8.0.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:
|
|
82
|
+
version: 8.0.1
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: quantile
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|