Browse Source

refactor: enhance logger module

dev
Dnomd343 11 months ago
parent
commit
d29208f465
  1. 17
      logger/encoder.go
  2. 38
      logger/interface.go
  3. 105
      logger/logger.go
  4. 6
      main.go

17
logger/encoder.go

@ -25,9 +25,9 @@ func getGid() uint64 {
// getCaller calculate relative source path of caller. // getCaller calculate relative source path of caller.
func getCaller(ec zapcore.EntryCaller, verbose bool) string { func getCaller(ec zapcore.EntryCaller, verbose bool) string {
file, err := filepath.Rel(logHandle.path, ec.File) file, err := filepath.Rel(project, ec.File)
if err != nil { if err != nil {
return "undefined" return "unknown"
} }
if verbose { if verbose {
return file + ":" + strconv.Itoa(ec.Line) return file + ":" + strconv.Itoa(ec.Line)
@ -46,24 +46,23 @@ func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
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(logHandle.prefix), // colored prefix color.Cyan.Render(logger.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(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { func callerEncoder(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
if !logHandle.verbose { if !logger.verbose {
enc.AppendString("[" + getCaller(ec, false) + "]") enc.AppendString("[" + getCaller(ec, false) + "]")
return return
} }
enc.AppendString(fmt.Sprintf("[%d] [%s]", getGid(), getCaller(ec, true))) enc.AppendString(fmt.Sprintf("[%d] [%s]", getGid(), getCaller(ec, true)))
} }
// callerColoredEncoder formats caller in square brackets with // callerColoredEncoder formats caller in square brackets with magenta color.
// magenta color.
func callerColoredEncoder(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { func callerColoredEncoder(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
if !logHandle.verbose { if !logger.verbose {
enc.AppendString(color.Magenta.Render("[" + getCaller(ec, false) + "]")) enc.AppendString(color.Magenta.Render("[" + getCaller(ec, false) + "]"))
return return
} }
@ -79,8 +78,8 @@ func levelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString("[" + level.CapitalString() + "]") enc.AppendString("[" + level.CapitalString() + "]")
} }
// levelColoredEncoder formats log level using square brackets // levelColoredEncoder formats log level using square brackets and uses
// and uses different colors. // different colors.
func levelColoredEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { func levelColoredEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
levelStr := "[" + level.CapitalString() + "]" levelStr := "[" + level.CapitalString() + "]"
switch level { switch level {

38
logger/interface.go

@ -14,46 +14,50 @@ const (
) )
func Debugf(template string, args ...interface{}) { func Debugf(template string, args ...interface{}) {
logHandle.sugar.Debugf(template, args...) logger.entry.Debugf(template, args...)
} }
func Infof(template string, args ...interface{}) { func Infof(template string, args ...interface{}) {
logHandle.sugar.Infof(template, args...) logger.entry.Infof(template, args...)
} }
func Warnf(template string, args ...interface{}) { func Warnf(template string, args ...interface{}) {
logHandle.sugar.Warnf(template, args...) logger.entry.Warnf(template, args...)
} }
func Errorf(template string, args ...interface{}) { func Errorf(template string, args ...interface{}) {
logHandle.sugar.Errorf(template, args...) logger.entry.Errorf(template, args...)
} }
func Panicf(template string, args ...interface{}) { func Panicf(template string, args ...interface{}) {
logHandle.sugar.Panicf(template, args...) logger.entry.Panicf(template, args...)
} }
// GetLevel return the current logger level. // GetLevel return the current logger level.
func GetLevel() zapcore.Level { func GetLevel() zapcore.Level {
return logHandle.level.Level() return logger.level.Level()
} }
// SetLevel configure logger output level. Note that debug level // SetLevel configure logger output level. Note that debug level will output
// will output more information and reduce performance. // more information and reduce performance.
func SetLevel(level zapcore.Level) { func SetLevel(level zapcore.Level) {
logHandle.level.SetLevel(level) logger.level.SetLevel(level)
if level == DebugLevel { if level == DebugLevel {
logHandle.verbose = true logger.verbose = true
} else { } else {
logHandle.verbose = false logger.verbose = false
} }
} }
// AddOutputs adds more plain output channel to the logger module. // AddWriters add more writers to target log channel.
func AddOutputs(outputs ...io.Writer) { func AddWriters(colored bool, writers ...io.Writer) {
var writers []zapcore.WriteSyncer var syncWriters []zapcore.WriteSyncer
for _, output := range outputs { for _, writer := range writers {
writers = append(writers, zapcore.AddSync(output)) syncWriters = append(syncWriters, zapcore.AddSync(writer))
}
if !colored {
logger.addPlainWrites(syncWriters...)
} else {
logger.addColoredWrites(syncWriters...)
} }
addWrites(writers...)
} }

105
logger/logger.go

@ -8,21 +8,44 @@ import (
"runtime" "runtime"
) )
type logger struct { var project string // project absolute path
logger *zap.Logger var logger *logCore // singleton logger handle
level *zap.AtomicLevel
sugar *zap.SugaredLogger // logChannel handle multiple writers with unified format.
type logChannel struct {
encoder zapcore.Encoder
writers []zapcore.WriteSyncer writers []zapcore.WriteSyncer
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 logHandle *logger // singleton logger handle // logCore manage log level, channels and other interfaces.
type logCore struct {
prefix string // custom output prefix
verbose bool // show verbose information
plain logChannel // log channel with plain text
colored logChannel // log channel with colored text
level *zap.AtomicLevel // zap log level pointer
entry *zap.SugaredLogger // zap sugared logger entry
}
func init() {
_, src, _, _ := runtime.Caller(0) // absolute path of current code
project = path.Join(path.Dir(src), "../")
// logConfig generates log config for XProxy. zapLevel := zap.NewAtomicLevelAt(InfoLevel) // using info level in default
func logConfig(colored bool) zapcore.EncoderConfig { logger = &logCore{
verbose: false,
level: &zapLevel,
prefix: "[XProxy]",
plain: buildChannel(false),
colored: buildChannel(true),
}
logger.addColoredWrites(os.Stderr) // output into stderr in default
}
// buildChannel generate logChannel with `colored` option.
func buildChannel(colored bool) logChannel {
config := zapcore.EncoderConfig{ config := zapcore.EncoderConfig{
ConsoleSeparator: " ", ConsoleSeparator: " ",
MessageKey: "msg", MessageKey: "msg",
@ -33,46 +56,40 @@ func logConfig(colored bool) zapcore.EncoderConfig {
EncodeLevel: levelEncoder, EncodeLevel: levelEncoder,
EncodeCaller: callerEncoder, EncodeCaller: callerEncoder,
} }
if colored { if colored { // using colored version
config.EncodeTime = timeColoredEncoder config.EncodeTime = timeColoredEncoder
config.EncodeLevel = levelColoredEncoder config.EncodeLevel = levelColoredEncoder
config.EncodeCaller = callerColoredEncoder config.EncodeCaller = callerColoredEncoder
} }
return config return logChannel{
encoder: zapcore.NewConsoleEncoder(config),
writers: []zapcore.WriteSyncer{}, // without any writer
}
} }
func init() { // update refreshes the binding of the log core to the writers.
zapLevel := zap.NewAtomicLevelAt(InfoLevel) // using info level in default func (handle *logCore) update() {
zapCore := zapcore.NewCore( buildCore := func(channel *logChannel) zapcore.Core { // build zap core from logChannel
zapcore.NewConsoleEncoder(logConfig(true)), // colorful output return zapcore.NewCore(
zapcore.Lock(os.Stderr), channel.encoder,
zapLevel, zap.CombineWriteSyncers(channel.writers...),
) handle.level,
zapLogger := zap.New(zapCore, zap.AddCaller(), zap.AddCallerSkip(1)) )
_, src, _, _ := runtime.Caller(0) // absolute path of current code
logHandle = &logger{
logger: zapLogger,
level: &zapLevel,
stderr: zapCore,
sugar: zapLogger.Sugar(),
writers: []zapcore.WriteSyncer{},
path: path.Join(path.Dir(src), "../"),
prefix: "[XProxy]",
verbose: false,
} }
handle.entry = zap.New(
zapcore.NewTee(buildCore(&handle.plain), buildCore(&handle.colored)),
zap.AddCaller(), zap.AddCallerSkip(1),
).Sugar()
} }
// addWrites adds more plain log writers. // addPlainWrites adds plain text writers to the logCore.
func addWrites(writers ...zapcore.WriteSyncer) { func (handle *logCore) addPlainWrites(writers ...zapcore.WriteSyncer) {
logHandle.writers = append(logHandle.writers, writers...) handle.plain.writers = append(handle.plain.writers, writers...)
plainCore := zapcore.NewCore( handle.update()
zapcore.NewConsoleEncoder(logConfig(false)), // without colored }
zap.CombineWriteSyncers(logHandle.writers...),
logHandle.level, // addColoredWrites adds colored text writers to the logCore.
) func (handle *logCore) addColoredWrites(writers ...zapcore.WriteSyncer) {
logHandle.logger = zap.New( handle.colored.writers = append(handle.colored.writers, writers...)
zapcore.NewTee(logHandle.stderr, plainCore), handle.update()
zap.AddCaller(), zap.AddCallerSkip(1),
)
logHandle.sugar = logHandle.logger.Sugar()
} }

6
main.go

@ -6,6 +6,8 @@ import (
) )
func main() { func main() {
//logger.SetLevel(zap.DebugLevel)
//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")
@ -19,13 +21,13 @@ func main() {
logger.Debugf("output msg 1 at debug") logger.Debugf("output msg 1 at debug")
logger.Infof("output msg 1 at info") logger.Infof("output msg 1 at info")
logger.Warnf("output msg 1 at warn") logger.Warnf("output msg 1 at warn")
logger.AddOutputs(fp1, fp2) logger.AddWriters(false, fp1, fp2)
logger.SetLevel(logger.InfoLevel) logger.SetLevel(logger.InfoLevel)
logger.Debugf("output msg 2 at debug") logger.Debugf("output msg 2 at debug")
logger.Infof("output msg 2 at info") logger.Infof("output msg 2 at info")
logger.Warnf("output msg 2 at warn") logger.Warnf("output msg 2 at warn")
logger.SetLevel(logger.WarnLevel) logger.SetLevel(logger.WarnLevel)
logger.AddOutputs(fp3) logger.AddWriters(true, fp3)
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")

Loading…
Cancel
Save