69
69
"maxwait" : {GAUGE , "client_maxwait_seconds" , 1 , "Age of oldest unserved client connection, shown as second" },
70
70
},
71
71
}
72
+
73
+ listsMap = map [string ]* (prometheus.Desc ){
74
+ "databases" : prometheus .NewDesc (
75
+ prometheus .BuildFQName (namespace , "" , "databases" ),
76
+ "Count of databases" , nil , nil ),
77
+ "users" : prometheus .NewDesc (
78
+ prometheus .BuildFQName (namespace , "" , "users" ),
79
+ "Count of users" , nil , nil ),
80
+ "pools" : prometheus .NewDesc (
81
+ prometheus .BuildFQName (namespace , "" , "pools" ),
82
+ "Count of pools" , nil , nil ),
83
+ "free_clients" : prometheus .NewDesc (
84
+ prometheus .BuildFQName (namespace , "" , "free_clients" ),
85
+ "Count of free clients" , nil , nil ),
86
+ "used_clients" : prometheus .NewDesc (
87
+ prometheus .BuildFQName (namespace , "" , "used_clients" ),
88
+ "Count of used clients" , nil , nil ),
89
+ "login_clients" : prometheus .NewDesc (
90
+ prometheus .BuildFQName (namespace , "" , "login_clients" ),
91
+ "Count of clients in login state" , nil , nil ),
92
+ "free_servers" : prometheus .NewDesc (
93
+ prometheus .BuildFQName (namespace , "" , "free_servers" ),
94
+ "Count of free servers" , nil , nil ),
95
+ "used_servers" : prometheus .NewDesc (
96
+ prometheus .BuildFQName (namespace , "" , "used_servers" ),
97
+ "Count of used servers" , nil , nil ),
98
+ "dns_names" : prometheus .NewDesc (
99
+ prometheus .BuildFQName (namespace , "" , "cached_dns_names" ),
100
+ "Count of DNS names in the cache" , nil , nil ),
101
+ "dns_zones" : prometheus .NewDesc (
102
+ prometheus .BuildFQName (namespace , "" , "cached_dns_zones" ),
103
+ "Count of DNS zones in the cache" , nil , nil ),
104
+ "dns_queries" : prometheus .NewDesc (
105
+ prometheus .BuildFQName (namespace , "" , "in_flight_dns_queries" ),
106
+ "Count of in-flight DNS queries" , nil , nil ),
107
+ }
72
108
)
73
109
74
110
// Metric descriptors.
@@ -101,6 +137,38 @@ func NewExporter(connectionString string, namespace string, logger log.Logger) *
101
137
}
102
138
}
103
139
140
+ // Query SHOW LISTS, which has a series of rows, not columns.
141
+ func queryShowLists (ch chan <- prometheus.Metric , db * sql.DB , logger log.Logger ) error {
142
+ rows , err := db .Query ("SHOW LISTS;" )
143
+ if err != nil {
144
+ return errors .New (fmt .Sprintln ("error running SHOW LISTS on database: " , err ))
145
+ }
146
+ defer rows .Close ()
147
+
148
+ columnNames , err := rows .Columns ()
149
+ if err != nil || len (columnNames ) != 2 {
150
+ return errors .New (fmt .Sprintln ("error retrieving columns list from SHOW LISTS: " , err ))
151
+ }
152
+
153
+ var list string
154
+ var items sql.RawBytes
155
+ for rows .Next () {
156
+ if err = rows .Scan (& list , & items ); err != nil {
157
+ return errors .New (fmt .Sprintln ("error retrieving SHOW LISTS rows:" , err ))
158
+ }
159
+ value , err := strconv .ParseFloat (string (items ), 64 )
160
+ if err != nil {
161
+ return errors .New (fmt .Sprintln ("error parsing SHOW LISTS column: " , list , err ))
162
+ }
163
+ if metric , ok := listsMap [list ]; ok {
164
+ ch <- prometheus .MustNewConstMetric (metric , prometheus .GaugeValue , value )
165
+ } else {
166
+ level .Debug (logger ).Log ("msg" , "SHOW LISTS unknown list" , "list" , list )
167
+ }
168
+ }
169
+ return nil
170
+ }
171
+
104
172
// Query within a namespace mapping and emit metrics. Returns fatal errors if
105
173
// the scrape fails, and a slice of errors if they were non-fatal.
106
174
func queryNamespaceMapping (ch chan <- prometheus.Metric , db * sql.DB , namespace string , mapping MetricMapNamespace , logger log.Logger ) ([]error , error ) {
@@ -109,15 +177,15 @@ func queryNamespaceMapping(ch chan<- prometheus.Metric, db *sql.DB, namespace st
109
177
// Don't fail on a bad scrape of one metric
110
178
rows , err := db .Query (query )
111
179
if err != nil {
112
- return []error {}, errors .New (fmt .Sprintln ("Error running query on database: " , namespace , err ))
180
+ return []error {}, errors .New (fmt .Sprintln ("error running query on database: " , namespace , err ))
113
181
}
114
182
115
183
defer rows .Close ()
116
184
117
185
var columnNames []string
118
186
columnNames , err = rows .Columns ()
119
187
if err != nil {
120
- return []error {}, errors .New (fmt .Sprintln ("Error retrieving column list for: " , namespace , err ))
188
+ return []error {}, errors .New (fmt .Sprintln ("error retrieving column list for: " , namespace , err ))
121
189
}
122
190
123
191
// Make a lookup map for the column indices
@@ -138,7 +206,7 @@ func queryNamespaceMapping(ch chan<- prometheus.Metric, db *sql.DB, namespace st
138
206
labelValues := make ([]string , len (mapping .labels ))
139
207
err = rows .Scan (scanArgs ... )
140
208
if err != nil {
141
- return []error {}, errors .New (fmt .Sprintln ("Error retrieving rows:" , namespace , err ))
209
+ return []error {}, errors .New (fmt .Sprintln ("error retrieving rows:" , namespace , err ))
142
210
}
143
211
144
212
for i , label := range mapping .labels {
@@ -156,14 +224,14 @@ func queryNamespaceMapping(ch chan<- prometheus.Metric, db *sql.DB, namespace st
156
224
case nil :
157
225
labelValues [i ] = ""
158
226
default :
159
- nonfatalErrors = append (nonfatalErrors , fmt .Errorf ("Column %s in %s has an unhandled type %v for label: %s " , columnName , namespace , v , columnData [idx ]))
227
+ nonfatalErrors = append (nonfatalErrors , fmt .Errorf ("column %s in %s has an unhandled type %v for label: %s " , columnName , namespace , v , columnData [idx ]))
160
228
labelValues [i ] = "<invalid>"
161
229
continue
162
230
}
163
231
164
232
// Prometheus will fail hard if the database and usernames are not UTF-8
165
233
if ! utf8 .ValidString (labelValues [i ]) {
166
- nonfatalErrors = append (nonfatalErrors , fmt .Errorf ("Column %s in %s has an invalid UTF-8 for a label: %s " , columnName , namespace , columnData [idx ]))
234
+ nonfatalErrors = append (nonfatalErrors , fmt .Errorf ("column %s in %s has an invalid UTF-8 for a label: %s " , columnName , namespace , columnData [idx ]))
167
235
labelValues [i ] = "<invalid>"
168
236
continue
169
237
}
@@ -183,7 +251,7 @@ func queryNamespaceMapping(ch chan<- prometheus.Metric, db *sql.DB, namespace st
183
251
184
252
value , ok := metricMapping .conversion (columnData [idx ])
185
253
if ! ok {
186
- nonfatalErrors = append (nonfatalErrors , errors .New (fmt .Sprintln ("Unexpected error parsing column: " , namespace , columnName , columnData [idx ])))
254
+ nonfatalErrors = append (nonfatalErrors , errors .New (fmt .Sprintln ("unexpected error parsing column: " , namespace , columnName , columnData [idx ])))
187
255
continue
188
256
}
189
257
// Generate the metric
@@ -345,6 +413,11 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
345
413
up = 0
346
414
}
347
415
416
+ if err = queryShowLists (ch , e .db , e .logger ); err != nil {
417
+ level .Error (e .logger ).Log ("msg" , "error getting SHOW LISTS" , "err" , err )
418
+ up = 0
419
+ }
420
+
348
421
errMap := queryNamespaceMappings (ch , e .db , e .metricMap , e .logger )
349
422
if len (errMap ) > 0 {
350
423
level .Error (e .logger ).Log ("msg" , "error querying namespace mappings" , "err" , errMap )
0 commit comments