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.DBas 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-loggerVersion 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 correctnessTo:
// 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 correctnessThat'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.Contextvalue 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.