重构日志
This commit is contained in:
parent
d13db94020
commit
811dad0218
21
app/admin/middleware/trace.go
Normal file
21
app/admin/middleware/trace.go
Normal file
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
2
go.mod
2
go.mod
|
@ -30,6 +30,7 @@ require (
|
||||||
github.com/shamsher31/goimgext v1.0.0 // indirect
|
github.com/shamsher31/goimgext v1.0.0 // indirect
|
||||||
github.com/shamsher31/goimgtype v1.0.0
|
github.com/shamsher31/goimgtype v1.0.0
|
||||||
github.com/shirou/gopsutil v2.21.11+incompatible
|
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/cast v1.3.1
|
||||||
github.com/spf13/cobra v1.0.0
|
github.com/spf13/cobra v1.0.0
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
|
@ -42,7 +43,6 @@ require (
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
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/mysql v0.3.2
|
||||||
gorm.io/driver/postgres v0.2.9
|
gorm.io/driver/postgres v0.2.9
|
||||||
gorm.io/driver/sqlite v1.0.9
|
gorm.io/driver/sqlite v1.0.9
|
||||||
|
|
4
go.sum
4
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.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.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
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 h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
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-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 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-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-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 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
114
logger/helper.go
114
logger/helper.go
|
@ -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}
|
|
||||||
}
|
|
126
logger/level.go
126
logger/level.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
84
logger/logx.go
Normal file
84
logger/logx.go
Normal file
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user