From 13334a989b583edbbeb5db211a8fa87268d5f23a Mon Sep 17 00:00:00 2001 From: Douglas Soo Date: Thu, 17 Oct 2019 14:26:46 -0700 Subject: [PATCH 1/4] First pass at go database stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More db stats everywhere Idle stats + updated changelog Don’t instrument stats calls Try adding basic tests to sql. Basic tests for common db stats event generation Get rid of duplicate fields, rename to match existing pattern --- .circleci/config.yml | 2 + CHANGELOG.md | 163 ++++++++++---------- version.go | 2 +- wrappers/common/common.go | 9 +- wrappers/common/common_go1.11.go | 26 ++++ wrappers/common/common_prego1.11.go | 18 +++ wrappers/common/common_test.go | 15 ++ wrappers/hnysql/sql.go | 99 ++++++------ wrappers/hnysql/sql_test.go | 56 +++++++ wrappers/hnysqlx/sqlx.go | 227 ++++++++++++++-------------- wrappers/hnysqlx/sqlx_test.go | 57 +++++++ 11 files changed, 425 insertions(+), 249 deletions(-) create mode 100644 wrappers/common/common_go1.11.go create mode 100644 wrappers/common/common_prego1.11.go diff --git a/.circleci/config.yml b/.circleci/config.yml index f0e257f7..4585c657 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,3 +33,5 @@ workflows: goversion: "11" - test_beeline: goversion: "12" + - test_beeline: + goversion: "13" diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c5c42c0..52b8c97d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,116 +1,107 @@ -Release v0.4.5 (2019-09-17) -== +# Release v0.4.6 (2019-10-17) + +### Additions + +- Add additional go database stats to `hnysql` and `hnysqlx` wrapppers. In go 1.11 and later, we additionally report `db.conns_in_use`, `db.conns_idle`, `db.wait_count`, and `db.wait_duration`. See https://golang.org/pkg/database/sql/#DB.Stats + +# Release v0.4.5 (2019-09-17) ### Bugfixes -* Fixed `db.error` not being added by `hnysql` and `hnysqlx` wrappers. -* Reduction in heap allocations when creating a span. +- Fixed `db.error` not being added by `hnysql` and `hnysqlx` wrappers. +- Reduction in heap allocations when creating a span. -Release v0.4.4 (2019-04-09) -== +# Release v0.4.4 (2019-04-09) ### Bugfixes -* Fixed an issue where the libhoney transmission was being spun up without a default batch timeout, so spans were only getting sent when they hit the batch max (50) rather than after a 100ms timeout. -* Use libhoney defaults for all missing parameters during initialization (previously the beeline had a few values that differed from the libhoney defaults). +- Fixed an issue where the libhoney transmission was being spun up without a default batch timeout, so spans were only getting sent when they hit the batch max (50) rather than after a 100ms timeout. +- Use libhoney defaults for all missing parameters during initialization (previously the beeline had a few values that differed from the libhoney defaults). ### Additions -* Added the Contributors file listing people that have made contributions to the Beeline - +- Added the Contributors file listing people that have made contributions to the Beeline -Release v0.4.3 (2019-04-09) -== +# Release v0.4.3 (2019-04-09) ### Bugfixes -* Fix race condition when concurrently adding children and sending a non-root +- Fix race condition when concurrently adding children and sending a non-root span. Contribution by @carlosgaldino -Release v0.4.2 (2019-04-08) -== +# Release v0.4.2 (2019-04-08) ### Additions -* @jamietsao contributed middleware for the Echo router (https://echo.labstack.com/) +- @jamietsao contributed middleware for the Echo router (https://echo.labstack.com/) ### Bugfixes -* Events that were coming in with an existing sample rate to a beeline +- Events that were coming in with an existing sample rate to a beeline configured to do additional sampling were not computing the final sample rate correctly. This change fixes the sample rate in that specific case. -* Added missing comment describing the semantics of the `dataset` field in the +- Added missing comment describing the semantics of the `dataset` field in the trace propagation header added in v0.3.5 - -Release v0.4.1 (2019-03-21) -== +# Release v0.4.1 (2019-03-21) ### Bugfixes -* Sample rate returned by the sampler hook was incorrectly being multiplied with the default global sample rate. +- Sample rate returned by the sampler hook was incorrectly being multiplied with the default global sample rate. -Release v0.4.0 (2018-11-28) -== +# Release v0.4.0 (2018-11-28) ### Additions -* Add a `libhoney.Client` as a configurable item in the beeline initial config. +- Add a `libhoney.Client` as a configurable item in the beeline initial config. This allows full control over the underlying transmission of spans, so you can replace the HTTP transport or adjust queue sizes and so on -Release v0.3.6 (2018-11-28) -== +# Release v0.3.6 (2018-11-28) ### Additions -* Add `CopyContext` function to simplify moving trace metadata to a new context +- Add `CopyContext` function to simplify moving trace metadata to a new context (for example, when trying to avoid a cancellation in an async span). -* Improve handling of broken or partial trace propagation headers +- Improve handling of broken or partial trace propagation headers -Release v0.3.5 (2018-11-28) -== +# Release v0.3.5 (2018-11-28) ### Additions -* Add `dataset` to serialized trace headers to allow one service with multiple +- Add `dataset` to serialized trace headers to allow one service with multiple upstream callers to send spans to the right destination dataset -Release v0.3.4 (2018-11-28) -== +# Release v0.3.4 (2018-11-28) ### Additions -* Delete spans from the trace when they're sent for improved memory management -* Add a benchmark +- Delete spans from the trace when they're sent for improved memory management +- Add a benchmark -Release v0.3.3 (2018-11-28) -== +# Release v0.3.3 (2018-11-28) ### Additions -* Add URL queries and add name even when empty +- Add URL queries and add name even when empty -Release v0.3.2 (2018-11-28) -== +# Release v0.3.2 (2018-11-28) ### Bugfixes -* Fix multiple races when sending spans. (https://github.com/honeycombio/beeline-go/pull/39 and https://github.com/honeycombio/beeline-go/pull/40) +- Fix multiple races when sending spans. (https://github.com/honeycombio/beeline-go/pull/39 and https://github.com/honeycombio/beeline-go/pull/40) -Release v0.3.1 (2018-10-25) -== +# Release v0.3.1 (2018-10-25) ### Bugfixes -* Fix race condition on map access that can occur with Sampler and Presend hooks when AddField is called concurrently with Send. +- Fix race condition on map access that can occur with Sampler and Presend hooks when AddField is called concurrently with Send. -Release v0.3.0 (2018-10-23) -== +# Release v0.3.0 (2018-10-23) ### Breaking Changes -* `NewResponseWriter` no longer returns a concrete type directly usable as an `http.ResponseWriter`. It now exposes the wrapped `http.ResponseWriter` through the field `Wrapped`. +- `NewResponseWriter` no longer returns a concrete type directly usable as an `http.ResponseWriter`. It now exposes the wrapped `http.ResponseWriter` through the field `Wrapped`. Code that would have previously looked like: @@ -126,37 +117,36 @@ wrappedWriter := common.NewResponseWriter(w) handler.ServeHTTP(wrappedWriter.Wrapped, r) ``` -Release v0.2.4 (2018-10-05) -=== +# Release v0.2.4 (2018-10-05) ### Minor Changes -* Allow override of MaxConcurrentBatches, MaxBatchSize, and PendingWorkCapacity in `beeline.Config` -* Sets default value for MaxConcurrentBatches to 20 (from 80), and PendingWorkCapacity to 1000 (from 10000). +- Allow override of MaxConcurrentBatches, MaxBatchSize, and PendingWorkCapacity in `beeline.Config` +- Sets default value for MaxConcurrentBatches to 20 (from 80), and PendingWorkCapacity to 1000 (from 10000). -Release v0.2.3 (2018-09-14) -=== +# Release v0.2.3 (2018-09-14) ### Bug Fixes -* rollup fields were not getting the rolled up values added to the root span + +- rollup fields were not getting the rolled up values added to the root span ### New Field -* sql and sqlx wrappers get both the DB call being made (eg Select) as well as the name of the function making the call (eg FetchThingsByID) -Release v0.2.2 (2018-09-1) -=== +- sql and sqlx wrappers get both the DB call being made (eg Select) as well as the name of the function making the call (eg FetchThingsByID) + +# Release v0.2.2 (2018-09-1) ### Bug Fixes -* fix version number inconsistency with a patch bump -Release v0.2.1 (2018-09-14) -=== +- fix version number inconsistency with a patch bump + +# Release v0.2.1 (2018-09-14) ### Bug Fixes -* fix propagation bug when an incoming request has a serialized beeline trace header -Release v0.2.0 (2018-09-12) -=== +- fix propagation bug when an incoming request has a serialized beeline trace header + +# Release v0.2.0 (2018-09-12) This is the second major release of the beeline. It changes the model from "one current span" to a to a doubly-linked tree of events (now dubbed "spans") @@ -164,44 +154,43 @@ representing a trace. ### Major Changes -* introduces the concept of a span -* adds functions to create new spans in a trace and add fields to specific spans -* adds the ability to create and accept a serialized chunk of data from an upstream service to connect in-process traces in a distributed infrastructure into one large trace. -* adds trace level fields that get copied to every downstream span -* adds rollup fields that sum their values and push them in to the root span -* adds a pre-send hook to modify spans before sending them to Honeycomb -* adds trace-aware deterministic sampling as the default -* adds a sampler hook to manually manage sampling if necessary +- introduces the concept of a span +- adds functions to create new spans in a trace and add fields to specific spans +- adds the ability to create and accept a serialized chunk of data from an upstream service to connect in-process traces in a distributed infrastructure into one large trace. +- adds trace level fields that get copied to every downstream span +- adds rollup fields that sum their values and push them in to the root span +- adds a pre-send hook to modify spans before sending them to Honeycomb +- adds trace-aware deterministic sampling as the default +- adds a sampler hook to manually manage sampling if necessary ### Breaking Changes -* removed `ContextEvent` and `ContextWithEvent` functions; replaced by spans +- removed `ContextEvent` and `ContextWithEvent` functions; replaced by spans ### Wrapper Changes -* augment the net/http wrapper to wrap `RoundTripper`s and handle outbound HTTP calls -* adding a wrapper for the `pop` package +- augment the net/http wrapper to wrap `RoundTripper`s and handle outbound HTTP calls +- adding a wrapper for the `pop` package -Release v0.1.2 (2018-08-30) -=== +# Release v0.1.2 (2018-08-30) ### New Features -* add new sqlx functions to add context to transactions and rollbacks -* add HTTP Headers X-Forwarded-For and X-Forwarded-Proto to events if they exist +- add new sqlx functions to add context to transactions and rollbacks +- add HTTP Headers X-Forwarded-For and X-Forwarded-Proto to events if they exist ### Bug Fixes -* use the passed in context in sqlx instead of creating a background context -Release v0.1.1 (2018-08-20) -=== +- use the passed in context in sqlx instead of creating a background context + +# Release v0.1.1 (2018-08-20) ### Bug Fixes -* Use the right Host header for incoming HTTP requests -* Recognize struct HTTP handlers and add their name -* Fix nil route bug -Release v0.1.0 (2018-05-16) -=== +- Use the right Host header for incoming HTTP requests +- Recognize struct HTTP handlers and add their name +- Fix nil route bug + +# Release v0.1.0 (2018-05-16) Initial Release diff --git a/version.go b/version.go index 0e2909ba..1e9764d9 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package beeline -const version = "0.4.5" +const version = "0.4.6" diff --git a/wrappers/common/common.go b/wrappers/common/common.go index afd2abe6..a7d0d078 100644 --- a/wrappers/common/common.go +++ b/wrappers/common/common.go @@ -2,6 +2,7 @@ package common import ( "context" + "database/sql" "net/http" "runtime" "strings" @@ -148,15 +149,16 @@ func sharedDBEvent(bld *libhoney.Builder, query string, args ...interface{}) *li } // BuildDBEvent tries to bring together most of the things that need to happen -// for an event to wrap a DB call in bot the sql and sqlx packages. It returns a +// for an event to wrap a DB call in both the sql and sqlx packages. It returns a // function which, when called, dispatches the event that it created. This lets // it finish a timer around the call automatically. This function is only used // when no context (and therefore no beeline trace) is available to the caller - // if context is available, use BuildDBSpan() instead to tie it in to the active // trace. -func BuildDBEvent(bld *libhoney.Builder, query string, args ...interface{}) (*libhoney.Event, func(error)) { +func BuildDBEvent(bld *libhoney.Builder, stats sql.DBStats, query string, args ...interface{}) (*libhoney.Event, func(error)) { timer := timer.Start() ev := sharedDBEvent(bld, query, args) + addDBStatsToEvent(ev, stats) fn := func(err error) { duration := timer.Finish() // rollup(ctx, ev, duration) @@ -173,7 +175,7 @@ func BuildDBEvent(bld *libhoney.Builder, query string, args ...interface{}) (*li // BuildDBSpan does the same things as BuildDBEvent except that it has access to // a trace from the context and takes advantage of that to add the DB events // into the trace. -func BuildDBSpan(ctx context.Context, bld *libhoney.Builder, query string, args ...interface{}) (context.Context, *trace.Span, func(error)) { +func BuildDBSpan(ctx context.Context, bld *libhoney.Builder, stats sql.DBStats, query string, args ...interface{}) (context.Context, *trace.Span, func(error)) { timer := timer.Start() parentSpan := trace.GetSpanFromContext(ctx) var span *trace.Span @@ -188,6 +190,7 @@ func BuildDBSpan(ctx context.Context, bld *libhoney.Builder, query string, args } else { ctx, span = parentSpan.CreateChild(ctx) } + addDBStatsToSpan(span, stats) ev := sharedDBEvent(bld, query, args...) for k, v := range ev.Fields() { diff --git a/wrappers/common/common_go1.11.go b/wrappers/common/common_go1.11.go new file mode 100644 index 00000000..361a041d --- /dev/null +++ b/wrappers/common/common_go1.11.go @@ -0,0 +1,26 @@ +//+build go1.11 + +package common + +import ( + "database/sql" + + "github.com/honeycombio/beeline-go/trace" + libhoney "github.com/honeycombio/libhoney-go" +) + +func addDBStatsToEvent(ev *libhoney.Event, stats sql.DBStats) { + ev.AddField("db.open_conns", stats.OpenConnections) + ev.AddField("db.conns_in_use", stats.InUse) + ev.AddField("db.conns_idle", stats.Idle) + ev.AddField("db.wait_count", stats.WaitCount) + ev.AddField("db.wait_duration", stats.WaitDuration) +} + +func addDBStatsToSpan(span *trace.Span, stats sql.DBStats) { + span.AddField("db.open_conns", stats.OpenConnections) + span.AddField("db.conns_in_use", stats.InUse) + span.AddField("db.conns_idle", stats.Idle) + span.AddField("db.wait_count", stats.WaitCount) + span.AddField("db.wait_duration", stats.WaitDuration) +} diff --git a/wrappers/common/common_prego1.11.go b/wrappers/common/common_prego1.11.go new file mode 100644 index 00000000..ea6bc60d --- /dev/null +++ b/wrappers/common/common_prego1.11.go @@ -0,0 +1,18 @@ +// +build !go1.11 + +package common + +import ( + "database/sql" + + "github.com/honeycombio/beeline-go/trace" + libhoney "github.com/honeycombio/libhoney-go" +) + +func addDBStatsToEvent(ev *libhoney.Event, stats sql.DBStats) { + ev.AddField("db.open_conns", stats.OpenConnections) +} + +func addDBStatsToSpan(span *trace.Span, stats sql.DBStats) { + span.AddField("db.open_conns", stats.OpenConnections) +} diff --git a/wrappers/common/common_test.go b/wrappers/common/common_test.go index 72e01ccc..b9e30c59 100644 --- a/wrappers/common/common_test.go +++ b/wrappers/common/common_test.go @@ -1,6 +1,8 @@ package common import ( + "context" + "database/sql" "io" "net/http" "net/http/httptest" @@ -105,3 +107,16 @@ func TestResponseWriterTypeAssertions(t *testing.T) { t.Errorf("ResponseWriter does not implement io.ReaderFrom") } } + +func TestBuildDBEvent(t *testing.T) { + b := libhoney.NewBuilder() + _, sender := BuildDBEvent(b, sql.DBStats{}, "") + sender(nil) +} + +func TestBuildDBSpan(t *testing.T) { + b := libhoney.NewBuilder() + ctx := context.Background() + ctx, _, sender := BuildDBSpan(ctx, b, sql.DBStats{}, "") + sender(nil) +} diff --git a/wrappers/hnysql/sql.go b/wrappers/hnysql/sql.go index 388a6eb0..53f8d1da 100644 --- a/wrappers/hnysql/sql.go +++ b/wrappers/hnysql/sql.go @@ -33,24 +33,20 @@ func WrapDB(s *sql.DB) *DB { wdb: s, Builder: b, } - addConns := func() interface{} { - stats := s.Stats() - return stats.OpenConnections - } - b.AddDynamicField("db.open_conns", addConns) b.AddField("meta.type", "sql") return db } func (db *DB) Begin() (*Tx, error) { var err error - ev, sender := common.BuildDBEvent(db.Builder, "") + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() bld := db.Builder.Clone() wrapTx := &Tx{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -68,7 +64,7 @@ func (db *DB) Begin() (*Tx, error) { func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, "") + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -77,6 +73,7 @@ func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { // submit an event indicating the rollback. bld := db.Builder.Clone() wrapTx := &Tx{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -101,7 +98,7 @@ func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { func (db *DB) Conn(ctx context.Context) (*Conn, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, "") + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -109,6 +106,7 @@ func (db *DB) Conn(ctx context.Context) (*Conn, error) { id, _ := uuid.NewRandom() connid := id.String() wrapConn := &Conn{ + db: db, Builder: bld, } bld.AddField("db.connId", connid) @@ -126,7 +124,7 @@ func (db *DB) Conn(ctx context.Context) (*Conn, error) { func (db *DB) Exec(query string, args ...interface{}) (sql.Result, error) { var err error - ev, sender := common.BuildDBEvent(db.Builder, query, args...) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -150,7 +148,7 @@ func (db *DB) Exec(query string, args ...interface{}) (sql.Result, error) { func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -178,7 +176,7 @@ func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{} func (db *DB) Ping() error { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -188,7 +186,7 @@ func (db *DB) Ping() error { func (db *DB) PingContext(ctx context.Context) error { var err error - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, "") + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -198,7 +196,7 @@ func (db *DB) PingContext(ctx context.Context) error { func (db *DB) Prepare(query string) (*Stmt, error) { var err error - ev, sender := common.BuildDBEvent(db.Builder, query) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query) defer func() { sender(err) }() @@ -207,6 +205,7 @@ func (db *DB) Prepare(query string) (*Stmt, error) { id, _ := uuid.NewRandom() stmtid := id.String() wrapStmt := &Stmt{ + db: db, Builder: bld, } bld.AddField("db.stmtId", stmtid) @@ -223,7 +222,7 @@ func (db *DB) Prepare(query string) (*Stmt, error) { func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query) defer func() { sender(err) }() @@ -232,6 +231,7 @@ func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) { id, _ := uuid.NewRandom() stmtid := id.String() wrapStmt := &Stmt{ + db: db, Builder: bld, } bld.AddField("db.stmtId", stmtid) @@ -250,7 +250,7 @@ func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) { func (db *DB) Query(query string, args ...interface{}) (*sql.Rows, error) { var err error - _, sender := common.BuildDBEvent(db.Builder, query, args) + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args) defer func() { sender(err) }() @@ -263,7 +263,7 @@ func (db *DB) Query(query string, args ...interface{}) (*sql.Rows, error) { func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, query, args) + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args) defer func() { sender(err) }() @@ -274,7 +274,7 @@ func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{ } func (db *DB) QueryRow(query string, args ...interface{}) *sql.Row { - _, sender := common.BuildDBEvent(db.Builder, query, args) + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args) defer sender(nil) // do DB call @@ -282,7 +282,7 @@ func (db *DB) QueryRow(query string, args ...interface{}) *sql.Row { return row } func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, query, args) + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args) defer sender(nil) // do DB call @@ -292,7 +292,7 @@ func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interfa func (db *DB) Close() error { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -308,13 +308,14 @@ func (db *DB) SetMaxOpenConns(n int) { db.wdb.SetMaxOpenConns(n) } func (db *DB) Stats() sql.DBStats { return db.wdb.Stats() } type Conn struct { + db *DB wconn *sql.Conn Builder *libhoney.Builder } func (c *Conn) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, c.Builder, "") + ctx, span, sender := common.BuildDBSpan(ctx, c.Builder, c.db.Stats(), "") defer func() { sender(err) }() @@ -324,6 +325,7 @@ func (c *Conn) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { id, _ := uuid.NewRandom() txid := id.String() wrapTx := &Tx{ + db: c.db, Builder: bld, } bld.AddField("db.txId", txid) @@ -346,7 +348,7 @@ func (c *Conn) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { func (c *Conn) Close() error { var err error - _, sender := common.BuildDBEvent(c.Builder, "") + _, sender := common.BuildDBEvent(c.Builder, c.db.Stats(), "") defer func() { sender(err) }() @@ -358,7 +360,7 @@ func (c *Conn) Close() error { func (c *Conn) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, c.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, c.Builder, c.db.Stats(), query, args...) defer func() { sender(err) }() @@ -386,7 +388,7 @@ func (c *Conn) ExecContext(ctx context.Context, query string, args ...interface{ func (c *Conn) PingContext(ctx context.Context) error { var err error - ctx, _, sender := common.BuildDBSpan(ctx, c.Builder, "") + ctx, _, sender := common.BuildDBSpan(ctx, c.Builder, c.db.Stats(), "") defer func() { sender(err) }() @@ -396,7 +398,7 @@ func (c *Conn) PingContext(ctx context.Context) error { func (c *Conn) PrepareContext(ctx context.Context, query string) (*Stmt, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, c.Builder, query) + ctx, span, sender := common.BuildDBSpan(ctx, c.Builder, c.db.Stats(), query) defer func() { sender(err) }() @@ -405,6 +407,7 @@ func (c *Conn) PrepareContext(ctx context.Context, query string) (*Stmt, error) id, _ := uuid.NewRandom() stmtid := id.String() wrapStmt := &Stmt{ + db: c.db, Builder: bld, } bld.AddField("db.stmtId", stmtid) @@ -423,7 +426,7 @@ func (c *Conn) PrepareContext(ctx context.Context, query string) (*Stmt, error) func (c *Conn) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, c.Builder, query, args) + ctx, _, sender := common.BuildDBSpan(ctx, c.Builder, c.db.Stats(), query, args) defer func() { sender(err) }() @@ -434,7 +437,7 @@ func (c *Conn) QueryContext(ctx context.Context, query string, args ...interface } func (c *Conn) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { - ctx, _, sender := common.BuildDBSpan(ctx, c.Builder, query, args) + ctx, _, sender := common.BuildDBSpan(ctx, c.Builder, c.db.Stats(), query, args) defer sender(nil) // do DB call @@ -443,13 +446,14 @@ func (c *Conn) QueryRowContext(ctx context.Context, query string, args ...interf } type Stmt struct { + db *DB wstmt *sql.Stmt Builder *libhoney.Builder } func (s *Stmt) Close() error { var err error - _, sender := common.BuildDBEvent(s.Builder, "") + _, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "") defer func() { sender(err) }() @@ -459,7 +463,7 @@ func (s *Stmt) Close() error { func (s *Stmt) Exec(args ...interface{}) (sql.Result, error) { var err error - ev, sender := common.BuildDBEvent(s.Builder, "", args...) + ev, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -483,7 +487,7 @@ func (s *Stmt) Exec(args ...interface{}) (sql.Result, error) { func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, "", args...) + ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -511,7 +515,7 @@ func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result func (s *Stmt) Query(args ...interface{}) (*sql.Rows, error) { var err error - _, sender := common.BuildDBEvent(s.Builder, "", args) + _, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "", args) defer func() { sender(err) }() @@ -523,7 +527,7 @@ func (s *Stmt) Query(args ...interface{}) (*sql.Rows, error) { func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*sql.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, "", args) + ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, s.db.Stats(), "", args) defer func() { sender(err) }() @@ -534,7 +538,7 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*sql.Rows } func (s *Stmt) QueryRow(args ...interface{}) *sql.Row { - _, sender := common.BuildDBEvent(s.Builder, "", args) + _, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "", args) defer sender(nil) // do DB call @@ -543,7 +547,7 @@ func (s *Stmt) QueryRow(args ...interface{}) *sql.Row { } func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *sql.Row { - ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, "", args) + ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, s.db.Stats(), "", args) defer sender(nil) // do DB call @@ -552,6 +556,7 @@ func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *sql.Ro } type Tx struct { + db *DB // wtx is the wrapped transaction wtx *sql.Tx Builder *libhoney.Builder @@ -559,7 +564,7 @@ type Tx struct { func (tx *Tx) Commit() error { var err error - _, sender := common.BuildDBEvent(tx.Builder, "") + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -571,7 +576,7 @@ func (tx *Tx) Commit() error { func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query, args...) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -595,7 +600,7 @@ func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) { func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -623,7 +628,7 @@ func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{} func (tx *Tx) Prepare(query string) (*Stmt, error) { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query) defer func() { sender(err) }() @@ -632,6 +637,7 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) { id, _ := uuid.NewRandom() stmtid := id.String() wrapStmt := &Stmt{ + db: tx.db, Builder: bld, } bld.AddField("db.stmtId", stmtid) @@ -646,7 +652,7 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) { func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query) defer func() { sender(err) }() @@ -655,6 +661,7 @@ func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) { id, _ := uuid.NewRandom() stmtid := id.String() wrapStmt := &Stmt{ + db: tx.db, Builder: bld, } bld.AddField("db.stmtId", stmtid) @@ -671,7 +678,7 @@ func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) { func (tx *Tx) Query(query string, args ...interface{}) (*sql.Rows, error) { var err error - _, sender := common.BuildDBEvent(tx.Builder, query, args) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args) defer func() { sender(err) }() @@ -683,7 +690,7 @@ func (tx *Tx) Query(query string, args ...interface{}) (*sql.Rows, error) { func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, query, args) + ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args) defer func() { sender(err) }() @@ -694,7 +701,7 @@ func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{ } func (tx *Tx) QueryRow(query string, args ...interface{}) *sql.Row { - _, sender := common.BuildDBEvent(tx.Builder, query, args) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args) defer sender(nil) // do DB call @@ -703,7 +710,7 @@ func (tx *Tx) QueryRow(query string, args ...interface{}) *sql.Row { } func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { - ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, query, args) + ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args) defer sender(nil) // do DB call @@ -713,7 +720,7 @@ func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interfa func (tx *Tx) Rollback() error { var err error - _, sender := common.BuildDBEvent(tx.Builder, "") + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -724,11 +731,12 @@ func (tx *Tx) Rollback() error { } func (tx *Tx) Stmt(stmt *Stmt) *Stmt { - ev, sender := common.BuildDBEvent(tx.Builder, "") + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer sender(nil) bld := stmt.Builder.Clone() wrapStmt := &Stmt{ + db: tx.db, Builder: bld, } // add the transaction's ID to the statement so that when it gets executed @@ -743,11 +751,12 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt { } func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt { - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, "") + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), "") defer sender(nil) bld := stmt.Builder.Clone() wrapStmt := &Stmt{ + db: tx.db, Builder: bld, } // add the transaction's ID to the statement so that when it gets executed diff --git a/wrappers/hnysql/sql_test.go b/wrappers/hnysql/sql_test.go index e3ca7973..75ee0e88 100644 --- a/wrappers/hnysql/sql_test.go +++ b/wrappers/hnysql/sql_test.go @@ -5,8 +5,11 @@ import ( "database/sql" "fmt" "log" + "testing" + "github.com/DATA-DOG/go-sqlmock" _ "github.com/go-sql-driver/mysql" + "github.com/stretchr/testify/assert" "github.com/honeycombio/beeline-go" "github.com/honeycombio/beeline-go/wrappers/hnysql" @@ -57,3 +60,56 @@ func Example() { log.Fatal(err) } } + +func TestSQLMiddleware(t *testing.T) { + beeline.Init(beeline.Config{ + WriteKey: "abcabc123123", + Dataset: "sql", + // for demonstration, send the event to STDOUT intead of Honeycomb. + // Remove the STDOUT setting when filling in a real write key. + STDOUT: true, + }) + // and make sure we close to force flushing all pending events before shutdown + defer beeline.Close() + + // Open a mock sql connection. + odb, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer odb.Close() + + mock.ExpectExec("insert into flavors.+").WillReturnResult(sqlmock.NewResult(0, 0)) + mock.ExpectQuery("SELECT id FROM flavors.+").WillReturnRows(sqlmock.NewRows([]string{"1"})) + + // replace it with a wrapped hnysql.DB + db := hnysql.WrapDB(odb) + // and start up a trace to capture all the calls + ctx, span := beeline.StartSpan(context.Background(), "start") + defer span.Send() + + // from here on, all SQL calls will emit events. + + _, err = db.ExecContext(ctx, "insert into flavors (flavor) values ('rose')") + assert.Nil(t, err) + fv := "rose" + rows, err := db.QueryContext(ctx, "SELECT id FROM flavors WHERE flavor=?", fv) + if err != nil { + log.Fatal(err) + } + defer rows.Close() + for rows.Next() { + var id int + if err := rows.Scan(&id); err != nil { + log.Fatal(err) + } + fmt.Printf("%d is %s\n", id, fv) + } + if err := rows.Err(); err != nil { + log.Fatal(err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} diff --git a/wrappers/hnysqlx/sqlx.go b/wrappers/hnysqlx/sqlx.go index 54ab3641..badf2c4f 100644 --- a/wrappers/hnysqlx/sqlx.go +++ b/wrappers/hnysqlx/sqlx.go @@ -38,11 +38,6 @@ func WrapDB(s *sqlx.DB) *DB { wdb: s, Builder: b, } - addConns := func() interface{} { - stats := s.DB.Stats() - return stats.OpenConnections - } - b.AddDynamicField("db.open_conns", addConns) b.AddField("meta.type", "sqlx") return db } @@ -53,7 +48,7 @@ func (db *DB) GetWrappedDB() *sqlx.DB { func (db *DB) Beginx() (*Tx, error) { var err error - ev, sender := common.BuildDBEvent(db.Builder, "") + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -67,6 +62,7 @@ func (db *DB) Beginx() (*Tx, error) { newid, _ := uuid.NewRandom() txid := newid.String() wrapTx := &Tx{ + db: db, Builder: bld, } bld.AddField("db.tx_id", txid) @@ -80,7 +76,7 @@ func (db *DB) Beginx() (*Tx, error) { func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, "") + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -92,6 +88,7 @@ func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { bld := db.Builder.Clone() wrapTx := &Tx{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -114,7 +111,7 @@ func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { func (db *DB) Exec(query string, args ...interface{}) (sql.Result, error) { var err error - ev, sender := common.BuildDBEvent(db.Builder, query, args...) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -143,7 +140,7 @@ func (db *DB) Exec(query string, args ...interface{}) (sql.Result, error) { func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -176,7 +173,7 @@ func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{} func (db *DB) Get(dest interface{}, query string, args ...interface{}) error { var err error - ev, sender := common.BuildDBEvent(db.Builder, query, args...) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -196,7 +193,7 @@ func (db *DB) Get(dest interface{}, query string, args ...interface{}) error { func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -218,7 +215,7 @@ func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, ar func (db *DB) MapperFunc(mf func(string) string) { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -238,7 +235,7 @@ func (db *DB) MapperFunc(mf func(string) string) { func (db *DB) MustBegin() *Tx { var err error - ev, sender := common.BuildDBEvent(db.Builder, "") + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -250,6 +247,7 @@ func (db *DB) MustBegin() *Tx { bld := db.Builder.Clone() wrapTx := &Tx{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -271,7 +269,7 @@ func (db *DB) MustBegin() *Tx { func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, "") + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -283,6 +281,7 @@ func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx { bld := db.Builder.Clone() wrapTx := &Tx{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -314,7 +313,7 @@ func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx { func (db *DB) MustExec(query string, args ...interface{}) sql.Result { var err error - ev, sender := common.BuildDBEvent(db.Builder, query, args...) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -348,7 +347,7 @@ func (db *DB) MustExec(query string, args ...interface{}) sql.Result { func (db *DB) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -387,7 +386,7 @@ func (db *DB) MustExecContext(ctx context.Context, query string, args ...interfa func (db *DB) NamedExec(query string, arg interface{}) (sql.Result, error) { var err error - ev, sender := common.BuildDBEvent(db.Builder, query, arg) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, arg) defer func() { sender(err) }() @@ -416,7 +415,7 @@ func (db *DB) NamedExec(query string, arg interface{}) (sql.Result, error) { func (db *DB) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query, arg) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, arg) defer func() { sender(err) }() @@ -449,7 +448,7 @@ func (db *DB) NamedExecContext(ctx context.Context, query string, arg interface{ func (db *DB) NamedQuery(query string, arg interface{}) (*sqlx.Rows, error) { var err error - _, sender := common.BuildDBEvent(db.Builder, query, arg) + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, arg) defer func() { sender(err) }() @@ -466,7 +465,7 @@ func (db *DB) NamedQuery(query string, arg interface{}) (*sqlx.Rows, error) { func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*sqlx.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, query, arg) + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, arg) defer func() { sender(err) }() @@ -483,7 +482,7 @@ func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface func (db *DB) Ping() error { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -499,7 +498,7 @@ func (db *DB) Ping() error { func (db *DB) PingContext(ctx context.Context) error { var err error - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, "") + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -515,7 +514,7 @@ func (db *DB) PingContext(ctx context.Context) error { func (db *DB) PrepareNamed(query string) (*NamedStmt, error) { var err error - ev, sender := common.BuildDBEvent(db.Builder, query) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query) defer func() { sender(err) }() @@ -527,6 +526,7 @@ func (db *DB) PrepareNamed(query string) (*NamedStmt, error) { bld := db.Builder.Clone() wrapStmt := &NamedStmt{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -546,7 +546,7 @@ func (db *DB) PrepareNamed(query string) (*NamedStmt, error) { func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query) defer func() { sender(err) }() @@ -558,6 +558,7 @@ func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt bld := db.Builder.Clone() wrapStmt := &NamedStmt{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -575,7 +576,7 @@ func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt func (db *DB) Preparex(query string) (*Stmt, error) { var err error - ev, sender := common.BuildDBEvent(db.Builder, query) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query) defer func() { sender(err) }() @@ -602,7 +603,7 @@ func (db *DB) Preparex(query string) (*Stmt, error) { func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query) defer func() { sender(err) }() @@ -631,7 +632,7 @@ func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) func (db *DB) Query(query string, args ...interface{}) (*sql.Rows, error) { var err error - _, sender := common.BuildDBEvent(db.Builder, query, args...) + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -648,7 +649,7 @@ func (db *DB) Query(query string, args ...interface{}) (*sql.Rows, error) { func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -666,7 +667,7 @@ func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{ func (db *DB) QueryRow(query string, args ...interface{}) *sql.Row { var err error - _, sender := common.BuildDBEvent(db.Builder, query, args...) + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -683,7 +684,7 @@ func (db *DB) QueryRow(query string, args ...interface{}) *sql.Row { func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { var err error - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -700,7 +701,7 @@ func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interfa func (db *DB) Queryx(query string, args ...interface{}) (*sqlx.Rows, error) { var err error - _, sender := common.BuildDBEvent(db.Builder, query, args...) + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -717,7 +718,7 @@ func (db *DB) Queryx(query string, args ...interface{}) (*sqlx.Rows, error) { func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface{}) (*sqlx.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -734,7 +735,7 @@ func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface func (db *DB) QueryRowx(query string, args ...interface{}) *sqlx.Row { var err error - _, sender := common.BuildDBEvent(db.Builder, query, args...) + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -751,7 +752,7 @@ func (db *DB) QueryRowx(query string, args ...interface{}) *sqlx.Row { func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *sqlx.Row { var err error - ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, _, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -768,7 +769,7 @@ func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interf func (db *DB) Rebind(query string) string { var err error - _, sender := common.BuildDBEvent(db.Builder, query) + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), query) defer func() { sender(err) }() @@ -784,7 +785,7 @@ func (db *DB) Rebind(query string) string { func (db *DB) Select(dest interface{}, query string, args ...interface{}) error { var err error - ev, sender := common.BuildDBEvent(db.Builder, query, args...) + ev, sender := common.BuildDBEvent(db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -803,7 +804,7 @@ func (db *DB) Select(dest interface{}, query string, args ...interface{}) error func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, db.Builder, db.Stats(), query, args...) defer func() { sender(err) }() @@ -825,7 +826,7 @@ func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, // not implemented in the wrapper - should just fall through to the superclass func (db *DB) Close() error { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -842,7 +843,7 @@ func (db *DB) Close() error { func (db *DB) Driver() driver.Driver { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -857,7 +858,7 @@ func (db *DB) Driver() driver.Driver { func (db *DB) SetConnMaxLifetime(d time.Duration) { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -872,7 +873,7 @@ func (db *DB) SetConnMaxLifetime(d time.Duration) { func (db *DB) SetMaxIdleConns(n int) { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -887,7 +888,7 @@ func (db *DB) SetMaxIdleConns(n int) { func (db *DB) SetMaxOpenConns(n int) { var err error - _, sender := common.BuildDBEvent(db.Builder, "") + _, sender := common.BuildDBEvent(db.Builder, db.Stats(), "") defer func() { sender(err) }() @@ -901,12 +902,6 @@ func (db *DB) SetMaxOpenConns(n int) { } func (db *DB) Stats() sql.DBStats { - var err error - _, sender := common.BuildDBEvent(db.Builder, "") - defer func() { - sender(err) - }() - // ensure any changes to the Mapper get passed along if db.Mapper != nil { db.wdb.Mapper = db.Mapper @@ -916,6 +911,7 @@ func (db *DB) Stats() sql.DBStats { } type NamedStmt struct { + db *DB wns *sqlx.NamedStmt Builder *libhoney.Builder } @@ -926,7 +922,7 @@ func (n *NamedStmt) GetWrappedNamedStmt() *sqlx.NamedStmt { func (n *NamedStmt) Close() error { var err error - _, sender := common.BuildDBEvent(n.Builder, "") + _, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "") defer func() { sender(err) }() @@ -937,7 +933,7 @@ func (n *NamedStmt) Close() error { func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) { var err error - ev, sender := common.BuildDBEvent(n.Builder, "", arg) + ev, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -960,7 +956,7 @@ func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) { func (n *NamedStmt) ExecContext(ctx context.Context, arg interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, n.Builder, "", arg) + ctx, span, sender := common.BuildDBSpan(ctx, n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -987,7 +983,7 @@ func (n *NamedStmt) ExecContext(ctx context.Context, arg interface{}) (sql.Resul func (n *NamedStmt) Get(dest interface{}, arg interface{}) error { var err error - ev, sender := common.BuildDBEvent(n.Builder, "", arg) + ev, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1001,7 +997,7 @@ func (n *NamedStmt) Get(dest interface{}, arg interface{}) error { func (n *NamedStmt) GetContext(ctx context.Context, dest interface{}, arg interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, n.Builder, "", arg) + ctx, span, sender := common.BuildDBSpan(ctx, n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1017,7 +1013,7 @@ func (n *NamedStmt) GetContext(ctx context.Context, dest interface{}, arg interf func (n *NamedStmt) MustExec(arg interface{}) sql.Result { var err error - ev, sender := common.BuildDBEvent(n.Builder, "", arg) + ev, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1045,7 +1041,7 @@ func (n *NamedStmt) MustExec(arg interface{}) sql.Result { func (n *NamedStmt) MustExecContext(ctx context.Context, arg interface{}) sql.Result { var err error - ctx, span, sender := common.BuildDBSpan(ctx, n.Builder, "", arg) + ctx, span, sender := common.BuildDBSpan(ctx, n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1079,7 +1075,7 @@ func (n *NamedStmt) MustExecContext(ctx context.Context, arg interface{}) sql.Re func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) { var err error - _, sender := common.BuildDBEvent(n.Builder, "", arg) + _, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1091,7 +1087,7 @@ func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) { func (n *NamedStmt) QueryContext(ctx context.Context, arg interface{}) (*sql.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, n.Builder, "", arg) + ctx, _, sender := common.BuildDBSpan(ctx, n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1103,7 +1099,7 @@ func (n *NamedStmt) QueryContext(ctx context.Context, arg interface{}) (*sql.Row func (n *NamedStmt) QueryRow(arg interface{}) *sqlx.Row { var err error - _, sender := common.BuildDBEvent(n.Builder, "", arg) + _, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1115,7 +1111,7 @@ func (n *NamedStmt) QueryRow(arg interface{}) *sqlx.Row { func (n *NamedStmt) QueryRowContext(ctx context.Context, arg interface{}) *sqlx.Row { var err error - ctx, _, sender := common.BuildDBSpan(ctx, n.Builder, "", arg) + ctx, _, sender := common.BuildDBSpan(ctx, n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1127,7 +1123,7 @@ func (n *NamedStmt) QueryRowContext(ctx context.Context, arg interface{}) *sqlx. func (n *NamedStmt) QueryRowx(arg interface{}) *sqlx.Row { var err error - _, sender := common.BuildDBEvent(n.Builder, "", arg) + _, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1139,7 +1135,7 @@ func (n *NamedStmt) QueryRowx(arg interface{}) *sqlx.Row { func (n *NamedStmt) QueryRowxContext(ctx context.Context, arg interface{}) *sqlx.Row { var err error - ctx, _, sender := common.BuildDBSpan(ctx, n.Builder, "", arg) + ctx, _, sender := common.BuildDBSpan(ctx, n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1151,7 +1147,7 @@ func (n *NamedStmt) QueryRowxContext(ctx context.Context, arg interface{}) *sqlx func (n *NamedStmt) Queryx(arg interface{}) (*sqlx.Rows, error) { var err error - _, sender := common.BuildDBEvent(n.Builder, "", arg) + _, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1163,7 +1159,7 @@ func (n *NamedStmt) Queryx(arg interface{}) (*sqlx.Rows, error) { func (n *NamedStmt) QueryxContext(ctx context.Context, arg interface{}) (*sqlx.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, n.Builder, "", arg) + ctx, _, sender := common.BuildDBSpan(ctx, n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1175,7 +1171,7 @@ func (n *NamedStmt) QueryxContext(ctx context.Context, arg interface{}) (*sqlx.R func (n *NamedStmt) Select(dest interface{}, arg interface{}) error { var err error - ev, sender := common.BuildDBEvent(n.Builder, "", arg) + ev, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1189,7 +1185,7 @@ func (n *NamedStmt) Select(dest interface{}, arg interface{}) error { func (n *NamedStmt) SelectContext(ctx context.Context, dest interface{}, arg interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, n.Builder, "", arg) + ctx, span, sender := common.BuildDBSpan(ctx, n.Builder, n.db.Stats(), "", arg) defer func() { sender(err) }() @@ -1205,7 +1201,7 @@ func (n *NamedStmt) SelectContext(ctx context.Context, dest interface{}, arg int func (n *NamedStmt) Unsafe() *NamedStmt { var err error - _, sender := common.BuildDBEvent(n.Builder, "") + _, sender := common.BuildDBEvent(n.Builder, n.db.Stats(), "") defer func() { sender(err) }() @@ -1223,7 +1219,7 @@ type Stmt struct { func (s *Stmt) Get(dest interface{}, args ...interface{}) error { var err error - ev, sender := common.BuildDBEvent(s.Builder, "", args...) + ev, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1242,7 +1238,7 @@ func (s *Stmt) Get(dest interface{}, args ...interface{}) error { func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, "", args...) + ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1263,7 +1259,7 @@ func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interfa func (s *Stmt) MustExec(args ...interface{}) sql.Result { var err error - ev, sender := common.BuildDBEvent(s.Builder, "", args...) + ev, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1296,7 +1292,7 @@ func (s *Stmt) MustExec(args ...interface{}) sql.Result { func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Result { var err error - ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, "", args...) + ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1335,7 +1331,7 @@ func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Res func (s *Stmt) QueryRowx(args ...interface{}) *sqlx.Row { var err error - _, sender := common.BuildDBEvent(s.Builder, "", args...) + _, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1352,7 +1348,7 @@ func (s *Stmt) QueryRowx(args ...interface{}) *sqlx.Row { func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *sqlx.Row { var err error - ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, "", args...) + ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1369,7 +1365,7 @@ func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *sqlx. func (s *Stmt) Queryx(args ...interface{}) (*sqlx.Rows, error) { var err error - _, sender := common.BuildDBEvent(s.Builder, "", args...) + _, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1386,7 +1382,7 @@ func (s *Stmt) Queryx(args ...interface{}) (*sqlx.Rows, error) { func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*sqlx.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, "", args...) + ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1403,7 +1399,7 @@ func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*sqlx.Ro func (s *Stmt) Select(dest interface{}, args ...interface{}) error { var err error - ev, sender := common.BuildDBEvent(s.Builder, "", args...) + ev, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1422,7 +1418,7 @@ func (s *Stmt) Select(dest interface{}, args ...interface{}) error { func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, "", args...) + ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) defer func() { sender(err) }() @@ -1443,7 +1439,7 @@ func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...inte func (s *Stmt) Unsafe() *Stmt { var err error - _, sender := common.BuildDBEvent(s.Builder, "") + _, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "") defer func() { sender(err) }() @@ -1468,6 +1464,7 @@ func (s *Stmt) Close() error { } type Tx struct { + db *DB wtx *sqlx.Tx Builder *libhoney.Builder Mapper *reflectx.Mapper @@ -1479,7 +1476,7 @@ func (tx *Tx) GetWrappedTx() *sqlx.Tx { func (tx *Tx) BindNamed(query string, arg interface{}) (string, []interface{}, error) { var err error - _, sender := common.BuildDBEvent(tx.Builder, query, arg) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, arg) defer func() { sender(err) }() @@ -1495,7 +1492,7 @@ func (tx *Tx) BindNamed(query string, arg interface{}) (string, []interface{}, e func (tx *Tx) Commit() error { var err error - _, sender := common.BuildDBEvent(tx.Builder, "") + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -1514,7 +1511,7 @@ func (tx *Tx) Commit() error { // to ensure that commits show up as part of a parent trace func (tx *Tx) CommitContext(ctx context.Context) error { var err error - _, _, sender := common.BuildDBSpan(ctx, tx.Builder, "") + _, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -1531,7 +1528,7 @@ func (tx *Tx) CommitContext(ctx context.Context) error { func (tx *Tx) DriverName() string { var err error - _, sender := common.BuildDBEvent(tx.Builder, "") + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -1547,7 +1544,7 @@ func (tx *Tx) DriverName() string { func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query, args...) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -1576,7 +1573,7 @@ func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) { func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -1609,7 +1606,7 @@ func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{} func (tx *Tx) Get(dest interface{}, query string, args ...interface{}) error { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query, args...) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -1627,7 +1624,7 @@ func (tx *Tx) Get(dest interface{}, query string, args ...interface{}) error { } func (tx *Tx) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -1648,7 +1645,7 @@ func (tx *Tx) GetContext(ctx context.Context, dest interface{}, query string, ar func (tx *Tx) MustExec(query string, args ...interface{}) sql.Result { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query, args...) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -1681,7 +1678,7 @@ func (tx *Tx) MustExec(query string, args ...interface{}) sql.Result { func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -1720,7 +1717,7 @@ func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interfa func (tx *Tx) NamedExec(query string, arg interface{}) (sql.Result, error) { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query, arg) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, arg) defer func() { sender(err) }() @@ -1749,7 +1746,7 @@ func (tx *Tx) NamedExec(query string, arg interface{}) (sql.Result, error) { func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query, arg) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, arg) defer func() { sender(err) }() @@ -1782,7 +1779,7 @@ func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg interface{ func (tx *Tx) NamedQuery(query string, arg interface{}) (*sqlx.Rows, error) { var err error - _, sender := common.BuildDBEvent(tx.Builder, query, arg) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, arg) defer func() { sender(err) }() @@ -1799,7 +1796,7 @@ func (tx *Tx) NamedQuery(query string, arg interface{}) (*sqlx.Rows, error) { func (tx *Tx) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*sqlx.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, query, arg) + ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, arg) defer func() { sender(err) }() @@ -1816,13 +1813,14 @@ func (tx *Tx) NamedQueryContext(ctx context.Context, query string, arg interface func (tx *Tx) NamedStmt(stmt *NamedStmt) *NamedStmt { var err error - _, sender := common.BuildDBEvent(tx.Builder, "") + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() bld := tx.Builder.Clone() wrapStmt := &NamedStmt{ + db: tx.db, Builder: bld, } @@ -1838,13 +1836,14 @@ func (tx *Tx) NamedStmt(stmt *NamedStmt) *NamedStmt { func (tx *Tx) NamedStmtContext(ctx context.Context, stmt *NamedStmt) *NamedStmt { var err error - ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, "") + ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() bld := tx.Builder.Clone() wrapStmt := &NamedStmt{ + db: tx.db, Builder: bld, } @@ -1860,7 +1859,7 @@ func (tx *Tx) NamedStmtContext(ctx context.Context, stmt *NamedStmt) *NamedStmt func (tx *Tx) PrepareNamed(query string) (*NamedStmt, error) { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query) defer func() { sender(err) }() @@ -1872,6 +1871,7 @@ func (tx *Tx) PrepareNamed(query string) (*NamedStmt, error) { bld := tx.Builder.Clone() wrapStmt := &NamedStmt{ + db: tx.db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -1888,7 +1888,7 @@ func (tx *Tx) PrepareNamed(query string) (*NamedStmt, error) { func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query) defer func() { sender(err) }() @@ -1900,6 +1900,7 @@ func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt bld := tx.Builder.Clone() wrapStmt := &NamedStmt{ + db: tx.db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -1918,7 +1919,7 @@ func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt func (tx *Tx) Preparex(query string) (*Stmt, error) { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query) defer func() { sender(err) }() @@ -1946,7 +1947,7 @@ func (tx *Tx) Preparex(query string) (*Stmt, error) { func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query) defer func() { sender(err) }() @@ -1976,7 +1977,7 @@ func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) func (tx *Tx) Query(query string, args ...interface{}) (*sql.Rows, error) { var err error - _, sender := common.BuildDBEvent(tx.Builder, query, args...) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -1993,7 +1994,7 @@ func (tx *Tx) Query(query string, args ...interface{}) (*sql.Rows, error) { func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, query, args...) + ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2010,7 +2011,7 @@ func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{ func (tx *Tx) QueryRow(query string, args ...interface{}) *sql.Row { var err error - _, sender := common.BuildDBEvent(tx.Builder, query, args...) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2027,7 +2028,7 @@ func (tx *Tx) QueryRow(query string, args ...interface{}) *sql.Row { func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { var err error - ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, query, args...) + ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2044,7 +2045,7 @@ func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interfa func (tx *Tx) QueryRowx(query string, args ...interface{}) *sqlx.Row { var err error - _, sender := common.BuildDBEvent(tx.Builder, query, args...) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2061,7 +2062,7 @@ func (tx *Tx) QueryRowx(query string, args ...interface{}) *sqlx.Row { func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *sqlx.Row { var err error - _, sender := common.BuildDBEvent(tx.Builder, query, args...) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2078,7 +2079,7 @@ func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...interf func (tx *Tx) Queryx(query string, args ...interface{}) (*sqlx.Rows, error) { var err error - _, sender := common.BuildDBEvent(tx.Builder, query, args...) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2095,7 +2096,7 @@ func (tx *Tx) Queryx(query string, args ...interface{}) (*sqlx.Rows, error) { func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface{}) (*sqlx.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, query, args...) + ctx, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2112,7 +2113,7 @@ func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface func (tx *Tx) Rebind(query string) string { var err error - _, sender := common.BuildDBEvent(tx.Builder, query) + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query) defer func() { sender(err) }() @@ -2128,7 +2129,7 @@ func (tx *Tx) Rebind(query string) string { func (tx *Tx) Rollback() error { var err error - _, sender := common.BuildDBEvent(tx.Builder, "") + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -2145,7 +2146,7 @@ func (tx *Tx) Rollback() error { func (tx *Tx) RollbackContext(ctx context.Context) error { var err error - _, _, sender := common.BuildDBSpan(ctx, tx.Builder, "") + _, _, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -2162,7 +2163,7 @@ func (tx *Tx) RollbackContext(ctx context.Context) error { func (tx *Tx) Select(dest interface{}, query string, args ...interface{}) error { var err error - ev, sender := common.BuildDBEvent(tx.Builder, query, args...) + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2180,7 +2181,7 @@ func (tx *Tx) Select(dest interface{}, query string, args ...interface{}) error func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, query, args...) + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), query, args...) defer func() { sender(err) }() @@ -2200,7 +2201,7 @@ func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, query string, func (tx *Tx) Stmtx(stmt *Stmt) *Stmt { var err error - ev, sender := common.BuildDBEvent(tx.Builder, "") + ev, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -2229,7 +2230,7 @@ func (tx *Tx) Stmtx(stmt *Stmt) *Stmt { func (tx *Tx) StmtxContext(ctx context.Context, stmt *Stmt) *Stmt { var err error - ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, "") + ctx, span, sender := common.BuildDBSpan(ctx, tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() @@ -2260,7 +2261,7 @@ func (tx *Tx) StmtxContext(ctx context.Context, stmt *Stmt) *Stmt { func (tx *Tx) Unsafe() *Tx { var err error - _, sender := common.BuildDBEvent(tx.Builder, "") + _, sender := common.BuildDBEvent(tx.Builder, tx.db.Stats(), "") defer func() { sender(err) }() diff --git a/wrappers/hnysqlx/sqlx_test.go b/wrappers/hnysqlx/sqlx_test.go index 9a695f50..08c363d8 100644 --- a/wrappers/hnysqlx/sqlx_test.go +++ b/wrappers/hnysqlx/sqlx_test.go @@ -4,9 +4,12 @@ import ( "context" "fmt" "log" + "testing" + "github.com/DATA-DOG/go-sqlmock" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" "github.com/honeycombio/beeline-go" "github.com/honeycombio/beeline-go/wrappers/hnysqlx" @@ -54,3 +57,57 @@ func Example() { log.Fatal(err) } } + +func TestSQLXMiddleware(t *testing.T) { + beeline.Init(beeline.Config{ + WriteKey: "abcabc123123", + Dataset: "sql", + // for demonstration, send the event to STDOUT intead of Honeycomb. + // Remove the STDOUT setting when filling in a real write key. + STDOUT: true, + }) + // and make sure we close to force flushing all pending events before shutdown + defer beeline.Close() + + // Open a mock sql connection. + odb, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer odb.Close() + sqlxodb := sqlx.NewDb(odb, "sqlmock") + + mock.ExpectExec("insert into flavors.+").WillReturnResult(sqlmock.NewResult(0, 0)) + mock.ExpectQuery("SELECT id FROM flavors.+").WillReturnRows(sqlmock.NewRows([]string{"1"})) + + // replace it with a wrapped hnysql.DB + db := hnysqlx.WrapDB(sqlxodb) + // and start up a trace to capture all the calls + ctx, span := beeline.StartSpan(context.Background(), "start") + defer span.Send() + + // from here on, all SQL calls will emit events. + + _, err = db.ExecContext(ctx, "insert into flavors (flavor) values ('rose')") + assert.Nil(t, err) + fv := "rose" + rows, err := db.QueryContext(ctx, "SELECT id FROM flavors WHERE flavor=?", fv) + if err != nil { + log.Fatal(err) + } + defer rows.Close() + for rows.Next() { + var id int + if err := rows.Scan(&id); err != nil { + log.Fatal(err) + } + fmt.Printf("%d is %s\n", id, fv) + } + if err := rows.Err(); err != nil { + log.Fatal(err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} From 01d24e38f11bdbd06e5116aaaa84c99a4bfa2d6f Mon Sep 17 00:00:00 2001 From: Douglas Soo Date: Wed, 6 Nov 2019 16:07:35 -0800 Subject: [PATCH 2/4] Update version and changelog --- CHANGELOG.md | 12 +++++++++++- version.go | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52b8c97d..2dce34d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,19 @@ -# Release v0.4.6 (2019-10-17) +# Release v0.4.7 (2019-11-07) ### Additions - Add additional go database stats to `hnysql` and `hnysqlx` wrapppers. In go 1.11 and later, we additionally report `db.conns_in_use`, `db.conns_idle`, `db.wait_count`, and `db.wait_duration`. See https://golang.org/pkg/database/sql/#DB.Stats +# Release v0.4.6 (2019-10-31) + +A few small fixes + +### Bugfixes + +- added missing `Close` function to the `Stmt` type +- renamed `echo` example binary for using the echo web framework so it doesn't collide with the builtin shell `echo` command +- updated transaction's `QueryxContext` to use a span instead of an event + # Release v0.4.5 (2019-09-17) ### Bugfixes diff --git a/version.go b/version.go index 1e9764d9..49027233 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package beeline -const version = "0.4.6" +const version = "0.4.7" From d3e8617d65f5e3f1f872a690069e327d960c41ba Mon Sep 17 00:00:00 2001 From: Douglas Soo Date: Wed, 6 Nov 2019 16:34:00 -0800 Subject: [PATCH 3/4] Missed adding param to Close() --- CHANGELOG.md | 2 -- wrappers/hnysqlx/sqlx.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dce34d1..680e81f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,6 @@ # Release v0.4.6 (2019-10-31) -A few small fixes - ### Bugfixes - added missing `Close` function to the `Stmt` type diff --git a/wrappers/hnysqlx/sqlx.go b/wrappers/hnysqlx/sqlx.go index badf2c4f..c3af85ed 100644 --- a/wrappers/hnysqlx/sqlx.go +++ b/wrappers/hnysqlx/sqlx.go @@ -1456,7 +1456,7 @@ func (s *Stmt) Unsafe() *Stmt { func (s *Stmt) Close() error { var err error - _, sender := common.BuildDBEvent(s.Builder, "") + _, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "") defer sender(err) err = s.wstmt.Close() From 15966b7d443cffcc75fb5924720a4b6b54bbf282 Mon Sep 17 00:00:00 2001 From: Douglas Soo Date: Thu, 7 Nov 2019 11:12:13 -0800 Subject: [PATCH 4/4] Fix sqlx Stmt so it can get DB stats --- wrappers/hnysqlx/sqlx.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/wrappers/hnysqlx/sqlx.go b/wrappers/hnysqlx/sqlx.go index c3af85ed..08c8d8a2 100644 --- a/wrappers/hnysqlx/sqlx.go +++ b/wrappers/hnysqlx/sqlx.go @@ -588,6 +588,7 @@ func (db *DB) Preparex(query string) (*Stmt, error) { bld := db.Builder.Clone() wrapStmt := &Stmt{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -615,6 +616,7 @@ func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) bld := db.Builder.Clone() wrapStmt := &Stmt{ + db: db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -1212,6 +1214,7 @@ func (n *NamedStmt) Unsafe() *NamedStmt { } type Stmt struct { + db *DB wstmt *sqlx.Stmt Builder *libhoney.Builder Mapper *reflectx.Mapper @@ -1219,7 +1222,7 @@ type Stmt struct { func (s *Stmt) Get(dest interface{}, args ...interface{}) error { var err error - ev, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) + ev, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1238,7 +1241,7 @@ func (s *Stmt) Get(dest interface{}, args ...interface{}) error { func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) + ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1259,7 +1262,7 @@ func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interfa func (s *Stmt) MustExec(args ...interface{}) sql.Result { var err error - ev, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) + ev, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1292,7 +1295,7 @@ func (s *Stmt) MustExec(args ...interface{}) sql.Result { func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Result { var err error - ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) + ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1331,7 +1334,7 @@ func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Res func (s *Stmt) QueryRowx(args ...interface{}) *sqlx.Row { var err error - _, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) + _, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1348,7 +1351,7 @@ func (s *Stmt) QueryRowx(args ...interface{}) *sqlx.Row { func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *sqlx.Row { var err error - ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) + ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1365,7 +1368,7 @@ func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *sqlx. func (s *Stmt) Queryx(args ...interface{}) (*sqlx.Rows, error) { var err error - _, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) + _, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1382,7 +1385,7 @@ func (s *Stmt) Queryx(args ...interface{}) (*sqlx.Rows, error) { func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*sqlx.Rows, error) { var err error - ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) + ctx, _, sender := common.BuildDBSpan(ctx, s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1399,7 +1402,7 @@ func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*sqlx.Ro func (s *Stmt) Select(dest interface{}, args ...interface{}) error { var err error - ev, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "", args...) + ev, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1418,7 +1421,7 @@ func (s *Stmt) Select(dest interface{}, args ...interface{}) error { func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error { var err error - ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, sql.DBStats{}, "", args...) + ctx, span, sender := common.BuildDBSpan(ctx, s.Builder, s.db.Stats(), "", args...) defer func() { sender(err) }() @@ -1439,7 +1442,7 @@ func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...inte func (s *Stmt) Unsafe() *Stmt { var err error - _, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "") + _, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "") defer func() { sender(err) }() @@ -1456,7 +1459,7 @@ func (s *Stmt) Unsafe() *Stmt { func (s *Stmt) Close() error { var err error - _, sender := common.BuildDBEvent(s.Builder, sql.DBStats{}, "") + _, sender := common.BuildDBEvent(s.Builder, s.db.Stats(), "") defer sender(err) err = s.wstmt.Close() @@ -1931,6 +1934,7 @@ func (tx *Tx) Preparex(query string) (*Stmt, error) { bld := tx.Builder.Clone() wrapStmt := &Stmt{ + db: tx.db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -1959,6 +1963,7 @@ func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) bld := tx.Builder.Clone() wrapStmt := &Stmt{ + db: tx.db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -2213,6 +2218,7 @@ func (tx *Tx) Stmtx(stmt *Stmt) *Stmt { bld := tx.Builder.Clone() wrapStmt := &Stmt{ + db: tx.db, Builder: bld, } newid, _ := uuid.NewRandom() @@ -2242,6 +2248,7 @@ func (tx *Tx) StmtxContext(ctx context.Context, stmt *Stmt) *Stmt { bld := tx.Builder.Clone() wrapStmt := &Stmt{ + db: tx.db, Builder: bld, } newid, _ := uuid.NewRandom()