sqlhooks

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 30, 2018 License: MIT Imports: 3 Imported by: 0

README

sqlhooks Build Status Coverage Status Go Report Card

Attach hooks to any database/sql driver.

The purpose of sqlhooks is to provide a way to instrument your sql statements, making really easy to log queries or measure execution time without modifying your actual code.

Install

go get github.com/gchaincl/sqlhooks

Breaking changes

V1 isn't backward compatible with previous versions, if you want to fetch old versions, you can get them from gopkg.in

go get gopkg.in/gchaincl/sqlhooks.v0

Usage GoDoc

// This example shows how to instrument sql queries in order to display the time that they consume
package main

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	"github.com/gchaincl/sqlhooks"
	"github.com/mattn/go-sqlite3"
)

// Hooks satisfies the sqlhook.Hooks interface
type Hooks struct {}

// Before hook will print the query with it's args and return the context with the timestamp
func (h *Hooks) Before(ctx context.Context, query string, args ...interface{}) (context.Context, error) {
	fmt.Printf("> %s %q", query, args)
	return context.WithValue(ctx, "begin", time.Now()), nil
}

// After hook will get the timestamp registered on the Before hook and print the elapsed time
func (h *Hooks) After(ctx context.Context, query string, args ...interface{}) (context.Context, error) {
	begin := ctx.Value("begin").(time.Time)
	fmt.Printf(". took: %s\n", time.Since(begin))
	return ctx, nil
}

func main() {
	// First, register the wrapper
	sql.Register("sqlite3WithHooks", sqlhooks.Wrap(&sqlite3.SQLiteDriver{}, &Hooks{}))

	// Connect to the registered wrapped driver
	db, _ := sql.Open("sqlite3WithHooks", ":memory:")

	// Do you're stuff
	db.Exec("CREATE TABLE t (id INTEGER, text VARCHAR(16))")
	db.Exec("INSERT into t (text) VALUES(?), (?)", "foo", "bar")
	db.Query("SELECT id, text FROM t")
}

/*
Output should look like:
> CREATE TABLE t (id INTEGER, text VARCHAR(16)) []. took: 121.238µs
> INSERT into t (text) VALUES(?), (?) ["foo" "bar"]. took: 36.364µs
> SELECT id, text FROM t []. took: 4.653µs
*/

Benchmarks

 go test -bench=. -benchmem
 BenchmarkSQLite3/Without_Hooks-4                  200000              8572 ns/op             627 B/op         16 allocs/op
 BenchmarkSQLite3/With_Hooks-4                     200000             10231 ns/op             738 B/op         18 allocs/op
 BenchmarkMySQL/Without_Hooks-4                     10000            108421 ns/op             437 B/op         10 allocs/op
 BenchmarkMySQL/With_Hooks-4                        10000            226085 ns/op             597 B/op         13 allocs/op
 BenchmarkPostgres/Without_Hooks-4                  10000            125718 ns/op             649 B/op         17 allocs/op
 BenchmarkPostgres/With_Hooks-4                      5000            354831 ns/op            1122 B/op         27 allocs/op
 PASS
 ok      github.com/gchaincl/sqlhooks    11.713s

Documentation

Overview

This example shows how to instrument sql queries in order to display the time that they consume package main

import (

"context"
"database/sql"
"fmt"
"time"

"github.com/gchaincl/sqlhooks"
"github.com/mattn/go-sqlite3"

)

// Hooks satisfies the sqlhook.Hooks interface type Hooks struct {}

// Before hook will print the query with it's args and return the context with the timestamp

func (h *Hooks) Before(ctx context.Context, query string, args ...interface{}) (context.Context, error) {
	fmt.Printf("> %s %q", query, args)
	return context.WithValue(ctx, "begin", time.Now()), nil
}

// After hook will get the timestamp registered on the Before hook and print the elapsed time

func (h *Hooks) After(ctx context.Context, query string, args ...interface{}) (context.Context, error) {
	begin := ctx.Value("begin").(time.Time)
	fmt.Printf(". took: %s\n", time.Since(begin))
	return ctx, nil
}
func main() {
	// First, register the wrapper
	sql.Register("sqlite3WithHooks", sqlhooks.Wrap(&sqlite3.SQLiteDriver{}, &Hooks{}))

	// Connect to the registered wrapped driver
	db, _ := sql.Open("sqlite3WithHooks", ":memory:")

	// Do you're stuff
	db.Exec("CREATE TABLE t (id INTEGER, text VARCHAR(16))")
	db.Exec("INSERT into t (text) VALUES(?), (?)", "foo", "bar")
	db.Query("SELECT id, text FROM t")
}

/* Output should look like: > CREATE TABLE t (id INTEGER, text VARCHAR(16)) []. took: 121.238µs > INSERT into t (text) VALUES(?), (?) ["foo" "bar"]. took: 36.364µs > SELECT id, text FROM t []. took: 4.653µs */

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Wrap

func Wrap(driver driver.Driver, hooks Hooks) driver.Driver

Wrap is used to create a new instrumented driver, it takes a vendor specific driver, and a Hooks instance to produce a new driver instance. It's usually used inside a sql.Register() statement

Types

type Conn

type Conn struct {
	Conn driver.Conn
	// contains filtered or unexported fields
}

Conn implements a database/sql.driver.Conn

func (*Conn) Begin

func (conn *Conn) Begin() (driver.Tx, error)

func (*Conn) Close

func (conn *Conn) Close() error

func (*Conn) Prepare

func (conn *Conn) Prepare(query string) (driver.Stmt, error)

func (*Conn) PrepareContext

func (conn *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)

type Driver

type Driver struct {
	driver.Driver
	// contains filtered or unexported fields
}

Driver implements a database/sql/driver.Driver

func (*Driver) Open

func (drv *Driver) Open(name string) (driver.Conn, error)

Open opens a connection

type ErrorHook

type ErrorHook func(ctx context.Context, err error, query string, args ...interface{}) error

ErrorHook is the error handling callback signature

type ExecerContext

type ExecerContext struct {
	*Conn
}

ExecerContext implements a database/sql.driver.ExecerContext

func (*ExecerContext) Exec

func (conn *ExecerContext) Exec(query string, args []driver.Value) (driver.Result, error)

func (*ExecerContext) ExecContext

func (conn *ExecerContext) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error)

type Hook

type Hook func(ctx context.Context, query string, args ...interface{}) (context.Context, error)

Hook is the hook callback signature

type Hooks

type Hooks interface {
	Before(ctx context.Context, query string, args ...interface{}) (context.Context, error)
	After(ctx context.Context, query string, args ...interface{}) (context.Context, error)
}

Hooks instances may be passed to Wrap() to define an instrumented driver

type OnErrorer

type OnErrorer interface {
	OnError(ctx context.Context, err error, query string, args ...interface{}) error
}

OnErrorer instances will be called if any error happens

type Stmt

type Stmt struct {
	Stmt driver.Stmt
	// contains filtered or unexported fields
}

Stmt implements a database/sql/driver.Stmt

func (*Stmt) Close

func (stmt *Stmt) Close() error

func (*Stmt) Exec

func (stmt *Stmt) Exec(args []driver.Value) (driver.Result, error)

func (*Stmt) ExecContext

func (stmt *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error)

func (*Stmt) NumInput

func (stmt *Stmt) NumInput() int

func (*Stmt) Query

func (stmt *Stmt) Query(args []driver.Value) (driver.Rows, error)

func (*Stmt) QueryContext

func (stmt *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error)

Directories

Path Synopsis
hooks

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL