sqlslog

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Mar 19, 2025 License: MIT Imports: 12 Imported by: 0

README

sql-slog

CI codecov Go Report Card Go project version Enabled Linters Documentation GitHub go.mod Go version license

A logger for Go SQL database drivers with log/slog without modifying existing *sql.DB stdlib usage.

FEATURES

  • Keep using (or re-use existing) *sql.DB as is.
  • No logger adapters. Just use log/slog
  • No dependencies
  • Leveled, detailed, and configurable logging.
  • Duration tracking
  • Trackable log output
  • 100% test coverage

See godoc for more details.

LOG EXAMPLES

INSTALL

To install sql-slog, use the following command:

go get -u github.com/akm/sql-slog

USAGE

To use sql-slog, you can open a database connection with logging enabled as follows:

db, logger, err := sqlslog.Open(ctx, "mysql", dsn)

This is the easiest way to use sqlslog. It's similar to the usage of Open from database/sql like this:

db, err := sql.Open("mysql", dsn)

The differences are:

  1. Pass context.Context as the first argument.
  2. *slog.Logger is returned as the second argument.
  3. sqlslog.Open can take a lot of Option s.

See godoc examples for more details.

EXAMPLES

examples/with-sqlc

An example showing how sql-slog works with sqlc. This example is almost same as Getting started with SQLite but uses sqlslog.Open instead of sql.Open.

Stdout with sqlslog package
$ make -C examples/with-sqlc run
go build ./...
go run .
time=2025-03-19T21:23:36.992+09:00 level=INFO msg=Open driver=sqlite dsn=:memory: duration=22083
time=2025-03-19T21:23:36.992+09:00 level=INFO msg=Driver.Open dsn=:memory: duration=274042 conn_id=_hMZDi7TQfEgBKN_
time=2025-03-19T21:23:36.992+09:00 level=INFO msg=Connector.Connect duration=294292
time=2025-03-19T21:23:36.993+09:00 level=INFO msg=Conn.ExecContext conn_id=_hMZDi7TQfEgBKN_ query="CREATE TABLE authors (\n  id   INTEGER PRIMARY KEY,\n  name text    NOT NULL,\n  bio  text\n);\n" args=[] duration=537125
time=2025-03-19T21:23:36.993+09:00 level=INFO msg=Conn.QueryContext conn_id=_hMZDi7TQfEgBKN_ query="-- name: ListAuthors :many\nSELECT id, name, bio FROM authors\nORDER BY name\n" args=[] duration=23250
2025/03/19 21:23:36 []
time=2025-03-19T21:23:36.993+09:00 level=INFO msg=Conn.QueryContext conn_id=_hMZDi7TQfEgBKN_ query="-- name: CreateAuthor :one\nINSERT INTO authors (\n  name, bio\n) VALUES (\n  ?, ?\n)\nRETURNING id, name, bio\n" args="[{Name: Ordinal:1 Value:Brian Kernighan} {Name: Ordinal:2 Value:Co-author of The C Programming Language and The Go Programming Language}]" duration=20375
2025/03/19 21:23:36 {1 Brian Kernighan {Co-author of The C Programming Language and The Go Programming Language true}}
time=2025-03-19T21:23:36.993+09:00 level=INFO msg=Conn.QueryContext conn_id=_hMZDi7TQfEgBKN_ query="-- name: GetAuthor :one\nSELECT id, name, bio FROM authors\nWHERE id = ? LIMIT 1\n" args="[{Name: Ordinal:1 Value:1}]" duration=8083
2025/03/19 21:23:36 true
Stdout without sqlslog package
$ SKIP_SQLSLOG=1 make -C examples/with-sqlc run
go build ./...
go run .
2025/03/19 21:23:19 []
2025/03/19 21:23:19 {1 Brian Kernighan {Co-author of The C Programming Language and The Go Programming Language true}}
2025/03/19 21:23:19 true
examples/with-go-requestid

An example showing how sql-slog works with go-requestid. You can see DB query logs with request IDs in the same log like the following:

