Skip to content

Commit eb3ef1d

Browse files
authored
Merge pull request #28 from opencensus-integrations/add-stats
adds stats to ocsql
2 parents cdb861a + ad37a17 commit eb3ef1d

File tree

4 files changed

+284
-3
lines changed

4 files changed

+284
-3
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,33 @@ func GetConn(...) driver.Conn {
8484
}
8585
```
8686

87+
## metrics
88+
89+
Next to tracing, ocsql also supports OpenCensus stats. To record call stats,
90+
register the available views or create your own using the provided Measures.
91+
92+
```go
93+
// register default views
94+
ocsql.RegisterAllViews()
95+
96+
```
97+
98+
From Go 1.11 and up, ocsql also has the ability to record database connection
99+
pool details. Use the `RecordStats` function and provide a `*sql.DB` to record
100+
details on, as well as the required record interval.
101+
102+
```go
103+
// register default views
104+
ocsql.RegisterAllViews()
105+
106+
// Connect to a SQLite3 database using the ocsql driver wrapper
107+
db, err = sql.Open("ocsql-sqlite3", "resource.db")
108+
109+
// Record DB stats every 5 seconds
110+
ocsql.RecordStats(db, 5 * time.Second)
111+
112+
```
113+
87114
## jmoiron/sqlx
88115

89116
If using the `sqlx` library with named queries you will need to use the

dbstats_go1.11.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// +build go1.11
2+
3+
package ocsql
4+
5+
import (
6+
"context"
7+
"database/sql"
8+
"sync"
9+
"time"
10+
11+
"go.opencensus.io/stats"
12+
)
13+
14+
// RecordStats records database statistics for provided sql.DB at the provided
15+
// interval.
16+
func RecordStats(db *sql.DB, interval time.Duration) (fnStop func()) {
17+
var (
18+
closeOnce sync.Once
19+
ctx = context.Background()
20+
ticker = time.NewTicker(interval)
21+
done = make(chan struct{})
22+
)
23+
24+
go func() {
25+
for {
26+
select {
27+
case <-ticker.C:
28+
dbStats := db.Stats()
29+
stats.Record(ctx,
30+
MeasureOpenConnections.M(int64(dbStats.OpenConnections)),
31+
MeasureIdleConnections.M(int64(dbStats.Idle)),
32+
MeasureActiveConnections.M(int64(dbStats.InUse)),
33+
MeasureWaitCount.M(dbStats.WaitCount),
34+
MeasureWaitDuration.M(float64(dbStats.WaitDuration.Nanoseconds())/1e6),
35+
MeasureIdleClosed.M(dbStats.MaxIdleClosed),
36+
MeasureLifetimeClosed.M(dbStats.MaxLifetimeClosed),
37+
)
38+
case <-done:
39+
ticker.Stop()
40+
return
41+
}
42+
}
43+
}()
44+
45+
return func() {
46+
closeOnce.Do(func() {
47+
close(done)
48+
})
49+
}
50+
}

driver.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ type ocConn struct {
123123
}
124124

125125
func (c ocConn) Ping(ctx context.Context) (err error) {
126+
defer recordCallStats(ctx, "go.sql.ping")(err)
127+
126128
if c.options.Ping && (c.options.AllowRoot || trace.FromContext(ctx) != nil) {
127129
var span *trace.Span
128130
ctx, span = trace.StartSpan(ctx, "sql:ping", trace.WithSpanKind(trace.SpanKindClient))
@@ -149,6 +151,8 @@ func (c ocConn) Ping(ctx context.Context) (err error) {
149151
}
150152

151153
func (c ocConn) Exec(query string, args []driver.Value) (res driver.Result, err error) {
154+
defer recordCallStats(context.Background(), "go.sql.exec")(err)
155+
152156
if exec, ok := c.parent.(driver.Execer); ok {
153157
if !c.options.AllowRoot {
154158
return exec.Exec(query, args)
@@ -188,6 +192,8 @@ func (c ocConn) Exec(query string, args []driver.Value) (res driver.Result, err
188192
}
189193

190194
func (c ocConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (res driver.Result, err error) {
195+
defer recordCallStats(ctx, "go.sql.exec")(err)
196+
191197
if execCtx, ok := c.parent.(driver.ExecerContext); ok {
192198
parentSpan := trace.FromContext(ctx)
193199
if !c.options.AllowRoot && parentSpan == nil {
@@ -225,6 +231,8 @@ func (c ocConn) ExecContext(ctx context.Context, query string, args []driver.Nam
225231
}
226232

227233
func (c ocConn) Query(query string, args []driver.Value) (rows driver.Rows, err error) {
234+
defer recordCallStats(context.Background(), "go.sql.query")(err)
235+
228236
if queryer, ok := c.parent.(driver.Queryer); ok {
229237
if !c.options.AllowRoot {
230238
return queryer.Query(query, args)
@@ -265,6 +273,8 @@ func (c ocConn) Query(query string, args []driver.Value) (rows driver.Rows, err
265273
}
266274

267275
func (c ocConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (rows driver.Rows, err error) {
276+
defer recordCallStats(ctx, "go.sql.query")(err)
277+
268278
if queryerCtx, ok := c.parent.(driver.QueryerContext); ok {
269279
parentSpan := trace.FromContext(ctx)
270280
if !c.options.AllowRoot && parentSpan == nil {
@@ -303,6 +313,8 @@ func (c ocConn) QueryContext(ctx context.Context, query string, args []driver.Na
303313
}
304314

305315
func (c ocConn) Prepare(query string) (stmt driver.Stmt, err error) {
316+
defer recordCallStats(context.Background(), "go.sql.prepare")(err)
317+
306318
if c.options.AllowRoot {
307319
_, span := trace.StartSpan(context.Background(), "sql:prepare", trace.WithSpanKind(trace.SpanKindClient))
308320
attrs := make([]trace.Attribute, 0, len(c.options.DefaultAttributes)+1)
@@ -337,6 +349,8 @@ func (c *ocConn) Begin() (driver.Tx, error) {
337349
}
338350

339351
func (c *ocConn) PrepareContext(ctx context.Context, query string) (stmt driver.Stmt, err error) {
352+
defer recordCallStats(ctx, "go.sql.prepare")(err)
353+
340354
var span *trace.Span
341355
attrs := append([]trace.Attribute(nil), c.options.DefaultAttributes...)
342356
if c.options.AllowRoot || trace.FromContext(ctx) != nil {
@@ -367,7 +381,9 @@ func (c *ocConn) PrepareContext(ctx context.Context, query string) (stmt driver.
367381
return
368382
}
369383

370-
func (c *ocConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
384+
func (c *ocConn) BeginTx(ctx context.Context, opts driver.TxOptions) (tx driver.Tx, err error) {
385+
defer recordCallStats(ctx, "go.sql.begin")(err)
386+
371387
if !c.options.AllowRoot && trace.FromContext(ctx) == nil {
372388
if connBeginTx, ok := c.parent.(driver.ConnBeginTx); ok {
373389
return connBeginTx.BeginTx(ctx, opts)
@@ -392,7 +408,7 @@ func (c *ocConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx,
392408
defer span.End()
393409

394410
if connBeginTx, ok := c.parent.(driver.ConnBeginTx); ok {
395-
tx, err := connBeginTx.BeginTx(ctx, opts)
411+
tx, err = connBeginTx.BeginTx(ctx, opts)
396412
setSpanStatus(span, err)
397413
if err != nil {
398414
return nil, err
@@ -407,7 +423,7 @@ func (c *ocConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx,
407423
"ocsql.deprecated", "driver does not support ConnBeginTx",
408424
),
409425
)
410-
tx, err := c.parent.Begin()
426+
tx, err = c.parent.Begin()
411427
setSpanStatus(span, err)
412428
if err != nil {
413429
return nil, err
@@ -462,6 +478,8 @@ type ocStmt struct {
462478
}
463479

464480
func (s ocStmt) Exec(args []driver.Value) (res driver.Result, err error) {
481+
defer recordCallStats(context.Background(), "go.sql.stmt.exec")(err)
482+
465483
if !s.options.AllowRoot {
466484
return s.parent.Exec(args)
467485
}
@@ -507,6 +525,8 @@ func (s ocStmt) NumInput() int {
507525
}
508526

509527
func (s ocStmt) Query(args []driver.Value) (rows driver.Rows, err error) {
528+
defer recordCallStats(context.Background(), "go.sql.stmt.query")(err)
529+
510530
if !s.options.AllowRoot {
511531
return s.parent.Query(args)
512532
}
@@ -543,6 +563,8 @@ func (s ocStmt) Query(args []driver.Value) (rows driver.Rows, err error) {
543563
}
544564

545565
func (s ocStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (res driver.Result, err error) {
566+
defer recordCallStats(ctx, "go.sql.stmt.exec")(err)
567+
546568
parentSpan := trace.FromContext(ctx)
547569
if !s.options.AllowRoot && parentSpan == nil {
548570
// we already tested driver to implement StmtExecContext
@@ -580,6 +602,8 @@ func (s ocStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (res
580602
}
581603

582604
func (s ocStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (rows driver.Rows, err error) {
605+
defer recordCallStats(ctx, "go.sql.stmt.query")(err)
606+
583607
parentSpan := trace.FromContext(ctx)
584608
if !s.options.AllowRoot && parentSpan == nil {
585609
// we already tested driver to implement StmtQueryContext
@@ -775,6 +799,8 @@ type ocTx struct {
775799
}
776800

777801
func (t ocTx) Commit() (err error) {
802+
defer recordCallStats(context.Background(), "go.sql.commit")(err)
803+
778804
_, span := trace.StartSpan(t.ctx, "sql:commit", trace.WithSpanKind(trace.SpanKindClient))
779805
if len(t.options.DefaultAttributes) > 0 {
780806
span.AddAttributes(t.options.DefaultAttributes...)
@@ -789,6 +815,8 @@ func (t ocTx) Commit() (err error) {
789815
}
790816

791817
func (t ocTx) Rollback() (err error) {
818+
defer recordCallStats(context.Background(), "go.sql.rollback")(err)
819+
792820
_, span := trace.StartSpan(t.ctx, "sql:rollback", trace.WithSpanKind(trace.SpanKindClient))
793821
if len(t.options.DefaultAttributes) > 0 {
794822
span.AddAttributes(t.options.DefaultAttributes...)

0 commit comments

Comments
 (0)