A logger for Go SQL database driver without modify existing *sql.DB
stdlib usage.
Colored console writer output above only for sample/development
- Leveled, detailed and configurable logging.
- Keep using (or re-use existing)
*sql.DB
as is. - Bring your own logger backend via simple log interface.
- Trackable log output:
- Every call has its own unique ID.
- Prepared statement and execution will have same ID.
- On execution/result error, it will include query, arguments, params, and related IDs.
go get -u -v github.com/simukti/sqldb-logger
Version pinning using dependency manager such as Mod or Dep is highly recommended.
As a start, Logger
is just a simple interface:
type Logger interface {
Log(ctx context.Context, level Level, msg string, data map[string]interface{})
}
There are 4 included basic implementation that uses well known JSON structured logger for quickstart:
- Zerolog adapter: Using rs/zerolog as its logger.
- Onelog adapter: Using francoispqt/onelog as its logger.
- Zap adapter: Using uber-go/zap as its logger.
- Logrus adapter: Using sirupsen/logrus as its logger.
Note: those adapters does not use given context
, you need to modify it and adjust with your needs.
(example: add http request id/whatever value from context to query log when you call QueryerContext
andExecerContext
methods)
Then for that logger to works, you need to integrate with compatible driver which will be used by *sql.DB
.
Re-use from existing *sql.DB
driver, this is the simplest way:
For example, from:
dsn := "username:passwd@tcp(mysqlserver:3306)/dbname?parseTime=true"
db, err := sql.Open("mysql", dsn) // db is *sql.DB
db.Ping() // to check connectivity and DSN correctness
To:
// import sqldblogger "github.com/simukti/sqldb-logger"
// import "github.com/simukti/sqldb-logger/logadapter/zerologadapter"
dsn := "username:passwd@tcp(mysqlserver:3306)/dbname?parseTime=true"
db, err := sql.Open("mysql", dsn) // db is *sql.DB
// handle err
loggerAdapter := zerologadapter.New(zerolog.New(os.Stdout))
db = sqldblogger.OpenDriver(dsn, db.Driver(), loggerAdapter/*, using_default_options*/) // db is STILL *sql.DB
db.Ping() // to check connectivity and DSN correctness
That's it, all *sql.DB
interaction now logged.
It is also possible to integrate with following public empty struct driver directly:
MySQL (go-sql-driver/mysql)
db := sqldblogger.OpenDriver(dsn, &mysql.MySQLDriver{}, loggerAdapter /*, ...options */)
PostgreSQL (lib/pq)
db := sqldblogger.OpenDriver(dsn, &pq.Driver{}, loggerAdapter /*, ...options */)
SQLite3 (mattn/go-sqlite3)
db := sqldblogger.OpenDriver(dsn, &sqlite3.SQLiteDriver{}, loggerAdapter /*, ...options */)
Following struct drivers maybe compatible:
SQL Server (denisenkom/go-mssqldb)
db := sqldblogger.OpenDriver(dsn, &mssql.Driver{}, loggerAdapter /*, ...options */)
Oracle (mattn/go-oci8)
db := sqldblogger.OpenDriver(dsn, oci8.OCI8Driver, loggerAdapter /*, ...options */)
When using sqldblogger.OpenDriver(dsn, driver, logger, opt...)
without 4th variadic argument, it will uses default options.
Here is sample of OpenDriver()
using all available options and use non-default value:
db = sqldblogger.OpenDriver(
dsn,
db.Driver(),
loggerAdapter,
// AVAILABLE OPTIONS
sqldblogger.WithErrorFieldname("sql_error"), // default: error
sqldblogger.WithDurationFieldname("query_duration"), // default: duration
sqldblogger.WithTimeFieldname("log_time"), // default: time
sqldblogger.WithSQLQueryFieldname("sql_query"), // default: query
sqldblogger.WithSQLArgsFieldname("sql_args"), // default: args
sqldblogger.WithMinimumLevel(sqldblogger.LevelTrace), // default: LevelDebug
sqldblogger.WithLogArguments(false), // default: true
sqldblogger.WithDurationUnit(sqldblogger.DurationNanosecond), // default: DurationMillisecond
sqldblogger.WithTimeFormat(sqldblogger.TimeFormatRFC3339), // default: TimeFormatUnix
sqldblogger.WithLogDriverErrorSkip(true), // default: false
sqldblogger.WithSQLQueryAsMessage(true), // default: false
sqldblogger.WithUIDGenerator(sqldblogger.UIDGenerator), // default: *defaultUID
sqldblogger.WithConnectionIDFieldname("con_id"), // default: conn_id
sqldblogger.WithStatementIDFieldname("stm_id"), // default: stmt_id
sqldblogger.WithTransactionIDFieldname("trx_id"), // default: tx_id
sqldblogger.WithWrapResult(false), // default: true
sqldblogger.WithIncludeStartTime(true), // default: false
sqldblogger.WithStartTimeFieldname("start_time"), // default: start
sqldblogger.WithPreparerLevel(sqldblogger.LevelDebug), // default: LevelInfo
sqldblogger.WithQueryerLevel(sqldblogger.LevelDebug), // default: LevelInfo
sqldblogger.WithExecerLevel(sqldblogger.LevelDebug), // default: LevelInfo
)
Click here for options documentation.
I want to:
- Keep using
*sql.DB
. - Have configurable output field.
- Leverage structured logging.
- Fetch and log
context.Context
value if needed. - Re-use pgx log interface.
I haven't found Go *sql.DB
logger with that features, so why not created myself?
If you found bug, typo, wrong test, idea, help with existing issue, or anything constructive.
Don't hesitate to create an issue or pull request.
- pgx for awesome PostgreSQL driver.