time=2025-02-27T23:53:48.982+09:00 level=DEBUG msg=Conn.QueryContext conn_id=L1snTUaknlmsin8b query="SELECT id, title, status FROM todos" args=[] req_id=0JKGwDLjw77BjBnf

conn_id is a tracking ID for DB connection by sql-slog, and req_id is a tracking ID for HTTP request by go-requestid.

See server-logs.txt and main.go for more details.

TEST

MOTIVATION

I want to:

  • Keep using *sql.DB.
    • To work with thin ORM
  • Use log/slog
    • Leverage structured logging
    • Fetch and log context.Context values if needed

REFERENCES

CONTRIBUTING

If you find a bug, typo, incorrect test, have an idea, or want to help with an existing issue, please create an issue or pull request.

INSPIRED BY

LICENSE

MIT

Documentation

Overview

sqlslog is a logger for Go SQL database drivers without modifying existing *sql.DB stdlib usage. sqlslog uses *slog.Logger to log SQL database driver operations.

How to use

db, logger, err := sqlslog.Open(ctx, "mysql", dsn)

You can also use options to customize the logger's behavior.

Open takes Option s to customize the logging behavior. Option is created by using functions like HandlerFunc, ConnPrepareContext, StmtQueryContext, etc.

HandlerFunc / Handler

HandlerFunc sets the function to create a slog.Handler for the logger. slogslog provides NewTextHandler and NewJSONHandler to create a slog.Handler for sqlslog.

You can also use your own slog.Handler by using Handler with your slog.Handler. But your own slog.Handler should know how to log LevelTrace and LevelVerbose log levels. So you should use sqlslog.ReplaceLevelAttr with your slog.Handler.

Level

sqlslog has 6 log levels: LevelVerbose, LevelTrace, LevelDebug, LevelInfo, LevelWarn, and LevelError. LevelDebug, LevelInfo, LevelWarn, and LevelError are the same as slog's log levels. LevelVerbose and LevelTrace are extra log levels for sqlslog. LevelVerbose is the lowest log level, and LevelTrace is the second lowest log level.

Step and Event

A Step is a logical operation in the database driver, such as a query, a ping, a prepare, etc. An Event is an event that occurs during a Step, such as EventStart, EventError, and EventComplete. A StepOptions is a set of options for logging a Step and has EventOptions for each event. sqlslog provides a way to customize the log message and log Level for each step event. You can customize them by using functions that take StepOptions and return Option, like ConnPrepareContext or StmtQueryContext.

DefaultStepEventMsgBuilder

The default step event message builder is StepEventMsgWithEventName. You can change the default step event message builder by calling SetStepEventMsgBuilder.

Duration

sqlslog measures the duration of each step and logs it. You can change the duration unit by calling Duration function and can change the key name of the duration by calling DurationKey function.

Tracking ID

sqlslog provides a way to track connections, transactions and statements by using a tracking ID. Each tracking ID is a unique identifier for a connection, transaction or statement. Tracking ID key in logs is conn_id, tx_id or stmt_id. Tracking IDs are generated by the ID generator function. The default ID generator function is IDGeneratorDefault. You can change the ID generator function by calling IDGenerator with functions created by RandIntIDGenerator or RandReadIDGenerator with IDGenErrorSuppressor.

Index

Examples

Constants

View Source
const (
	ConnIDKeyDefault = "conn_id"
	TxIDKeyDefault   = "tx_id"
	StmtIDKeyDefault = "stmt_id"
)
View Source
const DurationKeyDefault = "duration"

DurationKeyDefault is the default key for duration value in log.

Variables

View Source
var ErrUnknownLevel = errors.New("unknown level")
View Source
var IDGeneratorDefault = RandIntIDGenerator(rand.Int, defaultIDLetters, defaultIDLength)

IDGeneratorDefault is the default ID generator.

Functions

func ConnExecContextErrorHandler added in v0.1.2

func ConnExecContextErrorHandler(driverName string) func(err error) (bool, []slog.Attr)

func ConnQueryContextErrorHandler added in v0.1.2

func ConnQueryContextErrorHandler(driverName string) func(err error) (bool, []slog.Attr)

func ConnectorConnectErrorHandler added in v0.1.2

