@@ -22,6 +22,7 @@ import (
22
22
"context"
23
23
"errors"
24
24
"fmt"
25
+ "github.com/prometheus/client_golang/prometheus"
25
26
"os"
26
27
"path"
27
28
"path/filepath"
@@ -69,6 +70,7 @@ type engine struct {
69
70
sqlDB * gorm.DB
70
71
config Config
71
72
sqlMigrationLogger goose.Logger
73
+ prometheusMetrics []prometheus.Collector
72
74
}
73
75
74
76
func (e * engine ) Config () interface {} {
@@ -115,6 +117,12 @@ func (e *engine) CheckHealth() map[string]core.Health {
115
117
}
116
118
117
119
func (e * engine ) Start () error {
120
+ for _ , metric := range e .prometheusMetrics {
121
+ if err := prometheus .Register (metric ); err != nil && ! errors .As (err , & prometheus.AlreadyRegisteredError {}) {
122
+ println (errors .Is (err , prometheus.AlreadyRegisteredError {}))
123
+ return fmt .Errorf ("register metric: %w" , err )
124
+ }
125
+ }
118
126
return nil
119
127
}
120
128
@@ -154,7 +162,12 @@ func (e *engine) Shutdown() error {
154
162
if err != nil {
155
163
return err
156
164
}
157
- return underlyingDB .Close ()
165
+ if err := underlyingDB .Close (); err != nil {
166
+ return err
167
+ }
168
+ }
169
+ for _ , metric := range e .prometheusMetrics {
170
+ _ = prometheus .Unregister (metric )
158
171
}
159
172
return nil
160
173
}
@@ -259,12 +272,18 @@ func (e *engine) initSQLDatabase(strictmode bool) error {
259
272
if err != nil {
260
273
return err
261
274
}
262
- var dialect goose.Dialect
275
+
276
+ queryDurationMetric := prometheus .NewHistogram (prometheus.HistogramOpts {
277
+ Name : "sql_query_duration_seconds" ,
278
+ Help : "Duration of SQL queries in seconds (experimental, may be removed without notice)" ,
279
+ })
280
+ e .prometheusMetrics = append (e .prometheusMetrics , queryDurationMetric )
263
281
gormConfig := & gorm.Config {
264
282
TranslateError : true ,
265
283
Logger : gormLogrusLogger {
266
- underlying : log .Logger (),
267
- slowThreshold : sqlSlowQueryThreshold ,
284
+ underlying : log .Logger (),
285
+ slowThreshold : sqlSlowQueryThreshold ,
286
+ queryDurationMetric : queryDurationMetric ,
268
287
},
269
288
}
270
289
// SQL migration files use env variables for substitutions.
@@ -274,6 +293,7 @@ func (e *engine) initSQLDatabase(strictmode bool) error {
274
293
return err
275
294
}
276
295
defer os .Unsetenv ("TEXT_TYPE" )
296
+ var dialect goose.Dialect
277
297
switch dbType {
278
298
case "sqlite" :
279
299
// SQLite does not support SELECT FOR UPDATE and allows only 1 active write transaction at any time,
0 commit comments