From 742b2c0930dabd6cff66c8c2822ba3f815f8bc00 Mon Sep 17 00:00:00 2001 From: jonbodner Date: Tue, 10 Feb 2026 23:21:09 -0500 Subject: [PATCH 1/2] Replace custom logger with Go's slog package for streamlined logging. --- builder.go | 4 +- builder_test.go | 11 ++- cmd/null/main.go | 30 +++---- cmd/sample-ctx/main.go | 48 +++++------ cmd/sample/main.go | 48 +++++------ go.mod | 2 - go.sum | 19 +--- line_logger.go | 25 ++++++ logger/logger.go | 182 --------------------------------------- logger/logger_test.go | 21 ----- mapper/extract.go | 8 +- mapper/extract_test.go | 17 ++-- mapper/mapper.go | 18 ++-- mapper_test.go | 116 ++++++++++++++----------- proteus.go | 35 ++------ proteus_function.go | 27 +----- proteus_function_test.go | 82 ++++++------------ proteus_test.go | 57 ++++++------ runner.go | 36 ++------ runner_test.go | 17 ++-- 20 files changed, 255 insertions(+), 548 deletions(-) create mode 100644 line_logger.go delete mode 100644 logger/logger.go delete mode 100644 logger/logger_test.go diff --git a/builder.go b/builder.go index 913d4f0..2d47159 100644 --- a/builder.go +++ b/builder.go @@ -6,13 +6,13 @@ import ( "fmt" "go/scanner" "go/token" + "log/slog" "reflect" "strings" "text/template" "database/sql/driver" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/proteus/mapper" "github.com/jonbodner/stackerr" ) @@ -248,7 +248,7 @@ func validIdentifier(ctx context.Context, curVar string) (string, error) { loop: for { pos, tok, lit := s.Scan() - logger.Log(ctx, logger.DEBUG, fmt.Sprintf("%s\t%s\t%q\n", fset.Position(pos), tok, lit)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintf("%s\t%s\t%q\n", fset.Position(pos), tok, lit)) switch tok { case token.EOF: if first || lastPeriod { diff --git a/builder_test.go b/builder_test.go index daf7f1e..a0537b1 100644 --- a/builder_test.go +++ b/builder_test.go @@ -2,11 +2,10 @@ package proteus import ( "context" - "github.com/google/go-cmp/cmp" "reflect" "testing" - "github.com/jonbodner/proteus/logger" + "github.com/google/go-cmp/cmp" ) func TestFixNameForTemplate(t *testing.T) { @@ -123,9 +122,9 @@ func Test_convertToPositionalParameters(t *testing.T) { }{ // TODO: Add test cases. } - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() for _, tt := range tests { - got, got1, err := buildFixedQueryAndParamOrder(c, tt.args.query, tt.args.paramMap, tt.args.funcType, tt.args.pa) + got, got1, err := buildFixedQueryAndParamOrder(ctx, tt.args.query, tt.args.paramMap, tt.args.funcType, tt.args.pa) if (err != nil) != tt.wantErr { t.Errorf("%q. buildFixedQueryAndParamOrder() error = %v, wantErr %v", tt.name, err, tt.wantErr) continue @@ -206,9 +205,9 @@ func Test_validIdentifier(t *testing.T) { }{ // TODO: Add test cases. } - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() for _, tt := range tests { - got, err := validIdentifier(c, tt.args.curVar) + got, err := validIdentifier(ctx, tt.args.curVar) if (err != nil) != tt.wantErr { t.Errorf("%q. validIdentifier() error = %v, wantErr %v", tt.name, err, tt.wantErr) continue diff --git a/cmd/null/main.go b/cmd/null/main.go index 454958d..2fe59dd 100644 --- a/cmd/null/main.go +++ b/cmd/null/main.go @@ -4,10 +4,10 @@ import ( "context" "database/sql" "fmt" + "log/slog" "os" "github.com/jonbodner/proteus" - "github.com/jonbodner/proteus/logger" _ "github.com/lib/pq" ) @@ -35,11 +35,7 @@ type Product2Dao struct { type closer func(error) error func main() { - proteus.SetLogLevel(logger.DEBUG) - logger.Config(logger.LoggerFunc(func(vals ...interface{}) error { - fmt.Printf("%s: (%s) - %s\n", vals[1], vals[3], vals[5]) - return nil - })) + slog.SetLogLoggerLevel(slog.LevelDebug) var product2DaoPostgres Product2Dao err := proteus.Build(&product2DaoPostgres, proteus.Postgres) if err != nil { @@ -49,7 +45,7 @@ func main() { } func run(productDao Product2Dao) { - ctx := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() tx, closer := setupDBPostgres(ctx) var err error defer func() { @@ -63,16 +59,16 @@ func run(productDao Product2Dao) { populate(ctx, tx, productDao) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDao.FindByID(ctx, tx, 10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDao.FindByID(ctx, tx, 10))) cost := sql.NullFloat64{ Float64: 56.23, Valid: true, } p := Product2{10, "Thingie", cost} - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDao.Update(ctx, tx, p))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDao.FindByID(ctx, tx, 10))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDao.FindByNameAndCost(ctx, tx, "fred", 54.10))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDao.FindByNameAndCost(ctx, tx, "Thingie", 56.23))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDao.Update(ctx, tx, p))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDao.FindByID(ctx, tx, 10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDao.FindByNameAndCost(ctx, tx, "fred", 54.10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDao.FindByNameAndCost(ctx, tx, "Thingie", 56.23))) } func defineSchema(ctx context.Context, tx proteus.ContextWrapper) error { @@ -82,7 +78,7 @@ func defineSchema(ctx context.Context, tx proteus.ContextWrapper) error { ` _, err := tx.ExecContext(ctx, sqlStmt) if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintf("%q: %s\n", err, sqlStmt)) + slog.Log(ctx, slog.LevelError, fmt.Sprintf("%q: %s\n", err, sqlStmt)) return err } return nil @@ -92,13 +88,13 @@ func setupDBPostgres(ctx context.Context) (proteus.ContextWrapper, closer) { db, err := sql.Open("postgres", "postgres://pro_user:pro_pwd@localhost/proteus?sslmode=disable") if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) os.Exit(1) } tx, err := db.Begin() if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) os.Exit(1) } @@ -118,9 +114,9 @@ func populate(ctx context.Context, w proteus.ContextWrapper, productDao Product2 } rowCount, err := productDao.Insert(ctx, w, i, fmt.Sprintf("person%d", i), cost) if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) os.Exit(1) } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(rowCount)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(rowCount)) } } diff --git a/cmd/sample-ctx/main.go b/cmd/sample-ctx/main.go index 16500e5..0150044 100644 --- a/cmd/sample-ctx/main.go +++ b/cmd/sample-ctx/main.go @@ -4,10 +4,10 @@ import ( "context" "database/sql" "fmt" + "log/slog" "github.com/jonbodner/dbtimer" "github.com/jonbodner/proteus" - "github.com/jonbodner/proteus/logger" _ "github.com/lib/pq" ) @@ -46,10 +46,6 @@ func main() { dbtimer.SetTimerLoggerFunc(func(ti dbtimer.TimerInfo) { fmt.Printf("%s %s %v %v %d\n", ti.Method, ti.Query, ti.Args, ti.Err, ti.End.Sub(ti.Start).Nanoseconds()/1000) }) - logger.Config(logger.LoggerFunc(func(vals ...interface{}) error { - fmt.Printf("%s: (%s) - %+v\n", vals[1], vals[3], vals[5]) - return nil - })) ctx := context.Background() var productDAO ProductDAO @@ -62,7 +58,7 @@ func main() { } func run(setupDb setupDb, productDAO ProductDAO) { - ctx := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() db := setupDb(ctx, productDAO) defer db.Close() tx, err := db.Begin() @@ -71,36 +67,36 @@ func run(setupDb setupDb, productDAO ProductDAO) { } defer tx.Commit() - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByID(ctx, tx, 10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.FindByID(ctx, tx, 10))) cost := new(float64) *cost = 56.23 p := Product{10, "Thingie", cost} - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.Update(ctx, tx, p))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByID(ctx, tx, 10))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByNameAndCost(ctx, tx, "fred", 54.10))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByNameAndCost(ctx, tx, "Thingie", 56.23))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.Update(ctx, tx, p))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.FindByID(ctx, tx, 10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.FindByNameAndCost(ctx, tx, "fred", 54.10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.FindByNameAndCost(ctx, tx, "Thingie", 56.23))) //using a map of [string]interface{} works too! - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDMap(ctx, tx, 10)))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByNameAndCostMap(ctx, tx, "Thingie", 56.23)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDMap(ctx, tx, 10)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByNameAndCostMap(ctx, tx, "Thingie", 56.23)))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByID(ctx, tx, 11)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByID(ctx, tx, 11)))) m := map[string]interface{}{ "Id": 11, "Name": "bobbo", "Cost": 12.94, } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.UpdateMap(ctx, tx, m)))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByID(ctx, tx, 11)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.UpdateMap(ctx, tx, m)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByID(ctx, tx, 11)))) //searching using a slice - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSlice(ctx, tx, []int{1, 3, 5})))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceAndName(ctx, tx, []int{1, 3, 5}, "person1")))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceNameAndCost(ctx, tx, []int{1, 3, 5}, "person3", nil)))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceCostAndNameSlice(ctx, tx, []int{1, 3, 5}, []string{"person3", "person5"}, nil)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDSlice(ctx, tx, []int{1, 3, 5})))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDSliceAndName(ctx, tx, []int{1, 3, 5}, "person1")))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDSliceNameAndCost(ctx, tx, []int{1, 3, 5}, "person3", nil)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDSliceCostAndNameSlice(ctx, tx, []int{1, 3, 5}, []string{"person3", "person5"}, nil)))) //using positional parameters instead of names - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByNameAndCostUnlabeled(ctx, tx, "Thingie", 56.23)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByNameAndCostUnlabeled(ctx, tx, "Thingie", 56.23)))) } func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB { @@ -108,7 +104,7 @@ func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB { db, err := sql.Open("timer", "postgres postgres://pro_user:pro_pwd@localhost/proteus?sslmode=disable") if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) } sqlStmt := ` drop table if exists product; @@ -116,7 +112,7 @@ func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB { ` _, err = db.Exec(sqlStmt) if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintf("%q: %s\n", err, sqlStmt)) + slog.Log(ctx, slog.LevelError, fmt.Sprintf("%q: %s\n", err, sqlStmt)) return nil } populate(ctx, db, productDAO) @@ -126,7 +122,7 @@ func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB { func populate(ctx context.Context, db *sql.DB, productDao ProductDAO) { tx, err := db.Begin() if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) } defer tx.Commit() @@ -138,8 +134,8 @@ func populate(ctx context.Context, db *sql.DB, productDao ProductDAO) { } rowCount, err := productDao.Insert(ctx, tx, i, fmt.Sprintf("person%d", i), cost) if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(rowCount)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(rowCount)) } } diff --git a/cmd/sample/main.go b/cmd/sample/main.go index a082a69..5784806 100644 --- a/cmd/sample/main.go +++ b/cmd/sample/main.go @@ -4,10 +4,10 @@ import ( "context" "database/sql" "fmt" + "log/slog" "github.com/jonbodner/dbtimer" "github.com/jonbodner/proteus" - "github.com/jonbodner/proteus/logger" _ "github.com/lib/pq" ) @@ -46,10 +46,6 @@ func main() { dbtimer.SetTimerLoggerFunc(func(ti dbtimer.TimerInfo) { fmt.Printf("%s %s %v %v %d\n", ti.Method, ti.Query, ti.Args, ti.Err, ti.End.Sub(ti.Start).Nanoseconds()/1000) }) - logger.Config(logger.LoggerFunc(func(vals ...interface{}) error { - fmt.Printf("%s: (%s) - %+v\n", vals[1], vals[3], vals[5]) - return nil - })) var productDaoPostgres ProductDAO err := proteus.Build(&productDaoPostgres, proteus.Postgres) @@ -61,7 +57,7 @@ func main() { } func run(setupDb setupDb, productDAO ProductDAO) { - ctx := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() db := setupDb(ctx, productDAO) defer db.Close() tx, err := db.Begin() @@ -70,36 +66,36 @@ func run(setupDb setupDb, productDAO ProductDAO) { } defer tx.Commit() - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByID(tx, 10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.FindByID(tx, 10))) cost := new(float64) *cost = 56.23 p := Product{10, "Thingie", cost} - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.Update(tx, p))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByID(tx, 10))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByNameAndCost(tx, "fred", 54.10))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(productDAO.FindByNameAndCost(tx, "Thingie", 56.23))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.Update(tx, p))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.FindByID(tx, 10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.FindByNameAndCost(tx, "fred", 54.10))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(productDAO.FindByNameAndCost(tx, "Thingie", 56.23))) //using a map of [string]interface{} works too! - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDMap(tx, 10)))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByNameAndCostMap(tx, "Thingie", 56.23)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDMap(tx, 10)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByNameAndCostMap(tx, "Thingie", 56.23)))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByID(tx, 11)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByID(tx, 11)))) m := map[string]interface{}{ "Id": 11, "Name": "bobbo", "Cost": 12.94, } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.UpdateMap(tx, m)))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByID(tx, 11)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.UpdateMap(tx, m)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByID(tx, 11)))) //searching using a slice - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSlice(tx, []int{1, 3, 5})))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceAndName(tx, []int{1, 3, 5}, "person1")))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceNameAndCost(tx, []int{1, 3, 5}, "person3", nil)))) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByIDSliceCostAndNameSlice(tx, []int{1, 3, 5}, []string{"person3", "person5"}, nil)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDSlice(tx, []int{1, 3, 5})))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDSliceAndName(tx, []int{1, 3, 5}, "person1")))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDSliceNameAndCost(tx, []int{1, 3, 5}, "person3", nil)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByIDSliceCostAndNameSlice(tx, []int{1, 3, 5}, []string{"person3", "person5"}, nil)))) //using positional parameters instead of names - logger.Log(ctx, logger.DEBUG, fmt.Sprintln((productDAO.FindByNameAndCostUnlabeled(tx, "Thingie", 56.23)))) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln((productDAO.FindByNameAndCostUnlabeled(tx, "Thingie", 56.23)))) } func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB { @@ -107,7 +103,7 @@ func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB { db, err := sql.Open("timer", "postgres postgres://pro_user:pro_pwd@localhost/proteus?sslmode=disable") if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) } sqlStmt := ` drop table if exists product; @@ -115,7 +111,7 @@ func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB { ` _, err = db.Exec(sqlStmt) if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintf("%q: %s\n", err, sqlStmt)) + slog.Log(ctx, slog.LevelError, fmt.Sprintf("%q: %s\n", err, sqlStmt)) return nil } populate(ctx, db, productDAO) @@ -125,7 +121,7 @@ func setupDbPostgres(ctx context.Context, productDAO ProductDAO) *sql.DB { func populate(ctx context.Context, db *sql.DB, productDao ProductDAO) { tx, err := db.Begin() if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) } defer tx.Commit() @@ -137,8 +133,8 @@ func populate(ctx context.Context, db *sql.DB, productDao ProductDAO) { } rowCount, err := productDao.Insert(tx, i, fmt.Sprintf("person%d", i), cost) if err != nil { - logger.Log(ctx, logger.FATAL, fmt.Sprintln(err)) + slog.Log(ctx, slog.LevelError, fmt.Sprintln(err)) } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(rowCount)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(rowCount)) } } diff --git a/go.mod b/go.mod index 7ab2b39..a3ea2d7 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,5 @@ require ( require ( github.com/felixge/fgprof v0.9.3 // indirect github.com/google/pprof v0.0.0-20230429030804-905365eefe3e // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect - github.com/stretchr/testify v1.8.0 // indirect golang.org/x/sys v0.7.0 // indirect ) diff --git a/go.sum b/go.sum index ae89686..2db9441 100644 --- a/go.sum +++ b/go.sum @@ -16,47 +16,29 @@ github.com/google/pprof v0.0.0-20230429030804-905365eefe3e/go.mod h1:79YE0hCXdHa github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/jonbodner/dbtimer v0.0.0-20170410163237-7002f3758ae1 h1:mgFL7UFb88FOlSVgVoIRGJ4yKlkfp8KcXHqy7no+lEU= github.com/jonbodner/dbtimer v0.0.0-20170410163237-7002f3758ae1/go.mod h1:PjOlFbeJKs+4b2CvuN9FFF8Ed8cZ6FHWPb5tLK2QKOM= -github.com/jonbodner/multierr v0.0.0-20200223210354-ace728439446 h1:3JlpjXILq02AhL5iNC/T6M+UwkKvcKq7/h0LPYP+R44= -github.com/jonbodner/multierr v0.0.0-20200223210354-ace728439446/go.mod h1:BN5BmT8XsFrnRDB/uErUiXlda9UQs2YhrlFFtf74JaM= github.com/jonbodner/multierr v1.0.0 h1:qgMyn9QNDnIKuPVOxAh4/kE8E0KBVtREEpzgQ+z6nR8= github.com/jonbodner/multierr v1.0.0/go.mod h1:BN5BmT8XsFrnRDB/uErUiXlda9UQs2YhrlFFtf74JaM= github.com/jonbodner/stackerr v1.0.0 h1:rAe+Fh13cfC9IGuKE4YWiVCzwt9zce9Saldpc8fYEIM= github.com/jonbodner/stackerr v1.0.0/go.mod h1:In1ShJr570PDuDHbYfymEQle+H7PgY9KpT+alyk0nEM= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= -github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/pkg/profile v1.5.0 h1:042Buzk+NhDI+DeSAA62RwJL8VAuZUMQZUjCsRz1Mug= -github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rickar/props v0.0.0-20170718221555-0b06aeb2f037 h1:HFsTO5S+nnw/Xs9lRYF+UUJvH8wMSRMRal321W0hfdY= -github.com/rickar/props v0.0.0-20170718221555-0b06aeb2f037/go.mod h1:F1p8BNM4IXv2UcptwSp8HJOapKurodd/PYu1D6Gtn9Y= github.com/rickar/props v1.0.0 h1:3C3j+wF2/XbQ/sCGRK8DkCLwuRvzqToMvDzmdxHwCsg= github.com/rickar/props v1.0.0/go.mod h1:VVywBJXdOY3IwDtBmgAMIZs/XM/CtMKSJzu5dsHYwEY= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -64,4 +46,5 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IV golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/line_logger.go b/line_logger.go new file mode 100644 index 0000000..1c1ef14 --- /dev/null +++ b/line_logger.go @@ -0,0 +1,25 @@ +package proteus + +import ( + "bytes" + "log/slog" + "strings" + "testing" +) + +func RegisterLineLogger(t *testing.T) func() []string { + defaultLogger := slog.Default() + t.Cleanup(func() { + slog.SetDefault(defaultLogger) + }) + var buf bytes.Buffer + logger := slog.New(slog.NewTextHandler(&buf, &slog.HandlerOptions{ + Level: slog.LevelDebug, + })) + slog.SetDefault(logger) + return func() []string { + lines := strings.Split(strings.TrimSpace(buf.String()), "\n") + buf.Reset() + return lines + } +} diff --git a/logger/logger.go b/logger/logger.go deleted file mode 100644 index 35a5bc4..0000000 --- a/logger/logger.go +++ /dev/null @@ -1,182 +0,0 @@ -package logger - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "os" - "sync" - "time" -) - -type Level int - -const ( - OFF Level = iota - TRACE - DEBUG - INFO - WARN - ERROR - FATAL -) - -func (l Level) String() string { - switch l { - case OFF: - return "OFF" - case TRACE: - return "TRACE" - case DEBUG: - return "DEBUG" - case INFO: - return "INFO" - case WARN: - return "WARN" - case ERROR: - return "ERROR" - case FATAL: - return "FATAL" - default: - return "" - } -} - -func (l Level) MarshalJSON() ([]byte, error) { - return json.Marshal(l.String()) -} - -type key int - -const ( - level key = iota - values -) - -type Pair struct { - Key string - Value interface{} -} - -type Logger interface { - Log(vals ...interface{}) error -} - -type LoggerFunc func(vals ...interface{}) error - -func (lf LoggerFunc) Log(vals ...interface{}) error { - return lf(vals...) -} - -var impl Logger = DefaultLogger{Writer: os.Stdout} -var rw sync.RWMutex - -func Config(i Logger) { - rw.Lock() - defer rw.Unlock() - impl = i -} - -func WithLevel(ctx context.Context, l Level) context.Context { - return context.WithValue(ctx, level, l) -} - -func WithValues(ctx context.Context, vals ...Pair) context.Context { - //if there are any existing pairs, copy them into this vals as well - var pairs []Pair - if curVals, ok := ctx.Value(values).([]Pair); ok { - pairs = append(pairs, curVals...) - } - pairs = append(pairs, vals...) - - return context.WithValue(ctx, values, pairs) -} - -func LevelFromContext(ctx context.Context) (Level, bool) { - if l := ctx.Value(level); l != nil { - return l.(Level), true - } - return 0, false -} - -func ValuesFromContext(ctx context.Context) ([]Pair, bool) { - if p := ctx.Value(values); p != nil { - return p.([]Pair), true - } - return nil, false -} - -func Log(ctx context.Context, l Level, message string, vals ...Pair) { - curLevelVal := ctx.Value(level) - if curLevel, ok := curLevelVal.(Level); !ok || curLevel == OFF || curLevel > l { - return - } - outVals := []interface{}{"time", time.Now().UTC(), "level", l, "message", message} - - if curVals, ok := ctx.Value(values).([]Pair); ok { - for _, v := range curVals { - outVals = append(outVals, v.Key) - outVals = append(outVals, v.Value) - } - } - - for _, v := range vals { - outVals = append(outVals, v.Key) - outVals = append(outVals, v.Value) - } - rw.RLock() - defer rw.RUnlock() - impl.Log(outVals...) -} - -type Formatter interface { - Format(vals ...interface{}) string -} - -type FormatterFunc func(vals ...interface{}) string - -func (ff FormatterFunc) Format(vals ...interface{}) string { - return ff(vals...) -} - -type DefaultLogger struct { - io.Writer - Formatter Formatter -} - -func (dl DefaultLogger) Log(vals ...interface{}) error { - if dl.Writer == nil { - return nil - } - var out string - if dl.Formatter == nil { - out = jsonOutput(vals...) - } else { - out = dl.Formatter.Format(vals...) - } - _, err := dl.Writer.Write([]byte(out)) - return err -} - -func jsonOutput(vals ...interface{}) string { - var out bytes.Buffer - out.WriteString("{") - for i := 0; i < len(vals); i += 2 { - out.WriteString(fmt.Sprintf(`%s:%s`, toJSONString(vals[i]), toJSONString(vals[i+1]))) - if i < len(vals)-2 { - out.WriteRune(',') - } - } - out.WriteString("}\n") - return out.String() -} - -func toJSONString(i interface{}) string { - out, err := json.Marshal(i) - if err != nil { - out, _ = json.Marshal(err.Error()) - } - return string(out) -} diff --git a/logger/logger_test.go b/logger/logger_test.go deleted file mode 100644 index b6271e0..0000000 --- a/logger/logger_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package logger_test - -import ( - "context" - "testing" - - "github.com/jonbodner/proteus/logger" -) - -func TestLogging(t *testing.T) { - logger.Log(logger.WithLevel(context.Background(), logger.DEBUG), logger.DEBUG, "this is a message", []logger.Pair{ - {"Foo", "Bar"}, - {"int", 1}, - {"bool", true}, - {"float", 3.14}, - {"struct", struct { - A int - B string - }{1, "he\"ll:{},o"}}, - }...) -} diff --git a/mapper/extract.go b/mapper/extract.go index f6c64c5..cf4612b 100644 --- a/mapper/extract.go +++ b/mapper/extract.go @@ -4,10 +4,10 @@ import ( "context" "database/sql/driver" "fmt" + "log/slog" "reflect" "strconv" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/stackerr" ) @@ -65,10 +65,10 @@ func Extract(ctx context.Context, s interface{}, path []string) (interface{}, er if sv.Type().Key().Kind() != reflect.String { return nil, stackerr.New("cannot extract value; map does not have a string key") } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(path[1])) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(sv.MapKeys())) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(path[1])) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(sv.MapKeys())) v := sv.MapIndex(reflect.ValueOf(path[1])) - logger.Log(ctx, logger.DEBUG, fmt.Sprintln(v)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln(v)) if !v.IsValid() { return nil, stackerr.New("cannot extract value; no such map key " + path[1]) } diff --git a/mapper/extract_test.go b/mapper/extract_test.go index 5d2b4e2..073db3b 100644 --- a/mapper/extract_test.go +++ b/mapper/extract_test.go @@ -7,14 +7,13 @@ import ( "testing" "github.com/jonbodner/proteus/cmp" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/stackerr" ) func TestExtractPointer(t *testing.T) { - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() f := func(in interface{}, path []string, expected *int) { - v, err := Extract(c, in, path) + v, err := Extract(ctx, in, path) if err != nil { t.Errorf("Expected no error, got %s", err) } @@ -74,9 +73,9 @@ func TestExtractPointer(t *testing.T) { } func TestExtract(t *testing.T) { - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() f := func(in interface{}, path []string, expected int) { - v, err := Extract(c, in, path) + v, err := Extract(ctx, in, path) if err != nil { t.Errorf("Expected no error, got %s", err) } @@ -118,9 +117,9 @@ func TestExtract(t *testing.T) { } func TestExtractFail(t *testing.T) { - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() f := func(in interface{}, path []string, msg string) { - _, err := Extract(c, in, path) + _, err := Extract(ctx, in, path) if err == nil { t.Errorf("Expected an error %s, got none", msg) } @@ -146,12 +145,12 @@ func TestExtractFail(t *testing.T) { } func TestExtractType(t *testing.T) { - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() fmt.Println("asdf") type pp struct { Name string Cost float64 } - myType, err := ExtractType(c, reflect.TypeOf(pp{}), []string{"p", "Name"}) + myType, err := ExtractType(ctx, reflect.TypeOf(pp{}), []string{"p", "Name"}) fmt.Printf("%v, %s, %v\n", myType, myType.Kind(), err) } diff --git a/mapper/mapper.go b/mapper/mapper.go index eb68c03..7468888 100644 --- a/mapper/mapper.go +++ b/mapper/mapper.go @@ -4,11 +4,11 @@ import ( "context" "database/sql" "fmt" + "log/slog" "reflect" "strings" "unsafe" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/stackerr" ) @@ -19,7 +19,7 @@ func ptrConverter(ctx context.Context, isPtr bool, sType reflect.Type, out refle if isPtr { out2 := reflect.New(sType) k := out.Type().Kind() - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("kind of out", k)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("kind of out", k)) if (k == reflect.Interface || k == reflect.Ptr) && out.IsNil() { out2 = reflect.NewAt(sType, unsafe.Pointer(nil)) } else { @@ -148,7 +148,7 @@ var ( ) func buildStruct(ctx context.Context, sType reflect.Type, cols []string, vals []interface{}, colFieldMap map[string]fieldInfo) (reflect.Value, error) { - logger.Log(ctx, logger.DEBUG, fmt.Sprintf("sType: %s cols: %v vals: %+v colFieldMap: %+v", sType, cols, vals, colFieldMap)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintf("sType: %s cols: %v vals: %+v colFieldMap: %+v", sType, cols, vals, colFieldMap)) out := reflect.New(sType).Elem() for k, v := range cols { if sf, ok := colFieldMap[v]; ok { @@ -167,12 +167,12 @@ func buildStructInner(ctx context.Context, sType reflect.Type, out reflect.Value field := out.Field(sf.pos[depth]) curFieldType := sf.fieldType[depth] if curFieldType.Kind() == reflect.Ptr { - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("isPtr", sf, rv, rv.Type(), rv.Elem(), curVal, sType)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("isPtr", sf, rv, rv.Type(), rv.Elem(), curVal, sType)) if rv.Elem().IsNil() { - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("nil", sf, rv, curVal, sType)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("nil", sf, rv, curVal, sType)) return nil } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("isPtr Not Nil", rv.Elem().Type())) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("isPtr Not Nil", rv.Elem().Type())) if curFieldType.Implements(scannerType) { toScan := (reflect.New(curFieldType).Elem().Interface()).(sql.Scanner) err := toScan.Scan(rv.Elem().Elem().Interface()) @@ -184,7 +184,7 @@ func buildStructInner(ctx context.Context, sType reflect.Type, out reflect.Value field.Set(reflect.New(curFieldType.Elem())) field.Elem().Set(rv.Elem().Elem().Convert(curFieldType.Elem())) } else { - logger.Log(ctx, logger.ERROR, fmt.Sprintln("can't find the field")) + slog.Log(ctx, slog.LevelError, fmt.Sprintln("can't find the field")) return stackerr.Errorf("unable to assign pointer to value %v of type %v to struct field %s of type %v", rv.Elem().Elem(), rv.Elem().Elem().Type(), sf.name[depth], curFieldType) } } else { @@ -201,12 +201,12 @@ func buildStructInner(ctx context.Context, sType reflect.Type, out reflect.Value return err } } else if rv.Elem().IsNil() { - logger.Log(ctx, logger.ERROR, fmt.Sprintln("Attempting to assign a nil to a non-pointer field")) + slog.Log(ctx, slog.LevelError, fmt.Sprintln("Attempting to assign a nil to a non-pointer field")) return stackerr.Errorf("unable to assign nil value to non-pointer struct field %s of type %v", sf.name[depth], curFieldType) } else if rv.Elem().Elem().Type().ConvertibleTo(curFieldType) { field.Set(rv.Elem().Elem().Convert(curFieldType)) } else { - logger.Log(ctx, logger.ERROR, fmt.Sprintln("can't find the field")) + slog.Log(ctx, slog.LevelError, fmt.Sprintln("can't find the field")) return stackerr.Errorf("unable to assign value %v of type %v to struct field %s of type %v", rv.Elem().Elem(), rv.Elem().Elem().Type(), sf.name[depth], curFieldType) } } diff --git a/mapper_test.go b/mapper_test.go index af03874..2167642 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -4,22 +4,21 @@ import ( "context" "database/sql" "fmt" - "log" + "log/slog" "math" "reflect" "testing" "github.com/jonbodner/proteus/cmp" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/proteus/mapper" "github.com/jonbodner/stackerr" ) func TestMapRows(t *testing.T) { - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() //todo - b, _ := mapper.MakeBuilder(c, reflect.TypeOf(10)) - v, err := mapRows(c, nil, b) + b, _ := mapper.MakeBuilder(ctx, reflect.TypeOf(10)) + v, err := mapRows(ctx, nil, b) if v != nil { t.Error("Expected nil when passing in nil rows") } @@ -30,13 +29,15 @@ func TestMapRows(t *testing.T) { } func setupDb(t *testing.T) *sql.DB { + ctx := context.Background() if testing.Short() { t.Skip("skipping postgres test in short mode") } db, err := sql.Open("postgres", "postgres://pro_user:pro_pwd@localhost/proteus?sslmode=disable") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } sqlStmt := ` drop table if exists product; @@ -44,18 +45,20 @@ func setupDb(t *testing.T) *sql.DB { ` _, err = db.Exec(sqlStmt) if err != nil { - log.Fatalf("%q: %s\n", err, sqlStmt) - panic(err) + slog.Log(ctx, slog.LevelError, "err", "error", slog.AnyValue(err), "query", slog.StringValue(sqlStmt)) + t.FailNow() } tx, err := db.Begin() if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } defer tx.Commit() stmt, err := tx.Prepare("insert into product(id, name, cost) values($1, $2, $3)") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } defer stmt.Close() for i := 0; i < 5; i++ { @@ -66,7 +69,8 @@ func setupDb(t *testing.T) *sql.DB { } _, err = stmt.Exec(i, name, 1.1*float64(i)) if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } } return db @@ -85,14 +89,15 @@ func TestBuildStruct(t *testing.T) { rows, err := db.Query("select id, name, cost from product") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } defer rows.Close() pType := reflect.TypeOf((*Product)(nil)).Elem() - c := logger.WithLevel(context.Background(), logger.DEBUG) - b, _ := mapper.MakeBuilder(c, pType) + ctx := context.Background() + b, _ := mapper.MakeBuilder(ctx, pType) for i := 0; i < 5; i++ { - prod, err := mapRows(c, rows, b) + prod, err := mapRows(ctx, rows, b) if err != nil { t.Fatal(err) } @@ -125,7 +130,7 @@ func TestBuildStruct(t *testing.T) { if rows.Next() { t.Error("Expected no more rows, but had some") } - prod, err := mapRows(c, rows, b) + prod, err := mapRows(ctx, rows, b) if prod != nil || err != nil { t.Error("Expected to be at end, but wasn't") } @@ -138,18 +143,20 @@ func TestBuildPrimitive(t *testing.T) { //primitive stmt, err := db.Prepare("select name from product where id = $1") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } defer stmt.Close() rows, err := stmt.Query("4") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } sType := reflect.TypeOf("") - c := logger.WithLevel(context.Background(), logger.DEBUG) - b, _ := mapper.MakeBuilder(c, sType) - s, err := mapRows(c, rows, b) + ctx := context.Background() + b, _ := mapper.MakeBuilder(ctx, sType) + s, err := mapRows(ctx, rows, b) if err != nil { t.Error(err) } @@ -164,14 +171,15 @@ func TestBuildPrimitive(t *testing.T) { t.Errorf("Expected %s, got %s", "person4", s2) } - s, err = mapRows(c, rows, b) + s, err = mapRows(ctx, rows, b) if s != nil || err != nil { t.Error("Expected to be at end, but wasn't") } _, err = db.Exec("delete from product") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } } @@ -182,18 +190,20 @@ func TestBuildPrimitiveNilFail(t *testing.T) { //primitive stmt, err := db.Prepare("select name from product where id = $1") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } defer stmt.Close() rows, err := stmt.Query("3") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } sType := reflect.TypeOf("") - c := logger.WithLevel(context.Background(), logger.DEBUG) - b, _ := mapper.MakeBuilder(c, sType) - _, err = mapRows(c, rows, b) + ctx := context.Background() + b, _ := mapper.MakeBuilder(ctx, sType) + _, err = mapRows(ctx, rows, b) if err == nil { t.Error("Expected error didn't get one") } @@ -201,14 +211,15 @@ func TestBuildPrimitiveNilFail(t *testing.T) { t.Errorf("Expected error message '%s', got '%s'", "attempting to return nil for non-pointer type string", err.Error()) } - s, err := mapRows(c, rows, b) + s, err := mapRows(ctx, rows, b) if s != nil || err != nil { t.Error("Expected to be at end, but wasn't") } _, err = db.Exec("delete from product") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } } @@ -219,18 +230,20 @@ func TestBuildPrimitivePtr(t *testing.T) { //primitive stmt, err := db.Prepare("select name from product where id = $1") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } defer stmt.Close() rows, err := stmt.Query("4") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } sType := reflect.TypeOf((*string)(nil)) - c := logger.WithLevel(context.Background(), logger.DEBUG) - b, _ := mapper.MakeBuilder(c, sType) - s, err := mapRows(c, rows, b) + ctx := context.Background() + b, _ := mapper.MakeBuilder(ctx, sType) + s, err := mapRows(ctx, rows, b) if err != nil { t.Error(err) } @@ -246,14 +259,15 @@ func TestBuildPrimitivePtr(t *testing.T) { } } - s, err = mapRows(c, rows, b) + s, err = mapRows(ctx, rows, b) if s != nil || err != nil { t.Error("Expected to be at end, but wasn't") } _, err = db.Exec("delete from product") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } } @@ -264,18 +278,20 @@ func TestBuildPrimitivePtrNil(t *testing.T) { //primitive stmt, err := db.Prepare("select name from product where id = $1") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } defer stmt.Close() rows, err := stmt.Query("3") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } sType := reflect.TypeOf((*string)(nil)) - c := logger.WithLevel(context.Background(), logger.DEBUG) - b, _ := mapper.MakeBuilder(c, sType) - s, err := mapRows(c, rows, b) + ctx := context.Background() + b, _ := mapper.MakeBuilder(ctx, sType) + s, err := mapRows(ctx, rows, b) if err != nil { t.Error(err) } @@ -288,14 +304,15 @@ func TestBuildPrimitivePtrNil(t *testing.T) { } } - s, err = mapRows(c, rows, b) + s, err = mapRows(ctx, rows, b) if s != nil || err != nil { t.Error("Expected to be at end, but wasn't") } _, err = db.Exec("delete from product") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } } @@ -305,17 +322,18 @@ func TestBuildMap(t *testing.T) { rows, err := db.Query("select id, name, cost from product") if err != nil { - log.Fatal(err) + slog.Error("err", "error", slog.AnyValue(err)) + t.FailNow() } defer rows.Close() var m map[string]interface{} mType := reflect.TypeOf(m) - c := logger.WithLevel(context.Background(), logger.DEBUG) - b, _ := mapper.MakeBuilder(c, mType) + ctx := context.Background() + b, _ := mapper.MakeBuilder(ctx, mType) for i := 0; i < 5; i++ { - prod, err := mapRows(c, rows, b) + prod, err := mapRows(ctx, rows, b) if err != nil { t.Fatal(err) } @@ -363,7 +381,7 @@ func TestBuildMap(t *testing.T) { if rows.Next() { t.Error("Expected no more rows, but had some") } - prod, err := mapRows(c, rows, b) + prod, err := mapRows(ctx, rows, b) if prod != nil || err != nil { t.Error("Expected to be at end, but wasn't") } diff --git a/proteus.go b/proteus.go index 6fbfc48..4d8bec5 100644 --- a/proteus.go +++ b/proteus.go @@ -2,14 +2,13 @@ package proteus import ( "context" + "log/slog" "reflect" - "sync" "fmt" "strings" "github.com/jonbodner/multierr" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/stackerr" ) @@ -66,15 +65,6 @@ func (pe Error) Unwrap() error { return pe.OriginalError } -var l = logger.OFF -var rw sync.RWMutex - -func SetLogLevel(ll logger.Level) { - rw.Lock() - l = ll - rw.Unlock() -} - // ShouldBuild works like Build, with two differences: // // 1. It will not populate any function fields if there are errors. @@ -83,13 +73,6 @@ func SetLogLevel(ll logger.Level) { // when the generated functions are invoked. This overrides any logging level specified using the SetLogLevel // function. func ShouldBuild(ctx context.Context, dao interface{}, paramAdapter ParamAdapter, mappers ...QueryMapper) error { - //if log level is set and not in the context, use it - if _, ok := logger.LevelFromContext(ctx); !ok && l != logger.OFF { - rw.RLock() - ctx = logger.WithLevel(ctx, l) - rw.RUnlock() - } - daoPointerType := reflect.TypeOf(dao) //must be a pointer to struct if daoPointerType.Kind() != reflect.Ptr { @@ -177,9 +160,7 @@ func ShouldBuild(ctx context.Context, dao interface{}, paramAdapter ParamAdapter // As of version v0.12.0, all errors found during building will be reported back. Also, prefer using // proteus.ShouldBuild over proteus.Build. func Build(dao interface{}, paramAdapter ParamAdapter, mappers ...QueryMapper) error { - rw.RLock() - ctx := logger.WithLevel(context.Background(), l) - rw.RUnlock() + ctx := context.Background() daoPointerType := reflect.TypeOf(dao) //must be a pointer to struct if daoPointerType.Kind() != reflect.Ptr { @@ -218,7 +199,7 @@ func Build(dao interface{}, paramAdapter ParamAdapter, mappers ...QueryMapper) e //validate to make sure that the function matches what we expect hasCtx, err := validateFunction(funcType) if err != nil { - logger.Log(ctx, logger.WARN, fmt.Sprintln("skipping function", curField.Name, "due to error:", err.Error())) + slog.Log(ctx, slog.LevelWarn, fmt.Sprintln("skipping function", curField.Name, "due to error:", err.Error())) outErr = multierr.Append(outErr, err) continue } @@ -238,14 +219,14 @@ func Build(dao interface{}, paramAdapter ParamAdapter, mappers ...QueryMapper) e //check to see if the query is in a QueryMapper query, err = lookupQuery(query, mappers) if err != nil { - logger.Log(ctx, logger.WARN, fmt.Sprintln("skipping function", curField.Name, "due to error:", err.Error())) + slog.Log(ctx, slog.LevelWarn, fmt.Sprintln("skipping function", curField.Name, "due to error:", err.Error())) outErr = multierr.Append(outErr, err) continue } implementation, err := makeImplementation(ctx, funcType, query, paramAdapter, nameOrderMap) if err != nil { - logger.Log(ctx, logger.WARN, fmt.Sprintln("skipping function", curField.Name, "due to error:", err.Error())) + slog.Log(ctx, slog.LevelWarn, fmt.Sprintln("skipping function", curField.Name, "due to error:", err.Error())) outErr = multierr.Append(outErr, err) continue } @@ -267,7 +248,7 @@ var ( ) func validateFunction(funcType reflect.Type) (bool, error) { - //first parameter is Executor + //the first parameter is Executor if funcType.NumIn() == 0 { return false, stackerr.New("need to supply an Executor or Querier parameter") } @@ -315,7 +296,7 @@ func validateFunction(funcType reflect.Type) (bool, error) { } } - //if 1 or 2, 1st param is not a channel (handle map, I guess) + //if 1 or 2, the 1st param is not a channel (handle map, I guess) if funcType.NumOut() > 0 { if funcType.Out(0).Kind() == reflect.Chan { return false, stackerr.New("1st output parameter cannot be a channel") @@ -352,7 +333,7 @@ func makeImplementation(ctx context.Context, funcType reflect.Type, query string case fType.Implements(qType): return makeQuerierImplementation(ctx, funcType, fixedQuery, paramOrder) } - //this should impossible, since we already validated that the first parameter is either an executor or a querier + //this should be impossible, since we already validated that the first parameter is either an executor or a querier return nil, stackerr.New("first parameter must be of type Executor or Querier") } diff --git a/proteus_function.go b/proteus_function.go index 8e736bd..4862aa8 100644 --- a/proteus_function.go +++ b/proteus_function.go @@ -4,10 +4,10 @@ import ( "context" "database/sql" "fmt" + "log/slog" "reflect" "strings" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/proteus/mapper" "github.com/jonbodner/stackerr" ) @@ -25,13 +25,6 @@ func NewBuilder(adapter ParamAdapter, mappers ...QueryMapper) Builder { } func (fb Builder) BuildFunction(ctx context.Context, f interface{}, query string, names []string) error { - //if log level is set and not in the context, use it - if _, ok := logger.LevelFromContext(ctx); !ok && l != logger.OFF { - rw.RLock() - ctx = logger.WithLevel(ctx, l) - rw.RUnlock() - } - // make sure that f is of the right type (pointer to function) funcPointerType := reflect.TypeOf(f) //must be a pointer to func @@ -101,31 +94,17 @@ func (fb Builder) Exec(ctx context.Context, e ContextExecutor, query string, par } func (fb Builder) ExecResult(ctx context.Context, e ContextExecutor, query string, params map[string]interface{}) (sql.Result, error) { - //if log level is set and not in the context, use it - if _, ok := logger.LevelFromContext(ctx); !ok && l != logger.OFF { - rw.RLock() - ctx = logger.WithLevel(ctx, l) - rw.RUnlock() - } - finalQuery, queryArgs, err := fb.setupDynamicQueries(ctx, query, params) if err != nil { return nil, err } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) result, err := e.ExecContext(ctx, finalQuery, queryArgs...) return result, err } func (fb Builder) Query(ctx context.Context, q ContextQuerier, query string, params map[string]interface{}, output interface{}) error { - //if log level is set and not in the context, use it - if _, ok := logger.LevelFromContext(ctx); !ok && l != logger.OFF { - rw.RLock() - ctx = logger.WithLevel(ctx, l) - rw.RUnlock() - } - // make sure that output is a pointer to something outputPointerType := reflect.TypeOf(output) if outputPointerType.Kind() != reflect.Ptr { @@ -137,7 +116,7 @@ func (fb Builder) Query(ctx context.Context, q ContextQuerier, query string, par return err } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) rows, err := q.QueryContext(ctx, finalQuery, queryArgs...) if err != nil { return err diff --git a/proteus_function_test.go b/proteus_function_test.go index eb4b150..200aaff 100644 --- a/proteus_function_test.go +++ b/proteus_function_test.go @@ -2,11 +2,9 @@ package proteus import ( "context" - "fmt" "testing" "github.com/google/go-cmp/cmp" - "github.com/jonbodner/proteus/logger" ) func TestBuilder_BuildFunctionErrors(t *testing.T) { @@ -120,16 +118,13 @@ func TestBuilder_BuildFunction(t *testing.T) { t.Error("Unexpected output: ", p) } - var lines []string - logger.Config(logger.LoggerFunc(func(vals ...interface{}) error { - lines = append(lines, fmt.Sprintln(vals)) - return nil - })) - SetLogLevel(logger.DEBUG) + // need a lines logger + linesFunc := RegisterLineLogger(t) err = b.BuildFunction(ctx, &g, "SELECT * FROM PERSON WHERE id = :id:", []string{"id"}) if err != nil { t.Fatalf("build function 2a failed: %v", err) } + lines := linesFunc() if len(lines) != 3 { t.Errorf("Expected %d lines, got %d: %#v", 3, len(lines), lines) } @@ -142,16 +137,8 @@ func TestBuilder_Execute(t *testing.T) { defer db.Close() ctx := context.Background() - var lines []string - logger.Config(logger.LoggerFunc(func(vals ...interface{}) error { - lines = append(lines, fmt.Sprintln(vals)) - return nil - })) - data := []struct { name string - ctx context.Context - logLevel logger.Level query string params map[string]interface{} rows int64 @@ -204,16 +191,7 @@ func TestBuilder_Execute(t *testing.T) { errMsg: "no query found for name nope", }, { - name: "logging context", - ctx: logger.WithLevel(ctx, logger.DEBUG), - query: "INSERT INTO PERSON(name, age) VALUES(:name:, :age:)", - params: map[string]interface{}{"name": "Fred", "age": 20}, - rows: 1, - lineCount: 7, - }, - { - name: "logging default", - logLevel: logger.DEBUG, + name: "logging", query: "INSERT INTO PERSON(name, age) VALUES(:name:, :age:)", params: map[string]interface{}{"name": "Fred", "age": 20}, rows: 1, @@ -222,13 +200,8 @@ func TestBuilder_Execute(t *testing.T) { } for _, v := range data { t.Run(v.name, func(t *testing.T) { - lines = nil - SetLogLevel(v.logLevel) - c := ctx - if v.ctx != nil { - c = v.ctx - } - rows, err := b.Exec(c, db, v.query, v.params) + linesFunc := RegisterLineLogger(t) + rows, err := b.Exec(ctx, db, v.query, v.params) var errMsg string if err != nil { errMsg = err.Error() @@ -239,11 +212,13 @@ func TestBuilder_Execute(t *testing.T) { if rows != v.rows { t.Error("Unexpected # rows: ", rows) } - if v.lineCount != len(lines) { - t.Errorf("Expected %d lines of debug, got %d: %#v", v.lineCount, len(lines), lines) + if v.lineCount > 0 { + lines := linesFunc() + if v.lineCount != len(lines) { + t.Errorf("Expected %d lines of debug, got %d: %#v", v.lineCount, len(lines), lines) + } } - lines = nil - result, err := b.ExecResult(c, db, v.query, v.params) + result, err := b.ExecResult(ctx, db, v.query, v.params) errMsg = "" if err != nil { errMsg = err.Error() @@ -259,8 +234,11 @@ func TestBuilder_Execute(t *testing.T) { if rowsAffected != v.rows { t.Error("Unexpected # rows: ", rows) } - if v.lineCount != len(lines) { - t.Errorf("Expected %d lines of debug, got %d: %#v", v.lineCount, len(lines), lines) + if v.lineCount > 0 { + lines := linesFunc() + if v.lineCount != len(lines) { + t.Errorf("Expected %d lines of debug, got %d: %#v", v.lineCount, len(lines), lines) + } } } }) @@ -293,16 +271,8 @@ func TestBuilder_Query(t *testing.T) { Age string `prof:"age"` } - var lines []string - logger.Config(logger.LoggerFunc(func(vals ...interface{}) error { - lines = append(lines, fmt.Sprintln(vals)) - return nil - })) - data := []struct { name string - ctx context.Context - logLevel logger.Level query string params map[string]interface{} out interface{} @@ -394,7 +364,6 @@ func TestBuilder_Query(t *testing.T) { }, { name: "nothing returned logging context", - ctx: logger.WithLevel(ctx, logger.DEBUG), query: "SELECT * FROM PERSON WHERE id = :id:", params: map[string]interface{}{"id": 100}, out: &Person{}, @@ -403,7 +372,6 @@ func TestBuilder_Query(t *testing.T) { }, { name: "nothing returned logging default", - logLevel: logger.DEBUG, query: "SELECT * FROM PERSON WHERE id = :id:", params: map[string]interface{}{"id": 100}, out: &Person{}, @@ -462,13 +430,8 @@ func TestBuilder_Query(t *testing.T) { } for _, v := range data { t.Run(v.name, func(t *testing.T) { - lines = nil - SetLogLevel(v.logLevel) - c := ctx - if v.ctx != nil { - c = v.ctx - } - err := b.Query(c, db, v.query, v.params, v.out) + linesFunc := RegisterLineLogger(t) + err := b.Query(ctx, db, v.query, v.params, v.out) var errMsg string if err != nil { errMsg = err.Error() @@ -479,8 +442,11 @@ func TestBuilder_Query(t *testing.T) { if diff := cmp.Diff(v.out, v.expected); diff != "" { t.Error(diff) } - if v.lineCount != len(lines) { - t.Errorf("Expected %d lines of debug, got %d: %#v", v.lineCount, len(lines), lines) + if v.lineCount > 0 { + lines := linesFunc() + if v.lineCount != len(lines) { + t.Errorf("Expected %d lines of debug, got %d: %#v", v.lineCount, len(lines), lines) + } } }) } diff --git a/proteus_test.go b/proteus_test.go index 4c45388..140ee4d 100644 --- a/proteus_test.go +++ b/proteus_test.go @@ -12,7 +12,6 @@ import ( "github.com/google/go-cmp/cmp" pcmp "github.com/jonbodner/proteus/cmp" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/stackerr" _ "github.com/go-sql-driver/mysql" @@ -20,7 +19,7 @@ import ( ) func TestValidIdentifier(t *testing.T) { - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() values := map[string]bool{ "a": true, "main": true, @@ -37,7 +36,7 @@ func TestValidIdentifier(t *testing.T) { "a.b //comment": true, //yeah, we can do comments } for k, v := range values { - if _, err := validIdentifier(c, k); v != (err == nil) { + if _, err := validIdentifier(ctx, k); v != (err == nil) { t.Errorf("failed for %s == %v ", k, v) } } @@ -117,12 +116,12 @@ func TestConvertToPositionalParameters(t *testing.T) { }, } - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() for k, v := range values { - q, qps, err := buildFixedQueryAndParamOrder(c, k, v.paramMap, v.funcType, MySQL) + q, qps, err := buildFixedQueryAndParamOrder(ctx, k, v.paramMap, v.funcType, MySQL) var qSimple string if err == nil { - qSimple, _ = q.finalize(c, nil) + qSimple, _ = q.finalize(ctx, nil) } if qSimple != v.query || !reflect.DeepEqual(qps, v.qps) || !pcmp.Errors(err, v.err) { t.Errorf("failed for %s -> %#v: %v", k, v, err) @@ -279,8 +278,8 @@ func TestNilScanner(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { productDao := ScannerProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) - db, err := setup(c, &productDao) + ctx := context.Background() + db, err := setup(ctx, &productDao) if err != nil { t.Fatal(err) } @@ -365,8 +364,8 @@ func TestNoParams(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { productDao := ScannerProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) - db, err := setup(c, &productDao) + ctx := context.Background() + db, err := setup(ctx, &productDao) if err != nil { t.Fatal(err) } @@ -574,8 +573,8 @@ func TestShouldBuildEmbeddedWithNullField(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { productDao := ProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) - db, err := setup(c, &productDao) + ctx := context.Background() + db, err := setup(ctx, &productDao) if err != nil { t.Fatal(err) } @@ -653,8 +652,8 @@ func TestPositionalVariables(t *testing.T) { } productDao := ProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) - err := ShouldBuild(c, &productDao, Postgres) + ctx := context.Background() + err := ShouldBuild(ctx, &productDao, Postgres) if err != nil { t.Error(err) } @@ -675,8 +674,8 @@ func TestVariableMultipleUsage(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { productDao := ProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) - db, err := setup(c, &productDao) + ctx := context.Background() + db, err := setup(ctx, &productDao) if err != nil { t.Fatal(err) } @@ -725,8 +724,8 @@ func TestShouldBuild(t *testing.T) { } productDao := ProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) - err := ShouldBuild(c, &productDao, Postgres) + ctx := context.Background() + err := ShouldBuild(ctx, &productDao, Postgres) if err == nil { t.Fatal("This should have errors") } @@ -749,7 +748,7 @@ func TestShouldBuild(t *testing.T) { } productDao2 := ProductDao2{} - err2 := ShouldBuild(c, &productDao2, Postgres) + err2 := ShouldBuild(ctx, &productDao2, Postgres) if err2 == nil { t.Error(err2) } @@ -777,8 +776,8 @@ func TestShouldBuildEmbedded(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { productDao := ProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) - db, err := setup(c, &productDao) + ctx := context.Background() + db, err := setup(ctx, &productDao) if err != nil { t.Fatal(err) } @@ -833,9 +832,9 @@ func TestShouldBinaryColumn(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { productDao := ProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() - db, err := setup(c, &productDao) + db, err := setup(ctx, &productDao) if err != nil { t.Fatal(err) } @@ -894,9 +893,9 @@ func TestShouldTimeColumn(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { productDao := ProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() - db, err := setup(c, &productDao) + db, err := setup(ctx, &productDao) if err != nil { t.Fatal(err) } @@ -961,9 +960,9 @@ func TestArray(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { productDao := ProductDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() - db, err := setup(c, &productDao) + db, err := setup(ctx, &productDao) if err != nil { t.Fatalf("%+v\n", err) } @@ -1044,9 +1043,9 @@ func TestNested(t *testing.T) { doTest := func(t *testing.T, setup setup, create string) { personDao := PersonDao{} - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() - db, err := setup(c, &personDao) + db, err := setup(ctx, &personDao) if err != nil { t.Fatalf("%+v\n", errors.Unwrap(err)) } diff --git a/runner.go b/runner.go index f743e4c..36cdf9f 100644 --- a/runner.go +++ b/runner.go @@ -3,12 +3,12 @@ package proteus import ( "context" "fmt" + "log/slog" "reflect" "strings" "database/sql" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/proteus/mapper" "github.com/jonbodner/stackerr" ) @@ -50,18 +50,6 @@ func makeContextExecutorImplementation(ctx context.Context, funcType reflect.Typ executor := args[1].Interface().(ContextExecutor) ctx := args[0].Interface().(context.Context) - // if the passed-in context doesn't contain any logging settings, use the one that were supplied - // at build time - if _, ok := logger.LevelFromContext(ctx); !ok { - if defaultLevel, ok := logger.LevelFromContext(ctx); ok { - ctx = logger.WithLevel(ctx, defaultLevel) - } - } - // copy over any logging values that were supplied at build time - if defaultVals, ok := logger.ValuesFromContext(ctx); ok { - ctx = logger.WithValues(ctx, defaultVals...) - } - var result sql.Result finalQuery, err := query.finalize(ctx, args) @@ -75,7 +63,7 @@ func makeContextExecutorImplementation(ctx context.Context, funcType reflect.Typ return buildRetVals(result, err) } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) result, err = executor.ExecContext(ctx, finalQuery, queryArgs...) return buildRetVals(result, err) @@ -101,7 +89,7 @@ func makeExecutorImplementation(ctx context.Context, funcType reflect.Type, quer return buildRetVals(result, err) } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) result, err = executor.Exec(finalQuery, queryArgs...) return buildRetVals(result, err) @@ -182,18 +170,6 @@ func makeContextQuerierImplementation(ctx context.Context, funcType reflect.Type querier := args[1].Interface().(ContextQuerier) ctx := args[0].Interface().(context.Context) - // if the passed-in context doesn't contain any logging settings, use the one that were supplied - // at build time - if _, ok := logger.LevelFromContext(ctx); !ok { - if defaultLevel, ok := logger.LevelFromContext(ctx); ok { - ctx = logger.WithLevel(ctx, defaultLevel) - } - } - // copy over any logging values that were supplied at build time - if defaultVals, ok := logger.ValuesFromContext(ctx); ok { - ctx = logger.WithValues(ctx, defaultVals...) - } - var rows *sql.Rows finalQuery, err := query.finalize(ctx, args) if err != nil { @@ -205,7 +181,7 @@ func makeContextQuerierImplementation(ctx context.Context, funcType reflect.Type return buildRetVals(rows, err) } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) // going to work around the defective Go MySQL driver, which refuses to convert the text protocol properly. // It is used when doing a query without parameters. if len(queryArgs) == 0 { @@ -253,7 +229,7 @@ func makeQuerierImplementation(ctx context.Context, funcType reflect.Type, query return buildRetVals(rows, err) } - logger.Log(ctx, logger.DEBUG, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) + slog.Log(ctx, slog.LevelDebug, fmt.Sprintln("calling", finalQuery, "with params", queryArgs)) // going to work around the defective Go MySQL driver, which refuses to convert the text protocol properly. // It is used when doing a query without parameters. if len(queryArgs) == 0 { @@ -397,7 +373,7 @@ func mapRows(ctx context.Context, rows *sql.Rows, builder mapper.Builder) (inter err = rows.Scan(vals...) if err != nil { - logger.Log(ctx, logger.WARN, "scan failed") + slog.Log(ctx, slog.LevelWarn, "scan failed") return nil, err } diff --git a/runner_test.go b/runner_test.go index 9def1fb..de0f198 100644 --- a/runner_test.go +++ b/runner_test.go @@ -6,7 +6,6 @@ import ( "reflect" "testing" - "github.com/jonbodner/proteus/logger" "github.com/jonbodner/proteus/mapper" ) @@ -23,9 +22,9 @@ func Test_getQArgs(t *testing.T) { }{ // TODO: Add test cases. } - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() for _, tt := range tests { - got, err := buildQueryArgs(c, tt.args.args, tt.args.qps) + got, err := buildQueryArgs(ctx, tt.args.args, tt.args.qps) if (err != nil) != tt.wantErr { t.Errorf("%q. buildQueryArgs() error = %v, wantErr %v", tt.name, err, tt.wantErr) continue @@ -50,9 +49,9 @@ func Test_buildExec(t *testing.T) { }{ // TODO: Add test cases. } - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() for _, tt := range tests { - got := makeExecutorImplementation(c, tt.args.funcType, tt.args.positionalQuery, tt.args.qps) + got := makeExecutorImplementation(ctx, tt.args.funcType, tt.args.positionalQuery, tt.args.qps) if !reflect.DeepEqual(got, tt.want) { t.Errorf("%q. makeExecutorImplementation() = %T, want %T", tt.name, got, tt.want) } @@ -73,9 +72,9 @@ func Test_buildQuery(t *testing.T) { }{ // TODO: Add test cases. } - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() for _, tt := range tests { - got, err := makeQuerierImplementation(c, tt.args.funcType, tt.args.positionalQuery, tt.args.qps) + got, err := makeQuerierImplementation(ctx, tt.args.funcType, tt.args.positionalQuery, tt.args.qps) if (err != nil) != tt.wantErr { t.Errorf("%q. makeQuerierImplementation() error = %v, wantErr %v", tt.name, err, tt.wantErr) continue @@ -100,9 +99,9 @@ func Test_handleMapping(t *testing.T) { }{ // TODO: Add test cases. } - c := logger.WithLevel(context.Background(), logger.DEBUG) + ctx := context.Background() for _, tt := range tests { - got, err := handleMapping(c, tt.args.sType, tt.args.rows, tt.args.builder) + got, err := handleMapping(ctx, tt.args.sType, tt.args.rows, tt.args.builder) if (err != nil) != tt.wantErr { t.Errorf("%q. handleMapping() error = %v, wantErr %v", tt.name, err, tt.wantErr) continue From 14c1339a73ac4d006973135db88217bfae1815b1 Mon Sep 17 00:00:00 2001 From: jonbodner Date: Tue, 10 Feb 2026 23:26:48 -0500 Subject: [PATCH 2/2] Replace logrus with slog and update logging statements. --- go.mod | 2 -- go.sum | 6 ------ speed/speed.go | 16 ++++++++++------ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index a3ea2d7..483213d 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,9 @@ require ( github.com/lib/pq v1.10.9 github.com/pkg/profile v1.7.0 github.com/rickar/props v1.0.0 - github.com/sirupsen/logrus v1.9.0 ) require ( github.com/felixge/fgprof v0.9.3 // indirect github.com/google/pprof v0.0.0-20230429030804-905365eefe3e // indirect - golang.org/x/sys v0.7.0 // indirect ) diff --git a/go.sum b/go.sum index 2db9441..08c995d 100644 --- a/go.sum +++ b/go.sum @@ -28,19 +28,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rickar/props v1.0.0 h1:3C3j+wF2/XbQ/sCGRK8DkCLwuRvzqToMvDzmdxHwCsg= github.com/rickar/props v1.0.0/go.mod h1:VVywBJXdOY3IwDtBmgAMIZs/XM/CtMKSJzu5dsHYwEY= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/speed/speed.go b/speed/speed.go index 000f25c..9144e34 100644 --- a/speed/speed.go +++ b/speed/speed.go @@ -4,14 +4,15 @@ import ( "context" "database/sql" "fmt" + "log/slog" "math" + "os" "time" "github.com/jonbodner/proteus" "github.com/jonbodner/stackerr" _ "github.com/lib/pq" "github.com/pkg/profile" - log "github.com/sirupsen/logrus" ) func SelectProteus(ctx context.Context, db *sql.DB) time.Duration { @@ -122,7 +123,8 @@ func setupDbPostgres(ctx context.Context) *sql.DB { db, err := sql.Open("postgres", "postgres://pro_user:pro_pwd@localhost/proteus?sslmode=disable") if err != nil { - log.Fatal(err) + slog.Error("error", "err", slog.AnyValue(err)) + os.Exit(1) } sqlStmt := ` drop table if exists product; @@ -130,7 +132,7 @@ func setupDbPostgres(ctx context.Context) *sql.DB { ` _, err = db.Exec(sqlStmt) if err != nil { - log.Fatalf("%q: %s\n", err, sqlStmt) + slog.Error("error", "err", slog.AnyValue(err), "statement", slog.StringValue(sqlStmt)) return nil } populate(ctx, db) @@ -142,7 +144,8 @@ func populate(ctx context.Context, db *sql.DB) { proteus.Build(&productDao, proteus.Postgres) tx, err := db.Begin() if err != nil { - log.Fatal(err) + slog.Error("error", "err", slog.AnyValue(err)) + os.Exit(1) } defer tx.Commit() @@ -154,8 +157,9 @@ func populate(ctx context.Context, db *sql.DB) { } rowCount, err := productDao.Insert(ctx, tx, i, fmt.Sprintf("person%d", i), cost) if err != nil { - log.Fatal(err) + slog.Error("error", "err", slog.AnyValue(err)) + os.Exit(1) } - log.Debug(rowCount) + slog.Debug("rowCount", "rowCount", rowCount) } }