func ConnectorConnectErrorHandler(driverName string) func(err error) (bool, []slog.Attr)

ConnectorConnectErrorHandler returns a function that handles errors from driver.Connector.Connect. The function returns a boolean indicating completion and a slice of slog.Attr.

# For Postgres: If err is nil, it returns true and a slice of slog.Attr{slog.Bool("success", true)}. If err is io.EOF, it returns true and a slice of slog.Attr{slog.Bool("success", false)}. Otherwise, it returns false and nil.

func DriverOpenErrorHandler added in v0.1.2

func DriverOpenErrorHandler(driverName string) func(err error) (bool, []slog.Attr)

DriverOpenErrorHandler returns a function that handles errors from driver.Driver.Open. The function returns a boolean indicating completion and a slice of slog.Attr.

# For Postgres: If err is nil, it returns true and a slice of slog.Attr{slog.Bool("success", true)}. If err is io.EOF, it returns true and a slice of slog.Attr{slog.Bool("success", false)}. Otherwise, it returns false and nil.

func HandleRowsNextError added in v0.1.2

func HandleRowsNextError(err error) (bool, []slog.Attr)

HandleRowsNextError returns a boolean indicating completion and a slice of slog.Attr. If err is nil, it returns true and a slice of slog.Attr{slog.Bool("eof", false)}. If err is io.EOF, it returns true and a slice of slog.Attr{slog.Bool("eof", true)}. Otherwise, it returns false and nil.

func NewJSONHandler added in v0.1.1

func NewJSONHandler(w io.Writer, opts *slog.HandlerOptions) slog.Handler

NewJSONHandler returns a new JSON handler using slog.NewJSONHandler with custom options for sqlslog. See WrapHandlerOptions for details on the options.

Example
package main

import (
	"context"
	"log/slog"

	sqlslog "github.com/akm/sql-slog"
)

func removeTimeAndDuration(groups []string, a slog.Attr) slog.Attr {
	if len(groups) == 0 {
		switch a.Key {
		case slog.TimeKey:
			return slog.Attr{}
		case "duration":
			return slog.Attr{}
		}
	}
	return a
}

func main() {
	dsn := "dummy-dsn"
	ctx := context.TODO()
	db, logger, _ := sqlslog.Open(ctx, "mock", dsn,
		sqlslog.HandlerFunc(sqlslog.NewJSONHandler),
		sqlslog.LogReplaceAttr(removeTimeAndDuration),
	)
	defer db.Close()
	logger.InfoContext(ctx, "Hello, World!")

}
Output:

{"level":"INFO","msg":"Open","driver":"mock","dsn":"dummy-dsn"}
{"level":"INFO","msg":"Hello, World!"}

func NewTextHandler added in v0.1.1

func NewTextHandler(w io.Writer, opts *slog.HandlerOptions) slog.Handler

NewTextHandler returns a new Text handler using slog.NewTextHandler with custom options for sqlslog. See WrapHandlerOptions for details on the options.

Example
package main

import (
	"context"
	"log/slog"

	sqlslog "github.com/akm/sql-slog"
)

func removeTimeAndDuration(groups []string, a slog.Attr) slog.Attr {
	if len(groups) == 0 {
		switch a.Key {
		case slog.TimeKey:
			return slog.Attr{}
		case "duration":
			return slog.Attr{}
		}
	}
	return a
}

func main() {
	dsn := "dummy-dsn"
	ctx := context.TODO()
	db, logger, _ := sqlslog.Open(ctx, "mock", dsn,
		sqlslog.HandlerFunc(sqlslog.NewTextHandler),
		sqlslog.LogReplaceAttr(removeTimeAndDuration),
	)
	defer db.Close()
	logger.InfoContext(ctx, "Hello, World!")

}
Output:

level=INFO msg=Open driver=mock dsn=dummy-dsn
level=INFO msg="Hello, World!"

func Open

func Open(ctx context.Context, driverName, dsn string, opts ...Option) (*sql.DB, *slog.Logger, error)

Open opens a database specified by its driver name and a driver-specific data source name, and returns a new database handle with logging capabilities.

