From d4fe4e011295628c7c129ccaa26a4036b11f86ac Mon Sep 17 00:00:00 2001 From: loveuer Date: Fri, 7 Jun 2024 17:39:06 +0800 Subject: [PATCH] feat: refact default logger --- go.mod | 11 +++++ go.sum | 13 +++++ middleware.go | 73 ++++++++++++++-------------- nft/log/default.go | 67 ++++++++++++++++++++++++++ nft/log/log.go | 115 +++++++++++++++++++++++++++++++++++++++++++++ nft/log/new.go | 21 +++++++++ util.go | 21 +++++++++ 7 files changed, 282 insertions(+), 39 deletions(-) create mode 100644 nft/log/default.go create mode 100644 nft/log/log.go create mode 100644 nft/log/new.go diff --git a/go.mod b/go.mod index 8b5aac3..4965980 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,14 @@ module github.com/loveuer/nf go 1.20 + +require ( + github.com/fatih/color v1.17.0 + github.com/google/uuid v1.6.0 +) + +require ( + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + golang.org/x/sys v0.18.0 // indirect +) diff --git a/go.sum b/go.sum index e69de29..152870e 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,13 @@ +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/middleware.go b/middleware.go index 839afb7..e50149a 100644 --- a/middleware.go +++ b/middleware.go @@ -2,9 +2,11 @@ package nf import ( "fmt" - "log" + "github.com/google/uuid" + "github.com/loveuer/nf/nft/log" "os" "runtime/debug" + "strings" "time" ) @@ -27,51 +29,44 @@ func NewRecover(enableStackTrace bool) HandlerFunc { } } -func NewLogger() HandlerFunc { - l := log.New(os.Stdout, "[NF] ", 0) - - durationFormat := func(num int64) string { - var ( - unit = "ns" - ) - - if num > 1000 { - num = num / 1000 - unit = "µs" - } - - if num > 1000 { - num = num / 1000 - unit = "ms" - } - - if num > 1000 { - num = num / 1000 - unit = "s" - } - - return fmt.Sprintf("%3d %2s", num, unit) +func NewLogger(traceHeader ...string) HandlerFunc { + Header := "X-Trace-ID" + if len(traceHeader) > 0 && traceHeader[0] != "" { + Header = traceHeader[0] } return func(c *Ctx) error { - start := time.Now() + var ( + now = time.Now() + trace = c.Get(Header) + logFn func(msg string, data ...any) + ip = c.IP() + ) + + if trace == "" { + trace = uuid.Must(uuid.NewV7()).String() + } + + c.SetHeader(Header, trace) + + traces := strings.Split(trace, "-") + shortTrace := traces[len(traces)-1] err := c.Next() + duration := time.Since(now) - var ( - duration = time.Now().Sub(start).Nanoseconds() - status = c.StatusCode - path = c.path - method = c.Request.Method - ) + msg := fmt.Sprintf("NF | %s | %15s | %3d | %s | %6s | %s", shortTrace, ip, c.StatusCode, HumanDuration(duration.Nanoseconds()), c.Method(), c.Path()) - l.Printf("%s | %5s | %d | %s | %s", - start.Format("06/01/02T15:04:05"), - method, - status, - durationFormat(duration), - path, - ) + switch { + case c.StatusCode >= 500: + logFn = log.Error + case c.StatusCode >= 400: + logFn = log.Warn + default: + logFn = log.Info + } + + logFn(msg) return err } diff --git a/nft/log/default.go b/nft/log/default.go new file mode 100644 index 0000000..6ab24ee --- /dev/null +++ b/nft/log/default.go @@ -0,0 +1,67 @@ +package log + +import ( + "fmt" + "os" + "sync" +) + +var ( + nilLogger = func(prefix, timestamp, msg string, data ...any) {} + normalLogger = func(prefix, timestamp, msg string, data ...any) { + fmt.Printf(prefix+"| "+timestamp+" | "+msg+"\n", data...) + } + + panicLogger = func(prefix, timestamp, msg string, data ...any) { + panic(fmt.Sprintf(prefix+"| "+timestamp+" | "+msg+"\n", data...)) + } + + fatalLogger = func(prefix, timestamp, msg string, data ...any) { + fmt.Printf(prefix+"| "+timestamp+" | "+msg+"\n", data...) + os.Exit(1) + } + + defaultLogger = &logger{ + Mutex: sync.Mutex{}, + timeFormat: "2006-01-02T15:04:05", + writer: os.Stdout, + level: LogLevelInfo, + debug: nilLogger, + info: normalLogger, + warn: normalLogger, + error: normalLogger, + panic: panicLogger, + fatal: fatalLogger, + } +) + +func SetTimeFormat(format string) { + defaultLogger.SetTimeFormat(format) +} + +func SetLogLevel(level LogLevel) { + defaultLogger.SetLogLevel(level) +} + +func Debug(msg string, data ...any) { + defaultLogger.Debug(msg, data...) +} +func Info(msg string, data ...any) { + defaultLogger.Info(msg, data...) +} + +func Warn(msg string, data ...any) { + defaultLogger.Warn(msg, data...) +} + +func Error(msg string, data ...any) { + defaultLogger.Error(msg, data...) +} + +func Panic(msg string, data ...any) { + defaultLogger.Panic(msg, data...) +} + +func Fatal(msg string, data ...any) { + defaultLogger.Fatal(msg, data...) +} diff --git a/nft/log/log.go b/nft/log/log.go new file mode 100644 index 0000000..9e55695 --- /dev/null +++ b/nft/log/log.go @@ -0,0 +1,115 @@ +package log + +import ( + "github.com/fatih/color" + "io" + "sync" + "time" +) + +type LogLevel uint32 + +const ( + LogLevelDebug = iota + LogLevelInfo + LogLevelWarn + LogLevelError + LogLevelPanic + LogLevelFatal +) + +type logger struct { + sync.Mutex + timeFormat string + writer io.Writer + level LogLevel + debug func(prefix, timestamp, msg string, data ...any) + info func(prefix, timestamp, msg string, data ...any) + warn func(prefix, timestamp, msg string, data ...any) + error func(prefix, timestamp, msg string, data ...any) + panic func(prefix, timestamp, msg string, data ...any) + fatal func(prefix, timestamp, msg string, data ...any) +} + +var ( + red = color.New(color.FgRed) + hired = color.New(color.FgHiRed) + green = color.New(color.FgGreen) + yellow = color.New(color.FgYellow) + white = color.New(color.FgWhite) +) + +func (l *logger) SetTimeFormat(format string) { + l.Lock() + defer l.Unlock() + l.timeFormat = format +} + +func (l *logger) SetLogLevel(level LogLevel) { + l.Lock() + defer l.Unlock() + + if level > LogLevelDebug { + l.debug = nilLogger + } else { + l.debug = normalLogger + } + + if level > LogLevelInfo { + l.info = nilLogger + } else { + l.info = normalLogger + } + + if level > LogLevelWarn { + l.warn = nilLogger + } else { + l.warn = normalLogger + } + + if level > LogLevelError { + l.error = nilLogger + } else { + l.error = normalLogger + } + + if level > LogLevelPanic { + l.panic = nilLogger + } else { + l.panic = panicLogger + } + + if level > LogLevelFatal { + l.fatal = nilLogger + } else { + l.fatal = fatalLogger + } +} + +func (l *logger) Debug(msg string, data ...any) { + l.debug(white.Sprint("Debug "), time.Now().Format(l.timeFormat), msg, data...) +} + +func (l *logger) Info(msg string, data ...any) { + l.info(green.Sprint("Info "), time.Now().Format(l.timeFormat), msg, data...) +} + +func (l *logger) Warn(msg string, data ...any) { + l.warn(yellow.Sprint("Warn "), time.Now().Format(l.timeFormat), msg, data...) +} + +func (l *logger) Error(msg string, data ...any) { + l.error(red.Sprint("Error "), time.Now().Format(l.timeFormat), msg, data...) +} + +func (l *logger) Panic(msg string, data ...any) { + l.panic(hired.Sprint("Panic "), time.Now().Format(l.timeFormat), msg, data...) +} + +func (l *logger) Fatal(msg string, data ...any) { + l.fatal(hired.Sprint("Fatal "), time.Now().Format(l.timeFormat), msg, data...) +} + +type WroteLogger interface { + Info(msg string, data ...any) +} diff --git a/nft/log/new.go b/nft/log/new.go new file mode 100644 index 0000000..204fac1 --- /dev/null +++ b/nft/log/new.go @@ -0,0 +1,21 @@ +package log + +import ( + "os" + "sync" +) + +func New() *logger { + return &logger{ + Mutex: sync.Mutex{}, + timeFormat: "2006-01-02T15:04:05", + writer: os.Stdout, + level: LogLevelInfo, + debug: nilLogger, + info: normalLogger, + warn: normalLogger, + error: normalLogger, + panic: panicLogger, + fatal: fatalLogger, + } +} diff --git a/util.go b/util.go index f2f8ad3..5f8da30 100644 --- a/util.go +++ b/util.go @@ -202,3 +202,24 @@ func bufApp(buf *[]byte, s string, w int, c byte) { } b[w] = c } + +func HumanDuration(nano int64) string { + duration := float64(nano) + unit := "ns" + if duration >= 1000 { + duration /= 1000 + unit = "us" + } + + if duration >= 1000 { + duration /= 1000 + unit = "ms" + } + + if duration >= 1000 { + duration /= 1000 + unit = " s" + } + + return fmt.Sprintf("%6.2f%s", duration, unit) +}