From 7d93161fbd712457c9aadc47c4017dd9a8b804a1 Mon Sep 17 00:00:00 2001 From: caojiamingalan Date: Tue, 23 May 2023 20:33:24 -0500 Subject: [PATCH] add logger Signed-off-by: caojiamingalan --- db.go | 13 ++++++ logger.go | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tx.go | 4 ++ 3 files changed, 147 insertions(+) create mode 100644 logger.go diff --git a/db.go b/db.go index b848757..2c5c694 100644 --- a/db.go +++ b/db.go @@ -116,6 +116,9 @@ type DB struct { // Supported only on Unix via mlock/munlock syscalls. Mlock bool + // Logger is the logger used for bbolt. + Logger Logger + path string openFile func(string, int, os.FileMode) (*os.File, error) file *os.File @@ -194,6 +197,12 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) { db.MaxBatchDelay = common.DefaultMaxBatchDelay db.AllocSize = common.DefaultAllocSize + if options.Logger == nil { + db.Logger = getDiscardLogger() + } else { + db.Logger = options.Logger + } + flag := os.O_RDWR if options.ReadOnly { flag = os.O_RDONLY @@ -293,6 +302,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) { } // Mark the database as opened and return. + db.Logger.Debug("bbolt opened successfully") return db, nil } @@ -1268,6 +1278,9 @@ type Options struct { // It prevents potential page faults, however // used memory can't be reclaimed. (UNIX only) Mlock bool + + // Logger is the logger used for bbolt. + Logger Logger } // DefaultOptions represent the options used if nil options are passed into Open(). diff --git a/logger.go b/logger.go new file mode 100644 index 0000000..29418ab --- /dev/null +++ b/logger.go @@ -0,0 +1,130 @@ +// Copyright 2015 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bbolt + +import ( + "fmt" + "io" + "log" + "os" + "sync" +) + +type Logger interface { + Debug(v ...interface{}) + Debugf(format string, v ...interface{}) + + Error(v ...interface{}) + Errorf(format string, v ...interface{}) + + Info(v ...interface{}) + Infof(format string, v ...interface{}) + + Warning(v ...interface{}) + Warningf(format string, v ...interface{}) + + Fatal(v ...interface{}) + Fatalf(format string, v ...interface{}) + + Panic(v ...interface{}) + Panicf(format string, v ...interface{}) +} + +func getDiscardLogger() Logger { + bboltLoggerMu.Lock() + defer bboltLoggerMu.Unlock() + return discardLogger +} + +var ( + discardLogger = &DefaultLogger{Logger: log.New(io.Discard, "", 0)} + bboltLoggerMu sync.Mutex +) + +const ( + calldepth = 2 +) + +// DefaultLogger is a default implementation of the Logger interface. +type DefaultLogger struct { + *log.Logger + debug bool +} + +func (l *DefaultLogger) EnableTimestamps() { + l.SetFlags(l.Flags() | log.Ldate | log.Ltime) +} + +func (l *DefaultLogger) EnableDebug() { + l.debug = true +} + +func (l *DefaultLogger) Debug(v ...interface{}) { + if l.debug { + _ = l.Output(calldepth, header("DEBUG", fmt.Sprint(v...))) + } +} + +func (l *DefaultLogger) Debugf(format string, v ...interface{}) { + if l.debug { + _ = l.Output(calldepth, header("DEBUG", fmt.Sprintf(format, v...))) + } +} + +func (l *DefaultLogger) Info(v ...interface{}) { + _ = l.Output(calldepth, header("INFO", fmt.Sprint(v...))) +} + +func (l *DefaultLogger) Infof(format string, v ...interface{}) { + _ = l.Output(calldepth, header("INFO", fmt.Sprintf(format, v...))) +} + +func (l *DefaultLogger) Error(v ...interface{}) { + _ = l.Output(calldepth, header("ERROR", fmt.Sprint(v...))) +} + +func (l *DefaultLogger) Errorf(format string, v ...interface{}) { + _ = l.Output(calldepth, header("ERROR", fmt.Sprintf(format, v...))) +} + +func (l *DefaultLogger) Warning(v ...interface{}) { + _ = l.Output(calldepth, header("WARN", fmt.Sprint(v...))) +} + +func (l *DefaultLogger) Warningf(format string, v ...interface{}) { + _ = l.Output(calldepth, header("WARN", fmt.Sprintf(format, v...))) +} + +func (l *DefaultLogger) Fatal(v ...interface{}) { + _ = l.Output(calldepth, header("FATAL", fmt.Sprint(v...))) + os.Exit(1) +} + +func (l *DefaultLogger) Fatalf(format string, v ...interface{}) { + _ = l.Output(calldepth, header("FATAL", fmt.Sprintf(format, v...))) + os.Exit(1) +} + +func (l *DefaultLogger) Panic(v ...interface{}) { + l.Logger.Panic(v...) +} + +func (l *DefaultLogger) Panicf(format string, v ...interface{}) { + l.Logger.Panicf(format, v...) +} + +func header(lvl, msg string) string { + return fmt.Sprintf("%s: %s", lvl, msg) +} diff --git a/tx.go b/tx.go index 4e1f454..a71dc06 100644 --- a/tx.go +++ b/tx.go @@ -32,6 +32,7 @@ type Tx struct { pages map[common.Pgid]*common.Page stats TxStats commitHandlers []func() + Logger Logger // WriteFlag specifies the flag for write-related methods like WriteTo(). // Tx opens the database file with the specified flag to copy the data. @@ -56,6 +57,8 @@ func (tx *Tx) init(db *DB) { tx.root.InBucket = &common.InBucket{} *tx.root.InBucket = *(tx.meta.RootBucket()) + tx.Logger = db.Logger + // Increment the transaction id and add a page cache for writable transactions. if tx.writable { tx.pages = make(map[common.Pgid]*common.Page) @@ -142,6 +145,7 @@ func (tx *Tx) OnCommit(fn func()) { // called on a read-only transaction. func (tx *Tx) Commit() error { common.Assert(!tx.managed, "managed tx commit not allowed") + tx.Logger.Debugf("committing tx") if tx.db == nil { return berrors.ErrTxClosed } else if !tx.writable {