gitlab-exporter 17.0.2 → 17.1.1
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 +6 -6
- data/README.md +5 -0
- data/config/gitlab-exporter.yml.example +3 -0
- data/gitlab-exporter.gemspec +1 -1
- data/lib/gitlab_exporter/database/geo_node_status.rb +116 -0
- data/lib/gitlab_exporter/database.rb +1 -0
- data/lib/gitlab_exporter/version.rb +1 -1
- data/spec/config_spec.rb +36 -0
- data/spec/database/geo_node_status_spec.rb +210 -0
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 50fbeb1ab763a918c65648dcb9d400b724b15c46ff74512a226291d8d1b47a32
|
|
4
|
+
data.tar.gz: e80d1246a12289f9a117f91c4821bb779849b2bb3df22bdfe16063074031c804
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9d7174c179fc0cbb08c5caea1171be487a5005e1aa85817dc8f8a1495beaa92e03195a6bac17f9e60196649ded0bb8c0e18f42cfd797920e3cc2203cddfb4581
|
|
7
|
+
data.tar.gz: b1867eb94ccdd9fd44f79ac0e1278bb184c9923bb4e65cb4575c87dd3ec68ea9f6f753c27d2266c5f9a9510efa9d3873bd9702c48005310d97bb3394e26878c2
|
data/Gemfile.lock
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
gitlab-exporter (17.
|
|
4
|
+
gitlab-exporter (17.1.1)
|
|
5
5
|
base64 (= 0.3.0)
|
|
6
6
|
connection_pool (= 2.5.5)
|
|
7
7
|
deep_merge (~> 1.2.2)
|
|
8
|
-
faraday (= 2.14.
|
|
8
|
+
faraday (= 2.14.4)
|
|
9
9
|
pg (= 1.6.3)
|
|
10
10
|
quantile (= 0.2.1)
|
|
11
11
|
redis (= 4.8.1)
|
|
@@ -21,7 +21,7 @@ GEM
|
|
|
21
21
|
connection_pool (2.5.5)
|
|
22
22
|
deep_merge (1.2.2)
|
|
23
23
|
diff-lcs (1.5.0)
|
|
24
|
-
faraday (2.14.
|
|
24
|
+
faraday (2.14.4)
|
|
25
25
|
faraday-net_http (>= 2.0, < 3.5)
|
|
26
26
|
json
|
|
27
27
|
logger
|
|
@@ -57,8 +57,8 @@ GEM
|
|
|
57
57
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
58
58
|
rspec-support (~> 3.12.0)
|
|
59
59
|
rspec-support (3.12.0)
|
|
60
|
-
rubocop (1.
|
|
61
|
-
json (
|
|
60
|
+
rubocop (1.91.0)
|
|
61
|
+
json (>= 2.3)
|
|
62
62
|
language_server-protocol (~> 3.17.0.2)
|
|
63
63
|
lint_roller (~> 1.1.0)
|
|
64
64
|
parallel (>= 1.10)
|
|
@@ -91,4 +91,4 @@ DEPENDENCIES
|
|
|
91
91
|
rubocop (~> 1.0)
|
|
92
92
|
|
|
93
93
|
BUNDLED WITH
|
|
94
|
-
4.0.
|
|
94
|
+
4.0.18
|
data/README.md
CHANGED
|
@@ -32,6 +32,11 @@ metrics.
|
|
|
32
32
|
(table bloat) and keys `bloat_ratio bloat_size extra_size real_size` (see below)
|
|
33
33
|
* [Remote mirrors](lib/gitlab_exporter/database/remote_mirrors.rb) --
|
|
34
34
|
`project_remote_mirror_last_successful_update_time_seconds`, `project_remote_mirror_last_update_time_seconds`
|
|
35
|
+
* [Geo node status](lib/gitlab_exporter/database/geo_node_status.rb) -- Geo metrics from
|
|
36
|
+
`geo_node_statuses`, emitted as `geo_<status_field>` gauges with trailing `_count` and
|
|
37
|
+
`_total` suffixes removed, matching Rails' exported metric fields and `name`/`url` labels.
|
|
38
|
+
Usage-data counters are excluded. Enable the `geo_node_status` probe in the `database`
|
|
39
|
+
endpoint configuration.
|
|
35
40
|
* [Zoekt](lib/gitlab_exporter/database/zoekt.rb) --
|
|
36
41
|
`search_zoekt_task_processing_queue_size`
|
|
37
42
|
1. Git
|
data/gitlab-exporter.gemspec
CHANGED
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
|
28
28
|
s.add_runtime_dependency "base64", "0.3.0"
|
|
29
29
|
s.add_runtime_dependency "connection_pool", "2.5.5"
|
|
30
30
|
s.add_runtime_dependency "deep_merge", "~> 1.2.2"
|
|
31
|
-
s.add_runtime_dependency "faraday", "2.14.
|
|
31
|
+
s.add_runtime_dependency "faraday", "2.14.4"
|
|
32
32
|
s.add_runtime_dependency "pg", "1.6.3"
|
|
33
33
|
s.add_runtime_dependency "quantile", "0.2.1"
|
|
34
34
|
s.add_runtime_dependency "redis", "4.8.1"
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
module GitLab
|
|
2
|
+
module Exporter
|
|
3
|
+
module Database
|
|
4
|
+
# A helper class to collect Geo node status metrics.
|
|
5
|
+
class GeoNodeStatusCollector < Base
|
|
6
|
+
QUERY = <<~SQL.freeze
|
|
7
|
+
SELECT
|
|
8
|
+
geo_nodes.name AS geo_node_name,
|
|
9
|
+
geo_node_statuses.db_replication_lag_seconds,
|
|
10
|
+
geo_node_statuses.replication_slots_count,
|
|
11
|
+
geo_node_statuses.replication_slots_used_count,
|
|
12
|
+
geo_node_statuses.replication_slots_max_retained_wal_bytes,
|
|
13
|
+
geo_node_statuses.last_event_id,
|
|
14
|
+
geo_node_statuses.cursor_last_event_id,
|
|
15
|
+
geo_node_statuses.status,
|
|
16
|
+
EXTRACT(EPOCH FROM geo_node_statuses.last_event_date)::bigint AS last_event_timestamp,
|
|
17
|
+
EXTRACT(EPOCH FROM geo_node_statuses.cursor_last_event_date)::bigint AS cursor_last_event_timestamp,
|
|
18
|
+
EXTRACT(EPOCH FROM geo_node_statuses.last_successful_status_check_at)::bigint
|
|
19
|
+
AS last_successful_status_check_timestamp
|
|
20
|
+
FROM geo_node_statuses
|
|
21
|
+
INNER JOIN geo_nodes ON geo_nodes.id = geo_node_statuses.geo_node_id
|
|
22
|
+
WHERE geo_nodes.enabled = TRUE
|
|
23
|
+
SQL
|
|
24
|
+
|
|
25
|
+
def run
|
|
26
|
+
with_connection_pool do |conn|
|
|
27
|
+
conn.exec(QUERY)
|
|
28
|
+
end
|
|
29
|
+
rescue PG::UndefinedTable, PG::UndefinedColumn
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# The prober which is called when gathering metrics.
|
|
35
|
+
class GeoNodeStatusProber
|
|
36
|
+
METRIC_PREFIX = "geo_".freeze
|
|
37
|
+
COUNT_SUFFIX = /_(count|total)\z/
|
|
38
|
+
METRIC_ALIASES = { "project_repositories_count" => "repositories_count" }.freeze
|
|
39
|
+
COLUMN_METRICS = %w[
|
|
40
|
+
db_replication_lag_seconds
|
|
41
|
+
replication_slots_count
|
|
42
|
+
replication_slots_used_count
|
|
43
|
+
replication_slots_max_retained_wal_bytes
|
|
44
|
+
last_event_id
|
|
45
|
+
cursor_last_event_id
|
|
46
|
+
].freeze
|
|
47
|
+
TIMESTAMP_METRICS = %w[
|
|
48
|
+
last_event_timestamp
|
|
49
|
+
cursor_last_event_timestamp
|
|
50
|
+
last_successful_status_check_timestamp
|
|
51
|
+
].freeze
|
|
52
|
+
REPLICATOR_METRIC_SUFFIXES = %w[
|
|
53
|
+
_count
|
|
54
|
+
_checksum_total_count
|
|
55
|
+
_checksummed_count
|
|
56
|
+
_checksum_failed_count
|
|
57
|
+
_synced_count
|
|
58
|
+
_failed_count
|
|
59
|
+
_registry_count
|
|
60
|
+
_verification_total_count
|
|
61
|
+
_verified_count
|
|
62
|
+
_verification_failed_count
|
|
63
|
+
_oldest_unsynced_time
|
|
64
|
+
].freeze
|
|
65
|
+
NON_PROMETHEUS_STATUS_FIELDS = %w[projects_count].freeze
|
|
66
|
+
|
|
67
|
+
def initialize(metrics: PrometheusMetrics.new, **opts)
|
|
68
|
+
@metrics = metrics
|
|
69
|
+
@collector = opts[:collector] || GeoNodeStatusCollector.new(**opts)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def probe_db
|
|
73
|
+
@collector.run.to_a.each do |row|
|
|
74
|
+
labels = {
|
|
75
|
+
name: row["geo_node_name"],
|
|
76
|
+
url: row["geo_node_name"]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
row.fetch("status", {}).to_h.each do |name, value|
|
|
80
|
+
add_metric(name, value, labels) if value.is_a?(Integer) && prometheus_metric?(name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
(COLUMN_METRICS + TIMESTAMP_METRICS).each do |name|
|
|
84
|
+
add_metric(name, row[name], labels) if row[name].is_a?(Integer)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
self
|
|
89
|
+
rescue PG::ConnectionBad
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def write_to(target)
|
|
94
|
+
target.write(@metrics.to_s)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def prometheus_metric?(name)
|
|
100
|
+
name = name.to_s
|
|
101
|
+
return false if NON_PROMETHEUS_STATUS_FIELDS.include?(name)
|
|
102
|
+
return false if COLUMN_METRICS.include?(name)
|
|
103
|
+
|
|
104
|
+
REPLICATOR_METRIC_SUFFIXES.any? { |suffix| name.end_with?(suffix) }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def add_metric(name, value, labels)
|
|
108
|
+
name = METRIC_ALIASES.fetch(name.to_s, name.to_s)
|
|
109
|
+
metric_name = "#{METRIC_PREFIX}#{name.sub(COUNT_SUFFIX, '')}"
|
|
110
|
+
PrometheusMetrics.describe(metric_name, "Geo node status metric", "gauge")
|
|
111
|
+
@metrics.add(metric_name, value, **labels)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -8,6 +8,7 @@ module GitLab
|
|
|
8
8
|
autoload :RowCountProber, "gitlab_exporter/database/row_count"
|
|
9
9
|
autoload :BloatProber, "gitlab_exporter/database/bloat"
|
|
10
10
|
autoload :RemoteMirrorsProber, "gitlab_exporter/database/remote_mirrors"
|
|
11
|
+
autoload :GeoNodeStatusProber, "gitlab_exporter/database/geo_node_status"
|
|
11
12
|
autoload :PgSequencesProber, "gitlab_exporter/database/pg_sequences"
|
|
12
13
|
autoload :ZoektProber, "gitlab_exporter/database/zoekt"
|
|
13
14
|
end
|
data/spec/config_spec.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "yaml"
|
|
3
|
+
|
|
4
|
+
describe "config/gitlab-exporter.yml.example" do
|
|
5
|
+
let(:config_path) { File.expand_path("../config/gitlab-exporter.yml.example", __dir__) }
|
|
6
|
+
let(:config) { YAML.safe_load_file(config_path, aliases: true) }
|
|
7
|
+
|
|
8
|
+
it "parses as valid YAML with aliases" do
|
|
9
|
+
expect { config }.not_to raise_error
|
|
10
|
+
expect(config).to be_a(Hash)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "database probes" do
|
|
14
|
+
let(:database_probes) { config.dig("probes", "database") }
|
|
15
|
+
|
|
16
|
+
it "configures geo_node_status directly under probes.database" do
|
|
17
|
+
expect(database_probes).to include("geo_node_status")
|
|
18
|
+
expect(database_probes["geo_node_status"]).to include(
|
|
19
|
+
"class_name" => "Database::GeoNodeStatusProber",
|
|
20
|
+
"methods" => ["probe_db"]
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "keeps remote_mirrors and geo_node_status as sibling probes without nested leakage" do
|
|
25
|
+
expect(database_probes["remote_mirrors"]).not_to have_key("geo_node_status")
|
|
26
|
+
expect(database_probes.keys).to include(
|
|
27
|
+
"ci_builds",
|
|
28
|
+
"tuple_stats",
|
|
29
|
+
"rows_count",
|
|
30
|
+
"remote_mirrors",
|
|
31
|
+
"geo_node_status",
|
|
32
|
+
"zoekt"
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "gitlab_exporter/database/geo_node_status"
|
|
3
|
+
|
|
4
|
+
describe GitLab::Exporter::Database::GeoNodeStatusCollector do
|
|
5
|
+
let(:connection_pool) { double("connection pool") }
|
|
6
|
+
let(:connection) { double("connection") }
|
|
7
|
+
let(:results) { [{ "geo_node_name" => "secondary", "status" => { "projects_count" => 12 } }] }
|
|
8
|
+
|
|
9
|
+
subject(:collector) { described_class.new(connection_string: "host=localhost") }
|
|
10
|
+
|
|
11
|
+
before do
|
|
12
|
+
allow(collector).to receive(:connection_pool).and_return(connection_pool)
|
|
13
|
+
allow(connection_pool).to receive(:with).and_yield(connection)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "QUERY" do
|
|
17
|
+
it "selects all required status columns, timestamps, and node name" do
|
|
18
|
+
expect(described_class::QUERY).to include("geo_nodes.name AS geo_node_name")
|
|
19
|
+
expect(described_class::QUERY).to include("geo_node_statuses.db_replication_lag_seconds")
|
|
20
|
+
expect(described_class::QUERY).to include("geo_node_statuses.replication_slots_count")
|
|
21
|
+
expect(described_class::QUERY).to include("geo_node_statuses.replication_slots_used_count")
|
|
22
|
+
expect(described_class::QUERY).to include("geo_node_statuses.replication_slots_max_retained_wal_bytes")
|
|
23
|
+
expect(described_class::QUERY).to include("geo_node_statuses.last_event_id")
|
|
24
|
+
expect(described_class::QUERY).to include("geo_node_statuses.cursor_last_event_id")
|
|
25
|
+
expect(described_class::QUERY).to include("geo_node_statuses.status")
|
|
26
|
+
expect(described_class::QUERY).to include(
|
|
27
|
+
"EXTRACT(EPOCH FROM geo_node_statuses.last_event_date)::bigint AS last_event_timestamp"
|
|
28
|
+
)
|
|
29
|
+
expect(described_class::QUERY).to include(
|
|
30
|
+
"EXTRACT(EPOCH FROM geo_node_statuses.cursor_last_event_date)::bigint AS cursor_last_event_timestamp"
|
|
31
|
+
)
|
|
32
|
+
expect(described_class::QUERY).to include(
|
|
33
|
+
"EXTRACT(EPOCH FROM geo_node_statuses.last_successful_status_check_at)::bigint"
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe "#run" do
|
|
39
|
+
it "queries enabled Geo nodes and returns their status data" do
|
|
40
|
+
expect(connection).to receive(:exec).with(described_class::QUERY).and_return(results)
|
|
41
|
+
|
|
42
|
+
expect(collector.run).to eq(results)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "returns nil when Geo tables are unavailable" do
|
|
46
|
+
allow(connection).to receive(:exec).and_raise(PG::UndefinedTable)
|
|
47
|
+
|
|
48
|
+
expect(collector.run).to be_nil
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe GitLab::Exporter::Database::GeoNodeStatusProber do
|
|
54
|
+
let(:writer) { StringIO.new }
|
|
55
|
+
let(:metrics) { GitLab::Exporter::PrometheusMetrics.new(include_timestamp: false) }
|
|
56
|
+
let(:collector) { double(GitLab::Exporter::Database::GeoNodeStatusCollector, run: results) }
|
|
57
|
+
let(:results) do
|
|
58
|
+
[
|
|
59
|
+
{
|
|
60
|
+
"geo_node_id" => 7,
|
|
61
|
+
"geo_node_name" => "secondary",
|
|
62
|
+
"db_replication_lag_seconds" => 4,
|
|
63
|
+
"replication_slots_count" => 2,
|
|
64
|
+
"replication_slots_used_count" => 1,
|
|
65
|
+
"replication_slots_max_retained_wal_bytes" => 1024,
|
|
66
|
+
"last_event_id" => 100,
|
|
67
|
+
"cursor_last_event_id" => 98,
|
|
68
|
+
"last_event_timestamp" => 1_750_000_100,
|
|
69
|
+
"cursor_last_event_timestamp" => 1_750_000_090,
|
|
70
|
+
"last_successful_status_check_timestamp" => 1_750_000_000,
|
|
71
|
+
"status" => {
|
|
72
|
+
"projects_count" => 12,
|
|
73
|
+
"project_repositories_count" => 21,
|
|
74
|
+
"projects_verification_total_count" => 8,
|
|
75
|
+
"projects_synced_count" => 19,
|
|
76
|
+
"projects_failed_count" => 2,
|
|
77
|
+
"git_fetch_event_count_weekly" => 100,
|
|
78
|
+
"container_repositories_replication_enabled" => true,
|
|
79
|
+
"status_message" => "Healthy"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
subject(:prober) { described_class.new(metrics: metrics, collector: collector) }
|
|
86
|
+
|
|
87
|
+
describe "constants and data sources" do
|
|
88
|
+
it "defines the expected COLUMN_METRICS corresponding to table columns" do
|
|
89
|
+
expect(described_class::COLUMN_METRICS).to contain_exactly(
|
|
90
|
+
"db_replication_lag_seconds",
|
|
91
|
+
"replication_slots_count",
|
|
92
|
+
"replication_slots_used_count",
|
|
93
|
+
"replication_slots_max_retained_wal_bytes",
|
|
94
|
+
"last_event_id",
|
|
95
|
+
"cursor_last_event_id"
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "defines the expected TIMESTAMP_METRICS corresponding to epoch extractions" do
|
|
100
|
+
expect(described_class::TIMESTAMP_METRICS).to contain_exactly(
|
|
101
|
+
"last_event_timestamp",
|
|
102
|
+
"cursor_last_event_timestamp",
|
|
103
|
+
"last_successful_status_check_timestamp"
|
|
104
|
+
)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "does not define CORE_STATUS_METRICS" do
|
|
108
|
+
expect(described_class.const_defined?(:CORE_STATUS_METRICS)).to be false
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "does not emit column metrics if placed only inside status jsonb" do
|
|
112
|
+
allow(collector).to receive(:run).and_return([
|
|
113
|
+
{
|
|
114
|
+
"geo_node_name" => "secondary",
|
|
115
|
+
"status" => {
|
|
116
|
+
"db_replication_lag_seconds" => 4,
|
|
117
|
+
"replication_slots_count" => 2,
|
|
118
|
+
"replication_slots_used_count" => 1,
|
|
119
|
+
"replication_slots_max_retained_wal_bytes" => 1024,
|
|
120
|
+
"last_event_id" => 100,
|
|
121
|
+
"cursor_last_event_id" => 98
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
])
|
|
125
|
+
|
|
126
|
+
prober.probe_db
|
|
127
|
+
prober.write_to(writer)
|
|
128
|
+
|
|
129
|
+
expect(writer.string).not_to include("geo_db_replication_lag_seconds")
|
|
130
|
+
expect(writer.string).not_to include("geo_replication_slots")
|
|
131
|
+
expect(writer.string).not_to include("geo_replication_slots_used")
|
|
132
|
+
expect(writer.string).not_to include("geo_replication_slots_max_retained_wal_bytes")
|
|
133
|
+
expect(writer.string).not_to include("geo_last_event_id")
|
|
134
|
+
expect(writer.string).not_to include("geo_cursor_last_event_id")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "does not emit replicator metrics if placed only in row columns outside status jsonb" do
|
|
138
|
+
allow(collector).to receive(:run).and_return([
|
|
139
|
+
{
|
|
140
|
+
"geo_node_name" => "secondary",
|
|
141
|
+
"project_repositories_count" => 21,
|
|
142
|
+
"projects_synced_count" => 19,
|
|
143
|
+
"status" => {}
|
|
144
|
+
}
|
|
145
|
+
])
|
|
146
|
+
|
|
147
|
+
prober.probe_db
|
|
148
|
+
prober.write_to(writer)
|
|
149
|
+
|
|
150
|
+
expect(writer.string).not_to include("geo_repositories")
|
|
151
|
+
expect(writer.string).not_to include("geo_projects_synced")
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe "#probe_db" do
|
|
156
|
+
it "exports integer Geo metrics with Rails-compatible names and site labels" do
|
|
157
|
+
prober.probe_db
|
|
158
|
+
prober.write_to(writer)
|
|
159
|
+
labels = 'name="secondary",url="secondary"'
|
|
160
|
+
|
|
161
|
+
expect(writer.string).to include("geo_db_replication_lag_seconds{#{labels}} 4")
|
|
162
|
+
expect(writer.string).to include("# TYPE geo_db_replication_lag_seconds gauge")
|
|
163
|
+
expect(writer.string).to include("geo_replication_slots{#{labels}} 2")
|
|
164
|
+
expect(writer.string).to include("# TYPE geo_replication_slots gauge")
|
|
165
|
+
expect(writer.string).to include("geo_replication_slots_used{#{labels}} 1")
|
|
166
|
+
expect(writer.string).to include("# TYPE geo_replication_slots_used gauge")
|
|
167
|
+
expect(writer.string).to include("geo_replication_slots_max_retained_wal_bytes{#{labels}} 1024")
|
|
168
|
+
expect(writer.string).to include("# TYPE geo_replication_slots_max_retained_wal_bytes gauge")
|
|
169
|
+
expect(writer.string).to include("geo_last_event_id{#{labels}} 100")
|
|
170
|
+
expect(writer.string).to include("geo_cursor_last_event_id{#{labels}} 98")
|
|
171
|
+
expect(writer.string).to include("geo_last_event_timestamp{#{labels}} 1750000100")
|
|
172
|
+
expect(writer.string).to include("geo_cursor_last_event_timestamp{#{labels}} 1750000090")
|
|
173
|
+
expect(writer.string).to include("geo_last_successful_status_check_timestamp{#{labels}} 1750000000")
|
|
174
|
+
expect(writer.string).to include("geo_repositories{#{labels}} 21")
|
|
175
|
+
expect(writer.string).to include("geo_projects_verification_total{#{labels}} 8")
|
|
176
|
+
expect(writer.string).to include("geo_projects_synced{#{labels}} 19")
|
|
177
|
+
expect(writer.string).to include("geo_projects_failed{#{labels}} 2")
|
|
178
|
+
|
|
179
|
+
expect(writer.string).not_to include("event_log_max_id")
|
|
180
|
+
expect(writer.string).not_to include("geo_projects{")
|
|
181
|
+
expect(writer.string).not_to include("geo_git_fetch_event")
|
|
182
|
+
expect(writer.string).not_to include("container_repositories_replication_enabled")
|
|
183
|
+
expect(writer.string).not_to include("status_message")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "handles nil column values gracefully" do
|
|
187
|
+
allow(collector).to receive(:run).and_return([
|
|
188
|
+
{
|
|
189
|
+
"geo_node_name" => "secondary",
|
|
190
|
+
"db_replication_lag_seconds" => nil,
|
|
191
|
+
"replication_slots_count" => nil,
|
|
192
|
+
"status" => { "project_repositories_count" => 5 }
|
|
193
|
+
}
|
|
194
|
+
])
|
|
195
|
+
|
|
196
|
+
prober.probe_db
|
|
197
|
+
prober.write_to(writer)
|
|
198
|
+
|
|
199
|
+
expect(writer.string).not_to include("geo_db_replication_lag_seconds")
|
|
200
|
+
expect(writer.string).not_to include("geo_replication_slots")
|
|
201
|
+
expect(writer.string).to include('geo_repositories{name="secondary",url="secondary"} 5')
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "handles a missing status payload" do
|
|
205
|
+
allow(collector).to receive(:run).and_return([{ "geo_node_name" => "secondary" }])
|
|
206
|
+
|
|
207
|
+
expect { prober.probe_db }.not_to raise_error
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
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: 17.
|
|
4
|
+
version: 17.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pablo Carranza
|
|
@@ -58,14 +58,14 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - '='
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 2.14.
|
|
61
|
+
version: 2.14.4
|
|
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: 2.14.
|
|
68
|
+
version: 2.14.4
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: pg
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -209,6 +209,7 @@ files:
|
|
|
209
209
|
- lib/gitlab_exporter/database/bloat_btree.sql
|
|
210
210
|
- lib/gitlab_exporter/database/bloat_table.sql
|
|
211
211
|
- lib/gitlab_exporter/database/ci_builds.rb
|
|
212
|
+
- lib/gitlab_exporter/database/geo_node_status.rb
|
|
212
213
|
- lib/gitlab_exporter/database/pg_sequences.rb
|
|
213
214
|
- lib/gitlab_exporter/database/remote_mirrors.rb
|
|
214
215
|
- lib/gitlab_exporter/database/row_count.rb
|
|
@@ -228,8 +229,10 @@ files:
|
|
|
228
229
|
- lib/gitlab_exporter/version.rb
|
|
229
230
|
- lib/gitlab_exporter/web_exporter.rb
|
|
230
231
|
- spec/cli_spec.rb
|
|
232
|
+
- spec/config_spec.rb
|
|
231
233
|
- spec/database/bloat_spec.rb
|
|
232
234
|
- spec/database/ci_builds_spec.rb
|
|
235
|
+
- spec/database/geo_node_status_spec.rb
|
|
233
236
|
- spec/database/pg_sequences_spec.rb
|
|
234
237
|
- spec/database/row_count_spec.rb
|
|
235
238
|
- spec/database/tuple_stats_spec.rb
|
|
@@ -272,8 +275,10 @@ specification_version: 4
|
|
|
272
275
|
summary: GitLab metrics exporter
|
|
273
276
|
test_files:
|
|
274
277
|
- spec/cli_spec.rb
|
|
278
|
+
- spec/config_spec.rb
|
|
275
279
|
- spec/database/bloat_spec.rb
|
|
276
280
|
- spec/database/ci_builds_spec.rb
|
|
281
|
+
- spec/database/geo_node_status_spec.rb
|
|
277
282
|
- spec/database/pg_sequences_spec.rb
|
|
278
283
|
- spec/database/row_count_spec.rb
|
|
279
284
|
- spec/database/tuple_stats_spec.rb
|