ctx is the context for the open operation. driverName is the name of the database driver, same as the driverName in sql.Open. dsn is the data source name, same as the dataSourceName in sql.Open. opts are the options for logging behavior. See Option for details.

The returned DB can be used the same way as *sql.DB from sql.Open.

See the following example for usage:

[Logger]: sets the slog.Logger to be used. If not set, the default is slog.Default().

StepOptions: sets the options for logging behavior.

SetStepEventMsgBuilder: sets the function to format the step name.

Example
package main

import (
	"context"

	sqlslog "github.com/akm/sql-slog"
)

func main() {
	dsn := "file::memory:?cache=shared"
	ctx := context.TODO()
	db, logger, err := sqlslog.Open(ctx, "sqlite3", dsn)
	if err != nil {
		// Handle error
	}
	defer db.Close()
	// Use db as a regular *sql.DB
	logger.InfoContext(ctx, "Hello, World!")
}
Output:

Example (WithLevel)
package main

import (
	"context"

	sqlslog "github.com/akm/sql-slog"
)

func main() {
	dsn := "file::memory:?cache=shared"
	ctx := context.TODO()
	db, _, _ := sqlslog.Open(ctx, "sqlite3", dsn,
		sqlslog.LogLevel(sqlslog.LevelTrace),
	)
	defer db.Close()
}
Output:

Example (WithStmtQueryContext)
package main

import (
	"context"

	sqlslog "github.com/akm/sql-slog"
)

func main() {
	dsn := "file::memory:?cache=shared"
	ctx := context.TODO()
	db, _, _ := sqlslog.Open(ctx, "sqlite3", dsn,
		sqlslog.LogLevel(sqlslog.LevelTrace),
		sqlslog.StmtQueryContext(func(o *sqlslog.StepOptions) {
			o.SetLevel(sqlslog.LevelDebug)
		}),
	)
	defer db.Close()
}
Output:

func RandReadIDGenerator added in v0.2.0

func RandReadIDGenerator(
	randRead func(b []byte) (n int, err error),
	letters []byte,
	length int,
) func() (string, error)

Returns a random ID generator that generates a string of length characters using randRead to generate random bytes such as Read function from crypto/rand package.

func ReplaceLevelAttr added in v0.1.1

func ReplaceLevelAttr(_ []string, a slog.Attr) slog.Attr

ReplaceLevelAttr replaces the log level as sqlslog.Level with its string representation.

func SetStepEventMsgBuilder added in v0.2.0

func SetStepEventMsgBuilder(f StepEventMsgBuilder)

SetStepEventMsgBuilder sets the builder for the step event message used in logs. If not set, the default is StepLogMsgWithEventName.

Example
sqlslog.SetStepEventMsgBuilder(func(step sqlslog.Step, event sqlslog.Event) string {
	return "PRFIX:" + step.String() + "/" + event.String() + ":SUFFIX"
})
defer sqlslog.SetStepEventMsgBuilder(sqlslog.StepEventMsgWithoutEventName)

dsn := "dummy-dsn"
ctx := context.TODO()
db, logger, _ := sqlslog.Open(ctx, "mock", dsn,
	sqlslog.LogReplaceAttr(removeTimeAndDuration), // for testing
)
defer db.Close()
logger.InfoContext(ctx, "Hello, World!")
Output:

level=INFO msg=PRFIX:Open/Complete:SUFFIX driver=mock dsn=dummy-dsn
level=INFO msg="Hello, World!"

func StepEventMsgWithEventName added in v0.2.0

func StepEventMsgWithEventName(step Step, event Event) string

StepEventMsgWithEventName returns the formatted step log message with the event name.

func StepEventMsgWithoutEventName added in v0.2.0

func StepEventMsgWithoutEventName(step Step, _ Event) string

StepEventMsgWithoutEventName returns the formatted step log message without the event name.

func WrapHandlerOptions added in v0.1.1

func WrapHandlerOptions(opts *slog.HandlerOptions) *slog.HandlerOptions

WrapHandlerOptions wraps the options with custom options for sqlslog. It merges ReplaceAttr functions with ReplaceLevelAttr.

