Skip to content

Commit e29ccd1

Browse files
authored
#3663: Prometheus metrics for SQL query execution duration (#3787)
1 parent 7df4ad6 commit e29ccd1

File tree

3 files changed

+33
-6
lines changed

3 files changed

+33
-6
lines changed

storage/engine.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"context"
2323
"errors"
2424
"fmt"
25+
"github.com/prometheus/client_golang/prometheus"
2526
"os"
2627
"path"
2728
"path/filepath"
@@ -69,6 +70,7 @@ type engine struct {
6970
sqlDB *gorm.DB
7071
config Config
7172
sqlMigrationLogger goose.Logger
73+
prometheusMetrics []prometheus.Collector
7274
}
7375

7476
func (e *engine) Config() interface{} {
@@ -115,6 +117,12 @@ func (e *engine) CheckHealth() map[string]core.Health {
115117
}
116118

117119
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+
}
118126
return nil
119127
}
120128

@@ -154,7 +162,12 @@ func (e *engine) Shutdown() error {
154162
if err != nil {
155163
return err
156164
}
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)
158171
}
159172
return nil
160173
}
@@ -259,12 +272,18 @@ func (e *engine) initSQLDatabase(strictmode bool) error {
259272
if err != nil {
260273
return err
261274
}
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)
263281
gormConfig := &gorm.Config{
264282
TranslateError: true,
265283
Logger: gormLogrusLogger{
266-
underlying: log.Logger(),
267-
slowThreshold: sqlSlowQueryThreshold,
284+
underlying: log.Logger(),
285+
slowThreshold: sqlSlowQueryThreshold,
286+
queryDurationMetric: queryDurationMetric,
268287
},
269288
}
270289
// SQL migration files use env variables for substitutions.
@@ -274,6 +293,7 @@ func (e *engine) initSQLDatabase(strictmode bool) error {
274293
return err
275294
}
276295
defer os.Unsetenv("TEXT_TYPE")
296+
var dialect goose.Dialect
277297
switch dbType {
278298
case "sqlite":
279299
// SQLite does not support SELECT FOR UPDATE and allows only 1 active write transaction at any time,

storage/gorm_logger.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package storage
2121
import (
2222
"context"
2323
"errors"
24+
"github.com/prometheus/client_golang/prometheus"
2425
"github.com/sirupsen/logrus"
2526
"gorm.io/gorm"
2627
"gorm.io/gorm/logger"
@@ -32,8 +33,9 @@ var nowFunc = time.Now
3233

3334
// gormLogrusLogger is a logger that uses logrus as underlying logger for gorm
3435
type gormLogrusLogger struct {
35-
underlying *logrus.Entry
36-
slowThreshold time.Duration
36+
underlying *logrus.Entry
37+
slowThreshold time.Duration
38+
queryDurationMetric prometheus.Histogram
3739
}
3840

3941
func (g gormLogrusLogger) LogMode(level logger.LogLevel) logger.Interface {
@@ -62,6 +64,7 @@ func (g gormLogrusLogger) Trace(_ context.Context, begin time.Time, fn func() (s
6264
g.underlying.WithError(err).Warnf("Query failed (took %s): %s", elapsed, sql)
6365
return
6466
}
67+
g.queryDurationMetric.Observe(elapsed.Seconds())
6568
if elapsed >= g.slowThreshold {
6669
g.underlying.Warnf("Slow query (took %s): %s", elapsed, sql)
6770
} else {

storage/gorm_logger_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package storage
2020

2121
import (
22+
"github.com/prometheus/client_golang/prometheus"
2223
"github.com/sirupsen/logrus"
2324
"github.com/sirupsen/logrus/hooks/test"
2425
"github.com/stretchr/testify/assert"
@@ -36,6 +37,9 @@ func Test_gormLogrusLogger_Trace(t *testing.T) {
3637
logger := gormLogrusLogger{
3738
underlying: underlying.WithFields(nil),
3839
slowThreshold: 10 * time.Second,
40+
queryDurationMetric: prometheus.NewHistogram(prometheus.HistogramOpts{
41+
Name: "test",
42+
}),
3943
}
4044
now := time.Now()
4145
nowFunc = func() time.Time {

0 commit comments

Comments
 (0)