dbhook

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Feb 4, 2023 License: MIT Imports: 4 Imported by: 5

README

dbhook

GoDoc Go Report Card

This is a hook for any database/sql driver.
DBhook allows to log requests, measure their duration, control the behavior of requests without changing the code base.
This is the middelware for your database.

Install

go get github.com/loghole/dbhook

Usage

package main

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

	sqlite "github.com/mattn/go-sqlite3"

	"github.com/loghole/dbhook"
)

const durationName = "duration"

type Hook struct {
	log *log.Logger
}

func (h *Hook) Before(ctx context.Context, input *dbhook.HookInput) (context.Context, error) {
	h.log.Printf("before %s: %s", input.Caller, input.Query)

	return context.WithValue(ctx, durationName, time.Now()), nil
}

func (h *Hook) After(ctx context.Context, input *dbhook.HookInput) (context.Context, error) {
	h.log.Printf("after %s: %s. duration: %v", input.Caller, input.Query, time.Since(ctx.Value(durationName).(time.Time)))

	return ctx, nil
}

func (h *Hook) Error(ctx context.Context, input *dbhook.HookInput) (context.Context, error) {
	h.log.Printf("error %s: %v. duration: %v", input.Caller, input.Error, time.Since(ctx.Value(durationName).(time.Time)))

	return ctx, input.Error // if return nil, then the query will not return an error
}

func main() {
	// Init hooks
	hooks := dbhook.NewHooks(dbhook.WithHook(&Hook{log: log.Default()}))

	// Register the wrapper
	sql.Register("sqlite_with_hook", dbhook.Wrap(&sqlite.SQLiteDriver{}, hooks))

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

	ctx := context.Background()
	// Queries
	db.ExecContext(ctx, "CREATE TABLE t (id INTEGER, text VARCHAR(3))")

	tx, _ := db.BeginTx(context.Background(), nil)
	tx.ExecContext(ctx, "INSERT into t (text) VALUES(?), (?)", "foo", "bar")
	tx.QueryContext(ctx, "SELECT id, text FROM t")
	tx.Commit()

	db.QueryContext(ctx, "SELEC id, text FROM t")
}

/*
  Output:
  before exec: CREATE TABLE t (id INTEGER, text VARCHAR(3))
  after exec: CREATE TABLE t (id INTEGER, text VARCHAR(3)). duration: 66.915µs
  before begin:
  after begin: . duration: 3.456µs
  before exec: INSERT into t (text) VALUES(?), (?)
  after exec: INSERT into t (text) VALUES(?), (?). duration: 13.756µs
  before query: SELECT id, text FROM t
  after query: SELECT id, text FROM t. duration: 6.382µs
  before commit:
  after commit: . duration: 24.786µs
  before query: SELEC id, text FROM t
  error query: near "SELEC": syntax error. duration: 10.57µs
*/

Real worl examples

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNonExecer                 = errors.New("ExecerContext created for a non Execer driver.Conn")
	ErrNonQueryer                = errors.New("QueryerContext created for a non Queryer driver.Conn")
	ErrNonSessionResetter        = errors.New("ResetSession created for a non SessionResetter driver.Conn")
	ErrNamedParametersNotSupport = errors.New("sql: driver does not support the use of Named Parameters")
)

Functions

func Wrap

func Wrap(drv driver.Driver, hks Hook) driver.Driver

Types

type CallerType

type CallerType string
const (
	CallerStmt      CallerType = "stmt"
	CallerStmtExec  CallerType = "stmt_exec"
	CallerStmtQuery CallerType = "stmt_query"
	CallerExec      CallerType = "exec"
	CallerQuery     CallerType = "query"
	CallerBegin     CallerType = "begin"
	CallerCommit    CallerType = "commit"
	CallerRollback  CallerType = "rollback"
)

type Conn

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

func (*Conn) Begin

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

Begin Deprecated.

func (*Conn) BeginTx

func (conn *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)

func (*Conn) CheckNamedValue added in v0.3.0

func (conn *Conn) CheckNamedValue(namedValue *driver.NamedValue) (err 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
}

func (*Driver) Open

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

type ExecerContext

type ExecerContext struct {
	*Conn
}

func (*ExecerContext) ExecContext

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

type ExecerQueryer

type ExecerQueryer struct {
	*Conn
	*ExecerContext
	*QueryerContext
}

type ExecerQueryerSessionResetter

type ExecerQueryerSessionResetter struct {
	*Conn
	*ExecerContext
	*QueryerContext
	*SessionResetter
}

type Hook

type Hook interface {
	HookBefore
	HookAfter
	HookError
}

type HookAfter added in v0.2.0

type HookAfter interface {
	After(ctx context.Context, input *HookInput) (context.Context, error)
}

type HookBefore added in v0.2.0

type HookBefore interface {
	Before(ctx context.Context, input *HookInput) (context.Context, error)
}

type HookError added in v0.2.0

type HookError interface {
	Error(ctx context.Context, input *HookInput) (context.Context, error)
}

type HookInput

type HookInput struct {
	Query  string
	Error  error
	Caller CallerType
	Args   []driver.Value
}

type HookOption

type HookOption func(*Hooks)

func WithHook added in v0.2.0

func WithHook(hooks ...Hook) HookOption

func WithHooksAfter

func WithHooksAfter(hooks ...HookAfter) HookOption

func WithHooksBefore

func WithHooksBefore(hooks ...HookBefore) HookOption

func WithHooksError

func WithHooksError(hooks ...HookError) HookOption

type Hooks

type Hooks struct {
	// contains filtered or unexported fields
}

func NewHooks

func NewHooks(opts ...HookOption) *Hooks

func (*Hooks) After

func (h *Hooks) After(ctx context.Context, input *HookInput) (context.Context, error)

func (*Hooks) Before

func (h *Hooks) Before(ctx context.Context, input *HookInput) (context.Context, error)

func (*Hooks) Error

func (h *Hooks) Error(ctx context.Context, input *HookInput) (context.Context, error)

type QueryerContext

type QueryerContext struct {
	*Conn
}

func (*QueryerContext) QueryContext

func (conn *QueryerContext) QueryContext(
	ctx context.Context,
	query string,
	args []driver.NamedValue,
) (driver.Rows, error)

type SessionResetter

type SessionResetter struct {
	*Conn
}

func (*SessionResetter) ResetSession

func (s *SessionResetter) ResetSession(ctx context.Context) error

type Stmt

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

func (*Stmt) Close

func (stmt *Stmt) Close() error

func (*Stmt) Exec

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

Exec Deprecated.

func (*Stmt) ExecContext

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

ExecContext must honor the context timeout and return when it is canceled.

func (*Stmt) NumInput

func (stmt *Stmt) NumInput() int

func (*Stmt) Query

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

Query Deprecated.

func (*Stmt) QueryContext

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

QueryContext must honor the context timeout and return when it is canceled.

type Tx

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

func (*Tx) Commit

func (tx *Tx) Commit() error

func (*Tx) Rollback

func (tx *Tx) Rollback() error

Directories

Path Synopsis
examples
log
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

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