diff --git a/cmd/tableauc/main.go b/cmd/tableauc/main.go index 9b2492b3..4db66240 100644 --- a/cmd/tableauc/main.go +++ b/cmd/tableauc/main.go @@ -11,7 +11,6 @@ import ( "github.com/tableauio/tableau/format" "github.com/tableauio/tableau/log" "github.com/tableauio/tableau/options" - "github.com/tableauio/tableau/xerrors" "gopkg.in/yaml.v3" ) @@ -154,10 +153,7 @@ func genConf(workbooks []string, config *options.Options) error { } func logError(mode string, err error) { - if log.Mode() == log.ModeFull { - log.Errorf("generate %s file failed: %+v", mode, err) - } - log.Errorf("Error: %s", xerrors.NewDesc(err)) + log.Errorf("generate %s file failed: %+v", mode, err) } func loadConfig(path string) (*options.Options, error) { diff --git a/go.mod b/go.mod index 4d55d43e..a16fdca9 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/subchen/go-xmldom v1.1.2 github.com/xuri/excelize/v2 v2.9.0 - go.uber.org/zap v1.24.0 + go.uber.org/zap v1.26.0 golang.org/x/sync v0.8.0 golang.org/x/text v0.19.0 google.golang.org/protobuf v1.34.2 @@ -36,8 +36,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect + go.uber.org/multierr v1.10.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.28.0 // indirect golang.org/x/net v0.30.0 // indirect diff --git a/go.sum b/go.sum index 5c2644e0..51fa7aac 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ github.com/antchfx/xpath v0.0.0-20170515025933-1f3266e77307 h1:C735MoY/X+UOx6SECmHk5pVOj51h839Ph13pEoY8UmU= github.com/antchfx/xpath v0.0.0-20170515025933-1f3266e77307/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM= github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY= github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= @@ -31,8 +29,6 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/protocolbuffers/txtpbfmt v0.0.0-20240820135758-21b1d9897dc7 h1:GkKZUEPNgwIk3LK4Er5vxnaNKk1pdjI3Oc6oTBwBsxQ= @@ -52,7 +48,6 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An 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/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -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/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -69,14 +64,12 @@ github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQ github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE= github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A= github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= diff --git a/internal/confgen/util.go b/internal/confgen/util.go index 020f17c4..01d17bdc 100644 --- a/internal/confgen/util.go +++ b/internal/confgen/util.go @@ -18,7 +18,6 @@ import ( "github.com/tableauio/tableau/proto/tableaupb" "github.com/tableauio/tableau/store" "github.com/tableauio/tableau/xerrors" - "go.uber.org/zap" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" @@ -216,12 +215,10 @@ func buildWorkbookIndex(protoPackage, inputDir string, subdirs []string, subdirR return nil, err } // debugging - if log.LevelEnabled(zap.DebugLevel) { - for k, v := range bookIndexes { - for _, fd := range v.fds { - _, workbook := ParseFileOptions(fd) - log.Debugf("primary book index: %s -> %s (%s)", k, workbook.GetName(), fd.Path()) - } + for k, v := range bookIndexes { + for _, fd := range v.fds { + _, workbook := ParseFileOptions(fd) + log.Debugf("primary book index: %s -> %s (%s)", k, workbook.GetName(), fd.Path()) } } return bookIndexes, nil diff --git a/internal/importer/excel.go b/internal/importer/excel.go index 9abc7039..64eca2f9 100644 --- a/internal/importer/excel.go +++ b/internal/importer/excel.go @@ -28,8 +28,9 @@ func NewExcelImporter(ctx context.Context, filename string, setters ...Option) ( } defer func() { // Close the spreadsheet. - if err := file.Close(); err != nil { - log.Error(err) + err := file.Close() + if err != nil { + log.Panicf("failed to close file: %s", filename) } }() diff --git a/load/load.go b/load/load.go index d6f9eccd..4f10b6a8 100644 --- a/load/load.go +++ b/load/load.go @@ -120,7 +120,7 @@ func loadMessagerWithPatch(msg proto.Message, path string, fmt format.Format, pa default: return xerrors.Newf("unknown patch type: %v", patch) } - log.Debugf("patched(%s) %s by %v: %s", patch, name, patchPaths, msg) + log.Debugf("patched(%s) %s by %v", patch, name, patchPaths) return nil } diff --git a/log/core/core.go b/log/core/core.go deleted file mode 100644 index d3a18413..00000000 --- a/log/core/core.go +++ /dev/null @@ -1,52 +0,0 @@ -package core - -import ( - "fmt" - "strings" -) - -// refer: https://github.com/go-eden/slf4go/blob/master/slf_model.go - -// Fields represents attached fields of log -type Fields map[string]any - -// Record represent an log, contains all properties. -type Record struct { - Level Level - - Format *string - Args []any - - KVs []any // additional custom variadic key-value pairs - CxtFields Fields // caller's goroutine context fields -} - -type Mode string - -const ( - ModeSimple Mode = "SIMPLE" - ModeFull Mode = "FULL" -) - -type SinkType int - -const ( - SinkConsole SinkType = iota // default - SinkFile - SinkMulti -) - -var sinkMap = map[string]SinkType{ - "": SinkConsole, - "CONSOLE": SinkConsole, - "FILE": SinkFile, - "MULTI": SinkMulti, -} - -func GetSinkType(sink string) (SinkType, error) { - sinkType, ok := sinkMap[strings.ToUpper(sink)] - if !ok { - return SinkConsole, fmt.Errorf("illegal sink: %s", sink) - } - return sinkType, nil -} diff --git a/log/core/level.go b/log/core/level.go deleted file mode 100644 index f70b2582..00000000 --- a/log/core/level.go +++ /dev/null @@ -1,138 +0,0 @@ -package core - -import ( - "bytes" - "fmt" -) - -// A Level is a logging priority. Higher levels are more important. -type Level int8 - -const ( - // DebugLevel logs are typically voluminous, and are usually disabled in - // production. - DebugLevel Level = iota - 1 - // InfoLevel is the default logging priority. - InfoLevel - // WarnLevel logs are more important than Info, but don't need individual - // human review. - WarnLevel - // ErrorLevel logs are high-priority. If an application is running smoothly, - // it shouldn't generate any error-level logs. - ErrorLevel - // DPanicLevel logs are particularly important errors. In development the - // logger panics after writing the message. - DPanicLevel - // PanicLevel logs a message, then panics. - PanicLevel - // FatalLevel logs a message, then calls os.Exit(1). - FatalLevel - - // _minLevel = DebugLevel - // _maxLevel = FatalLevel -) - -// String returns a lower-case ASCII representation of the log level. -func (l Level) String() string { - switch l { - case DebugLevel: - return "debug" - case InfoLevel: - return "info" - case WarnLevel: - return "warn" - case ErrorLevel: - return "error" - case DPanicLevel: - return "dpanic" - case PanicLevel: - return "panic" - case FatalLevel: - return "fatal" - default: - return fmt.Sprintf("Level(%d)", l) - } -} - -// CapitalString returns an all-caps ASCII representation of the log level. -func (l Level) CapitalString() string { - // Printing levels in all-caps is common enough that we should export this - // functionality. - switch l { - case DebugLevel: - return "DEBUG" - case InfoLevel: - return "INFO" - case WarnLevel: - return "WARN" - case ErrorLevel: - return "ERROR" - case DPanicLevel: - return "DPANIC" - case PanicLevel: - return "PANIC" - case FatalLevel: - return "FATAL" - default: - return fmt.Sprintf("LEVEL(%d)", l) - } -} - -// MarshalText marshals the Level to text. Note that the text representation -// drops the -Level suffix (see example). -func (l Level) MarshalText() ([]byte, error) { - return []byte(l.String()), nil -} - -// UnmarshalText unmarshals text to a level. Like MarshalText, UnmarshalText -// expects the text representation of a Level to drop the -Level suffix (see -// example). -// -// In particular, this makes it easy to configure logging levels using YAML, -// TOML, or JSON files. -func (l *Level) UnmarshalText(text []byte) error { - if l == nil { - return fmt.Errorf("Level is nil") - } - if !l.unmarshalText(text) && !l.unmarshalText(bytes.ToLower(text)) { - return fmt.Errorf("unrecognized level: %q", text) - } - return nil -} - -func (l *Level) unmarshalText(text []byte) bool { - switch string(text) { - case "debug", "DEBUG": - *l = DebugLevel - case "info", "INFO", "": // make the zero value useful - *l = InfoLevel - case "warn", "WARN": - *l = WarnLevel - case "error", "ERROR": - *l = ErrorLevel - case "dpanic", "DPANIC": - *l = DPanicLevel - case "panic", "PANIC": - *l = PanicLevel - case "fatal", "FATAL": - *l = FatalLevel - default: - return false - } - return true -} - -// Set sets the level for the flag.Value interface. -func (l *Level) Set(s string) error { - return l.UnmarshalText([]byte(s)) -} - -// Get gets the level for the flag.Getter interface. -func (l *Level) Get() any { - return *l -} - -// Enabled returns true if the given level is at or above this level. -func (l Level) Enabled(lvl Level) bool { - return lvl >= l -} diff --git a/log/driver/defaultdriver/defaultdriver.go b/log/driver/defaultdriver/defaultdriver.go deleted file mode 100644 index 406151c0..00000000 --- a/log/driver/defaultdriver/defaultdriver.go +++ /dev/null @@ -1,104 +0,0 @@ -package defaultdriver - -import ( - "fmt" - "path" - "runtime" - "time" - - "github.com/tableauio/tableau/log/core" - "github.com/tableauio/tableau/log/driver" -) - -type DefaultDriver struct { - CallerSkip int -} - -func init() { - driver.RegisteDriver(&DefaultDriver{ - CallerSkip: 2, - }) -} - -func (d *DefaultDriver) Name() string { - return "default" -} - -func (d *DefaultDriver) Print(r *core.Record) { - if r.Level < d.GetLevel(d.Name()) { - return - } - - msg := getMessage(*r.Format, r.Args) - callInfo := getCallerInfo(d.CallerSkip) - text := fmt.Sprintf("%s\t%s\t%s\t%s:%d", ISO8601TimeEncoder(time.Now()), r.Level.CapitalString(), callInfo.FuncName, callInfo.File, callInfo.Line) - // if len(context) != 0 { - // text += fmt.Sprintf(" %+v", context) - // } - text += "\t\t" + msg - fmt.Println(text) -} - -func (d *DefaultDriver) GetLevel(logger string) core.Level { - return core.DebugLevel -} - -// getMessage format with Sprint, Sprintf, or neither. -func getMessage(format string, fmtArgs []any) string { - if len(fmtArgs) == 0 { - return format - } - - if format != "" { - return fmt.Sprintf(format, fmtArgs...) - } - - if len(fmtArgs) == 1 { - if str, ok := fmtArgs[0].(string); ok { - return str - } - } - return fmt.Sprint(fmtArgs...) -} - -type CallerInfo struct { - FullFuncName string - FuncName string - File string - Line int -} - -func getCallerInfo(callerSkip int) *CallerInfo { - pc, file, line, ok := runtime.Caller(4 + callerSkip) // backtrace two frames - if !ok { - return &CallerInfo{ - FullFuncName: "unknown", - FuncName: "unknown", - File: "unknown", - } - } - fullFuncName := runtime.FuncForPC(pc).Name() - return &CallerInfo{ - FullFuncName: fullFuncName, - FuncName: path.Base(fullFuncName), - File: file, - Line: line, - } -} - -// ISO8601TimeEncoder serializes a time.Time to an ISO8601-formatted string -// with millisecond precision. -func ISO8601TimeEncoder(t time.Time) string { - return t.Format("2006-01-02T15:04:05.000Z0700") -} - -// RFC3339TimeEncoder serializes a time.Time to an RFC3339-formatted string. -func RFC3339TimeEncoder(t time.Time) string { - return t.Format(time.RFC3339) -} - -// RFC3339NanoTimeEncoder serializes a time.Time to an RFC3339-formatted string -// with nanosecond precision. -func RFC3339NanoTimeEncoder(t time.Time) string { - return t.Format(time.RFC3339Nano) -} diff --git a/log/driver/driver.go b/log/driver/driver.go deleted file mode 100644 index a2649d9b..00000000 --- a/log/driver/driver.go +++ /dev/null @@ -1,45 +0,0 @@ -package driver - -import ( - "strings" - - "github.com/tableauio/tableau/log/core" -) - -// refer: https://github.com/go-eden/slf4go/blob/master/slf_model.go - -// Driver define the standard log print specification -type Driver interface { - // Retrieve the name of current driver, like 'default', 'zap', 'logrus' ... - Name() string - - // Print responsible of printing the standard Log - Print(r *core.Record) - - // Retrieve log level of the specified logger, - // it should return the lowest Level that could be print, - // which can help invoker to decide whether prepare print or not. - GetLevel(logger string) core.Level -} - -var registeredDrivers = make(map[string]Driver) - -// registered with the same name, the one registered last will take effect. -func RegisteDriver(driver Driver) { - if driver == nil { - panic("cannot register a nil Driver") - } - if driver.Name() == "" { - panic("cannot register Driver with empty string result for Name()") - } - name := strings.ToLower(driver.Name()) - registeredDrivers[name] = driver -} - -// GetDriver gets a registered Driver by driver name, or nil if no Driver is -// registered for the driver name. -// -// The driver name is expected to be lowercase. -func GetDriver(name string) Driver { - return registeredDrivers[name] -} diff --git a/log/driver/zapdriver/logger.go b/log/driver/zapdriver/logger.go index 7988adce..680dd42d 100644 --- a/log/driver/zapdriver/logger.go +++ b/log/driver/zapdriver/logger.go @@ -5,7 +5,6 @@ import ( "os" "strings" - "github.com/tableauio/tableau/log/core" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" @@ -18,20 +17,19 @@ var modeMap = map[string]LogModeEncoder{ // Init set the log options for debugging. func NewLogger(mode, level, filename, sink string) (*zap.Logger, error) { - sinkType, err := core.GetSinkType(sink) - if err != nil { - return nil, err - } - switch sinkType { - case core.SinkFile: + switch sink { + case "FILE": return newFileLogger(mode, level, filename) - case core.SinkMulti: + case "MULTI": return newMultiLogger(mode, level, filename) default: return newConsoleLogger(mode, level) } } +// SkipUntilTrueCaller is the skip level which prints out the actual caller instead of slf4go or slf4go-zap wrappers +const SkipUntilTrueCaller = 4 + // newConsoleLogger set the console log level and mode for debugging. func newConsoleLogger(mode, level string) (*zap.Logger, error) { core, err := createConsoleZapCore(mode, level) diff --git a/log/driver/zapdriver/zapdriver.go b/log/driver/zapdriver/zapdriver.go deleted file mode 100644 index d904693d..00000000 --- a/log/driver/zapdriver/zapdriver.go +++ /dev/null @@ -1,194 +0,0 @@ -package zapdriver - -import ( - "errors" - - "github.com/tableauio/tableau/log/core" - "github.com/tableauio/tableau/log/driver" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -const ( - _oddNumberErrMsg = "Ignored key without a value." - _nonStringKeyErrMsg = "Ignored key-value pairs with non-string keys." -) - -type ZapDriver struct { - logger *zap.Logger - level zap.AtomicLevel -} - -// SkipUntilTrueCaller is the skip level which prints out the actual caller instead of slf4go or slf4go-zap wrappers -const SkipUntilTrueCaller = 4 - -func init() { - dr := New(zap.NewProductionConfig(), zap.AddCallerSkip(SkipUntilTrueCaller)) - driver.RegisteDriver(dr) -} - -// New creates the driver using the provided config wrapper -func New(config zap.Config, opts ...zap.Option) *ZapDriver { - logger, err := config.Build(opts...) - if err != nil { - panic(err) - } - return &ZapDriver{ - logger: logger, - level: config.Level, - } -} - -func NewWithLogger(level zap.AtomicLevel, logger *zap.Logger) *ZapDriver { - return &ZapDriver{ - logger: logger, - level: level, - } -} - -func (*ZapDriver) Name() string { - return "zap" -} - -// refer: https://github.com/uber-go/zap/blob/v1.21.0/sugar.go#L249 -func (d *ZapDriver) sweetenFields(args []any) []zap.Field { - if len(args) == 0 { - return nil - } - - // Allocate enough space for the worst case; if users pass only structured - // fields, we shouldn't penalize them with extra allocations. - fields := make([]zap.Field, 0, len(args)) - var invalid invalidPairs - - for i := 0; i < len(args); { - // This is a strongly-typed field. Consume it and move on. - if f, ok := args[i].(zap.Field); ok { - fields = append(fields, f) - i++ - continue - } - - // Make sure this element isn't a dangling key. - if i == len(args)-1 { - d.logger.Error(_oddNumberErrMsg, zap.Any("ignored", args[i])) - break - } - - // Consume this value and the next, treating them as a key-value pair. If the - // key isn't a string, add this pair to the slice of invalid pairs. - key, val := args[i], args[i+1] - if keyStr, ok := key.(string); !ok { - // Subsequent errors are likely, so allocate once up front. - if cap(invalid) == 0 { - invalid = make(invalidPairs, 0, len(args)/2) - } - invalid = append(invalid, invalidPair{i, key, val}) - } else { - fields = append(fields, zap.Any(keyStr, val)) - } - i += 2 - } - - // If we encountered any invalid key-value pairs, log an error. - if len(invalid) > 0 { - d.logger.Error(_nonStringKeyErrMsg, zap.Array("invalid", invalid)) - } - return fields -} - -func (d *ZapDriver) Print(r *core.Record) { - logger := d.logger - // append key value pairs to the message - if r.KVs != nil { - fields := d.sweetenFields(r.KVs) - logger = d.logger.With(fields...) - } - - defer func() { - // For console: sync /dev/stderr: invalid argument - // TODO: fix it - _ = logger.Sync() - }() - switch r.Level { - case core.DebugLevel: - if r.Format == nil { - logger.Sugar().Debug(r.Args...) - } else { - logger.Sugar().Debugf(*r.Format, r.Args...) - } - case core.InfoLevel: - if r.Format == nil { - logger.Sugar().Info(r.Args...) - } else { - logger.Sugar().Infof(*r.Format, r.Args...) - } - case core.WarnLevel: - if r.Format == nil { - logger.Sugar().Warn(r.Args...) - } else { - logger.Sugar().Warnf(*r.Format, r.Args...) - } - case core.ErrorLevel: - if r.Format == nil { - logger.Sugar().Error(r.Args...) - } else { - logger.Sugar().Errorf(*r.Format, r.Args...) - } - case core.PanicLevel: - if r.Format == nil { - logger.Sugar().Panic(r.Args...) - } else { - logger.Sugar().Panicf(*r.Format, r.Args...) - } - case core.FatalLevel: - if r.Format == nil { - logger.Sugar().Fatal(r.Args...) - } else { - logger.Sugar().Fatalf(*r.Format, r.Args...) - } - } -} - -func (d *ZapDriver) GetLevel(logger string) core.Level { - switch d.level.Level() { - case zap.DebugLevel: - return core.DebugLevel - case zap.InfoLevel: - return core.InfoLevel - case zap.WarnLevel: - return core.WarnLevel - case zap.ErrorLevel: - return core.ErrorLevel - case zap.DPanicLevel: - return core.PanicLevel - case zap.PanicLevel: - return core.PanicLevel - case zap.FatalLevel: - return core.FatalLevel - default: - return core.DebugLevel - } -} - -type invalidPair struct { - position int - key, value any -} - -func (p invalidPair) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddInt64("position", int64(p.position)) - zap.Any("key", p.key).AddTo(enc) - zap.Any("value", p.value).AddTo(enc) - return nil -} - -type invalidPairs []invalidPair - -func (ps invalidPairs) MarshalLogArray(enc zapcore.ArrayEncoder) error { - var err error - for i := range ps { - err = errors.Join(err, enc.AppendObject(ps[i])) - } - return err -} diff --git a/log/log.go b/log/log.go index d456ab51..f73b23b2 100644 --- a/log/log.go +++ b/log/log.go @@ -1,96 +1,23 @@ -// Refer: -// -// https://github.com/go-eden/slf4go -// https://github.com/go-eden/slf4go-zap package log import ( - "fmt" - - "github.com/tableauio/tableau/log/core" - "github.com/tableauio/tableau/log/driver" "github.com/tableauio/tableau/log/driver/zapdriver" "go.uber.org/zap" - "go.uber.org/zap/zapcore" ) -var defaultLogger *Logger - -var gOpts *Options -var atomicLevel zap.AtomicLevel - -func init() { - defaultLogger = &Logger{ - level: core.DebugLevel, - } - gOpts = &Options{} - atomicLevel = zap.NewAtomicLevelAt(zap.DebugLevel) -} +var defaultLogger LoggerIface = zap.NewNop().Sugar() func Init(opts *Options) error { - gOpts = opts // remember as global options. - logger, err := zapdriver.NewLogger(opts.Mode, opts.Level, opts.Filename, opts.Sink) if err != nil { return err } - if err := atomicLevel.UnmarshalText([]byte(opts.Level)); err != nil { - return fmt.Errorf("illegal log level: %s", opts.Level) - } - SetDriver(zapdriver.NewWithLogger(atomicLevel, logger)) + SetLogger(logger.Sugar()) return nil } -func Mode() string { - return gOpts.Mode -} - -func Level() string { - return gOpts.Level -} - -func LevelEnabled(lvl zapcore.Level) bool { - return atomicLevel.Enabled(lvl) -} - -func SetDriver(driver driver.Driver) { - defaultLogger.driver = driver -} - -// Debug uses fmt.Sprint to construct and log a message. -func Debug(args ...any) { - defaultLogger.Debug(args...) -} - -// Info uses fmt.Sprint to construct and log a message. -func Info(args ...any) { - defaultLogger.Info(args...) -} - -// Warn uses fmt.Sprint to construct and log a message. -func Warn(args ...any) { - defaultLogger.Warn(args...) -} - -// Error uses fmt.Sprint to construct and log a message. -func Error(args ...any) { - defaultLogger.Error(args...) -} - -// DPanic uses fmt.Sprint to construct and log a message. In development, the -// logger then panics. (See DPanicLevel for details.) -func DPanic(args ...any) { - defaultLogger.DPanic(args...) -} - -// Panic uses fmt.Sprint to construct and log a message, then panics. -func Panic(args ...any) { - defaultLogger.Panic(args...) -} - -// Fatal uses fmt.Sprint to construct and log a message, then calls os.Exit. -func Fatal(args ...any) { - defaultLogger.Fatal(args...) +func SetLogger(logger LoggerIface) { + defaultLogger = logger } // Debugf uses fmt.Sprintf to log a templated message. @@ -128,39 +55,3 @@ func Panicf(template string, args ...any) { func Fatalf(template string, args ...any) { defaultLogger.Fatalf(template, args...) } - -// Debugw logs a message with some additional context. The variadic key-value -// pairs are treated as they are in With. -func Debugw(msg string, keysAndValues ...any) { - defaultLogger.Debugw(msg, keysAndValues...) -} - -// Infow logs a message with some additional context. -func Infow(msg string, keysAndValues ...any) { - defaultLogger.Infow(msg, keysAndValues...) -} - -// Warnw logs a message with some additional context. -func Warnw(msg string, keysAndValues ...any) { - defaultLogger.Warnw(msg, keysAndValues...) -} - -// Errorw logs a message with some additional context. -func Errorw(msg string, keysAndValues ...any) { - defaultLogger.Errorw(msg, keysAndValues...) -} - -// DPanicw logs a message with some additional context. -func DPanicw(msg string, keysAndValues ...any) { - defaultLogger.DPanicw(msg, keysAndValues...) -} - -// Panicw logs a message with some additional context. -func Panicw(msg string, keysAndValues ...any) { - defaultLogger.Panicw(msg, keysAndValues...) -} - -// Fatalw logs a message with some additional context. -func Fatalw(msg string, keysAndValues ...any) { - defaultLogger.Fatalw(msg, keysAndValues...) -} diff --git a/log/log_test.go b/log/log_test.go index 18f25b64..092cc5ea 100644 --- a/log/log_test.go +++ b/log/log_test.go @@ -5,134 +5,23 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/tableauio/tableau/log/core" - "github.com/tableauio/tableau/log/driver/zapdriver" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" ) -func TestDebug(t *testing.T) { - type args struct { - args []any - } - tests := []struct { - name string - args args - }{ - // TODO: Add test cases. - { - name: "test", - args: args{ - args: []any{"xxx", 1, true}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - Debug(tt.args.args...) - }) - } -} - -func TestInfow(t *testing.T) { - type args struct { - msg string - keysAndValues []any - } - tests := []struct { - name string - args args - }{ - // TODO: Add test cases. - { - name: "test", - args: args{ - msg: "infow test", - keysAndValues: []any{"xxx", 1, "key2", true}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - Infow(tt.args.msg, tt.args.keysAndValues...) - }) - } -} - -func TestLevel(t *testing.T) { - tests := []struct { - name string - want string - }{ - { - name: "test", - want: "DEBUG", - }, - } - err := Init(&Options{ - Level: "DEBUG", - Mode: "FULL", - }) - assert.NoError(t, err) - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := Level(); got != tt.want { - t.Errorf("Level() = %v, want %v", got, tt.want) - } - }) - } -} - func Test_logs(t *testing.T) { - args := []any{"xxx", 1, "key2", true} - Info(args...) - Warn(args...) - Error(args...) - - // Panic(args...) Debugf("count: %d", 1) Infof("count: %d", 1) Warnf("count: %d", 1) Errorf("count: %d", 1) - Debugw("test", args) - Infow("test", args...) - Warnw("test", args) - Errorw("test", args) - assert.Panics(t, func() { - Panic(args...) - }) - assert.Panics(t, func() { - Panic(args...) Panicf("count: %d", 1) }) - assert.Panics(t, func() { - Panicw("test", args) - }) // NOTE: we cannot test fatal, because it will exit the process. // assert.Panics(t, func() { - // Fatal(args...) - // }) - // assert.Panics(t, func() { // Fatalf("count: %d", 1) // }) - // assert.Panics(t, func() { - // Fatalw("test", args) - // }) } func TestMain(m *testing.M) { - defaultLogger = &Logger{ - level: core.DebugLevel, - // driver: &defaultdriver.DefaultDriver{ - // CallerSkip: 1, - // }, - driver: zapdriver.New( - zap.NewDevelopmentConfig(), - zap.AddCallerSkip(4), - zap.WithFatalHook(zapcore.WriteThenPanic), - ), - } os.Exit(m.Run()) } diff --git a/log/logger.go b/log/logger.go index 0a6227b7..599c402f 100644 --- a/log/logger.go +++ b/log/logger.go @@ -1,181 +1,25 @@ -package log - -import ( - "os" - - "github.com/tableauio/tableau/log/core" - "github.com/tableauio/tableau/log/driver" -) - -type LoggerIface interface { - // Debug uses fmt.Sprint to construct and log a message. - Debug(args ...any) - - // Info uses fmt.Sprint to construct and log a message. - Info(args ...any) - - // Warn uses fmt.Sprint to construct and log a message. - Warn(args ...any) - - // Error uses fmt.Sprint to construct and log a message. - Error(args ...any) - - // DPanic uses fmt.Sprint to construct and log a message. In development, the - // logger then panics. (See DPanicLevel for details.) - DPanic(args ...any) - - // Panic uses fmt.Sprint to construct and log a message, then panics. - Panic(args ...any) - - // Fatal uses fmt.Sprint to construct and log a message, then calls os.Exit. - Fatal(args ...any) - - // Debugf uses fmt.Sprintf to log a templated message. - Debugf(format string, args ...any) - - // Infof uses fmt.Sprintf to log a templated message. - Infof(format string, args ...any) - - // Warnf uses fmt.Sprintf to log a templated message. - Warnf(format string, args ...any) - - // Errorf uses fmt.Sprintf to log a templated message. - Errorf(format string, args ...any) - - // DPanicf uses fmt.Sprintf to log a templated message. In development, the - // logger then panics. (See DPanicLevel for details.) - DPanicf(format string, args ...any) - - // Panicf uses fmt.Sprintf to log a templated message, then panics. - Panicf(format string, args ...any) - - // Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit. - Fatalf(format string, args ...any) -} - -type Logger struct { - level core.Level - driver driver.Driver -} - -func (l *Logger) Debug(args ...any) { - l.log(core.DebugLevel, "", args, nil) -} - -func (l *Logger) Info(args ...any) { - l.log(core.InfoLevel, "", args, nil) -} - -func (l *Logger) Warn(args ...any) { - l.log(core.WarnLevel, "", args, nil) -} - -func (l *Logger) Error(args ...any) { - l.log(core.ErrorLevel, "", args, nil) -} - -func (l *Logger) DPanic(args ...any) { - l.log(core.DPanicLevel, "%+v", args, nil) - // TODO: panic only in development - os.Exit(-1) -} - -func (l *Logger) Panic(args ...any) { - l.log(core.PanicLevel, "%+v", args, nil) - os.Exit(-1) -} - -func (l *Logger) Fatal(args ...any) { - l.log(core.FatalLevel, "%+v", args, nil) - os.Exit(-1) -} - -func (l *Logger) Debugf(format string, args ...any) { - l.log(core.DebugLevel, format, args, nil) -} - -func (l *Logger) Infof(format string, args ...any) { - l.log(core.InfoLevel, format, args, nil) -} - -func (l *Logger) Warnf(format string, args ...any) { - l.log(core.WarnLevel, format, args, nil) -} - -func (l *Logger) Errorf(format string, args ...any) { - l.log(core.ErrorLevel, format, args, nil) -} - -func (l *Logger) DPanicf(format string, args ...any) { - l.log(core.DPanicLevel, format, args, nil) - // TODO: panic only in development - panic("log panic") -} - -func (l *Logger) Panicf(format string, args ...any) { - l.log(core.PanicLevel, format, args, nil) - panic("log panic") -} - -func (l *Logger) Fatalf(format string, args ...any) { - l.log(core.FatalLevel, format, args, nil) - os.Exit(-1) -} - -// Debugw logs a message with some additional context. The variadic key-value -// pairs are treated as they are in With. -func (l *Logger) Debugw(msg string, keysAndValues ...any) { - l.log(core.DebugLevel, msg, nil, keysAndValues) -} - -// Infow logs a message with some additional context. -func (l *Logger) Infow(msg string, keysAndValues ...any) { - l.log(core.InfoLevel, msg, nil, keysAndValues) -} - -// Warnw logs a message with some additional context. -func (l *Logger) Warnw(msg string, keysAndValues ...any) { - l.log(core.WarnLevel, msg, nil, keysAndValues) -} - -// Errorw logs a message with some additional context. -func (l *Logger) Errorw(msg string, keysAndValues ...any) { - l.log(core.ErrorLevel, msg, nil, keysAndValues) -} - -// DPanicw logs a message with some additional context. -func (l *Logger) DPanicw(msg string, keysAndValues ...any) { - l.log(core.DPanicLevel, msg, nil, keysAndValues) -} - -// Panicw logs a message with some additional context. -func (l *Logger) Panicw(msg string, keysAndValues ...any) { - l.log(core.PanicLevel, msg, nil, keysAndValues) -} - -// Fatalw logs a message with some additional context. -func (l *Logger) Fatalw(msg string, keysAndValues ...any) { - l.log(core.FatalLevel, msg, nil, keysAndValues) -} - -func (l *Logger) log(lvl core.Level, format string, fmtArgs []any, kvs []any) { - // If logging at this level is completely disabled, skip the overhead of - // string formatting. - // if lvl < DPanicLevel { - // return - // } - - if l.driver == nil { - return - } - - r := &core.Record{ - Level: lvl, - Format: &format, - Args: fmtArgs, - - KVs: kvs, - } - - l.driver.Print(r) -} +package log + +type LoggerIface interface { + // Debugf uses fmt.Sprintf to log a templated message. + Debugf(format string, args ...any) + + // Infof uses fmt.Sprintf to log a templated message. + Infof(format string, args ...any) + + // Warnf uses fmt.Sprintf to log a templated message. + Warnf(format string, args ...any) + + // Errorf uses fmt.Sprintf to log a templated message. + Errorf(format string, args ...any) + + // DPanicf uses fmt.Sprintf to log a templated message. In development, the + // logger then panics. (See DPanicLevel for details.) + DPanicf(format string, args ...any) + + // Panicf uses fmt.Sprintf to log a templated message, then panics. + Panicf(format string, args ...any) + + // Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit. + Fatalf(format string, args ...any) +} diff --git a/log/logger_test.go b/log/logger_test.go deleted file mode 100644 index 49f550dd..00000000 --- a/log/logger_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package log - -import ( - "testing" - - "github.com/tableauio/tableau/log/core" - "github.com/tableauio/tableau/log/driver/defaultdriver" -) - -func TestDefaultLogger_Debugf(t *testing.T) { - type args struct { - format string - args []any - } - tests := []struct { - name string - l *Logger - args args - }{ - // TODO: Add test cases. - { - name: "test", - l: &Logger{ - level: core.DebugLevel, - driver: &defaultdriver.DefaultDriver{}, - }, - args: args{ - format: "format: %s, %d", - args: []any{"haha", 3}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.l.Debugf(tt.args.format, tt.args.args...) - }) - } -} diff --git a/log/options.go b/log/options.go index 8e2d9a70..1d591568 100644 --- a/log/options.go +++ b/log/options.go @@ -18,8 +18,3 @@ type Options struct { // Default: "CONSOLE". Sink string } - -const ( - ModeSimple = "SIMPLE" - ModeFull = "FULL" -)