@@ -8,7 +8,7 @@ use std::net::SocketAddr;
8
8
9
9
use crate :: config:: Address ;
10
10
use crate :: pool:: get_all_pools;
11
- use crate :: stats:: get_address_stats;
11
+ use crate :: stats:: { get_address_stats, get_pool_stats , get_server_stats , ServerInformation } ;
12
12
13
13
struct MetricHelpType {
14
14
help : & ' static str ,
@@ -19,113 +19,141 @@ struct MetricHelpType {
19
19
// counters only increase
20
20
// gauges can arbitrarily increase or decrease
21
21
static METRIC_HELP_AND_TYPES_LOOKUP : phf:: Map < & ' static str , MetricHelpType > = phf_map ! {
22
- "total_query_count " => MetricHelpType {
22
+ "stats_total_query_count " => MetricHelpType {
23
23
help: "Number of queries sent by all clients" ,
24
24
ty: "counter" ,
25
25
} ,
26
- "total_query_time " => MetricHelpType {
26
+ "stats_total_query_time " => MetricHelpType {
27
27
help: "Total amount of time for queries to execute" ,
28
28
ty: "counter" ,
29
29
} ,
30
- "total_received " => MetricHelpType {
30
+ "stats_total_received " => MetricHelpType {
31
31
help: "Number of bytes received from the server" ,
32
32
ty: "counter" ,
33
33
} ,
34
- "total_sent " => MetricHelpType {
34
+ "stats_total_sent " => MetricHelpType {
35
35
help: "Number of bytes sent to the server" ,
36
36
ty: "counter" ,
37
37
} ,
38
- "total_xact_count " => MetricHelpType {
38
+ "stats_total_xact_count " => MetricHelpType {
39
39
help: "Total number of transactions started by the client" ,
40
40
ty: "counter" ,
41
41
} ,
42
- "total_xact_time " => MetricHelpType {
42
+ "stats_total_xact_time " => MetricHelpType {
43
43
help: "Total amount of time for all transactions to execute" ,
44
44
ty: "counter" ,
45
45
} ,
46
- "total_wait_time " => MetricHelpType {
46
+ "stats_total_wait_time " => MetricHelpType {
47
47
help: "Total time client waited for a server connection" ,
48
48
ty: "counter" ,
49
49
} ,
50
- "avg_query_count " => MetricHelpType {
50
+ "stats_avg_query_count " => MetricHelpType {
51
51
help: "Average of total_query_count every 15 seconds" ,
52
52
ty: "gauge" ,
53
53
} ,
54
- "avg_query_time " => MetricHelpType {
54
+ "stats_avg_query_time " => MetricHelpType {
55
55
help: "Average time taken for queries to execute every 15 seconds" ,
56
56
ty: "gauge" ,
57
57
} ,
58
- "avg_recv " => MetricHelpType {
58
+ "stats_avg_recv " => MetricHelpType {
59
59
help: "Average of total_received bytes every 15 seconds" ,
60
60
ty: "gauge" ,
61
61
} ,
62
- "avg_sent " => MetricHelpType {
62
+ "stats_avg_sent " => MetricHelpType {
63
63
help: "Average of total_sent bytes every 15 seconds" ,
64
64
ty: "gauge" ,
65
65
} ,
66
- "avg_errors " => MetricHelpType {
66
+ "stats_avg_errors " => MetricHelpType {
67
67
help: "Average number of errors every 15 seconds" ,
68
68
ty: "gauge" ,
69
69
} ,
70
- "avg_xact_count " => MetricHelpType {
70
+ "stats_avg_xact_count " => MetricHelpType {
71
71
help: "Average of total_xact_count every 15 seconds" ,
72
72
ty: "gauge" ,
73
73
} ,
74
- "avg_xact_time " => MetricHelpType {
74
+ "stats_avg_xact_time " => MetricHelpType {
75
75
help: "Average of total_xact_time every 15 seconds" ,
76
76
ty: "gauge" ,
77
77
} ,
78
- "avg_wait_time " => MetricHelpType {
78
+ "stats_avg_wait_time " => MetricHelpType {
79
79
help: "Average of total_wait_time every 15 seconds" ,
80
80
ty: "gauge" ,
81
81
} ,
82
- "maxwait_us " => MetricHelpType {
82
+ "pools_maxwait_us " => MetricHelpType {
83
83
help: "The time a client waited for a server connection in microseconds" ,
84
84
ty: "gauge" ,
85
85
} ,
86
- "maxwait " => MetricHelpType {
86
+ "pools_maxwait " => MetricHelpType {
87
87
help: "The time a client waited for a server connection in seconds" ,
88
88
ty: "gauge" ,
89
89
} ,
90
- "cl_waiting " => MetricHelpType {
90
+ "pools_cl_waiting " => MetricHelpType {
91
91
help: "How many clients are waiting for a connection from the pool" ,
92
92
ty: "gauge" ,
93
93
} ,
94
- "cl_active " => MetricHelpType {
94
+ "pools_cl_active " => MetricHelpType {
95
95
help: "How many clients are actively communicating with a server" ,
96
96
ty: "gauge" ,
97
97
} ,
98
- "cl_idle " => MetricHelpType {
98
+ "pools_cl_idle " => MetricHelpType {
99
99
help: "How many clients are idle" ,
100
100
ty: "gauge" ,
101
101
} ,
102
- "sv_idle " => MetricHelpType {
102
+ "pools_sv_idle " => MetricHelpType {
103
103
help: "How many server connections are idle" ,
104
104
ty: "gauge" ,
105
105
} ,
106
- "sv_active " => MetricHelpType {
106
+ "pools_sv_active " => MetricHelpType {
107
107
help: "How many server connections are actively communicating with a client" ,
108
108
ty: "gauge" ,
109
109
} ,
110
- "sv_login " => MetricHelpType {
110
+ "pools_sv_login " => MetricHelpType {
111
111
help: "How many server connections are currently being created" ,
112
112
ty: "gauge" ,
113
113
} ,
114
- "sv_tested " => MetricHelpType {
114
+ "pools_sv_tested " => MetricHelpType {
115
115
help: "How many server connections are currently waiting on a health check to succeed" ,
116
116
ty: "gauge" ,
117
117
} ,
118
+ "servers_bytes_received" => MetricHelpType {
119
+ help: "Volume in bytes of network traffic received by server" ,
120
+ ty: "gauge" ,
121
+ } ,
122
+ "servers_bytes_sent" => MetricHelpType {
123
+ help: "Volume in bytes of network traffic sent by server" ,
124
+ ty: "gauge" ,
125
+ } ,
126
+ "servers_transaction_count" => MetricHelpType {
127
+ help: "Number of transactions executed by server" ,
128
+ ty: "gauge" ,
129
+ } ,
130
+ "servers_query_count" => MetricHelpType {
131
+ help: "Number of queries executed by server" ,
132
+ ty: "gauge" ,
133
+ } ,
134
+ "servers_error_count" => MetricHelpType {
135
+ help: "Number of errors" ,
136
+ ty: "gauge" ,
137
+ } ,
138
+ "databases_pool_size" => MetricHelpType {
139
+ help: "Maximum number of server connections" ,
140
+ ty: "gauge" ,
141
+ } ,
142
+ "databases_current_connections" => MetricHelpType {
143
+ help: "Current number of connections for this database" ,
144
+ ty: "gauge" ,
145
+ } ,
118
146
} ;
119
147
120
- struct PrometheusMetric {
148
+ struct PrometheusMetric < Value : fmt :: Display > {
121
149
name : String ,
122
150
help : String ,
123
151
ty : String ,
124
152
labels : HashMap < & ' static str , String > ,
125
- value : i64 ,
153
+ value : Value ,
126
154
}
127
155
128
- impl fmt:: Display for PrometheusMetric {
156
+ impl < Value : fmt:: Display > fmt :: Display for PrometheusMetric < Value > {
129
157
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
130
158
let formatted_labels = self
131
159
. labels
@@ -145,50 +173,81 @@ impl fmt::Display for PrometheusMetric {
145
173
}
146
174
}
147
175
148
- impl PrometheusMetric {
149
- fn new ( address : & Address , name : & str , value : i64 ) -> Option < PrometheusMetric > {
150
- let mut labels = HashMap :: new ( ) ;
151
- labels. insert ( "host" , address. host . clone ( ) ) ;
152
- labels. insert ( "shard" , address. shard . to_string ( ) ) ;
153
- labels. insert ( "role" , address. role . to_string ( ) ) ;
154
- labels. insert ( "database" , address. database . to_string ( ) ) ;
155
-
176
+ impl < Value : fmt:: Display > PrometheusMetric < Value > {
177
+ fn from_name < V : fmt:: Display > (
178
+ name : & str ,
179
+ value : V ,
180
+ labels : HashMap < & ' static str , String > ,
181
+ ) -> Option < PrometheusMetric < V > > {
156
182
METRIC_HELP_AND_TYPES_LOOKUP
157
183
. get ( name)
158
- . map ( |metric| PrometheusMetric {
184
+ . map ( |metric| PrometheusMetric :: < V > {
159
185
name : name. to_owned ( ) ,
160
186
help : metric. help . to_owned ( ) ,
161
187
ty : metric. ty . to_owned ( ) ,
162
- labels,
163
188
value,
189
+ labels,
164
190
} )
165
191
}
192
+
193
+ fn from_database_info (
194
+ address : & Address ,
195
+ name : & str ,
196
+ value : u32 ,
197
+ ) -> Option < PrometheusMetric < u32 > > {
198
+ let mut labels = HashMap :: new ( ) ;
199
+ labels. insert ( "host" , address. host . clone ( ) ) ;
200
+ labels. insert ( "shard" , address. shard . to_string ( ) ) ;
201
+ labels. insert ( "role" , address. role . to_string ( ) ) ;
202
+ labels. insert ( "pool" , address. pool_name . clone ( ) ) ;
203
+ labels. insert ( "database" , address. database . to_string ( ) ) ;
204
+
205
+ Self :: from_name ( & format ! ( "databases_{}" , name) , value, labels)
206
+ }
207
+
208
+ fn from_server_info (
209
+ address : & Address ,
210
+ name : & str ,
211
+ value : u64 ,
212
+ ) -> Option < PrometheusMetric < u64 > > {
213
+ let mut labels = HashMap :: new ( ) ;
214
+ labels. insert ( "host" , address. host . clone ( ) ) ;
215
+ labels. insert ( "shard" , address. shard . to_string ( ) ) ;
216
+ labels. insert ( "role" , address. role . to_string ( ) ) ;
217
+ labels. insert ( "pool" , address. pool_name . clone ( ) ) ;
218
+ labels. insert ( "database" , address. database . to_string ( ) ) ;
219
+
220
+ Self :: from_name ( & format ! ( "servers_{}" , name) , value, labels)
221
+ }
222
+
223
+ fn from_address ( address : & Address , name : & str , value : i64 ) -> Option < PrometheusMetric < i64 > > {
224
+ let mut labels = HashMap :: new ( ) ;
225
+ labels. insert ( "host" , address. host . clone ( ) ) ;
226
+ labels. insert ( "shard" , address. shard . to_string ( ) ) ;
227
+ labels. insert ( "pool" , address. pool_name . clone ( ) ) ;
228
+ labels. insert ( "role" , address. role . to_string ( ) ) ;
229
+ labels. insert ( "database" , address. database . to_string ( ) ) ;
230
+
231
+ Self :: from_name ( & format ! ( "stats_{}" , name) , value, labels)
232
+ }
233
+
234
+ fn from_pool ( pool : & ( String , String ) , name : & str , value : i64 ) -> Option < PrometheusMetric < i64 > > {
235
+ let mut labels = HashMap :: new ( ) ;
236
+ labels. insert ( "pool" , pool. 0 . clone ( ) ) ;
237
+ labels. insert ( "user" , pool. 1 . clone ( ) ) ;
238
+
239
+ Self :: from_name ( & format ! ( "pools_{}" , name) , value, labels)
240
+ }
166
241
}
167
242
168
243
async fn prometheus_stats ( request : Request < Body > ) -> Result < Response < Body > , hyper:: http:: Error > {
169
244
match ( request. method ( ) , request. uri ( ) . path ( ) ) {
170
245
( & Method :: GET , "/metrics" ) => {
171
- let stats: HashMap < usize , HashMap < String , i64 > > = get_address_stats ( ) ;
172
-
173
246
let mut lines = Vec :: new ( ) ;
174
- for ( _, pool) in get_all_pools ( ) {
175
- for shard in 0 ..pool. shards ( ) {
176
- for server in 0 ..pool. servers ( shard) {
177
- let address = pool. address ( shard, server) ;
178
- if let Some ( address_stats) = stats. get ( & address. id ) {
179
- for ( key, value) in address_stats. iter ( ) {
180
- if let Some ( prometheus_metric) =
181
- PrometheusMetric :: new ( address, key, * value)
182
- {
183
- lines. push ( prometheus_metric. to_string ( ) ) ;
184
- } else {
185
- warn ! ( "Metric {} not implemented for {}" , key, address. name( ) ) ;
186
- }
187
- }
188
- }
189
- }
190
- }
191
- }
247
+ push_address_stats ( & mut lines) ;
248
+ push_pool_stats ( & mut lines) ;
249
+ push_server_stats ( & mut lines) ;
250
+ push_database_stats ( & mut lines) ;
192
251
193
252
Response :: builder ( )
194
253
. header ( "content-type" , "text/plain; version=0.0.4" )
@@ -200,6 +259,109 @@ async fn prometheus_stats(request: Request<Body>) -> Result<Response<Body>, hype
200
259
}
201
260
}
202
261
262
+ // Adds metrics shown in a SHOW STATS admin command.
263
+ fn push_address_stats ( lines : & mut Vec < String > ) {
264
+ let address_stats: HashMap < usize , HashMap < String , i64 > > = get_address_stats ( ) ;
265
+ for ( _, pool) in get_all_pools ( ) {
266
+ for shard in 0 ..pool. shards ( ) {
267
+ for server in 0 ..pool. servers ( shard) {
268
+ let address = pool. address ( shard, server) ;
269
+ if let Some ( address_stats) = address_stats. get ( & address. id ) {
270
+ for ( key, value) in address_stats. iter ( ) {
271
+ if let Some ( prometheus_metric) =
272
+ PrometheusMetric :: < i64 > :: from_address ( address, key, * value)
273
+ {
274
+ lines. push ( prometheus_metric. to_string ( ) ) ;
275
+ } else {
276
+ warn ! ( "Metric {} not implemented for {}" , key, address. name( ) ) ;
277
+ }
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+
285
+ // Adds relevant metrics shown in a SHOW POOLS admin command.
286
+ fn push_pool_stats ( lines : & mut Vec < String > ) {
287
+ let pool_stats = get_pool_stats ( ) ;
288
+ for ( pool, stats) in pool_stats. iter ( ) {
289
+ for ( name, value) in stats. iter ( ) {
290
+ if let Some ( prometheus_metric) = PrometheusMetric :: < i64 > :: from_pool ( pool, name, * value)
291
+ {
292
+ lines. push ( prometheus_metric. to_string ( ) ) ;
293
+ } else {
294
+ warn ! (
295
+ "Metric {} not implemented for ({},{})" ,
296
+ name, pool. 0 , pool. 1
297
+ ) ;
298
+ }
299
+ }
300
+ }
301
+ }
302
+
303
+ // Adds relevant metrics shown in a SHOW DATABASES admin command.
304
+ fn push_database_stats ( lines : & mut Vec < String > ) {
305
+ for ( _, pool) in get_all_pools ( ) {
306
+ let pool_config = pool. settings . clone ( ) ;
307
+ for shard in 0 ..pool. shards ( ) {
308
+ for server in 0 ..pool. servers ( shard) {
309
+ let address = pool. address ( shard, server) ;
310
+ let pool_state = pool. pool_state ( shard, server) ;
311
+
312
+ let metrics = vec ! [
313
+ ( "pool_size" , pool_config. user. pool_size) ,
314
+ ( "current_connections" , pool_state. connections) ,
315
+ ] ;
316
+ for ( key, value) in metrics {
317
+ if let Some ( prometheus_metric) =
318
+ PrometheusMetric :: < u32 > :: from_database_info ( address, key, value)
319
+ {
320
+ lines. push ( prometheus_metric. to_string ( ) ) ;
321
+ } else {
322
+ warn ! ( "Metric {} not implemented for {}" , key, address. name( ) ) ;
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+
330
+ // Adds relevant metrics shown in a SHOW SERVERS admin command.
331
+ fn push_server_stats ( lines : & mut Vec < String > ) {
332
+ let server_stats = get_server_stats ( ) ;
333
+ let mut server_stats_by_addresses = HashMap :: < String , ServerInformation > :: new ( ) ;
334
+ for ( _, info) in server_stats {
335
+ server_stats_by_addresses. insert ( info. address_name . clone ( ) , info) ;
336
+ }
337
+
338
+ for ( _, pool) in get_all_pools ( ) {
339
+ for shard in 0 ..pool. shards ( ) {
340
+ for server in 0 ..pool. servers ( shard) {
341
+ let address = pool. address ( shard, server) ;
342
+ if let Some ( server_info) = server_stats_by_addresses. get ( & address. name ( ) ) {
343
+ let metrics = [
344
+ ( "bytes_received" , server_info. bytes_received ) ,
345
+ ( "bytes_sent" , server_info. bytes_sent ) ,
346
+ ( "transaction_count" , server_info. transaction_count ) ,
347
+ ( "query_count" , server_info. query_count ) ,
348
+ ( "error_count" , server_info. error_count ) ,
349
+ ] ;
350
+ for ( key, value) in metrics {
351
+ if let Some ( prometheus_metric) =
352
+ PrometheusMetric :: < u64 > :: from_server_info ( address, key, value)
353
+ {
354
+ lines. push ( prometheus_metric. to_string ( ) ) ;
355
+ } else {
356
+ warn ! ( "Metric {} not implemented for {}" , key, address. name( ) ) ;
357
+ }
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+
203
365
pub async fn start_metric_server ( http_addr : SocketAddr ) {
204
366
let http_service_factory =
205
367
make_service_fn ( |_conn| async { Ok :: < _ , hyper:: Error > ( service_fn ( prometheus_stats) ) } ) ;
0 commit comments