gitlab-exporter 6.0.0 → 6.1.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 +2 -2
- data/config/gitlab-exporter.yml.example +3 -0
- data/lib/gitlab_exporter/database/row_count.rb +69 -10
- data/lib/gitlab_exporter/version.rb +1 -1
- data/spec/database/row_count_spec.rb +23 -5
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61203f2c5d53c61f05151255076c5004c65a254c2445d632ae8c7262ae0e1f82
|
4
|
+
data.tar.gz: 66b13da650dd0e66b3a4d639bf1738de51474e047e0df878893a5b675d158827
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ab02d67cc6e2bf4e443e73f49138eb7549961d535a1c7425e7f9a7872ec7095f6ad77522105eee8111c674cbdebbfec304296953c884dd006832d452079414c
|
7
|
+
data.tar.gz: 81bf3b39c8cb1462dabbf51be56057efb9fddfbe0db6da4d6f1f7827f71f4a8cebf04e5890caf07ccaa588b873897dfef32e91d7276361a6fe629349eb2691b0
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
gitlab-exporter (6.
|
4
|
+
gitlab-exporter (6.1.0)
|
5
5
|
connection_pool (~> 2.2.1)
|
6
6
|
pg (~> 1.1)
|
7
7
|
quantile (~> 0.2.0)
|
@@ -23,7 +23,7 @@ GEM
|
|
23
23
|
pg (1.2.2)
|
24
24
|
powerpack (0.1.1)
|
25
25
|
quantile (0.2.1)
|
26
|
-
rack (2.
|
26
|
+
rack (2.2.2)
|
27
27
|
rack-protection (2.0.8.1)
|
28
28
|
rack
|
29
29
|
rainbow (2.1.0)
|
@@ -79,7 +79,40 @@ module GitLab
|
|
79
79
|
joins: "LEFT JOIN namespaces ON projects.namespace_id = namespaces.id",
|
80
80
|
where: "namespaces.id IS NULL"
|
81
81
|
},
|
82
|
-
uploads: { select: :uploads }
|
82
|
+
uploads: { select: :uploads },
|
83
|
+
users: {
|
84
|
+
select: :users,
|
85
|
+
joins: "LEFT JOIN
|
86
|
+
(
|
87
|
+
SELECT
|
88
|
+
members.user_id,
|
89
|
+
MAX(access_level) as access_level
|
90
|
+
FROM members
|
91
|
+
GROUP BY members.user_id
|
92
|
+
) AS u
|
93
|
+
ON users.id = u.user_id",
|
94
|
+
where: "ghost IS NULL AND bot_type IS NULL",
|
95
|
+
fields: {
|
96
|
+
admin: {},
|
97
|
+
external: {},
|
98
|
+
state: {},
|
99
|
+
access_level: { definition: "COALESCE(u.access_level, 0)" }
|
100
|
+
}
|
101
|
+
},
|
102
|
+
projects: {
|
103
|
+
select: :projects,
|
104
|
+
fields: {
|
105
|
+
visibility_level: {},
|
106
|
+
archived: {}
|
107
|
+
}
|
108
|
+
},
|
109
|
+
groups: {
|
110
|
+
select: :namespaces,
|
111
|
+
fields: {
|
112
|
+
visibility_level: {},
|
113
|
+
root: { definition: "(parent_id IS NULL)" }
|
114
|
+
}
|
115
|
+
}
|
83
116
|
}.freeze
|
84
117
|
|
85
118
|
def initialize(args)
|
@@ -105,21 +138,37 @@ module GitLab
|
|
105
138
|
|
106
139
|
def count_from_query_hash(query_hash)
|
107
140
|
result = execute(construct_query(query_hash))
|
108
|
-
return 0 unless result
|
141
|
+
return [{ "count": 0, "labels": {} }] unless result
|
109
142
|
|
110
|
-
result
|
143
|
+
result.map do |row|
|
144
|
+
labels = {}
|
145
|
+
(query_hash[:fields] || []).each do |key, _| labels[key] = row[key.to_s] end
|
146
|
+
{ "count": row["count"], "labels": labels }
|
147
|
+
end
|
111
148
|
end
|
112
149
|
|
113
150
|
def successful_check?(query)
|
114
151
|
result = execute("SELECT EXISTS (#{query})")
|
115
152
|
return unless result
|
116
153
|
|
117
|
-
result[0]["exists"]
|
154
|
+
result[0]["exists"]
|
118
155
|
end
|
119
156
|
|
120
157
|
def execute(query)
|
121
158
|
with_connection_pool do |conn|
|
122
|
-
|
159
|
+
tm = PG::BasicTypeMapForResults.new(conn)
|
160
|
+
|
161
|
+
# Remove warning message:
|
162
|
+
# Warning: no type cast defined for type "name" with oid 19.
|
163
|
+
# Please cast this type explicitly to TEXT to be safe for future changes.
|
164
|
+
# Warning: no type cast defined for type "regproc" with oid 24.
|
165
|
+
# Please cast this type explicitly to TEXT to be safe for future changes.
|
166
|
+
[{ "type": "text", "oid": 19 }, { "type": "int4", "oid": 24 }].each do |value|
|
167
|
+
old_coder = tm.coders.find { |c| c.name == value[:type] }
|
168
|
+
tm.add_coder(old_coder.dup.tap { |c| c.oid = value[:oid] })
|
169
|
+
end
|
170
|
+
|
171
|
+
conn.exec(query).map_types!(tm)
|
123
172
|
end
|
124
173
|
rescue PG::UndefinedTable, PG::UndefinedColumn
|
125
174
|
nil
|
@@ -127,9 +176,16 @@ module GitLab
|
|
127
176
|
|
128
177
|
# Not private so I can test it without meta programming tricks
|
129
178
|
def construct_query(query)
|
130
|
-
query_string = "SELECT COUNT(*)
|
131
|
-
|
132
|
-
|
179
|
+
query_string = "SELECT COUNT(*)"
|
180
|
+
(query[:fields] || []).each do |key, value|
|
181
|
+
query_string << ", "
|
182
|
+
query_string << "(#{value[:definition]}) AS " if value[:definition]
|
183
|
+
query_string << key.to_s
|
184
|
+
end
|
185
|
+
query_string << " FROM #{query[:select]}"
|
186
|
+
query_string << " #{query[:joins]}" if query[:joins]
|
187
|
+
query_string << " WHERE #{query[:where]}" if query[:where]
|
188
|
+
query_string << " GROUP BY " + query[:fields].keys.join(", ") if query[:fields]
|
133
189
|
query_string << ";"
|
134
190
|
end
|
135
191
|
end
|
@@ -146,8 +202,11 @@ module GitLab
|
|
146
202
|
|
147
203
|
def probe_db
|
148
204
|
results = @collector.run
|
149
|
-
results.each do |
|
150
|
-
|
205
|
+
results.each do |query_name, result|
|
206
|
+
labels = { query_name: query_name.to_s }
|
207
|
+
result.each do |row|
|
208
|
+
@metrics.add("gitlab_database_rows", row[:count].to_f, **labels, **row[:labels])
|
209
|
+
end
|
151
210
|
end
|
152
211
|
|
153
212
|
self
|
@@ -4,7 +4,8 @@ require "gitlab_exporter/database/row_count"
|
|
4
4
|
describe GitLab::Exporter::Database::RowCountCollector do
|
5
5
|
let(:query) {
|
6
6
|
{ project_1: { select: :projects, where: "id=1" },
|
7
|
-
project_2: { select: :projects, where: "id=2" }
|
7
|
+
project_2: { select: :projects, where: "id=2" },
|
8
|
+
project_3: { select: :projects, fields: { is_public: { definition: "visibility_level == 20" } } } }
|
8
9
|
}
|
9
10
|
let(:collector) { described_class.new(connection_string: "host=localhost") }
|
10
11
|
|
@@ -12,19 +13,31 @@ describe GitLab::Exporter::Database::RowCountCollector do
|
|
12
13
|
before do
|
13
14
|
stub_const("GitLab::Exporter::Database::RowCountCollector::QUERIES", query)
|
14
15
|
|
15
|
-
allow(collector).to receive(:
|
16
|
-
allow(collector).to receive(:
|
16
|
+
allow(collector).to receive(:execute).with("SELECT COUNT(*) FROM projects WHERE id=1;").and_return(false)
|
17
|
+
allow(collector).to receive(:execute).with("SELECT COUNT(*) FROM projects WHERE id=2;").and_return(
|
18
|
+
[{ "count" => 6 }]
|
19
|
+
)
|
20
|
+
allow(collector).to receive(:execute).with(
|
21
|
+
"SELECT COUNT(*), (visibility_level == 20) AS is_public FROM projects GROUP BY is_public;"
|
22
|
+
).and_return(
|
23
|
+
[{ "count" => 3, "is_public" => true }, { "count" => 6, "is_public" => false }]
|
24
|
+
)
|
17
25
|
end
|
18
26
|
|
19
27
|
it "executes all the queries" do
|
20
|
-
expect(collector.run).to eq(
|
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 } }]
|
33
|
+
)
|
21
34
|
end
|
22
35
|
|
23
36
|
context "when selected_queries is passed" do
|
24
37
|
let(:collector) { described_class.new(connection_string: "host=localhost", selected_queries: ["project_2"]) }
|
25
38
|
|
26
39
|
it "executes the selected queries" do
|
27
|
-
expect(collector.run).to eq(project_2: 6)
|
40
|
+
expect(collector.run).to eq(project_2: [{ count: 6, labels: {} }])
|
28
41
|
end
|
29
42
|
end
|
30
43
|
end
|
@@ -33,5 +46,10 @@ describe GitLab::Exporter::Database::RowCountCollector do
|
|
33
46
|
it "accepts a table and where clause" do
|
34
47
|
expect(collector.send(:construct_query, query[:project_1])).to eq "SELECT COUNT(*) FROM projects WHERE id=1;"
|
35
48
|
end
|
49
|
+
|
50
|
+
it "accepts a table and group (field) clause" do
|
51
|
+
expect(collector.send(:construct_query, query[:project_3])).to eq \
|
52
|
+
"SELECT COUNT(*), (visibility_level == 20) AS is_public FROM projects GROUP BY is_public;"
|
53
|
+
end
|
36
54
|
end
|
37
55
|
end
|