Add dev sql interceptor for logging of queries (#3815)

* Add dev sql interceptor for logging of queries

* Remove extra spaces and tabs from queries

* Make regex global
This commit is contained in:
Lucas Manuel Rodriguez 2022-01-21 14:28:21 -03:00 committed by GitHub
parent 85487eb5b2
commit 81672ee50e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 10 deletions

View File

@ -3,6 +3,7 @@ package main
import (
"context"
"crypto/tls"
"database/sql/driver"
"errors"
"fmt"
"io/ioutil"
@ -47,6 +48,7 @@ import (
"github.com/go-kit/kit/log/level"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/kolide/kit/version"
"github.com/ngrok/sqlmw"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/cobra"
@ -154,11 +156,17 @@ the way that the Fleet server works.
var carveStore fleet.CarveStore
mailService := mail.NewService()
var replicaOpt mysql.DBOption
opts := []mysql.DBOption{mysql.Logger(logger)}
if config.MysqlReadReplica.Address != "" {
replicaOpt = mysql.Replica(&config.MysqlReadReplica)
opts = append(opts, mysql.Replica(&config.MysqlReadReplica))
}
ds, err = mysql.New(config.Mysql, clock.C, mysql.Logger(logger), replicaOpt)
if dev && os.Getenv("FLEET_ENABLE_DEV_SQL_INTERCEPTOR") != "" {
opts = append(opts, mysql.WithInterceptor(&devSQLInterceptor{
logger: kitlog.With(logger, "component", "sql-interceptor"),
}))
}
ds, err = mysql.New(config.Mysql, clock.C, opts...)
if err != nil {
initFatal(err, "initializing datastore")
}
@ -839,3 +847,51 @@ func getTLSConfig(profile string) *tls.Config {
return &cfg
}
// devSQLInterceptor is a sql interceptor to be used for development purposes.
type devSQLInterceptor struct {
sqlmw.NullInterceptor
logger kitlog.Logger
}
func (in *devSQLInterceptor) StmtQueryContext(ctx context.Context, stmt driver.StmtQueryContext, query string, args []driver.NamedValue) (driver.Rows, error) {
start := time.Now()
rows, err := stmt.QueryContext(ctx, args)
in.logQuery(start, query, args, err)
return rows, err
}
func (in *devSQLInterceptor) StmtExecContext(ctx context.Context, stmt driver.StmtExecContext, query string, args []driver.NamedValue) (driver.Result, error) {
start := time.Now()
result, err := stmt.ExecContext(ctx, args)
in.logQuery(start, query, args, err)
return result, err
}
var spaceRegex = regexp.MustCompile(`\s+`)
func (in *devSQLInterceptor) logQuery(start time.Time, query string, args []driver.NamedValue, err error) {
logLevel := level.Debug
if err != nil {
logLevel = level.Error
}
query = strings.TrimSpace(spaceRegex.ReplaceAllString(query, " "))
logLevel(in.logger).Log("duration", time.Since(start), "query", query, "args", argsToString(args), "err", err)
}
func argsToString(args []driver.NamedValue) string {
var allArgs strings.Builder
allArgs.WriteString("{")
for i, arg := range args {
if i > 0 {
allArgs.WriteString(", ")
}
if arg.Name != "" {
allArgs.WriteString(fmt.Sprintf("%s=", arg.Name))
}
allArgs.WriteString(fmt.Sprintf("%v", arg.Value))
}
allArgs.WriteString("}")
return allArgs.String()
}

3
go.mod
View File

@ -25,7 +25,7 @@ require (
github.com/facebookincubator/nvdtools v0.1.4
github.com/fatih/color v1.12.0
github.com/fleetdm/goose v0.0.0-20210209032905-c3c01484bacb
github.com/getsentry/sentry-go v0.12.0 // indirect
github.com/getsentry/sentry-go v0.12.0
github.com/ghodss/yaml v1.0.0
github.com/go-kit/kit v0.9.0
github.com/go-sql-driver/mysql v1.6.0
@ -54,6 +54,7 @@ require (
github.com/mitchellh/go-ps v1.0.0
github.com/mitchellh/gon v0.2.3
github.com/mna/redisc v1.3.2
github.com/ngrok/sqlmw v0.0.0-20211220175533-9d16fdc47b31
github.com/oklog/run v1.1.0
github.com/olekukonko/tablewriter v0.0.5
github.com/open-policy-agent/opa v0.24.0

8
go.sum
View File

@ -383,6 +383,7 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
@ -741,7 +742,6 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
@ -753,7 +753,6 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
@ -815,6 +814,8 @@ github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5Vgl
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/ngrok/sqlmw v0.0.0-20211220175533-9d16fdc47b31 h1:FFHgfAIoAXCCL4xBoAugZVpekfGmZ/fBBueneUKBv7I=
github.com/ngrok/sqlmw v0.0.0-20211220175533-9d16fdc47b31/go.mod h1:E26fwEtRNigBfFfHDWsklmo0T7Ixbg0XXgck+Hq4O9k=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@ -849,6 +850,7 @@ github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrap
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.0.0-20181023235946-059132a15dd0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -1049,7 +1051,6 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/zclconf/go-cty v1.1.0 h1:uJwc9HiBOCpoKIObTQaLR+tsEXx1HBHnOsOOpcdhZgw=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
github.com/zwass/kit v0.0.0-20210625184505-ec5b5c5cce9c h1:TWQ2UvXPkhPxI2KmApKBOCaV6yD2N4mlvqFQ/DlPtpQ=
github.com/zwass/kit v0.0.0-20210625184505-ec5b5c5cce9c/go.mod h1:OYYulo9tUqRadRLwB0+LE914sa1ui2yL7OrcU3Q/1XY=
@ -1205,7 +1206,6 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211007125505-59d4e928ea9d h1:QWMn1lFvU/nZ58ssWqiFJMd3DKIII8NYc4sn708XgKs=
golang.org/x/net v0.0.0-20211007125505-59d4e928ea9d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f h1:1scJEYZBaF48BaG6tYbtxmLcXqwYGSfGcMoStTqkkIw=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=

View File

@ -3,6 +3,7 @@ package mysql
import (
"github.com/fleetdm/fleet/v4/server/config"
"github.com/go-kit/kit/log"
"github.com/ngrok/sqlmw"
)
const defaultMaxAttempts int = 15
@ -15,9 +16,10 @@ type dbOptions struct {
maxAttempts int
logger log.Logger
replicaConfig *config.MysqlConfig
interceptor sqlmw.Interceptor
}
// Logger adds a logger to the datastore
// Logger adds a logger to the datastore.
func Logger(l log.Logger) DBOption {
return func(o *dbOptions) error {
o.logger = l
@ -25,6 +27,14 @@ func Logger(l log.Logger) DBOption {
}
}
// WithInterceptor adds the sql interceptor to the datastore.
func WithInterceptor(i sqlmw.Interceptor) DBOption {
return func(o *dbOptions) error {
o.interceptor = i
return nil
}
}
// Replica sets the configuration of the read replica for the datastore.
func Replica(conf *config.MysqlConfig) DBOption {
return func(o *dbOptions) error {

View File

@ -28,6 +28,7 @@ import (
"github.com/go-kit/kit/log/level"
"github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
"github.com/ngrok/sqlmw"
)
const (
@ -249,8 +250,14 @@ func (d *Datastore) writeChanLoop() {
}
func newDB(conf *config.MysqlConfig, opts *dbOptions) (*sqlx.DB, error) {
driverName := "mysql"
if opts.interceptor != nil {
driverName = "mysql-mw"
sql.Register(driverName, sqlmw.Driver(mysql.MySQLDriver{}, opts.interceptor))
}
dsn := generateMysqlConnectionString(*conf)
db, err := sqlx.Open("mysql", dsn)
db, err := sqlx.Open(driverName, dsn)
if err != nil {
return nil, err
}