Types

type DurationType added in v0.1.3

type DurationType int
const (
	DurationNanoSeconds  DurationType = iota // Duration in nanoseconds. Durations in log are expressed by slog.Int64
	DurationMicroSeconds                     // Duration in microseconds. Durations in log are expressed by slog.Int64
	DurationMilliSeconds                     // Duration in milliseconds. Durations in log are expressed by slog.Int64
	DurationGoDuration                       // Values in log are expressed with slog.Duration
	DurationString                           // Values in log are expressed with slog.String and time.Duration.String
)

type Event added in v0.1.1

type Event int

Event is the event type of the step.

const (
	EventStart    Event = iota + 1 // Event when the step starts.
	EventError                     // Event when the step ends with an error.
	EventComplete                  // Event when the step completes successfully.
)

func (*Event) String added in v0.1.1

func (pe *Event) String() string

String returns the string representation of the event.

type EventOptions added in v0.1.1

type EventOptions struct {
	Msg   string
	Level Level
}

type Factory added in v0.2.0

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

func New added in v0.2.0

func New(driverName, dsn string, opts ...Option) *Factory

func (*Factory) Handler added in v0.2.0

func (f *Factory) Handler() slog.Handler

func (*Factory) Logger added in v0.2.0

func (f *Factory) Logger() *slog.Logger

func (*Factory) Open added in v0.2.0

func (f *Factory) Open(ctx context.Context) (*sql.DB, error)

type IDGen added in v0.1.4

type IDGen = func() string

IDGen is a function that generates an ID string.

func IDGenErrorSuppressor added in v0.2.0

func IDGenErrorSuppressor(idGen func() (string, error), recoveryFunc func(error) string) IDGen

IDGenErrorSuppressor returns an ID generator that suppresses errors. If an error occurs, the recover function is called with the error and the result is returned.

Example
package main

import (
	"context"
	cryptorand "crypto/rand"

	sqlslog "github.com/akm/sql-slog"
)

func main() {
	idGen := sqlslog.IDGenErrorSuppressor(
		sqlslog.RandReadIDGenerator(
			cryptorand.Read,
			[]byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
			8,
		),
		func(error) string { return "recovered" },
	)

	db, _, _ := sqlslog.Open(context.TODO(), "sqlite3", "file::memory:?cache=shared",
		sqlslog.HandlerFunc(sqlslog.NewJSONHandler),
		sqlslog.IDGenerator(idGen),
	)
	defer db.Close()
}
Output:

func RandIntIDGenerator added in v0.2.0

func RandIntIDGenerator(
	randInt func() int,
	letters []byte,
	length int,
) IDGen

Returns a random ID generator that generates a string of length characters using randInt to generate random integers such as Int function from math/rand/v2 package.

Example
package main

import (
	"context"

	mathrandv2 "math/rand/v2"

	sqlslog "github.com/akm/sql-slog"
)

func main() {
	idGen := sqlslog.RandIntIDGenerator(
		mathrandv2.Int,
		[]byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
		8,
	)

	db, _, _ := sqlslog.Open(context.TODO(), "sqlite3", "file::memory:?cache=shared",
		sqlslog.HandlerFunc(sqlslog.NewJSONHandler),
		sqlslog.IDGenerator(idGen),
	)
	defer db.Close()
}
Output:

type Level added in v0.1.1

type Level slog.Level

Level is the log level for sqlslog.

const (
	LevelVerbose Level = Level(-12)             // Lower than slog.LevelTrace.
	LevelTrace   Level = Level(-8)              // Lower than slog.LevelDebug.
	LevelDebug   Level = Level(slog.LevelDebug) // Same as slog.LevelDebug.
	LevelInfo    Level = Level(slog.LevelInfo)  // Same as slog.LevelInfo.
	LevelWarn    Level = Level(slog.LevelWarn)  // Same as slog.LevelWarn.
	LevelError   Level = Level(slog.LevelError) // Same as slog.LevelError.
)

func ParseLevel added in v0.2.0

func ParseLevel(s string) (Level, error)

func ParseLevelWithDefault added in v0.2.0

