From fae4dea37a702ebea32ce7378944c5c8aebdf75a Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 15 Jul 2021 13:31:32 +0800 Subject: [PATCH] improve color feature for package glog --- .example/os/glog/glog_color.go | 15 +++++++ os/gfile/gfile_contents.go | 2 +- os/glog/glog_chaining.go | 2 +- os/glog/glog_logger.go | 38 +++++++++++++----- os/glog/glog_logger_chaining.go | 14 ------- os/glog/glog_logger_color.go | 41 ++++++++++++++++++++ os/glog/glog_logger_config.go | 44 ++++++++++----------- os/glog/glog_logger_handler.go | 69 ++++++++++----------------------- os/glog/glog_logger_level.go | 29 ++------------ 9 files changed, 130 insertions(+), 124 deletions(-) create mode 100644 .example/os/glog/glog_color.go create mode 100644 os/glog/glog_logger_color.go diff --git a/.example/os/glog/glog_color.go b/.example/os/glog/glog_color.go new file mode 100644 index 000000000..b178db5e0 --- /dev/null +++ b/.example/os/glog/glog_color.go @@ -0,0 +1,15 @@ +package main + +import ( + "github.com/gogf/gf/frame/g" +) + +func main() { + g.Log().Print("Print") + g.Log().Debug("Debug") + g.Log().Info("Info") + g.Log().Notice("Notice") + g.Log().Warning("Warning") + g.Log().Error("Error") + g.Log().Critical("Critical") +} diff --git a/os/gfile/gfile_contents.go b/os/gfile/gfile_contents.go index 6b3a7c5d6..048e15d76 100644 --- a/os/gfile/gfile_contents.go +++ b/os/gfile/gfile_contents.go @@ -16,7 +16,7 @@ import ( ) var ( - // Buffer size for reading file content. + // DefaultReadBuffer is the buffer size for reading file content. DefaultReadBuffer = 1024 ) diff --git a/os/glog/glog_chaining.go b/os/glog/glog_chaining.go index f55012fa3..db25843ef 100644 --- a/os/glog/glog_chaining.go +++ b/os/glog/glog_chaining.go @@ -78,7 +78,7 @@ func StackWithFilter(filter string) *Logger { return logger.StackWithFilter(filter) } -// StdPrint is a chaining function, +// Stdout is a chaining function, // which enables/disables stdout for the current logging content output. // It's enabled in default. func Stdout(enabled ...bool) *Logger { diff --git a/os/glog/glog_logger.go b/os/glog/glog_logger.go index 891bd2ab3..be9a4c210 100644 --- a/os/glog/glog_logger.go +++ b/os/glog/glog_logger.go @@ -7,7 +7,6 @@ package glog import ( - "bytes" "context" "fmt" "github.com/gogf/gf/container/gtype" @@ -119,6 +118,7 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { index: -1, Ctx: ctx, Time: now, + Color: defaultLevelColor[level], Level: level, } ) @@ -219,30 +219,48 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { } } -// printToWriter writes buffer to writer. -func (l *Logger) printToWriter(ctx context.Context, input *HandlerInput) { +// doPrint outputs the logging content according configuration. +func (l *Logger) doPrint(ctx context.Context, input *HandlerInput) { if l.config.Writer == nil { // Output content to disk file. if l.config.Path != "" { - l.printToFile(ctx, input.Time, input.Buffer()) + l.printToFile(ctx, input.Time, input) } // Allow output to stdout? if l.config.StdoutPrint { - if err := input.Stdout(); err != nil { - intlog.Error(ctx, err) - } + l.printToStdout(ctx, input) } } else { - if _, err := l.config.Writer.Write(input.Buffer().Bytes()); err != nil { - // panic(err) + // Output to custom writer. + l.printToWriter(ctx, input) + } +} + +// printToWriter writes buffer to writer. +func (l *Logger) printToWriter(ctx context.Context, input *HandlerInput) { + if l.config.Writer != nil { + var ( + buffer = input.getBuffer(l.config.WriterColorEnable) + ) + if _, err := l.config.Writer.Write(buffer.Bytes()); err != nil { + intlog.Error(ctx, err) + } + } +} + +// printToStdout outputs logging content to stdout. +func (l *Logger) printToStdout(ctx context.Context, input *HandlerInput) { + if l.config.StdoutPrint { + if _, err := os.Stdout.Write(input.getBuffer(true).Bytes()); err != nil { intlog.Error(ctx, err) } } } // printToFile outputs logging content to disk file. -func (l *Logger) printToFile(ctx context.Context, t time.Time, buffer *bytes.Buffer) { +func (l *Logger) printToFile(ctx context.Context, t time.Time, input *HandlerInput) { var ( + buffer = input.getBuffer(l.config.WriterColorEnable) logFilePath = l.getFilePath(t) memoryLockKey = memoryLockPrefixForPrintingToFile + logFilePath ) diff --git a/os/glog/glog_logger_chaining.go b/os/glog/glog_logger_chaining.go index bb9529023..c0213b982 100644 --- a/os/glog/glog_logger_chaining.go +++ b/os/glog/glog_logger_chaining.go @@ -8,7 +8,6 @@ package glog import ( "context" - "github.com/fatih/color" "github.com/gogf/gf/internal/intlog" "io" @@ -246,16 +245,3 @@ func (l *Logger) Async(enabled ...bool) *Logger { } return logger } - -// Color is a chaining function, -// which set level prefix color logging output feature. -func (l *Logger) Color(color color.Attribute) *Logger { - logger := (*Logger)(nil) - if l.parent == nil { - logger = l.Clone() - } else { - logger = l - } - logger.config.currentColor = color - return logger -} diff --git a/os/glog/glog_logger_color.go b/os/glog/glog_logger_color.go new file mode 100644 index 000000000..6ab51a0f3 --- /dev/null +++ b/os/glog/glog_logger_color.go @@ -0,0 +1,41 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package glog + +import "github.com/fatih/color" + +const ( + COLOR_BLACK = 30 + iota + COLOR_RED + COLOR_GREEN + COLOR_YELLOW + COLOR_BLUE + COLOR_MAGENTA + COLOR_CYAN + COLOR_WHITE +) + +// defaultLevelColor defines the default level and its mapping prefix string. +var defaultLevelColor = map[int]int{ + LEVEL_DEBU: COLOR_YELLOW, + LEVEL_INFO: COLOR_GREEN, + LEVEL_NOTI: COLOR_CYAN, + LEVEL_WARN: COLOR_YELLOW, + LEVEL_ERRO: COLOR_RED, + LEVEL_CRIT: COLOR_RED, + LEVEL_PANI: COLOR_RED, + LEVEL_FATA: COLOR_RED, +} + +// getColoredStr returns a string that is colored by given color. +func (l *Logger) getColoredStr(c int, s string) string { + return color.New(color.Attribute(c)).Sprint(s) +} + +func (l *Logger) getColorByLevel(level int) int { + return defaultLevelColor[level] +} diff --git a/os/glog/glog_logger_config.go b/os/glog/glog_logger_config.go index d16564662..b4d17b6f7 100644 --- a/os/glog/glog_logger_config.go +++ b/os/glog/glog_logger_config.go @@ -7,7 +7,6 @@ package glog import ( - "github.com/fatih/color" "io" "strings" "time" @@ -21,28 +20,27 @@ import ( // Config is the configuration object for logger. type Config struct { - Handlers []Handler `json:"-"` // Logger handlers which implement feature similar as middleware. - Writer io.Writer `json:"-"` // Customized io.Writer. - Flags int `json:"flags"` // Extra flags for logging output features. - Path string `json:"path"` // Logging directory path. - File string `json:"file"` // Format for logging file. - Level int `json:"level"` // Output level. - Prefix string `json:"prefix"` // Prefix string for every logging content. - StSkip int `json:"stSkip"` // Skip count for stack. - StStatus int `json:"stStatus"` // Stack status(1: enabled - default; 0: disabled) - StFilter string `json:"stFilter"` // Stack string filter. - CtxKeys []interface{} `json:"ctxKeys"` // Context keys for logging, which is used for value retrieving from context. - HeaderPrint bool `json:"header"` // Print header or not(true in default). - StdoutPrint bool `json:"stdout"` // Output to stdout or not(true in default). - LevelPrefixes map[int]string `json:"levelPrefixes"` // Logging level to its prefix string mapping. - RotateSize int64 `json:"rotateSize"` // Rotate the logging file if its size > 0 in bytes. - RotateExpire time.Duration `json:"rotateExpire"` // Rotate the logging file if its mtime exceeds this duration. - RotateBackupLimit int `json:"rotateBackupLimit"` // Max backup for rotated files, default is 0, means no backups. - RotateBackupExpire time.Duration `json:"rotateBackupExpire"` // Max expire for rotated files, which is 0 in default, means no expiration. - RotateBackupCompress int `json:"rotateBackupCompress"` // Compress level for rotated files using gzip algorithm. It's 0 in default, means no compression. - RotateCheckInterval time.Duration `json:"rotateCheckInterval"` // Asynchronizely checks the backups and expiration at intervals. It's 1 hour in default. - FileColorEnable bool `json:"fileColorEnable"` // Logging level prefix with color or not (false in default). - currentColor color.Attribute `json:"-"` + Handlers []Handler `json:"-"` // Logger handlers which implement feature similar as middleware. + Writer io.Writer `json:"-"` // Customized io.Writer. + Flags int `json:"flags"` // Extra flags for logging output features. + Path string `json:"path"` // Logging directory path. + File string `json:"file"` // Format for logging file. + Level int `json:"level"` // Output level. + Prefix string `json:"prefix"` // Prefix string for every logging content. + StSkip int `json:"stSkip"` // Skip count for stack. + StStatus int `json:"stStatus"` // Stack status(1: enabled - default; 0: disabled) + StFilter string `json:"stFilter"` // Stack string filter. + CtxKeys []interface{} `json:"ctxKeys"` // Context keys for logging, which is used for value retrieving from context. + HeaderPrint bool `json:"header"` // Print header or not(true in default). + StdoutPrint bool `json:"stdout"` // Output to stdout or not(true in default). + LevelPrefixes map[int]string `json:"levelPrefixes"` // Logging level to its prefix string mapping. + RotateSize int64 `json:"rotateSize"` // Rotate the logging file if its size > 0 in bytes. + RotateExpire time.Duration `json:"rotateExpire"` // Rotate the logging file if its mtime exceeds this duration. + RotateBackupLimit int `json:"rotateBackupLimit"` // Max backup for rotated files, default is 0, means no backups. + RotateBackupExpire time.Duration `json:"rotateBackupExpire"` // Max expire for rotated files, which is 0 in default, means no expiration. + RotateBackupCompress int `json:"rotateBackupCompress"` // Compress level for rotated files using gzip algorithm. It's 0 in default, means no compression. + RotateCheckInterval time.Duration `json:"rotateCheckInterval"` // Asynchronously checks the backups and expiration at intervals. It's 1 hour in default. + WriterColorEnable bool `json:"writerColorEnable"` // Logging level prefix with color to writer or not (false in default). } // DefaultConfig returns the default configuration for logger. diff --git a/os/glog/glog_logger_handler.go b/os/glog/glog_logger_handler.go index 152629e90..e2d990567 100644 --- a/os/glog/glog_logger_handler.go +++ b/os/glog/glog_logger_handler.go @@ -9,9 +9,6 @@ package glog import ( "bytes" "context" - "github.com/fatih/color" - "github.com/gogf/gf/internal/intlog" - "os" "time" ) @@ -23,6 +20,7 @@ type HandlerInput struct { Ctx context.Context Time time.Time TimeFormat string + Color int Level int LevelFormat string CallerFunc string @@ -35,52 +33,34 @@ type HandlerInput struct { // defaultHandler is the default handler for logger. func defaultHandler(ctx context.Context, input *HandlerInput) { - input.logger.printToWriter(ctx, input) + input.logger.doPrint(ctx, input) } -func (i *HandlerInput) addStringToBuffer(buffer *bytes.Buffer, s string) { - if buffer.Len() > 0 { - buffer.WriteByte(' ') +func (i *HandlerInput) addStringToBuffer(buffer *bytes.Buffer, strings ...string) { + for _, s := range strings { + if buffer.Len() > 0 { + buffer.WriteByte(' ') + } + buffer.WriteString(s) } - buffer.WriteString(s) } func (i *HandlerInput) Buffer() *bytes.Buffer { + return i.getBuffer(false) +} + +func (i *HandlerInput) getBuffer(withColor bool) *bytes.Buffer { buffer := bytes.NewBuffer(nil) buffer.WriteString(i.TimeFormat) - levelString := i.LevelFormat - if i.logger.config.FileColorEnable { - fg := i.getLevelFormatColor() - levelString = color.New(fg).Sprintf(i.LevelFormat) + if i.LevelFormat != "" { + if withColor { + i.addStringToBuffer(buffer, i.logger.getColoredStr( + i.logger.getColorByLevel(i.Level), i.LevelFormat, + )) + } else { + i.addStringToBuffer(buffer, i.LevelFormat) + } } - i.addStringToBuffer(buffer, levelString) - msg := i.GetContent() - i.addStringToBuffer(buffer, msg.String()) - return buffer -} - -// Stdout print log to console -func (i *HandlerInput) Stdout() error { - if _, err := os.Stdout.Write([]byte(i.TimeFormat)); err != nil { - intlog.Error(i.Ctx, err) - return err - } - fg := i.getLevelFormatColor() - if _, err := color.New(fg).Print(" " + i.LevelFormat + " "); err != nil { - intlog.Error(i.Ctx, err) - return err - } - msg := i.GetContent() - if _, err := os.Stdout.Write(msg.Bytes()); err != nil { - intlog.Error(i.Ctx, err) - return err - } - return nil -} - -// GetContent returns the primary content. -func (i *HandlerInput) GetContent() *bytes.Buffer { - buffer := bytes.NewBuffer(nil) if i.CallerFunc != "" { i.addStringToBuffer(buffer, i.CallerFunc) } @@ -100,15 +80,6 @@ func (i *HandlerInput) GetContent() *bytes.Buffer { return buffer } -// getLevelFormatColor returns the prefix string color. -func (i *HandlerInput) getLevelFormatColor() color.Attribute { - fg := defaultLevelColor[i.Level] - if i.logger.config.currentColor != 0 { - fg = i.logger.config.currentColor - } - return fg -} - func (i *HandlerInput) String() string { return i.Buffer().String() } diff --git a/os/glog/glog_logger_level.go b/os/glog/glog_logger_level.go index f726bd7bb..67fae2cd7 100644 --- a/os/glog/glog_logger_level.go +++ b/os/glog/glog_logger_level.go @@ -7,7 +7,6 @@ package glog import ( - "github.com/fatih/color" "github.com/gogf/gf/errors/gerror" "strings" ) @@ -29,17 +28,6 @@ const ( LEVEL_FATA // 1024 ) -const ( - COLOR_BLACK = 30 + iota - COLOR_RED - COLOR_GREEN - COLOR_YELLOW - COLOR_BLUE - COLOR_MAGENTA - COLOR_CYAN - COLOR_WHITE -) - // defaultLevelPrefixes defines the default level and its mapping prefix string. var defaultLevelPrefixes = map[int]string{ LEVEL_DEBU: "DEBU", @@ -52,18 +40,6 @@ var defaultLevelPrefixes = map[int]string{ LEVEL_FATA: "FATA", } -// defaultLevelColor defines the default level and its mapping prefix string. -var defaultLevelColor = map[int]color.Attribute{ - LEVEL_DEBU: COLOR_YELLOW, - LEVEL_INFO: COLOR_GREEN, - LEVEL_NOTI: COLOR_CYAN, - LEVEL_WARN: COLOR_YELLOW, - LEVEL_ERRO: COLOR_RED, - LEVEL_CRIT: COLOR_RED, - LEVEL_PANI: COLOR_RED, - LEVEL_FATA: COLOR_RED, -} - // levelStringMap defines level string name to its level mapping. var levelStringMap = map[string]int{ "ALL": LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT, @@ -125,8 +101,9 @@ func (l *Logger) GetLevelPrefix(level int) string { // getLevelPrefixWithBrackets returns the prefix string with brackets for specified level. func (l *Logger) getLevelPrefixWithBrackets(level int) string { + levelStr := "" if s, ok := l.config.LevelPrefixes[level]; ok { - return "[" + s + "]" + levelStr = "[" + s + "]" } - return "" + return levelStr }