Browse Source

refactor: enhance logger module

dev
Dnomd343 5 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.
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 {
return "undefined"
return "unknown"
}
if verbose {
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) {
enc.AppendString(fmt.Sprintf(
"%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")),
))
}
// callerEncoder formats caller in square brackets.
func callerEncoder(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
if !logHandle.verbose {
if !logger.verbose {
enc.AppendString("[" + getCaller(ec, false) + "]")
return
}
enc.AppendString(fmt.Sprintf("[%d] [%s]", getGid(), getCaller(ec, true)))
}
// callerColoredEncoder formats caller in square brackets with
// magenta color.
// callerColoredEncoder formats caller in square brackets with magenta color.
func callerColoredEncoder(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
if !logHandle.verbose {
if !logger.verbose {
enc.AppendString(color.Magenta.Render("[" + getCaller(ec, false) + "]"))
return
}
@ -79,8 +78,8 @@ func levelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString("[" + level.CapitalString() + "]")
}
// levelColoredEncoder formats log level using square brackets
// and uses different colors.
// levelColoredEncoder formats log level using square brackets and uses
// different colors.
func levelColoredEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
levelStr := "[" + level.CapitalString() + "]"
switch level {

38
logger/interface.go

@ -14,46 +14,50 @@ const (
)
func Debugf(template string, args ...interface{}) {
logHandle.sugar.Debugf(template, args...)
logger.entry.Debugf(template, args...)
}
func Infof(template string, args ...interface{}) {
logHandle.sugar.Infof(template, args...)
logger.entry.Infof(template, args...)
}
func Warnf(template string, args ...interface{}) {
logHandle.sugar.Warnf(template, args...)
logger.entry.Warnf(template, args...)
}
func Errorf(template string, args ...interface{}) {
logHandle.sugar.Errorf(template, args...)
logger.entry.Errorf(template, args...)
}
func Panicf(template string, args ...interface{}) {
logHandle.sugar.Panicf(template, args...)
logger.entry.Panicf(template, args...)
}
// GetLevel return the current logger level.
func GetLevel() zapcore.Level {
return logHandle.level.Level()
return logger.level.Level()
}
// SetLevel configure logger output level. Note that debug level
// will output more information and reduce performance.
// 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)
logger.level.SetLevel(level)
if level == DebugLevel {
logHandle.verbose = true
logger.verbose = true
} else {
logHandle.verbose = false
logger.verbose = false
}
}
// AddOutputs adds more plain output channel to the logger module.
func AddOutputs(outputs ...io.Writer) {
var writers []zapcore.WriteSyncer
for _, output := range outputs {
writers = append(writers, zapcore.AddSync(output))
// AddWriters add more writers to target log channel.
func AddWriters(colored bool, writers ...io.Writer) {
var syncWriters []zapcore.WriteSyncer
for _, writer := range writers {
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"
)
type logger struct {
logger *zap.Logger
level *zap.AtomicLevel
sugar *zap.SugaredLogger
var project string // project absolute path
var logger *logCore // singleton logger handle
// logChannel handle multiple writers with unified format.
type logChannel struct {
encoder zapcore.Encoder
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.
func logConfig(colored bool) zapcore.EncoderConfig {
zapLevel := zap.NewAtomicLevelAt(InfoLevel) // using info level in default
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{
ConsoleSeparator: " ",
MessageKey: "msg",
@ -33,46 +56,40 @@ func logConfig(colored bool) zapcore.EncoderConfig {
EncodeLevel: levelEncoder,
EncodeCaller: callerEncoder,
}
if colored {
if colored { // using colored version
config.EncodeTime = timeColoredEncoder
config.EncodeLevel = levelColoredEncoder
config.EncodeCaller = callerColoredEncoder
}
return config
return logChannel{
encoder: zapcore.NewConsoleEncoder(config),
writers: []zapcore.WriteSyncer{}, // without any writer
}
}
func init() {
zapLevel := zap.NewAtomicLevelAt(InfoLevel) // using info level in default
zapCore := zapcore.NewCore(
zapcore.NewConsoleEncoder(logConfig(true)), // colorful output
zapcore.Lock(os.Stderr),
zapLevel,
)
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,
// update refreshes the binding of the log core to the writers.
func (handle *logCore) update() {
buildCore := func(channel *logChannel) zapcore.Core { // build zap core from logChannel
return zapcore.NewCore(
channel.encoder,
zap.CombineWriteSyncers(channel.writers...),
handle.level,
)
}
handle.entry = zap.New(
zapcore.NewTee(buildCore(&handle.plain), buildCore(&handle.colored)),
zap.AddCaller(), zap.AddCallerSkip(1),
).Sugar()
}
// addWrites adds more plain log writers.
func addWrites(writers ...zapcore.WriteSyncer) {
logHandle.writers = append(logHandle.writers, writers...)
plainCore := zapcore.NewCore(
zapcore.NewConsoleEncoder(logConfig(false)), // without colored
zap.CombineWriteSyncers(logHandle.writers...),
logHandle.level,
)
logHandle.logger = zap.New(
zapcore.NewTee(logHandle.stderr, plainCore),
zap.AddCaller(), zap.AddCallerSkip(1),
)
logHandle.sugar = logHandle.logger.Sugar()
// addPlainWrites adds plain text writers to the logCore.
func (handle *logCore) addPlainWrites(writers ...zapcore.WriteSyncer) {
handle.plain.writers = append(handle.plain.writers, writers...)
handle.update()
}
// addColoredWrites adds colored text writers to the logCore.
func (handle *logCore) addColoredWrites(writers ...zapcore.WriteSyncer) {
handle.colored.writers = append(handle.colored.writers, writers...)
handle.update()
}

6
main.go

@ -6,6 +6,8 @@ import (
)
func main() {
//logger.SetLevel(zap.DebugLevel)
//logger.Debugf("here is %s level", "debug")
//logger.Infof("here is %s level", "info")
//logger.Warnf("here is %s level", "warn")
@ -19,13 +21,13 @@ func main() {
logger.Debugf("output msg 1 at debug")
logger.Infof("output msg 1 at info")
logger.Warnf("output msg 1 at warn")
logger.AddOutputs(fp1, fp2)
logger.AddWriters(false, fp1, fp2)
logger.SetLevel(logger.InfoLevel)
logger.Debugf("output msg 2 at debug")
logger.Infof("output msg 2 at info")
logger.Warnf("output msg 2 at warn")
logger.SetLevel(logger.WarnLevel)
logger.AddOutputs(fp3)
logger.AddWriters(true, fp3)
logger.Debugf("output msg 3 at debug")
logger.Infof("output msg 3 at info")
logger.Warnf("output msg 3 at warn")

Loading…
Cancel
Save