func ParseLevelWithDefault(s string, def Level) Level

func (Level) Level added in v0.1.1

func (l Level) Level() slog.Level

Level returns the slog.Level.

func (Level) String added in v0.1.1

func (l Level) String() string

String returns the string representation of the log level.

type Option added in v0.1.1

type Option func(*options)

Option is a function that sets an option on the options struct.

func AddSource added in v0.2.0

func AddSource(v bool) Option

AddSource sets whether to add the source to the log.

func ConnBegin added in v0.1.1

func ConnBegin(f func(*StepOptions)) Option

Set the options for Conn.Begin.

func ConnBeginTx added in v0.1.1

func ConnBeginTx(f func(*StepOptions)) Option

Set the options for Conn.BeginTx.

func ConnClose added in v0.1.1

func ConnClose(f func(*StepOptions)) Option

Set the options for Conn.Close.

func ConnExecContext added in v0.1.1

func ConnExecContext(f func(*StepOptions)) Option

Set the options for Conn.ExecContext.

func ConnIDKey added in v0.1.4

func ConnIDKey(key string) Option

ConnIDKey sets the key for the connection ID. The default is ConnIDKeyDefault.

func ConnPing added in v0.1.1

func ConnPing(f func(*StepOptions)) Option

Set the options for Conn.Ping.

func ConnPrepare added in v0.1.1

func ConnPrepare(f func(*StepOptions)) Option

Set the options for Conn.Prepare.

func ConnPrepareContext added in v0.1.1

func ConnPrepareContext(f func(*StepOptions)) Option

Set the options for Conn.PrepareContext.

func ConnQueryContext added in v0.1.1

func ConnQueryContext(f func(*StepOptions)) Option

Set the options for Conn.QueryContext.

func ConnResetSession added in v0.1.1

func ConnResetSession(f func(*StepOptions)) Option

Set the options for Conn.ResetSession.

func ConnectorConnect added in v0.1.1

func ConnectorConnect(f func(*StepOptions)) Option

Set the options for Connector.Connect.

func DriverOpen added in v0.1.1

func DriverOpen(f func(*StepOptions)) Option

Set the options for Driver.Open.

func DriverOpenConnector added in v0.1.1

func DriverOpenConnector(f func(*StepOptions)) Option

Set the options for Driver.OpenConnector.

func Duration added in v0.1.3

func Duration(v DurationType) Option

Duration is an option to specify duration value in log. The default is DurationNanoSeconds.

func DurationKey added in v0.1.3

func DurationKey(key string) Option

DurationKey is an option to specify the key for duration value in log. The default is specified by DurationKeyDefault.

func Handler added in v0.2.0

func Handler(handler slog.Handler) Option

Handler sets the slog.Handler to be used. If not set, the default is created by HandlerFunc, Writer, SlogOptions. If you set this option, HandlerFunc, Writer, SlogOptions will be ignored. WARNING: If given handler is created without ReplaceAttr options, LevelTrace and LevelVerbose will be logged as DEBUG-4 and DEBUG-8.

Example
package main

import (
	"context"
	"log/slog"
	"os"

	sqlslog "github.com/akm/sql-slog"
)

func removeTimeAndDuration(groups []string, a slog.Attr) slog.Attr {
	if len(groups) == 0 {
		switch a.Key {
		case slog.TimeKey:
			return slog.Attr{}
		case "duration":
			return slog.Attr{}
		}
	}
	return a
}

func main() {
	// Normal slog.Handler with sqlslog.ReplaceLevelAttr knows how to show LevelTrace and LevelVerbose.
	handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		ReplaceAttr: sqlslog.MergeReplaceAttrs(
			sqlslog.ReplaceLevelAttr,
			removeTimeAndDuration, // for testing
		),
		Level: sqlslog.LevelVerbose,
	})

	dsn := "dummy-dsn"
	ctx := context.TODO()

	logger := sqlslog.New("mock", dsn, sqlslog.Handler(handler)).Logger()
	logger.Log(ctx, slog.Level(sqlslog.LevelTrace), "Foo")
	logger.Log(ctx, slog.Level(sqlslog.LevelVerbose), "Bar")

}
Output:

