You've already forked mysqld_exporter
mirror of
https://github.com/prometheus/mysqld_exporter.git
synced 2025-07-31 17:44:21 +03:00
Add the instance struct to handle connections (#859)
The intent is to use the instance struct to hold the connection to the database as well as metadata about the instance: - version - flavor (mariadb or mysql) Change is similar to prometheus-community/postgres_exporter#785 Signed-off-by: Vlad Gusev <vlad.esten@gmail.com>
This commit is contained in:
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -72,8 +71,9 @@ func (ScrapeBinlogSize) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeBinlogSize) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeBinlogSize) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var logBin uint8
|
var logBin uint8
|
||||||
|
db := instance.getDB()
|
||||||
err := db.QueryRowContext(ctx, logbinQuery).Scan(&logBin)
|
err := db.QueryRowContext(ctx, logbinQuery).Scan(&logBin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -31,6 +31,8 @@ func TestScrapeBinlogSize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
mock.ExpectQuery(logbinQuery).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(1))
|
mock.ExpectQuery(logbinQuery).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(1))
|
||||||
|
|
||||||
columns := []string{"Log_name", "File_size"}
|
columns := []string{"Log_name", "File_size"}
|
||||||
@ -42,7 +44,7 @@ func TestScrapeBinlogSize(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeBinlogSize{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeBinlogSize{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -52,7 +51,8 @@ func (ScrapeEngineInnodbStatus) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeEngineInnodbStatus) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeEngineInnodbStatus) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
rows, err := db.QueryContext(ctx, engineInnodbStatusQuery)
|
rows, err := db.QueryContext(ctx, engineInnodbStatusQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -152,10 +152,10 @@ END OF INNODB MONITOR OUTPUT
|
|||||||
rows := sqlmock.NewRows(columns).AddRow("InnoDB", "", sample)
|
rows := sqlmock.NewRows(columns).AddRow("InnoDB", "", sample)
|
||||||
|
|
||||||
mock.ExpectQuery(sanitizeQuery(engineInnodbStatusQuery)).WillReturnRows(rows)
|
mock.ExpectQuery(sanitizeQuery(engineInnodbStatusQuery)).WillReturnRows(rows)
|
||||||
|
inst := &instance{db: db}
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeEngineInnodbStatus{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeEngineInnodbStatus{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -50,7 +50,8 @@ func (ScrapeEngineTokudbStatus) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeEngineTokudbStatus) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeEngineTokudbStatus) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
tokudbRows, err := db.QueryContext(ctx, engineTokudbStatusQuery)
|
tokudbRows, err := db.QueryContext(ctx, engineTokudbStatusQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -46,6 +46,7 @@ func TestScrapeEngineTokudbStatus(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"Type", "Name", "Status"}
|
columns := []string{"Type", "Name", "Status"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -59,7 +60,7 @@ func TestScrapeEngineTokudbStatus(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeEngineTokudbStatus{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeEngineTokudbStatus{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -15,10 +15,7 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -38,18 +35,12 @@ const (
|
|||||||
|
|
||||||
// SQL queries and parameters.
|
// SQL queries and parameters.
|
||||||
const (
|
const (
|
||||||
versionQuery = `SELECT @@version`
|
|
||||||
|
|
||||||
// System variable params formatting.
|
// System variable params formatting.
|
||||||
// See: https://github.com/go-sql-driver/mysql#system-variables
|
// See: https://github.com/go-sql-driver/mysql#system-variables
|
||||||
sessionSettingsParam = `log_slow_filter=%27tmp_table_on_disk,filesort_on_disk%27`
|
sessionSettingsParam = `log_slow_filter=%27tmp_table_on_disk,filesort_on_disk%27`
|
||||||
timeoutParam = `lock_wait_timeout=%d`
|
timeoutParam = `lock_wait_timeout=%d`
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
versionRE = regexp.MustCompile(`^\d+\.\d+`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Tunable flags.
|
// Tunable flags.
|
||||||
var (
|
var (
|
||||||
exporterLockTimeout = kingpin.Flag(
|
exporterLockTimeout = kingpin.Flag(
|
||||||
@ -92,6 +83,7 @@ type Exporter struct {
|
|||||||
logger log.Logger
|
logger log.Logger
|
||||||
dsn string
|
dsn string
|
||||||
scrapers []Scraper
|
scrapers []Scraper
|
||||||
|
instance *instance
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new MySQL exporter for the provided DSN.
|
// New returns a new MySQL exporter for the provided DSN.
|
||||||
@ -135,27 +127,23 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
|||||||
func (e *Exporter) scrape(ctx context.Context, ch chan<- prometheus.Metric) float64 {
|
func (e *Exporter) scrape(ctx context.Context, ch chan<- prometheus.Metric) float64 {
|
||||||
var err error
|
var err error
|
||||||
scrapeTime := time.Now()
|
scrapeTime := time.Now()
|
||||||
db, err := sql.Open("mysql", e.dsn)
|
instance, err := newInstance(e.dsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Error(e.logger).Log("msg", "Error opening connection to database", "err", err)
|
level.Error(e.logger).Log("msg", "Error opening connection to database", "err", err)
|
||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer instance.Close()
|
||||||
|
e.instance = instance
|
||||||
|
|
||||||
// By design exporter should use maximum one connection per request.
|
if err := instance.Ping(); err != nil {
|
||||||
db.SetMaxOpenConns(1)
|
|
||||||
db.SetMaxIdleConns(1)
|
|
||||||
// Set max lifetime for a connection.
|
|
||||||
db.SetConnMaxLifetime(1 * time.Minute)
|
|
||||||
|
|
||||||
if err := db.PingContext(ctx); err != nil {
|
|
||||||
level.Error(e.logger).Log("msg", "Error pinging mysqld", "err", err)
|
level.Error(e.logger).Log("msg", "Error pinging mysqld", "err", err)
|
||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(mysqlScrapeDurationSeconds, prometheus.GaugeValue, time.Since(scrapeTime).Seconds(), "connection")
|
ch <- prometheus.MustNewConstMetric(mysqlScrapeDurationSeconds, prometheus.GaugeValue, time.Since(scrapeTime).Seconds(), "connection")
|
||||||
|
|
||||||
version := getMySQLVersion(db, e.logger)
|
version := instance.versionMajorMinor
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
defer wg.Wait()
|
defer wg.Wait()
|
||||||
for _, scraper := range e.scrapers {
|
for _, scraper := range e.scrapers {
|
||||||
@ -169,7 +157,7 @@ func (e *Exporter) scrape(ctx context.Context, ch chan<- prometheus.Metric) floa
|
|||||||
label := "collect." + scraper.Name()
|
label := "collect." + scraper.Name()
|
||||||
scrapeTime := time.Now()
|
scrapeTime := time.Now()
|
||||||
collectorSuccess := 1.0
|
collectorSuccess := 1.0
|
||||||
if err := scraper.Scrape(ctx, db, ch, log.With(e.logger, "scraper", scraper.Name())); err != nil {
|
if err := scraper.Scrape(ctx, instance, ch, log.With(e.logger, "scraper", scraper.Name())); err != nil {
|
||||||
level.Error(e.logger).Log("msg", "Error from scraper", "scraper", scraper.Name(), "target", e.getTargetFromDsn(), "err", err)
|
level.Error(e.logger).Log("msg", "Error from scraper", "scraper", scraper.Name(), "target", e.getTargetFromDsn(), "err", err)
|
||||||
collectorSuccess = 0.0
|
collectorSuccess = 0.0
|
||||||
}
|
}
|
||||||
@ -189,19 +177,3 @@ func (e *Exporter) getTargetFromDsn() string {
|
|||||||
}
|
}
|
||||||
return dsnConfig.Addr
|
return dsnConfig.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMySQLVersion(db *sql.DB, logger log.Logger) float64 {
|
|
||||||
var versionStr string
|
|
||||||
var versionNum float64
|
|
||||||
if err := db.QueryRow(versionQuery).Scan(&versionStr); err == nil {
|
|
||||||
versionNum, _ = strconv.ParseFloat(versionRE.FindString(versionStr), 64)
|
|
||||||
} else {
|
|
||||||
level.Debug(logger).Log("msg", "Error querying version", "err", err)
|
|
||||||
}
|
|
||||||
// If we can't match/parse the version, set it some big value that matches all versions.
|
|
||||||
if versionNum == 0 {
|
|
||||||
level.Debug(logger).Log("msg", "Error parsing version string", "version", versionStr)
|
|
||||||
versionNum = 999
|
|
||||||
}
|
|
||||||
return versionNum
|
|
||||||
}
|
|
||||||
|
@ -15,12 +15,9 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
"github.com/smartystreets/goconvey/convey"
|
"github.com/smartystreets/goconvey/convey"
|
||||||
@ -68,20 +65,3 @@ func TestExporter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetMySQLVersion(t *testing.T) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("-short is passed, skipping test")
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := log.NewLogfmtLogger(os.Stderr)
|
|
||||||
logger = level.NewFilter(logger, level.AllowDebug())
|
|
||||||
|
|
||||||
convey.Convey("Version parsing", t, func() {
|
|
||||||
db, err := sql.Open("mysql", dsn)
|
|
||||||
convey.So(err, convey.ShouldBeNil)
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
convey.So(getMySQLVersion(db, logger), convey.ShouldBeBetweenOrEqual, 5.6, 12.0)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -99,7 +99,8 @@ func (ScrapeGlobalStatus) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeGlobalStatus) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeGlobalStatus) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
globalStatusRows, err := db.QueryContext(ctx, globalStatusQuery)
|
globalStatusRows, err := db.QueryContext(ctx, globalStatusQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeGlobalStatus(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"Variable_name", "Value"}
|
columns := []string{"Variable_name", "Value"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -63,7 +64,7 @@ func TestScrapeGlobalStatus(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeGlobalStatus{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeGlobalStatus{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -138,7 +138,8 @@ func (ScrapeGlobalVariables) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeGlobalVariables) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeGlobalVariables) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
globalVariablesRows, err := db.QueryContext(ctx, globalVariablesQuery)
|
globalVariablesRows, err := db.QueryContext(ctx, globalVariablesQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeGlobalVariables(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"Variable_name", "Value"}
|
columns := []string{"Variable_name", "Value"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -52,7 +53,7 @@ func TestScrapeGlobalVariables(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeGlobalVariables{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeGlobalVariables{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -100,7 +100,8 @@ func nowExpr() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeHeartbeat) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeHeartbeat) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
query := fmt.Sprintf(heartbeatQuery, nowExpr(), *collectHeartbeatDatabase, *collectHeartbeatTable)
|
query := fmt.Sprintf(heartbeatQuery, nowExpr(), *collectHeartbeatDatabase, *collectHeartbeatTable)
|
||||||
heartbeatRows, err := db.QueryContext(ctx, query)
|
heartbeatRows, err := db.QueryContext(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -65,6 +65,7 @@ func TestScrapeHeartbeat(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
rows := sqlmock.NewRows(tt.Columns).
|
rows := sqlmock.NewRows(tt.Columns).
|
||||||
AddRow("1487597613.001320", "1487598113.448042", 1)
|
AddRow("1487597613.001320", "1487598113.448042", 1)
|
||||||
@ -72,7 +73,7 @@ func TestScrapeHeartbeat(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeHeartbeat{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeHeartbeat{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -70,7 +69,8 @@ func (ScrapeAutoIncrementColumns) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeAutoIncrementColumns) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeAutoIncrementColumns) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
autoIncrementRows, err := db.QueryContext(ctx, infoSchemaAutoIncrementQuery)
|
autoIncrementRows, err := db.QueryContext(ctx, infoSchemaAutoIncrementQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -161,8 +160,9 @@ func (ScrapeClientStat) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeClientStat) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeClientStat) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var varName, varVal string
|
var varName, varVal string
|
||||||
|
db := instance.getDB()
|
||||||
err := db.QueryRowContext(ctx, userstatCheckQuery).Scan(&varName, &varVal)
|
err := db.QueryRowContext(ctx, userstatCheckQuery).Scan(&varName, &varVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Debug(logger).Log("msg", "Detailed client stats are not available.")
|
level.Debug(logger).Log("msg", "Detailed client stats are not available.")
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeClientStat(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
mock.ExpectQuery(sanitizeQuery(userstatCheckQuery)).WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).
|
mock.ExpectQuery(sanitizeQuery(userstatCheckQuery)).WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).
|
||||||
AddRow("userstat", "ON"))
|
AddRow("userstat", "ON"))
|
||||||
@ -41,7 +42,7 @@ func TestScrapeClientStat(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeClientStat{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeClientStat{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -77,7 +76,8 @@ func (ScrapeInnodbCmp) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeInnodbCmp) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeInnodbCmp) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
informationSchemaInnodbCmpRows, err := db.QueryContext(ctx, innodbCmpQuery)
|
informationSchemaInnodbCmpRows, err := db.QueryContext(ctx, innodbCmpQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeInnodbCmp(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"page_size", "compress_ops", "compress_ops_ok", "compress_time", "uncompress_ops", "uncompress_time"}
|
columns := []string{"page_size", "compress_ops", "compress_ops_ok", "compress_time", "uncompress_ops", "uncompress_time"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -38,7 +39,7 @@ func TestScrapeInnodbCmp(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeInnodbCmp{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeInnodbCmp{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -72,7 +71,8 @@ func (ScrapeInnodbCmpMem) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeInnodbCmpMem) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeInnodbCmpMem) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
informationSchemaInnodbCmpMemRows, err := db.QueryContext(ctx, innodbCmpMemQuery)
|
informationSchemaInnodbCmpMemRows, err := db.QueryContext(ctx, innodbCmpMemQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeInnodbCmpMem(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"page_size", "buffer_pool", "pages_used", "pages_free", "relocation_ops", "relocation_time"}
|
columns := []string{"page_size", "buffer_pool", "pages_used", "pages_free", "relocation_ops", "relocation_time"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -38,7 +39,7 @@ func TestScrapeInnodbCmpMem(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeInnodbCmpMem{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeInnodbCmpMem{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -93,10 +92,11 @@ func (ScrapeInnodbMetrics) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeInnodbMetrics) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeInnodbMetrics) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var enabledColumnName string
|
var enabledColumnName string
|
||||||
var query string
|
var query string
|
||||||
|
|
||||||
|
db := instance.getDB()
|
||||||
err := db.QueryRowContext(ctx, infoSchemaInnodbMetricsEnabledColumnQuery).Scan(&enabledColumnName)
|
err := db.QueryRowContext(ctx, infoSchemaInnodbMetricsEnabledColumnQuery).Scan(&enabledColumnName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -31,6 +31,7 @@ func TestScrapeInnodbMetrics(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
enabledColumnName := []string{"COLUMN_NAME"}
|
enabledColumnName := []string{"COLUMN_NAME"}
|
||||||
rows := sqlmock.NewRows(enabledColumnName).
|
rows := sqlmock.NewRows(enabledColumnName).
|
||||||
@ -53,7 +54,7 @@ func TestScrapeInnodbMetrics(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeInnodbMetrics{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeInnodbMetrics{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
@ -85,9 +84,10 @@ func (ScrapeInfoSchemaInnodbTablespaces) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeInfoSchemaInnodbTablespaces) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeInfoSchemaInnodbTablespaces) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var tablespacesTablename string
|
var tablespacesTablename string
|
||||||
var query string
|
var query string
|
||||||
|
db := instance.getDB()
|
||||||
err := db.QueryRowContext(ctx, innodbTablespacesTablenameQuery).Scan(&tablespacesTablename)
|
err := db.QueryRowContext(ctx, innodbTablespacesTablenameQuery).Scan(&tablespacesTablename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -31,6 +31,7 @@ func TestScrapeInfoSchemaInnodbTablespaces(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"TABLE_NAME"}
|
columns := []string{"TABLE_NAME"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -47,7 +48,7 @@ func TestScrapeInfoSchemaInnodbTablespaces(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeInfoSchemaInnodbTablespaces{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeInfoSchemaInnodbTablespaces{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
@ -97,11 +96,12 @@ func (ScrapeProcesslist) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeProcesslist) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeProcesslist) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
processQuery := fmt.Sprintf(
|
processQuery := fmt.Sprintf(
|
||||||
infoSchemaProcesslistQuery,
|
infoSchemaProcesslistQuery,
|
||||||
*processlistMinTime,
|
*processlistMinTime,
|
||||||
)
|
)
|
||||||
|
db := instance.getDB()
|
||||||
processlistRows, err := db.QueryContext(ctx, processQuery)
|
processlistRows, err := db.QueryContext(ctx, processQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -40,6 +40,7 @@ func TestScrapeProcesslist(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
query := fmt.Sprintf(infoSchemaProcesslistQuery, 0)
|
query := fmt.Sprintf(infoSchemaProcesslistQuery, 0)
|
||||||
columns := []string{"user", "host", "command", "state", "processes", "seconds"}
|
columns := []string{"user", "host", "command", "state", "processes", "seconds"}
|
||||||
@ -56,7 +57,7 @@ func TestScrapeProcesslist(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeProcesslist{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeProcesslist{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -56,7 +55,8 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func processQueryResponseTimeTable(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, query string, i int) error {
|
func processQueryResponseTimeTable(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, query string, i int) error {
|
||||||
|
db := instance.getDB()
|
||||||
queryDistributionRows, err := db.QueryContext(ctx, query)
|
queryDistributionRows, err := db.QueryContext(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -119,8 +119,9 @@ func (ScrapeQueryResponseTime) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeQueryResponseTime) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeQueryResponseTime) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var queryStats uint8
|
var queryStats uint8
|
||||||
|
db := instance.getDB()
|
||||||
err := db.QueryRowContext(ctx, queryResponseCheckQuery).Scan(&queryStats)
|
err := db.QueryRowContext(ctx, queryResponseCheckQuery).Scan(&queryStats)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Debug(logger).Log("msg", "Query response time distribution is not available.")
|
level.Debug(logger).Log("msg", "Query response time distribution is not available.")
|
||||||
@ -132,7 +133,7 @@ func (ScrapeQueryResponseTime) Scrape(ctx context.Context, db *sql.DB, ch chan<-
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, query := range queryResponseTimeQueries {
|
for i, query := range queryResponseTimeQueries {
|
||||||
err := processQueryResponseTimeTable(ctx, db, ch, query, i)
|
err := processQueryResponseTimeTable(ctx, instance, ch, query, i)
|
||||||
// The first query should not fail if query_response_time_stats is ON,
|
// The first query should not fail if query_response_time_stats is ON,
|
||||||
// unlike the other two when the read/write tables exist only with Percona Server 5.6/5.7.
|
// unlike the other two when the read/write tables exist only with Percona Server 5.6/5.7.
|
||||||
if i == 0 && err != nil {
|
if i == 0 && err != nil {
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeQueryResponseTime(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
mock.ExpectQuery(queryResponseCheckQuery).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(1))
|
mock.ExpectQuery(queryResponseCheckQuery).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(1))
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ func TestScrapeQueryResponseTime(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeQueryResponseTime{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeQueryResponseTime{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/go-kit/log/level"
|
"github.com/go-kit/log/level"
|
||||||
@ -84,7 +83,8 @@ func (ScrapeReplicaHost) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeReplicaHost) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeReplicaHost) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
replicaHostRows, err := db.QueryContext(ctx, replicaHostQuery)
|
replicaHostRows, err := db.QueryContext(ctx, replicaHostQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if mysqlErr, ok := err.(*MySQL.MySQLError); ok { // Now the error number is accessible directly
|
if mysqlErr, ok := err.(*MySQL.MySQLError); ok { // Now the error number is accessible directly
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeReplicaHost(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"SERVER_ID", "ROLE", "CPU", "MASTER_SLAVE_LATENCY_IN_MICROSECONDS", "REPLICA_LAG_IN_MILLISECONDS", "LOG_STREAM_SPEED_IN_KiB_PER_SECOND", "CURRENT_REPLAY_LATENCY_IN_MICROSECONDS"}
|
columns := []string{"SERVER_ID", "ROLE", "CPU", "MASTER_SLAVE_LATENCY_IN_MICROSECONDS", "REPLICA_LAG_IN_MILLISECONDS", "LOG_STREAM_SPEED_IN_KiB_PER_SECOND", "CURRENT_REPLAY_LATENCY_IN_MICROSECONDS"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -39,7 +40,7 @@ func TestScrapeReplicaHost(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeReplicaHost{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeReplicaHost{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/go-kit/log/level"
|
"github.com/go-kit/log/level"
|
||||||
@ -72,9 +71,10 @@ func (ScrapeSchemaStat) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeSchemaStat) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeSchemaStat) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var varName, varVal string
|
var varName, varVal string
|
||||||
|
|
||||||
|
db := instance.getDB()
|
||||||
err := db.QueryRowContext(ctx, userstatCheckQuery).Scan(&varName, &varVal)
|
err := db.QueryRowContext(ctx, userstatCheckQuery).Scan(&varName, &varVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Debug(logger).Log("msg", "Detailed schema stats are not available.")
|
level.Debug(logger).Log("msg", "Detailed schema stats are not available.")
|
||||||
|
@ -29,6 +29,7 @@ func TestScrapeSchemaStat(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
mock.ExpectQuery(sanitizeQuery(userstatCheckQuery)).WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).
|
mock.ExpectQuery(sanitizeQuery(userstatCheckQuery)).WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).
|
||||||
AddRow("userstat", "ON"))
|
AddRow("userstat", "ON"))
|
||||||
@ -41,7 +42,7 @@ func TestScrapeSchemaStat(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeSchemaStat{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeSchemaStat{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -97,8 +96,9 @@ func (ScrapeTableSchema) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeTableSchema) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeTableSchema) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var dbList []string
|
var dbList []string
|
||||||
|
db := instance.getDB()
|
||||||
if *tableSchemaDatabases == "*" {
|
if *tableSchemaDatabases == "*" {
|
||||||
dbListRows, err := db.QueryContext(ctx, dbListQuery)
|
dbListRows, err := db.QueryContext(ctx, dbListQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/go-kit/log/level"
|
"github.com/go-kit/log/level"
|
||||||
@ -72,8 +71,9 @@ func (ScrapeTableStat) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeTableStat) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeTableStat) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var varName, varVal string
|
var varName, varVal string
|
||||||
|
db := instance.getDB()
|
||||||
err := db.QueryRowContext(ctx, userstatCheckQuery).Scan(&varName, &varVal)
|
err := db.QueryRowContext(ctx, userstatCheckQuery).Scan(&varName, &varVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Debug(logger).Log("msg", "Detailed table stats are not available.")
|
level.Debug(logger).Log("msg", "Detailed table stats are not available.")
|
||||||
|
@ -29,6 +29,7 @@ func TestScrapeTableStat(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
mock.ExpectQuery(sanitizeQuery(userstatCheckQuery)).WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).
|
mock.ExpectQuery(sanitizeQuery(userstatCheckQuery)).WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).
|
||||||
AddRow("userstat", "ON"))
|
AddRow("userstat", "ON"))
|
||||||
@ -42,7 +43,7 @@ func TestScrapeTableStat(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeTableStat{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeTableStat{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -157,8 +156,9 @@ func (ScrapeUserStat) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeUserStat) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeUserStat) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var varName, varVal string
|
var varName, varVal string
|
||||||
|
db := instance.getDB()
|
||||||
err := db.QueryRowContext(ctx, userstatCheckQuery).Scan(&varName, &varVal)
|
err := db.QueryRowContext(ctx, userstatCheckQuery).Scan(&varName, &varVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Debug(logger).Log("msg", "Detailed user stats are not available.")
|
level.Debug(logger).Log("msg", "Detailed user stats are not available.")
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeUserStat(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
mock.ExpectQuery(sanitizeQuery(userstatCheckQuery)).WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).
|
mock.ExpectQuery(sanitizeQuery(userstatCheckQuery)).WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).
|
||||||
AddRow("userstat", "ON"))
|
AddRow("userstat", "ON"))
|
||||||
@ -41,7 +42,7 @@ func TestScrapeUserStat(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeUserStat{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeUserStat{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
114
collector/instance.go
Normal file
114
collector/instance.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// Copyright 2024 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/blang/semver/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FlavorMySQL = "mysql"
|
||||||
|
FlavorMariaDB = "mariadb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type instance struct {
|
||||||
|
db *sql.DB
|
||||||
|
flavor string
|
||||||
|
version semver.Version
|
||||||
|
versionMajorMinor float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInstance(dsn string) (*instance, error) {
|
||||||
|
i := &instance{}
|
||||||
|
db, err := sql.Open("mysql", dsn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
db.SetMaxOpenConns(1)
|
||||||
|
db.SetMaxIdleConns(1)
|
||||||
|
i.db = db
|
||||||
|
|
||||||
|
version, versionString, err := queryVersion(db)
|
||||||
|
if err != nil {
|
||||||
|
db.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
i.version = version
|
||||||
|
|
||||||
|
versionMajorMinor, err := strconv.ParseFloat(fmt.Sprintf("%d.%d", i.version.Major, i.version.Minor), 64)
|
||||||
|
if err != nil {
|
||||||
|
db.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
i.versionMajorMinor = versionMajorMinor
|
||||||
|
|
||||||
|
if strings.Contains(strings.ToLower(versionString), "mariadb") {
|
||||||
|
i.flavor = FlavorMariaDB
|
||||||
|
} else {
|
||||||
|
i.flavor = FlavorMySQL
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *instance) getDB() *sql.DB {
|
||||||
|
return i.db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *instance) Close() error {
|
||||||
|
return i.db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping checks connection availability and possibly invalidates the connection if it fails.
|
||||||
|
func (i *instance) Ping() error {
|
||||||
|
if err := i.db.Ping(); err != nil {
|
||||||
|
if cerr := i.Close(); cerr != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The result of SELECT version() is something like:
|
||||||
|
// for MariaDB: "10.5.17-MariaDB-1:10.5.17+maria~ubu2004-log"
|
||||||
|
// for MySQL: "8.0.36-28.1"
|
||||||
|
var versionRegex = regexp.MustCompile(`^((\d+)(\.\d+)(\.\d+))`)
|
||||||
|
|
||||||
|
func queryVersion(db *sql.DB) (semver.Version, string, error) {
|
||||||
|
var version string
|
||||||
|
err := db.QueryRow("SELECT @@version;").Scan(&version)
|
||||||
|
if err != nil {
|
||||||
|
return semver.Version{}, version, err
|
||||||
|
}
|
||||||
|
|
||||||
|
matches := versionRegex.FindStringSubmatch(version)
|
||||||
|
if len(matches) > 1 {
|
||||||
|
parsedVersion, err := semver.ParseTolerant(matches[1])
|
||||||
|
if err != nil {
|
||||||
|
return semver.Version{}, version, fmt.Errorf("could not parse version from %q", matches[1])
|
||||||
|
}
|
||||||
|
return parsedVersion, version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return semver.Version{}, version, fmt.Errorf("could not parse version from %q", version)
|
||||||
|
}
|
@ -120,7 +120,8 @@ func (ScrapeUser) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeUser) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeUser) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
var (
|
var (
|
||||||
userRows *sql.Rows
|
userRows *sql.Rows
|
||||||
err error
|
err error
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
@ -168,13 +167,14 @@ func (ScrapePerfEventsStatements) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfEventsStatements) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfEventsStatements) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
perfQuery := fmt.Sprintf(
|
perfQuery := fmt.Sprintf(
|
||||||
perfEventsStatementsQuery,
|
perfEventsStatementsQuery,
|
||||||
*perfEventsStatementsDigestTextLimit,
|
*perfEventsStatementsDigestTextLimit,
|
||||||
*perfEventsStatementsTimeLimit,
|
*perfEventsStatementsTimeLimit,
|
||||||
*perfEventsStatementsLimit,
|
*perfEventsStatementsLimit,
|
||||||
)
|
)
|
||||||
|
db := instance.getDB()
|
||||||
// Timers here are returned in picoseconds.
|
// Timers here are returned in picoseconds.
|
||||||
perfSchemaEventsStatementsRows, err := db.QueryContext(ctx, perfQuery)
|
perfSchemaEventsStatementsRows, err := db.QueryContext(ctx, perfQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -177,7 +176,8 @@ func (ScrapePerfEventsStatementsSum) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfEventsStatementsSum) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfEventsStatementsSum) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
// Timers here are returned in picoseconds.
|
// Timers here are returned in picoseconds.
|
||||||
perfEventsStatementsSumRows, err := db.QueryContext(ctx, perfEventsStatementsSumQuery)
|
perfEventsStatementsSumRows, err := db.QueryContext(ctx, perfEventsStatementsSumQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -61,7 +60,8 @@ func (ScrapePerfEventsWaits) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfEventsWaits) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfEventsWaits) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
// Timers here are returned in picoseconds.
|
// Timers here are returned in picoseconds.
|
||||||
perfSchemaEventsWaitsRows, err := db.QueryContext(ctx, perfEventsWaitsQuery)
|
perfSchemaEventsWaitsRows, err := db.QueryContext(ctx, perfEventsWaitsQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -70,7 +69,8 @@ func (ScrapePerfFileEvents) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfFileEvents) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfFileEvents) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
// Timers here are returned in picoseconds.
|
// Timers here are returned in picoseconds.
|
||||||
perfSchemaFileEventsRows, err := db.QueryContext(ctx, perfFileEventsQuery)
|
perfSchemaFileEventsRows, err := db.QueryContext(ctx, perfFileEventsQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
@ -80,7 +79,8 @@ func (ScrapePerfFileInstances) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfFileInstances) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfFileInstances) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
// Timers here are returned in picoseconds.
|
// Timers here are returned in picoseconds.
|
||||||
perfSchemaFileInstancesRows, err := db.QueryContext(ctx, perfFileInstancesQuery, *performanceSchemaFileInstancesFilter)
|
perfSchemaFileInstancesRows, err := db.QueryContext(ctx, perfFileInstancesQuery, *performanceSchemaFileInstancesFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -37,6 +37,7 @@ func TestScrapePerfFileInstances(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"FILE_NAME", "EVENT_NAME", "COUNT_READ", "COUNT_WRITE", "SUM_NUMBER_OF_BYTES_READ", "SUM_NUMBER_OF_BYTES_WRITE"}
|
columns := []string{"FILE_NAME", "EVENT_NAME", "COUNT_READ", "COUNT_WRITE", "SUM_NUMBER_OF_BYTES_READ", "SUM_NUMBER_OF_BYTES_WRITE"}
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ func TestScrapePerfFileInstances(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapePerfFileInstances{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapePerfFileInstances{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
panic(fmt.Sprintf("error calling function on test: %s", err))
|
panic(fmt.Sprintf("error calling function on test: %s", err))
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -64,7 +63,8 @@ func (ScrapePerfIndexIOWaits) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfIndexIOWaits) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfIndexIOWaits) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
perfSchemaIndexWaitsRows, err := db.QueryContext(ctx, perfIndexIOWaitsQuery)
|
perfSchemaIndexWaitsRows, err := db.QueryContext(ctx, perfIndexIOWaitsQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapePerfIndexIOWaits(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"OBJECT_SCHEMA", "OBJECT_NAME", "INDEX_NAME", "COUNT_FETCH", "COUNT_INSERT", "COUNT_UPDATE", "COUNT_DELETE", "SUM_TIMER_FETCH", "SUM_TIMER_INSERT", "SUM_TIMER_UPDATE", "SUM_TIMER_DELETE"}
|
columns := []string{"OBJECT_SCHEMA", "OBJECT_NAME", "INDEX_NAME", "COUNT_FETCH", "COUNT_INSERT", "COUNT_UPDATE", "COUNT_DELETE", "SUM_TIMER_FETCH", "SUM_TIMER_INSERT", "SUM_TIMER_UPDATE", "SUM_TIMER_DELETE"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -40,7 +41,7 @@ func TestScrapePerfIndexIOWaits(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapePerfIndexIOWaits{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapePerfIndexIOWaits{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
@ -79,7 +78,8 @@ func (ScrapePerfMemoryEvents) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfMemoryEvents) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfMemoryEvents) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
perfSchemaMemoryEventsRows, err := db.QueryContext(ctx, perfMemoryEventsQuery)
|
perfSchemaMemoryEventsRows, err := db.QueryContext(ctx, perfMemoryEventsQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -37,6 +37,7 @@ func TestScrapePerfMemoryEvents(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{
|
columns := []string{
|
||||||
"EVENT_NAME",
|
"EVENT_NAME",
|
||||||
@ -54,7 +55,7 @@ func TestScrapePerfMemoryEvents(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapePerfMemoryEvents{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapePerfMemoryEvents{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
panic(fmt.Sprintf("error calling function on test: %s", err))
|
panic(fmt.Sprintf("error calling function on test: %s", err))
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -15,7 +15,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
@ -101,7 +100,8 @@ func (ScrapePerfReplicationApplierStatsByWorker) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfReplicationApplierStatsByWorker) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfReplicationApplierStatsByWorker) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
perfReplicationApplierStatsByWorkerRows, err := db.QueryContext(ctx, perfReplicationApplierStatsByWorkerQuery)
|
perfReplicationApplierStatsByWorkerRows, err := db.QueryContext(ctx, perfReplicationApplierStatsByWorkerQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -31,6 +31,7 @@ func TestScrapePerfReplicationApplierStatsByWorker(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{
|
columns := []string{
|
||||||
"CHANNEL_NAME",
|
"CHANNEL_NAME",
|
||||||
@ -54,7 +55,7 @@ func TestScrapePerfReplicationApplierStatsByWorker(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapePerfReplicationApplierStatsByWorker{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapePerfReplicationApplierStatsByWorker{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -79,7 +79,8 @@ func (ScrapePerfReplicationGroupMemberStats) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfReplicationGroupMemberStats) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfReplicationGroupMemberStats) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
rows, err := db.QueryContext(ctx, perfReplicationGroupMemberStatsQuery)
|
rows, err := db.QueryContext(ctx, perfReplicationGroupMemberStatsQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapePerfReplicationGroupMemberStats(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{
|
columns := []string{
|
||||||
"CHANNEL_NAME",
|
"CHANNEL_NAME",
|
||||||
@ -66,7 +67,7 @@ func TestScrapePerfReplicationGroupMemberStats(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapePerfReplicationGroupMemberStats{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapePerfReplicationGroupMemberStats{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -16,9 +16,10 @@ package collector
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const perfReplicationGroupMembersQuery = `
|
const perfReplicationGroupMembersQuery = `
|
||||||
@ -44,7 +45,8 @@ func (ScrapePerfReplicationGroupMembers) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfReplicationGroupMembers) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfReplicationGroupMembers) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
perfReplicationGroupMembersRows, err := db.QueryContext(ctx, perfReplicationGroupMembersQuery)
|
perfReplicationGroupMembersRows, err := db.QueryContext(ctx, perfReplicationGroupMembersQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -15,12 +15,13 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/DATA-DOG/go-sqlmock"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
"github.com/smartystreets/goconvey/convey"
|
"github.com/smartystreets/goconvey/convey"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScrapePerfReplicationGroupMembers(t *testing.T) {
|
func TestScrapePerfReplicationGroupMembers(t *testing.T) {
|
||||||
@ -29,6 +30,7 @@ func TestScrapePerfReplicationGroupMembers(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{
|
columns := []string{
|
||||||
"CHANNEL_NAME",
|
"CHANNEL_NAME",
|
||||||
@ -49,7 +51,7 @@ func TestScrapePerfReplicationGroupMembers(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapePerfReplicationGroupMembers{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapePerfReplicationGroupMembers{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
@ -82,6 +84,7 @@ func TestScrapePerfReplicationGroupMembersMySQL57(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{
|
columns := []string{
|
||||||
"CHANNEL_NAME",
|
"CHANNEL_NAME",
|
||||||
@ -100,7 +103,7 @@ func TestScrapePerfReplicationGroupMembersMySQL57(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapePerfReplicationGroupMembers{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapePerfReplicationGroupMembers{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -65,7 +64,8 @@ func (ScrapePerfTableIOWaits) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfTableIOWaits) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfTableIOWaits) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
perfSchemaTableWaitsRows, err := db.QueryContext(ctx, perfTableIOWaitsQuery)
|
perfSchemaTableWaitsRows, err := db.QueryContext(ctx, perfTableIOWaitsQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -17,7 +17,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -94,7 +93,8 @@ func (ScrapePerfTableLockWaits) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapePerfTableLockWaits) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapePerfTableLockWaits) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
db := instance.getDB()
|
||||||
perfSchemaTableLockWaitsRows, err := db.QueryContext(ctx, perfTableLockWaitsQuery)
|
perfSchemaTableLockWaitsRows, err := db.QueryContext(ctx, perfTableLockWaitsQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -15,7 +15,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
@ -35,5 +34,5 @@ type Scraper interface {
|
|||||||
Version() float64
|
Version() float64
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error
|
Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,12 @@ func (ScrapeSlaveHosts) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeSlaveHosts) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeSlaveHosts) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var (
|
var (
|
||||||
slaveHostsRows *sql.Rows
|
slaveHostsRows *sql.Rows
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
db := instance.getDB()
|
||||||
// Try the both syntax for MySQL 8.0 and MySQL 8.4
|
// Try the both syntax for MySQL 8.0 and MySQL 8.4
|
||||||
if slaveHostsRows, err = db.QueryContext(ctx, slaveHostsQuery); err != nil {
|
if slaveHostsRows, err = db.QueryContext(ctx, slaveHostsQuery); err != nil {
|
||||||
if slaveHostsRows, err = db.QueryContext(ctx, showReplicasQuery); err != nil {
|
if slaveHostsRows, err = db.QueryContext(ctx, showReplicasQuery); err != nil {
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeSlaveHostsOldFormat(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"Server_id", "Host", "Port", "Rpl_recovery_rank", "Master_id"}
|
columns := []string{"Server_id", "Host", "Port", "Rpl_recovery_rank", "Master_id"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -39,7 +40,7 @@ func TestScrapeSlaveHostsOldFormat(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeSlaveHosts{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeSlaveHosts{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
@ -68,6 +69,7 @@ func TestScrapeSlaveHostsNewFormat(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"Server_id", "Host", "Port", "Master_id", "Slave_UUID"}
|
columns := []string{"Server_id", "Host", "Port", "Master_id", "Slave_UUID"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -77,7 +79,7 @@ func TestScrapeSlaveHostsNewFormat(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeSlaveHosts{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeSlaveHosts{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
@ -106,6 +108,7 @@ func TestScrapeSlaveHostsWithoutSlaveUuid(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"Server_id", "Host", "Port", "Master_id"}
|
columns := []string{"Server_id", "Host", "Port", "Master_id"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -115,7 +118,7 @@ func TestScrapeSlaveHostsWithoutSlaveUuid(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeSlaveHosts{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeSlaveHosts{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -69,11 +69,12 @@ func (ScrapeSlaveStatus) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
// Scrape collects data from database connection and sends it over channel as prometheus metric.
|
||||||
func (ScrapeSlaveStatus) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeSlaveStatus) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
var (
|
var (
|
||||||
slaveStatusRows *sql.Rows
|
slaveStatusRows *sql.Rows
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
db := instance.getDB()
|
||||||
// Try the both syntax for MySQL/Percona and MariaDB
|
// Try the both syntax for MySQL/Percona and MariaDB
|
||||||
for _, query := range slaveStatusQueries {
|
for _, query := range slaveStatusQueries {
|
||||||
slaveStatusRows, err = db.QueryContext(ctx, query)
|
slaveStatusRows, err = db.QueryContext(ctx, query)
|
||||||
|
@ -30,6 +30,7 @@ func TestScrapeSlaveStatus(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{"Master_Host", "Read_Master_Log_Pos", "Slave_IO_Running", "Slave_SQL_Running", "Seconds_Behind_Master"}
|
columns := []string{"Master_Host", "Read_Master_Log_Pos", "Slave_IO_Running", "Slave_SQL_Running", "Seconds_Behind_Master"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -38,7 +39,7 @@ func TestScrapeSlaveStatus(t *testing.T) {
|
|||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeSlaveStatus{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeSlaveStatus{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
@ -15,7 +15,6 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -99,7 +98,9 @@ func (ScrapeSysUserSummary) Version() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrape the information from sys.user_summary, creating a metric for each value of each row, labeled with the user
|
// Scrape the information from sys.user_summary, creating a metric for each value of each row, labeled with the user
|
||||||
func (ScrapeSysUserSummary) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
|
func (ScrapeSysUserSummary) Scrape(ctx context.Context, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) error {
|
||||||
|
|
||||||
|
db := instance.getDB()
|
||||||
|
|
||||||
userSummaryRows, err := db.QueryContext(ctx, sysUserSummaryQuery)
|
userSummaryRows, err := db.QueryContext(ctx, sysUserSummaryQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -16,14 +16,15 @@ package collector
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/DATA-DOG/go-sqlmock"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
"github.com/smartystreets/goconvey/convey"
|
"github.com/smartystreets/goconvey/convey"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScrapeSysUserSummary(t *testing.T) {
|
func TestScrapeSysUserSummary(t *testing.T) {
|
||||||
@ -33,6 +34,7 @@ func TestScrapeSysUserSummary(t *testing.T) {
|
|||||||
t.Fatalf("error opening a stub database connection: %s", err)
|
t.Fatalf("error opening a stub database connection: %s", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
inst := &instance{db: db}
|
||||||
|
|
||||||
columns := []string{
|
columns := []string{
|
||||||
"user",
|
"user",
|
||||||
@ -111,7 +113,7 @@ func TestScrapeSysUserSummary(t *testing.T) {
|
|||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err = (ScrapeSysUserSummary{}).Scrape(context.Background(), db, ch, log.NewNopLogger()); err != nil {
|
if err = (ScrapeSysUserSummary{}).Scrape(context.Background(), inst, ch, log.NewNopLogger()); err != nil {
|
||||||
t.Errorf("error calling function on test: %s", err)
|
t.Errorf("error calling function on test: %s", err)
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
|
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.21
|
|||||||
require (
|
require (
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.2
|
github.com/DATA-DOG/go-sqlmock v1.5.2
|
||||||
github.com/alecthomas/kingpin/v2 v2.4.0
|
github.com/alecthomas/kingpin/v2 v2.4.0
|
||||||
|
github.com/blang/semver/v4 v4.0.0
|
||||||
github.com/go-kit/log v0.2.1
|
github.com/go-kit/log v0.2.1
|
||||||
github.com/go-sql-driver/mysql v1.8.1
|
github.com/go-sql-driver/mysql v1.8.1
|
||||||
github.com/google/go-cmp v0.6.0
|
github.com/google/go-cmp v0.6.0
|
||||||
|
2
go.sum
2
go.sum
@ -8,6 +8,8 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu
|
|||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||||
|
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
|
Reference in New Issue
Block a user