mirror of https://github.com/dnomd343/XProxy.git
Dnomd343
1 year ago
5 changed files with 258 additions and 4 deletions
@ -0,0 +1,99 @@ |
|||
package logger |
|||
|
|||
import ( |
|||
"bytes" |
|||
"fmt" |
|||
"github.com/gookit/color" |
|||
"go.uber.org/zap/zapcore" |
|||
"path/filepath" |
|||
"runtime" |
|||
"strconv" |
|||
"strings" |
|||
"time" |
|||
) |
|||
|
|||
// getGid get goroutine ID only for debugging.
|
|||
// -> https://blog.sgmansfield.com/2015/12/goroutine-ids/
|
|||
func getGid() uint64 { |
|||
b := make([]byte, 64) |
|||
b = b[:runtime.Stack(b, false)] |
|||
b = bytes.TrimPrefix(b, []byte("goroutine ")) |
|||
b = b[:bytes.IndexByte(b, ' ')] |
|||
n, _ := strconv.ParseUint(string(b), 10, 64) |
|||
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.
|
|||
func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { |
|||
enc.AppendString(t.Format("2006-01-02 15:04:05.000")) |
|||
} |
|||
|
|||
// timeColoredEncoder formats the time as a colored string
|
|||
// with custom prefix.
|
|||
func timeColoredEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { |
|||
enc.AppendString(fmt.Sprintf( |
|||
"%s %s", |
|||
color.Cyan.Render(logHandle.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 { |
|||
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.
|
|||
func callerColoredEncoder(ec zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { |
|||
if !logHandle.verbose { |
|||
enc.AppendString(color.Magenta.Render("[" + getCaller(ec, false) + "]")) |
|||
return |
|||
} |
|||
enc.AppendString(fmt.Sprintf( |
|||
"%s %s", |
|||
color.Blue.Render(fmt.Sprintf("[%d]", getGid())), |
|||
color.Magenta.Render("["+getCaller(ec, true)+"]"), |
|||
)) |
|||
} |
|||
|
|||
// levelEncoder formats log level using square brackets.
|
|||
func levelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { |
|||
enc.AppendString("[" + level.CapitalString() + "]") |
|||
} |
|||
|
|||
// levelColoredEncoder formats log level using square brackets
|
|||
// and uses different colors.
|
|||
func levelColoredEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { |
|||
levelStr := "[" + level.CapitalString() + "]" |
|||
switch level { |
|||
case zapcore.DebugLevel: |
|||
levelStr = color.FgDefault.Render(levelStr) |
|||
case zapcore.InfoLevel: |
|||
levelStr = color.Green.Render(levelStr) |
|||
case zapcore.WarnLevel: |
|||
levelStr = color.Yellow.Render(levelStr) |
|||
case zapcore.ErrorLevel: |
|||
levelStr = color.Red.Render(levelStr) |
|||
case zapcore.PanicLevel: |
|||
levelStr = color.LightRed.Render(levelStr) |
|||
} |
|||
enc.AppendString(levelStr) |
|||
} |
@ -0,0 +1,59 @@ |
|||
package logger |
|||
|
|||
import ( |
|||
"go.uber.org/zap/zapcore" |
|||
"io" |
|||
) |
|||
|
|||
const ( |
|||
DebugLevel = zapcore.DebugLevel |
|||
InfoLevel = zapcore.InfoLevel |
|||
WarnLevel = zapcore.WarnLevel |
|||
ErrorLevel = zapcore.ErrorLevel |
|||
PanicLevel = zapcore.PanicLevel |
|||
) |
|||
|
|||
func Debugf(template string, args ...interface{}) { |
|||
logHandle.sugar.Debugf(template, args...) |
|||
} |
|||
|
|||
func Infof(template string, args ...interface{}) { |
|||
logHandle.sugar.Infof(template, args...) |
|||
} |
|||
|
|||
func Warnf(template string, args ...interface{}) { |
|||
logHandle.sugar.Warnf(template, args...) |
|||
} |
|||
|
|||
func Errorf(template string, args ...interface{}) { |
|||
logHandle.sugar.Errorf(template, args...) |
|||
} |
|||
|
|||
func Panicf(template string, args ...interface{}) { |
|||
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 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)) |
|||
} |
|||
addWrites(writers...) |
|||
} |
@ -0,0 +1,78 @@ |
|||
package logger |
|||
|
|||
import ( |
|||
"go.uber.org/zap" |
|||
"go.uber.org/zap/zapcore" |
|||
"os" |
|||
"path" |
|||
"runtime" |
|||
) |
|||
|
|||
type logger struct { |
|||
logger *zap.Logger |
|||
level *zap.AtomicLevel |
|||
sugar *zap.SugaredLogger |
|||
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
|
|||
|
|||
// logConfig generates log config for XProxy.
|
|||
func logConfig(colored bool) zapcore.EncoderConfig { |
|||
config := zapcore.EncoderConfig{ |
|||
ConsoleSeparator: " ", |
|||
MessageKey: "msg", |
|||
LevelKey: "level", |
|||
TimeKey: "time", |
|||
CallerKey: "caller", |
|||
EncodeTime: timeEncoder, |
|||
EncodeLevel: levelEncoder, |
|||
EncodeCaller: callerEncoder, |
|||
} |
|||
if colored { |
|||
config.EncodeTime = timeColoredEncoder |
|||
config.EncodeLevel = levelColoredEncoder |
|||
config.EncodeCaller = callerColoredEncoder |
|||
} |
|||
return config |
|||
} |
|||
|
|||
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, |
|||
} |
|||
} |
|||
|
|||
// 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() |
|||
} |
Loading…
Reference in new issue