level=TRACE msg=Foo
level=VERBOSE msg=Bar
Example (WithoutReplaceLevelAttr)
package main

import (
	"context"
	"log/slog"
	"os"

	sqlslog "github.com/akm/sql-slog"
)

func removeTimeAndDuration(groups []string, a slog.Attr) slog.Attr {
	if len(groups) == 0 {
		switch a.Key {
		case slog.TimeKey:
			return slog.Attr{}
		case "duration":
			return slog.Attr{}
		}
	}
	return a
}

func main() {
	// Normal slog.Handler without sqlslog.ReplaceLevelAttr does not know how to show LevelTrace and LevelVerbose.
	handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		ReplaceAttr: removeTimeAndDuration,
		Level:       sqlslog.LevelVerbose,
	})

	dsn := "dummy-dsn"
	ctx := context.TODO()
	logger := sqlslog.New("mock", dsn, sqlslog.Handler(handler)).Logger()

	logger.Log(ctx, slog.Level(sqlslog.LevelTrace), "Foo")
	logger.Log(ctx, slog.Level(sqlslog.LevelVerbose), "Bar")

}
Output:

level=DEBUG-4 msg=Foo
level=DEBUG-8 msg=Bar

func HandlerFunc added in v0.2.0

func HandlerFunc(handlerFunc func(io.Writer, *slog.HandlerOptions) slog.Handler) Option

HandlerFunc sets the function to create the slog.Handler. If not set, the default is NewTextHandler. WARNING: Unless given handlerFunc considers ReplaceAttr options like NewJSONHandler or NewTextHandler of sqlslog package, LevelTrace and LevelVerbose will be logged as DEBUG-4 and DEBUG-8.

Example
package main

import (
	"context"

	sqlslog "github.com/akm/sql-slog"
)

func main() {
	dsn := "file::memory:?cache=shared"
	ctx := context.TODO()
	db, logger, _ := sqlslog.Open(ctx, "sqlite3", dsn,
		sqlslog.HandlerFunc(sqlslog.NewJSONHandler),
	)
	defer db.Close()
	logger.InfoContext(ctx, "Hello, World!")
}
Output:

func HandlerOptions added in v0.2.0

func HandlerOptions(opts *slog.HandlerOptions) Option

HandlerOptions sets the options to be used for the slog.Handler. If not set, the default is an empty slog.HandlerOptions.

func IDGenerator added in v0.1.4

func IDGenerator(idGen IDGen) Option

IDGenerator returns an Option that sets the ID generator. The default is IDGeneratorDefault.

Example
package main

import (
	"context"

	mathrandv2 "math/rand/v2"

	sqlslog "github.com/akm/sql-slog"
)

func main() {
	idGen := sqlslog.RandIntIDGenerator(
		mathrandv2.Int,
		[]byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
		8,
	)

	db, _, _ := sqlslog.Open(context.TODO(), "sqlite3", "file::memory:?cache=shared",
		sqlslog.HandlerFunc(sqlslog.NewJSONHandler),
		sqlslog.IDGenerator(idGen),
	)
	defer db.Close()
}
Output:

func LogLevel added in v0.2.0

func LogLevel(v slog.Leveler) Option

LogLevel sets the log level to be used.

func LogReplaceAttr added in v0.2.0

func LogReplaceAttr(f func([]string, slog.Attr) slog.Attr) Option

ReplaceAttr sets the function to replace the attributes.

func LogWriter added in v0.2.0

func LogWriter(w io.Writer) Option

LogWriter sets the writer to be used for the slog.Handler. If not set, the default is os.Stdout.

func RowsClose added in v0.1.1

func RowsClose(f func(*StepOptions)) Option

Set the options for Rows.Close.

func RowsNext added in v0.1.1

func RowsNext(f func(*StepOptions)) Option

Set the options for Rows.Next.

func RowsNextResultSet added in v0.1.1

func RowsNextResultSet(f func(*StepOptions)) Option

Set the options for Rows.NextResultSet.

func SqlslogOpen added in v0.1.1

func SqlslogOpen(f func(*StepOptions)) Option

