diff --git a/config.go b/config.go index 4735aa67325315f138441aef689826a8d3f71970..26cb1523f8c12786bae5734c41736c0e3d6bb16c 100644 --- a/config.go +++ b/config.go @@ -1,6 +1,7 @@ package db import ( + "sync" "sync/atomic" ) @@ -20,19 +21,28 @@ type Settings interface { type conf struct { loggingEnabled uint32 - queryLogger atomic.Value - defaultLogger defaultLogger + + queryLogger Logger + queryLoggerMu sync.RWMutex + defaultLogger defaultLogger } func (c *conf) Logger() Logger { - if lg := c.queryLogger.Load(); lg != nil { - return lg.(Logger) + c.queryLoggerMu.RLock() + defer c.queryLoggerMu.RUnlock() + + if c.queryLogger == nil { + return &c.defaultLogger } - return &c.defaultLogger + + return c.queryLogger } func (c *conf) SetLogger(lg Logger) { - c.queryLogger.Store(lg) + c.queryLoggerMu.Lock() + defer c.queryLoggerMu.Unlock() + + c.queryLogger = lg } func (c *conf) SetLogging(value bool) { diff --git a/internal/sqladapter/testing/adapter.go.tpl b/internal/sqladapter/testing/adapter.go.tpl index e015ff4501c6c15334e9a3f46b8adf5bc0a1f7de..bd9dd0b2513e7246c8157f37772545674d5efb83 100644 --- a/internal/sqladapter/testing/adapter.go.tpl +++ b/internal/sqladapter/testing/adapter.go.tpl @@ -5,8 +5,8 @@ package ADAPTER import ( "database/sql" "flag" - "log" "fmt" + "log" "math/rand" "os" "strconv" @@ -20,6 +20,18 @@ import ( "upper.io/db.v2/lib/sqlbuilder" ) +type customLogger struct { +} + +func (*customLogger) Log(q *db.QueryStatus) { + switch q.Err { + case nil, db.ErrNoMoreRows: + return // Don't log successful queries. + } + // Alert of any other error. + log.Printf("Unexpected database error: %v\n%s", q.Err, q.String()) +} + type artistType struct { ID int64 `db:"id,omitempty"` Name string `db:"name"` @@ -83,6 +95,23 @@ func TestTruncateAllCollections(t *testing.T) { } } +func TestCustomQueryLogger(t *testing.T) { + sess, err := Open(settings) + assert.NoError(t, err) + defer sess.Close() + + db.Conf.SetLogger(&customLogger{}) + defer func() { + db.Conf.SetLogger(nil) + }() + + _, err = sess.Collection("artist").Find().Count() + assert.Equal(t, nil, err) + + _, err = sess.Collection("artist_x").Find().Count() + assert.NotEqual(t, nil, err) +} + func TestExpectCursorError(t *testing.T) { sess := mustOpen() defer sess.Close() @@ -117,7 +146,7 @@ func TestInsertReturning(t *testing.T) { assert.NotZero(t, itemMap["id"], "Must not be zero after inserting") itemStruct := struct { - ID int `db:"id,omitempty"` + ID int `db:"id,omitempty"` Name string `db:"name"` }{ 0, @@ -133,7 +162,7 @@ func TestInsertReturning(t *testing.T) { assert.Equal(t, uint64(2), count, "Expecting 2 elements") itemStruct2 := struct { - ID int `db:"id,omitempty"` + ID int `db:"id,omitempty"` Name string `db:"name"` }{ 0, @@ -180,7 +209,7 @@ func TestInsertReturningWithinTransaction(t *testing.T) { assert.NotZero(t, itemMap["id"], "Must not be zero after inserting") itemStruct := struct { - ID int `db:"id,omitempty"` + ID int `db:"id,omitempty"` Name string `db:"name"` }{ 0, @@ -196,7 +225,7 @@ func TestInsertReturningWithinTransaction(t *testing.T) { assert.Equal(t, uint64(2), count, "Expecting 2 elements") itemStruct2 := struct { - ID int `db:"id,omitempty"` + ID int `db:"id,omitempty"` Name string `db:"name"` }{ 0, @@ -362,7 +391,7 @@ func TestGetResultsOneByOne(t *testing.T) { // Dumping into a tagged struct. rowStruct2 := struct { - Value1 int64 `db:"id"` + Value1 int64 `db:"id"` Value2 string `db:"name"` }{} @@ -402,7 +431,7 @@ func TestGetResultsOneByOne(t *testing.T) { // Dumping into a slice of structs. allRowsStruct := []struct { - ID int64 `db:"id,omitempty"` + ID int64 `db:"id,omitempty"` Name string `db:"name"` }{} @@ -423,7 +452,7 @@ func TestGetResultsOneByOne(t *testing.T) { // Dumping into a slice of tagged structs. allRowsStruct2 := []struct { - Value1 int64 `db:"id"` + Value1 int64 `db:"id"` Value2 string `db:"name"` }{} @@ -536,7 +565,7 @@ func TestUpdate(t *testing.T) { // Defining destination struct value := struct { - ID int64 `db:"id,omitempty"` + ID int64 `db:"id,omitempty"` Name string `db:"name"` }{} @@ -1130,7 +1159,9 @@ func TestBatchInsertNoColumns(t *testing.T) { go func() { defer batch.Done() for i := 0; i < totalItems; i++ { - value := struct{Name string `db:"name"`}{fmt.Sprintf("artist-%d", i)} + value := struct { + Name string `db:"name"` + }{fmt.Sprintf("artist-%d", i)} batch.Values(value) } }() @@ -1209,7 +1240,7 @@ func TestBuilder(t *testing.T) { err := sess.Collection("artist").Truncate() assert.NoError(t, err) - _, err = sess.InsertInto("artist").Values(struct{ + _, err = sess.InsertInto("artist").Values(struct { Name string `db:"name"` }{"Rinko Kikuchi"}).Exec() assert.NoError(t, err) @@ -1285,7 +1316,6 @@ func TestBuilder(t *testing.T) { assert.Error(t, iter.Err()) } - // Using implicit iterator. q := sess.SelectFrom("artist") err = q.All(&all) @@ -1319,7 +1349,7 @@ func TestExhaustConnectionPool(t *testing.T) { t.Fatal(err) } - tLogf := func(format string, args... interface{}) { + tLogf := func(format string, args ...interface{}) { tMu.Lock() defer tMu.Unlock() t.Logf(format, args...) @@ -1349,7 +1379,7 @@ func TestExhaustConnectionPool(t *testing.T) { // transaction lasts 3 seconds. time.Sleep(time.Second * 3) - switch i%7 { + switch i % 7 { case 0: var account map[string]interface{} if err := tx.Collection("artist").Find().One(&account); err != nil {