Skip to content

Commit 7edd749

Browse files
committed
Expose query duration as histogram
Signed-off-by: Wilfried Roset <[email protected]>
1 parent 1c69ded commit 7edd749

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

config.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/go-kit/log"
1414
"github.com/jmoiron/sqlx"
1515
"github.com/prometheus/client_golang/prometheus"
16+
"github.com/prometheus/client_golang/prometheus/promauto"
1617
"github.com/robfig/cron/v3"
1718
"gopkg.in/yaml.v2"
1819
)
@@ -25,9 +26,10 @@ func getenv(key, defaultVal string) string {
2526
}
2627

2728
var (
29+
metricsPrefix = "sql_exporter"
2830
failedScrapes = prometheus.NewGaugeVec(
2931
prometheus.GaugeOpts{
30-
Name: "sql_exporter_last_scrape_failed",
32+
Name: fmt.Sprintf("%s_last_scrape_failed", metricsPrefix),
3133
Help: "Failed scrapes",
3234
},
3335
[]string{"driver", "host", "database", "user", "sql_job", "query"},
@@ -41,6 +43,18 @@ var (
4143
regexp.QuoteMeta(tmplEnd),
4244
),
4345
)
46+
QueryMetricsLabels = []string{"sql_job", "query"}
47+
queryCounter = promauto.NewCounterVec(prometheus.CounterOpts{
48+
Name: fmt.Sprintf("%s_queries_total", metricsPrefix),
49+
}, QueryMetricsLabels)
50+
failedQueryCounter = promauto.NewCounterVec(prometheus.CounterOpts{
51+
Name: fmt.Sprintf("%s_query_failures_total", metricsPrefix),
52+
}, QueryMetricsLabels)
53+
54+
// Those are the default buckets
55+
DefaultQueryDurationHistogramBuckets = prometheus.DefBuckets
56+
// To make the buckets configurable let's init it after loading the configuration.
57+
queryDurationHistogram *prometheus.HistogramVec
4458
)
4559

4660
func init() {
@@ -100,11 +114,16 @@ type CloudSQLConfig struct {
100114

101115
// File is a collection of jobs
102116
type File struct {
117+
Configuration Configuration `yaml:"configuration,omitempty"`
103118
Jobs []*Job `yaml:"jobs"`
104119
Queries map[string]string `yaml:"queries"`
105120
CloudSQLConfig *CloudSQLConfig `yaml:"cloudsql_config"`
106121
}
107122

123+
type Configuration struct {
124+
HistogramBuckets []float64 `yaml:"histogram_buckets"`
125+
}
126+
108127
type cronConfig struct {
109128
definition string
110129
schedule cron.Schedule

exporter.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
package main
22

33
import (
4+
"context"
5+
"fmt"
6+
47
"cloud.google.com/go/cloudsqlconn"
58
"cloud.google.com/go/cloudsqlconn/mysql/mysql"
69
"cloud.google.com/go/cloudsqlconn/postgres/pgxv4"
7-
"context"
8-
"fmt"
910
"github.com/go-kit/log"
1011
"github.com/go-kit/log/level"
1112
"github.com/prometheus/client_golang/prometheus"
13+
"github.com/prometheus/client_golang/prometheus/promauto"
1214
"github.com/robfig/cron/v3"
1315
"google.golang.org/api/option"
1416
sqladmin "google.golang.org/api/sqladmin/v1beta4"
@@ -34,6 +36,18 @@ func NewExporter(logger log.Logger, configFile string) (*Exporter, error) {
3436
return nil, err
3537
}
3638

39+
var queryDurationHistogramBuckets []float64
40+
if len(cfg.Configuration.HistogramBuckets) == 0 {
41+
queryDurationHistogramBuckets = DefaultQueryDurationHistogramBuckets
42+
} else {
43+
queryDurationHistogramBuckets = cfg.Configuration.HistogramBuckets
44+
}
45+
queryDurationHistogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
46+
Name: fmt.Sprintf("%s_query_duration_seconds", metricsPrefix),
47+
Help: "Time spent by querying the database.",
48+
Buckets: queryDurationHistogramBuckets,
49+
}, QueryMetricsLabels)
50+
3751
exp := &Exporter{
3852
jobs: make([]*Job, 0, len(cfg.Jobs)),
3953
logger: logger,

job.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ func (j *Job) runOnceConnection(conn *connection, done chan int) {
329329
if err := conn.connect(j); err != nil {
330330
level.Warn(j.log).Log("msg", "Failed to connect", "err", err, "host", conn.host)
331331
j.markFailed(conn)
332+
// we don't have the query name yet.
333+
failedQueryCounter.WithLabelValues(j.Name, "").Inc()
332334
return
333335
}
334336

query.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,30 @@ func (q *Query) Run(conn *connection) error {
1515
if q.log == nil {
1616
q.log = log.NewNopLogger()
1717
}
18+
queryCounter.WithLabelValues(q.jobName, q.Name).Inc()
1819
if q.desc == nil {
20+
failedQueryCounter.WithLabelValues(q.jobName, q.Name).Inc()
1921
return fmt.Errorf("metrics descriptor is nil")
2022
}
2123
if q.Query == "" {
24+
failedQueryCounter.WithLabelValues(q.jobName, q.Name).Inc()
2225
return fmt.Errorf("query is empty")
2326
}
2427
if conn == nil || conn.conn == nil {
28+
failedQueryCounter.WithLabelValues(q.jobName, q.Name).Inc()
2529
return fmt.Errorf("db connection not initialized (should not happen)")
2630
}
2731
// execute query
32+
now := time.Now()
2833
rows, err := conn.conn.Queryx(q.Query)
2934
if err != nil {
3035
failedScrapes.WithLabelValues(conn.driver, conn.host, conn.database, conn.user, q.jobName, q.Name).Set(1.0)
36+
failedQueryCounter.WithLabelValues(q.jobName, q.Name).Inc()
3137
return err
3238
}
3339
defer rows.Close()
40+
duration := time.Since(now)
41+
queryDurationHistogram.WithLabelValues(q.jobName, q.Name).Observe(duration.Seconds())
3442

3543
updated := 0
3644
metrics := make([]prometheus.Metric, 0, len(q.metrics))

0 commit comments

Comments
 (0)