Set the options for sqlslog.Open.

func StmtClose added in v0.1.1

func StmtClose(f func(*StepOptions)) Option

Set the options for Stmt.Close.

func StmtExec added in v0.1.1

func StmtExec(f func(*StepOptions)) Option

Set the options for Stmt.Exec.

func StmtExecContext added in v0.1.1

func StmtExecContext(f func(*StepOptions)) Option

Set the options for Stmt.ExecContext.

func StmtIDKey added in v0.1.4

func StmtIDKey(key string) Option

StmtIDKey sets the key for the statement ID. The default is StmtIDKeyDefault.

func StmtQuery added in v0.1.1

func StmtQuery(f func(*StepOptions)) Option

Set the options for Stmt.Query.

func StmtQueryContext added in v0.1.1

func StmtQueryContext(f func(*StepOptions)) Option

Set the options for Stmt.QueryContext.

func TxCommit added in v0.1.1

func TxCommit(f func(*StepOptions)) Option

Set the options for Tx.Commit.

func TxIDKey added in v0.1.4

func TxIDKey(key string) Option

TxIDKey sets the key for the transaction ID. The default is TxIDKeyDefault.

func TxRollback added in v0.1.1

func TxRollback(f func(*StepOptions)) Option

Set the options for Tx.Rollback.

type ReplaceAttrFunc added in v0.1.1

type ReplaceAttrFunc = func([]string, slog.Attr) slog.Attr

ReplaceLevelAttr is a type of ReplaceAttr for slog.HandlerOptions.

func MergeReplaceAttrs added in v0.1.1

func MergeReplaceAttrs(funcs ...ReplaceAttrFunc) ReplaceAttrFunc

MergeReplaceAttrs merges multiple ReplaceAttrFunc functions. If functions are nil or empty, it returns nil. If there is only one function, it returns that function. If there are multiple functions, it returns a merged function.

type Step added in v0.2.0

type Step string
const (
	StepConnBegin          Step = "Conn.Begin"
	StepConnBeginTx        Step = "Conn.BeginTx"
	StepConnClose          Step = "Conn.Close"
	StepConnPrepare        Step = "Conn.Prepare"
	StepConnPrepareContext Step = "Conn.PrepareContext"
	StepConnResetSession   Step = "Conn.ResetSession"
	StepConnPing           Step = "Conn.Ping"
	StepConnExecContext    Step = "Conn.ExecContext"
	StepConnQueryContext   Step = "Conn.QueryContext"

	StepConnectorConnect Step = "Connector.Connect"

	StepDriverOpen          Step = "Driver.Open"
	StepDriverOpenConnector Step = "Driver.OpenConnector"

	StepSqlslogOpen Step = "Open"

	StepRowsClose         Step = "Rows.Close"
	StepRowsNext          Step = "Rows.Next"
	StepRowsNextResultSet Step = "Rows.NextResultSet"

	StepStmtClose        Step = "Stmt.Close"
	StepStmtExec         Step = "Stmt.Exec"
	StepStmtQuery        Step = "Stmt.Query"
	StepStmtExecContext  Step = "Stmt.ExecContext"
	StepStmtQueryContext Step = "Stmt.QueryContext"

	StepTxCommit   Step = "Tx.Commit"
	StepTxRollback Step = "Tx.Rollback"
)

func (Step) String added in v0.2.0

func (s Step) String() string

type StepEventMsgBuilder added in v0.2.0

type StepEventMsgBuilder func(step Step, event Event) string

StepEventMsgBuilder is the function type to format the step log message.

type StepOptions added in v0.1.1

type StepOptions struct {
	Start    EventOptions
	Error    EventOptions
	Complete EventOptions

	// ErrorHandler is the function to handle the error.
	// When the error should not be logged as an error but as complete, it should return true.
	// It can also add attributes to the log.
	ErrorHandler func(error) (bool, []slog.Attr)
}

StepOptions is an struct that expresses the options for the step.

func (*StepOptions) SetLevel added in v0.1.1

func (o *StepOptions) SetLevel(lv Level)

Jump to

Keyboard shortcuts

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