Browse Source

feat: add verbose option

dev
Dnomd343 1 year ago
parent
commit
f1618a3c4e
  1. 47
      next/logger/encoder.go
  2. 36
      next/logger/interface.go
  3. 52
      next/logger/logger.go
  4. 5
      next/main.go

47
next/logger/encoder.go

@ -5,14 +5,16 @@ import (
"fmt" "fmt"
"github.com/gookit/color" "github.com/gookit/color"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
"path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"time" "time"
) )
// getGID get goroutine ID only for debugging. // getGid get goroutine ID only for debugging.
// -> https://blog.sgmansfield.com/2015/12/goroutine-ids/ // -> https://blog.sgmansfield.com/2015/12/goroutine-ids/
func getGID() uint64 { func getGid() uint64 {
b := make([]byte, 64) b := make([]byte, 64)
b = b[:runtime.Stack(b, false)] b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine ")) b = bytes.TrimPrefix(b, []byte("goroutine "))
@ -21,41 +23,54 @@ func getGID() uint64 {
return n return n
} }
// getCaller calculate relative source path of caller.
func getCaller(ec zapcore.EntryCaller, verbose bool) string {
file, err := filepath.Rel(logHandle.path, ec.File)
if err != nil {
return "undefined"
}
if verbose {
return file + ":" + strconv.Itoa(ec.Line)
}
file, _ = strings.CutSuffix(file, ".go") // remove `.go` suffix
return file
}
// timeEncoder formats the time as a string. // timeEncoder formats the time as a string.
func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05.000")) enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
} }
// timeColoredEncoder formats the time as a colored string // timeColoredEncoder formats the time as a colored string
// with `[XProxy]` prefix. // with custom prefix.
func timeColoredEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { func timeColoredEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(fmt.Sprintf( enc.AppendString(fmt.Sprintf(
"%s %s", "%s %s",
color.Cyan.Render("[XProxy]"), color.Cyan.Render(logHandle.prefix), // colored prefix
color.Gray.Render(t.Format("2006-01-02 15:04:05.000")), color.Gray.Render(t.Format("2006-01-02 15:04:05.000")),
)) ))
} }
// callerEncoder formats caller in square brackets. // callerEncoder formats caller in square brackets.
func callerEncoder(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { func callerEncoder(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
if !handle.gid { if !logHandle.verbose {
enc.AppendString("[" + caller.TrimmedPath() + "]") enc.AppendString("[" + getCaller(ec, false) + "]")
} else { return
enc.AppendString(fmt.Sprintf("[%s] [%d]", caller.TrimmedPath(), getGID()))
} }
enc.AppendString(fmt.Sprintf("[%d] [%s]", getGid(), getCaller(ec, true)))
} }
// callerColoredEncoder formats caller in square brackets // callerColoredEncoder formats caller in square brackets with
// with magenta color. // magenta color.
func callerColoredEncoder(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { func callerColoredEncoder(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
if !handle.gid { if !logHandle.verbose {
enc.AppendString(color.Magenta.Render("[" + caller.TrimmedPath() + "]")) enc.AppendString(color.Magenta.Render("[" + getCaller(ec, false) + "]"))
return return
} }
enc.AppendString(fmt.Sprintf( enc.AppendString(fmt.Sprintf(
"%s %s", "%s %s",
color.Magenta.Render("["+caller.TrimmedPath()+"]"), color.Blue.Render(fmt.Sprintf("[%d]", getGid())),
color.Blue.Render(fmt.Sprintf("[%d]", getGID())), color.Magenta.Render("["+getCaller(ec, true)+"]"),
)) ))
} }

36
next/logger/interface.go

@ -13,35 +13,43 @@ const (
PanicLevel = zapcore.PanicLevel PanicLevel = zapcore.PanicLevel
) )
func GetLevel() zapcore.Level {
return handle.level.Level()
}
func SetLevel(level zapcore.Level) {
handle.level.SetLevel(level)
}
func Debugf(template string, args ...interface{}) { func Debugf(template string, args ...interface{}) {
handle.sugar.Debugf(template, args...) logHandle.sugar.Debugf(template, args...)
} }
func Infof(template string, args ...interface{}) { func Infof(template string, args ...interface{}) {
handle.sugar.Infof(template, args...) logHandle.sugar.Infof(template, args...)
} }
func Warnf(template string, args ...interface{}) { func Warnf(template string, args ...interface{}) {
handle.sugar.Warnf(template, args...) logHandle.sugar.Warnf(template, args...)
} }
func Errorf(template string, args ...interface{}) { func Errorf(template string, args ...interface{}) {
handle.sugar.Errorf(template, args...) logHandle.sugar.Errorf(template, args...)
} }
func Panicf(template string, args ...interface{}) { func Panicf(template string, args ...interface{}) {
handle.sugar.Panicf(template, args...) logHandle.sugar.Panicf(template, args...)
}
// GetLevel return the current logger level.
func GetLevel() zapcore.Level {
return logHandle.level.Level()
}
// SetLevel configure logger output level. Note that debug level
// will output more information and reduce performance.
func SetLevel(level zapcore.Level) {
logHandle.level.SetLevel(level)
if level == DebugLevel {
logHandle.verbose = true
} else {
logHandle.verbose = false
}
} }
// AddOutputs adds more plain log outputs. // AddOutputs adds more plain output channel to the logger module.
func AddOutputs(outputs ...io.Writer) { func AddOutputs(outputs ...io.Writer) {
var writers []zapcore.WriteSyncer var writers []zapcore.WriteSyncer
for _, output := range outputs { for _, output := range outputs {

52
next/logger/logger.go

@ -4,18 +4,22 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
"os" "os"
"path"
"runtime"
) )
type Logger struct { type logger struct {
gid bool
logger *zap.Logger logger *zap.Logger
level *zap.AtomicLevel level *zap.AtomicLevel
sugar *zap.SugaredLogger sugar *zap.SugaredLogger
writers []zapcore.WriteSyncer writers []zapcore.WriteSyncer
stdCore zapcore.Core stderr zapcore.Core // fixed stderr output
prefix string // custom output prefix
path string // project absolute path
verbose bool // show goroutine id and caller line
} }
var handle Logger var logHandle *logger // singleton logger handle
// logConfig generates log config for XProxy. // logConfig generates log config for XProxy.
func logConfig(colored bool) zapcore.EncoderConfig { func logConfig(colored bool) zapcore.EncoderConfig {
@ -38,33 +42,37 @@ func logConfig(colored bool) zapcore.EncoderConfig {
} }
func init() { func init() {
level := zap.NewAtomicLevelAt(DebugLevel) zapLevel := zap.NewAtomicLevelAt(InfoLevel) // using info level in default
core := zapcore.NewCore( zapCore := zapcore.NewCore(
zapcore.NewConsoleEncoder(logConfig(true)), zapcore.NewConsoleEncoder(logConfig(true)), // colorful output
zapcore.Lock(os.Stderr), level, zapcore.Lock(os.Stderr),
zapLevel,
) )
logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) zapLogger := zap.New(zapCore, zap.AddCaller(), zap.AddCallerSkip(1))
handle = Logger{ _, src, _, _ := runtime.Caller(0) // absolute path of current code
gid: true, logHandle = &logger{
logger: logger, logger: zapLogger,
level: &level, level: &zapLevel,
sugar: logger.Sugar(), stderr: zapCore,
sugar: zapLogger.Sugar(),
writers: []zapcore.WriteSyncer{}, writers: []zapcore.WriteSyncer{},
stdCore: core, path: path.Join(path.Dir(src), "../"),
prefix: "[XProxy]",
verbose: false,
} }
} }
// addWrites adds more plain log writers. // addWrites adds more plain log writers.
func addWrites(writers ...zapcore.WriteSyncer) { func addWrites(writers ...zapcore.WriteSyncer) {
handle.writers = append(handle.writers, writers...) logHandle.writers = append(logHandle.writers, writers...)
plainCore := zapcore.NewCore( plainCore := zapcore.NewCore(
zapcore.NewConsoleEncoder(logConfig(false)), zapcore.NewConsoleEncoder(logConfig(false)), // without colored
zap.CombineWriteSyncers(handle.writers...), zap.CombineWriteSyncers(logHandle.writers...),
handle.level, logHandle.level,
) )
handle.logger = zap.New( logHandle.logger = zap.New(
zapcore.NewTee(handle.stdCore, plainCore), zapcore.NewTee(logHandle.stderr, plainCore),
zap.AddCaller(), zap.AddCallerSkip(1), zap.AddCaller(), zap.AddCallerSkip(1),
) )
handle.sugar = handle.logger.Sugar() logHandle.sugar = logHandle.logger.Sugar()
} }

5
next/main.go

@ -6,7 +6,6 @@ import (
) )
func main() { func main() {
//logger.Debugf("here is %s level", "debug") //logger.Debugf("here is %s level", "debug")
//logger.Infof("here is %s level", "info") //logger.Infof("here is %s level", "info")
//logger.Warnf("here is %s level", "warn") //logger.Warnf("here is %s level", "warn")
@ -30,4 +29,8 @@ func main() {
logger.Debugf("output msg 3 at debug") logger.Debugf("output msg 3 at debug")
logger.Infof("output msg 3 at info") logger.Infof("output msg 3 at info")
logger.Warnf("output msg 3 at warn") logger.Warnf("output msg 3 at warn")
logger.SetLevel(logger.DebugLevel)
logger.Debugf("output msg 4 at debug")
logger.Infof("output msg 4 at info")
logger.Warnf("output msg 4 at warn")
} }

Loading…
Cancel
Save