From 811dad02188900510e7093fa8cd4d9bc18864618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8C=83=E4=BF=8A=E6=88=90?= Date: Fri, 13 Oct 2023 17:51:56 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/middleware/trace.go | 21 ++++ go.mod | 2 +- go.sum | 4 + logger/context.go | 14 --- logger/default.go | 185 ---------------------------------- logger/helper.go | 114 --------------------- logger/level.go | 126 ----------------------- logger/logger.go | 43 -------- logger/logger_test.go | 18 ---- logger/logx.go | 84 +++++++++++++++ logger/options.go | 58 ----------- 11 files changed, 110 insertions(+), 559 deletions(-) create mode 100644 app/admin/middleware/trace.go delete mode 100644 logger/context.go delete mode 100644 logger/default.go delete mode 100644 logger/helper.go delete mode 100644 logger/level.go delete mode 100644 logger/logger.go delete mode 100644 logger/logger_test.go create mode 100644 logger/logx.go delete mode 100644 logger/options.go diff --git a/app/admin/middleware/trace.go b/app/admin/middleware/trace.go new file mode 100644 index 0000000..bb46e72 --- /dev/null +++ b/app/admin/middleware/trace.go @@ -0,0 +1,21 @@ +package middleware + +import ( + "context" + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "go-admin/logger" +) + +type Trace struct { +} + +func (t Trace) Handle() gin.HandlerFunc { + return func(ctx *gin.Context) { + traceId := uuid.New().String() + logger.WithContext(context.WithValue(ctx, logger.TraceIdKey, traceId)) + + ctx.Header("trace_id", traceId) + ctx.Next() + } +} diff --git a/go.mod b/go.mod index 1fcb2f2..7dea717 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/shamsher31/goimgext v1.0.0 // indirect github.com/shamsher31/goimgtype v1.0.0 github.com/shirou/gopsutil v2.21.11+incompatible + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cast v1.3.1 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.7.1 @@ -42,7 +43,6 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect gorm.io/driver/mysql v0.3.2 gorm.io/driver/postgres v0.2.9 gorm.io/driver/sqlite v1.0.9 diff --git a/go.sum b/go.sum index a9a03d4..e9e9e48 100644 --- a/go.sum +++ b/go.sum @@ -437,6 +437,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -642,6 +644,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/logger/context.go b/logger/context.go deleted file mode 100644 index 6940122..0000000 --- a/logger/context.go +++ /dev/null @@ -1,14 +0,0 @@ -package logger - -import "context" - -type loggerKey struct{} - -func FromContext(ctx context.Context) (Logger, bool) { - l, ok := ctx.Value(loggerKey{}).(Logger) - return l, ok -} - -func NewContext(ctx context.Context, l Logger) context.Context { - return context.WithValue(ctx, loggerKey{}, l) -} diff --git a/logger/default.go b/logger/default.go deleted file mode 100644 index 294c049..0000000 --- a/logger/default.go +++ /dev/null @@ -1,185 +0,0 @@ -package logger - -import ( - "context" - "fmt" - "os" - "runtime" - "sort" - "strings" - "sync" - "time" - - dlog "go-admin/debug/log" -) - -func init() { - lvl, err := GetLevel(os.Getenv("GO_ADMIN_LOG_LEVEL")) - if err != nil { - lvl = InfoLevel - } - - DefaultLogger = NewHelper(NewLogger(WithLevel(lvl))) -} - -type defaultLogger struct { - sync.RWMutex - opts Options -} - -// Init(opts...) should only overwrite provided options -func (l *defaultLogger) Init(opts ...Option) error { - for _, o := range opts { - o(&l.opts) - } - return nil -} - -func (l *defaultLogger) String() string { - return "default" -} - -func (l *defaultLogger) Fields(fields map[string]interface{}) Logger { - l.Lock() - l.opts.Fields = copyFields(fields) - l.Unlock() - return l -} - -func copyFields(src map[string]interface{}) map[string]interface{} { - dst := make(map[string]interface{}, len(src)) - for k, v := range src { - dst[k] = v - } - return dst -} - -// logCallerfilePath returns a package/file:line description of the caller, -// preserving only the leaf directory name and file name. -func logCallerfilePath(loggingFilePath string) string { - // To make sure we trim the path correctly on Windows too, we - // counter-intuitively need to use '/' and *not* os.PathSeparator here, - // because the path given originates from Go stdlib, specifically - // runtime.Caller() which (as of Mar/17) returns forward slashes even on - // Windows. - // - // See https://github.com/golang/go/issues/3335 - // and https://github.com/golang/go/issues/18151 - // - // for discussion on the issue on Go side. - idx := strings.LastIndexByte(loggingFilePath, '/') - if idx == -1 { - return loggingFilePath - } - idx = strings.LastIndexByte(loggingFilePath[:idx], '/') - if idx == -1 { - return loggingFilePath - } - return loggingFilePath[idx+1:] -} - -func (l *defaultLogger) Log(level Level, v ...interface{}) { - // TODO decide does we need to write message if log level not used? - if !l.opts.Level.Enabled(level) { - return - } - - l.RLock() - fields := copyFields(l.opts.Fields) - l.RUnlock() - - fields["level"] = level.String() - - if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok { - fields["file"] = fmt.Sprintf("%s:%d", logCallerfilePath(file), line) - } - - rec := dlog.Record{ - Timestamp: time.Now(), - Message: fmt.Sprint(v...), - Metadata: make(map[string]string, len(fields)), - } - - keys := make([]string, 0, len(fields)) - for k, v := range fields { - keys = append(keys, k) - rec.Metadata[k] = fmt.Sprintf("%v", v) - } - - sort.Strings(keys) - metadata := "" - - for _, k := range keys { - metadata += fmt.Sprintf(" %s=%v", k, fields[k]) - } - - t := rec.Timestamp.Format("2006-01-02 15:04:05") - fmt.Printf("%s %s %v\n", t, metadata, rec.Message) -} - -func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) { - // TODO decide does we need to write message if log level not used? - if level < l.opts.Level { - return - } - - l.RLock() - fields := copyFields(l.opts.Fields) - l.RUnlock() - - fields["level"] = level.String() - - if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok { - fields["file"] = fmt.Sprintf("%s:%d", logCallerfilePath(file), line) - } - - rec := dlog.Record{ - Timestamp: time.Now(), - Message: fmt.Sprintf(format, v...), - Metadata: make(map[string]string, len(fields)), - } - - keys := make([]string, 0, len(fields)) - for k, v := range fields { - keys = append(keys, k) - rec.Metadata[k] = fmt.Sprintf("%v", v) - } - - sort.Strings(keys) - metadata := "" - - for _, k := range keys { - metadata += fmt.Sprintf(" %s=%v", k, fields[k]) - } - - t := rec.Timestamp.Format("2006-01-02 15:04:05") - fmt.Printf("%s %s %v\n", t, metadata, rec.Message) -} - -func (l *defaultLogger) Options() Options { - // not guard against options Context values - l.RLock() - opts := l.opts - opts.Fields = copyFields(l.opts.Fields) - l.RUnlock() - return opts -} - -// NewLogger builds a new logger based on options -func NewLogger(opts ...Option) Logger { - // Default options - options := Options{ - Level: InfoLevel, - Fields: make(map[string]interface{}), - Out: os.Stderr, - CallerSkipCount: 2, - Context: context.Background(), - } - - l := &defaultLogger{opts: options} - if err := l.Init(opts...); err != nil { - l.Log(FatalLevel, err) - } - - return l -} diff --git a/logger/helper.go b/logger/helper.go deleted file mode 100644 index 94c2f36..0000000 --- a/logger/helper.go +++ /dev/null @@ -1,114 +0,0 @@ -package logger - -import ( - "os" -) - -type Helper struct { - Logger - fields map[string]interface{} -} - -func NewHelper(log Logger) *Helper { - return &Helper{Logger: log} -} - -func (h *Helper) Info(args ...interface{}) { - if !h.Logger.Options().Level.Enabled(InfoLevel) { - return - } - h.Logger.Fields(h.fields).Log(InfoLevel, args...) -} - -func (h *Helper) Infof(template string, args ...interface{}) { - if !h.Logger.Options().Level.Enabled(InfoLevel) { - return - } - h.Logger.Fields(h.fields).Logf(InfoLevel, template, args...) -} - -func (h *Helper) Trace(args ...interface{}) { - if !h.Logger.Options().Level.Enabled(TraceLevel) { - return - } - h.Logger.Fields(h.fields).Log(TraceLevel, args...) -} - -func (h *Helper) Tracef(template string, args ...interface{}) { - if !h.Logger.Options().Level.Enabled(TraceLevel) { - return - } - h.Logger.Fields(h.fields).Logf(TraceLevel, template, args...) -} - -func (h *Helper) Debug(args ...interface{}) { - if !h.Logger.Options().Level.Enabled(DebugLevel) { - return - } - h.Logger.Fields(h.fields).Log(DebugLevel, args...) -} - -func (h *Helper) Debugf(template string, args ...interface{}) { - if !h.Logger.Options().Level.Enabled(DebugLevel) { - return - } - h.Logger.Fields(h.fields).Logf(DebugLevel, template, args...) -} - -func (h *Helper) Warn(args ...interface{}) { - if !h.Logger.Options().Level.Enabled(WarnLevel) { - return - } - h.Logger.Fields(h.fields).Log(WarnLevel, args...) -} - -func (h *Helper) Warnf(template string, args ...interface{}) { - if !h.Logger.Options().Level.Enabled(WarnLevel) { - return - } - h.Logger.Fields(h.fields).Logf(WarnLevel, template, args...) -} - -func (h *Helper) Error(args ...interface{}) { - if !h.Logger.Options().Level.Enabled(ErrorLevel) { - return - } - h.Logger.Fields(h.fields).Log(ErrorLevel, args...) -} - -func (h *Helper) Errorf(template string, args ...interface{}) { - if !h.Logger.Options().Level.Enabled(ErrorLevel) { - return - } - h.Logger.Fields(h.fields).Logf(ErrorLevel, template, args...) -} - -func (h *Helper) Fatal(args ...interface{}) { - if !h.Logger.Options().Level.Enabled(FatalLevel) { - return - } - h.Logger.Fields(h.fields).Log(FatalLevel, args...) - os.Exit(1) -} - -func (h *Helper) Fatalf(template string, args ...interface{}) { - if !h.Logger.Options().Level.Enabled(FatalLevel) { - return - } - h.Logger.Fields(h.fields).Logf(FatalLevel, template, args...) - os.Exit(1) -} - -func (h *Helper) WithError(err error) *Helper { - fields := copyFields(h.fields) - fields["error"] = err - return &Helper{Logger: h.Logger, fields: fields} -} - -func (h *Helper) WithFields(fields map[string]interface{}) *Helper { - nfields := copyFields(fields) - for k, v := range h.fields { - nfields[k] = v - } - return &Helper{Logger: h.Logger, fields: nfields} -} diff --git a/logger/level.go b/logger/level.go deleted file mode 100644 index 915f0d4..0000000 --- a/logger/level.go +++ /dev/null @@ -1,126 +0,0 @@ -package logger - -import ( - "fmt" - "os" -) - -type Level int8 - -const ( - // TraceLevel level. Designates finer-grained informational events than the Debug. - TraceLevel Level = iota - 2 - // DebugLevel level. Usually only enabled when debugging. Very verbose logging. - DebugLevel - // InfoLevel is the default logging priority. - // General operational entries about what's going on inside the application. - InfoLevel - // WarnLevel level. Non-critical entries that deserve eyes. - WarnLevel - // ErrorLevel level. Logs. Used for errors that should definitely be noted. - ErrorLevel - // FatalLevel level. Logs and then calls `logger.Exit(1)`. highest level of severity. - FatalLevel -) - -func (l Level) String() string { - switch l { - case TraceLevel: - return "trace" - case DebugLevel: - return "debug" - case InfoLevel: - return "info" - case WarnLevel: - return "warn" - case ErrorLevel: - return "error" - case FatalLevel: - return "fatal" - } - return "" -} - -// Enabled returns true if the given level is at or above this level. -func (l Level) Enabled(lvl Level) bool { - return lvl >= l -} - -// GetLevel converts a level string into a logger Level value. -// returns an error if the input string does not match known values. -func GetLevel(levelStr string) (Level, error) { - switch levelStr { - case TraceLevel.String(): - return TraceLevel, nil - case DebugLevel.String(): - return DebugLevel, nil - case InfoLevel.String(): - return InfoLevel, nil - case WarnLevel.String(): - return WarnLevel, nil - case ErrorLevel.String(): - return ErrorLevel, nil - case FatalLevel.String(): - return FatalLevel, nil - } - return InfoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to InfoLevel", levelStr) -} - -func Info(args ...interface{}) { - DefaultLogger.Log(InfoLevel, args...) -} - -func Infof(template string, args ...interface{}) { - DefaultLogger.Logf(InfoLevel, template, args...) -} - -func Trace(args ...interface{}) { - DefaultLogger.Log(TraceLevel, args...) -} - -func Tracef(template string, args ...interface{}) { - DefaultLogger.Logf(TraceLevel, template, args...) -} - -func Debug(args ...interface{}) { - DefaultLogger.Log(DebugLevel, args...) -} - -func Debugf(template string, args ...interface{}) { - DefaultLogger.Logf(DebugLevel, template, args...) -} - -func Warn(args ...interface{}) { - DefaultLogger.Log(WarnLevel, args...) -} - -func Warnf(template string, args ...interface{}) { - DefaultLogger.Logf(WarnLevel, template, args...) -} - -func Error(args ...interface{}) { - DefaultLogger.Log(ErrorLevel, args...) -} - -func Errorf(template string, args ...interface{}) { - DefaultLogger.Logf(ErrorLevel, template, args...) -} - -func Fatal(args ...interface{}) { - DefaultLogger.Log(FatalLevel, args...) - os.Exit(1) -} - -func Fatalf(template string, args ...interface{}) { - DefaultLogger.Logf(FatalLevel, template, args...) - os.Exit(1) -} - -// Returns true if the given level is at or lower the current logger level -func V(lvl Level, log Logger) bool { - l := DefaultLogger - if log != nil { - l = log - } - return l.Options().Level <= lvl -} diff --git a/logger/logger.go b/logger/logger.go deleted file mode 100644 index ad3b41a..0000000 --- a/logger/logger.go +++ /dev/null @@ -1,43 +0,0 @@ -// Package log provides a log interface -package logger - -var ( - // Default logger - DefaultLogger Logger = NewHelper(NewLogger()) -) - -// Logger is a generic logging interface -type Logger interface { - // Init initialises options - Init(options ...Option) error - // The Logger options - Options() Options - // Fields set fields to always be logged - Fields(fields map[string]interface{}) Logger - // Log writes a log entry - Log(level Level, v ...interface{}) - // Logf writes a formatted log entry - Logf(level Level, format string, v ...interface{}) - // String returns the name of logger - String() string -} - -func Init(opts ...Option) error { - return DefaultLogger.Init(opts...) -} - -func Fields(fields map[string]interface{}) Logger { - return DefaultLogger.Fields(fields) -} - -func Log(level Level, v ...interface{}) { - DefaultLogger.Log(level, v...) -} - -func Logf(level Level, format string, v ...interface{}) { - DefaultLogger.Logf(level, format, v...) -} - -func String() string { - return DefaultLogger.String() -} diff --git a/logger/logger_test.go b/logger/logger_test.go deleted file mode 100644 index f36a3a3..0000000 --- a/logger/logger_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package logger - -import ( - "testing" -) - -func TestLogger(t *testing.T) { - l := NewLogger(WithLevel(TraceLevel)) - h1 := NewHelper(l).WithFields(map[string]interface{}{"key1": "val1"}) - h1.Trace("trace_msg1") - h1.Warn("warn_msg1") - - h2 := NewHelper(l).WithFields(map[string]interface{}{"key2": "val2"}) - h2.Trace("trace_msg2") - h2.Warn("warn_msg2") - - l.Fields(map[string]interface{}{"key3": "val4"}).Log(InfoLevel, "test_msg") -} diff --git a/logger/logx.go b/logger/logx.go new file mode 100644 index 0000000..2286820 --- /dev/null +++ b/logger/logx.go @@ -0,0 +1,84 @@ +package logger + +import ( + "context" + "github.com/sirupsen/logrus" + "os" +) + +var l *Logx + +var TraceIdKey = "trace_id" + +type Logx struct { + *logrus.Logger + ctx *context.Context +} + +type LogField struct { + Key string + Value interface{} +} + +func init() { + ctx := context.Background() + l = &Logx{ + Logger: logrus.New(), + ctx: &ctx, + } + + l.SetFormatter(&logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"}) + // 设置输出 + l.SetOutput(os.Stdout) + + // 设置最低loglevel + l.SetLevel(logrus.DebugLevel) +} + +func WithContext(ctx context.Context) { + l.ctx = &ctx +} + +func Field(key string, value interface{}) *LogField { + return &LogField{Key: key, Value: value} +} + +func Info(msg string, fields ...*LogField) { + e := newEntry(fields...) + e.Info(msg) +} + +func Error(msg string, fields ...*LogField) { + e := newEntry(fields...) + e.Error(msg) +} + +func Debug(msg string, fields ...*LogField) { + e := newEntry(fields...) + e.Debug(msg) +} + +func Warning(msg string, fields ...*LogField) { + e := newEntry(fields...) + e.Warning(msg) +} + +func newEntry(fields ...*LogField) *logrus.Entry { + e := logrus.NewEntry(l.Logger) + traceId, ok := (*l.ctx).Value(TraceIdKey).(string) + if ok { + e = e.WithField("trace_id", traceId) + } + for _, field := range fields { + e = e.WithField(field.Key, field.Value) + } + return e +} + +func Errorf(format string, args ...interface{}) { + l.Errorf(format, args) +} + +func Fatal(args interface{}) { + l.Fatal(args) +} diff --git a/logger/options.go b/logger/options.go deleted file mode 100644 index d0a0330..0000000 --- a/logger/options.go +++ /dev/null @@ -1,58 +0,0 @@ -package logger - -import ( - "context" - "io" -) - -type Option func(*Options) - -type Options struct { - // The logging level the logger should log at. default is `InfoLevel` - Level Level - // fields to always be logged - Fields map[string]interface{} - // It's common to set this to a file, or leave it default which is `os.Stderr` - Out io.Writer - // Caller skip frame count for file:line info - CallerSkipCount int - // Alternative options - Context context.Context -} - -// WithFields set default fields for the logger -func WithFields(fields map[string]interface{}) Option { - return func(args *Options) { - args.Fields = fields - } -} - -// WithLevel set default level for the logger -func WithLevel(level Level) Option { - return func(args *Options) { - args.Level = level - } -} - -// WithOutput set default output writer for the logger -func WithOutput(out io.Writer) Option { - return func(args *Options) { - args.Out = out - } -} - -// WithCallerSkipCount set frame count to skip -func WithCallerSkipCount(c int) Option { - return func(args *Options) { - args.CallerSkipCount = c - } -} - -func SetOption(k, v interface{}) Option { - return func(o *Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, k, v) - } -}