logger: add wrapper support
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
f28b107372
commit
e545eb4e13
@ -24,6 +24,8 @@ type defaultLogger struct {
|
||||
enc *json.Encoder
|
||||
opts Options
|
||||
sync.RWMutex
|
||||
logFunc LogFunc
|
||||
logfFunc LogfFunc
|
||||
}
|
||||
|
||||
// Init(opts...) should only overwrite provided options
|
||||
@ -33,6 +35,15 @@ func (l *defaultLogger) Init(opts ...Option) error {
|
||||
o(&l.opts)
|
||||
}
|
||||
l.enc = json.NewEncoder(l.opts.Out)
|
||||
|
||||
l.logFunc = l.Log
|
||||
l.logfFunc = l.Logf
|
||||
// wrap the Log func
|
||||
for i := len(l.opts.Wrappers); i > 0; i-- {
|
||||
l.logFunc = l.opts.Wrappers[i-1].Log(l.logFunc)
|
||||
l.logfFunc = l.opts.Wrappers[i-1].Logf(l.logfFunc)
|
||||
}
|
||||
|
||||
l.Unlock()
|
||||
return nil
|
||||
}
|
||||
@ -121,27 +132,27 @@ func (l *defaultLogger) Fatal(ctx context.Context, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Infof(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.Logf(ctx, InfoLevel, msg, args...)
|
||||
l.logfFunc(ctx, InfoLevel, msg, args...)
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Errorf(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.Logf(ctx, ErrorLevel, msg, args...)
|
||||
l.logfFunc(ctx, ErrorLevel, msg, args...)
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Debugf(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.Logf(ctx, DebugLevel, msg, args...)
|
||||
l.logfFunc(ctx, DebugLevel, msg, args...)
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Warnf(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.Logf(ctx, WarnLevel, msg, args...)
|
||||
l.logfFunc(ctx, WarnLevel, msg, args...)
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Tracef(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.Logf(ctx, TraceLevel, msg, args...)
|
||||
l.logfFunc(ctx, TraceLevel, msg, args...)
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Fatalf(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.Logf(ctx, FatalLevel, msg, args...)
|
||||
l.logfFunc(ctx, FatalLevel, msg, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
@ -16,3 +17,21 @@ func TestLogger(t *testing.T) {
|
||||
l.Fields(map[string]interface{}{"error": "test"}).Info(ctx, "error message")
|
||||
l.Warn(ctx, "first", " ", "second")
|
||||
}
|
||||
|
||||
func TestLoggerWrapper(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
buf := bytes.NewBuffer(nil)
|
||||
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf))
|
||||
if err := l.Init(WrapLogger(NewOmitWrapper())); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
type secret struct {
|
||||
Name string
|
||||
Passw string `logger:"omit"`
|
||||
}
|
||||
s := &secret{Name: "name", Passw: "secret"}
|
||||
l.Errorf(ctx, "test %#+v", s)
|
||||
if !bytes.Contains(buf.Bytes(), []byte(`logger.secret{Name:\"name\", Passw:\"\"}"`)) {
|
||||
t.Fatalf("omit not works, struct: %v, output: %s", s, buf.Bytes())
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ type Options struct {
|
||||
CallerSkipCount int
|
||||
// The logging level the logger should log
|
||||
Level Level
|
||||
// Wrappers logger wrapper that called before actual Log/Logf function
|
||||
Wrappers []Wrapper
|
||||
}
|
||||
|
||||
// NewOptions creates new options struct
|
||||
@ -81,3 +83,10 @@ func WithName(n string) Option {
|
||||
o.Name = n
|
||||
}
|
||||
}
|
||||
|
||||
// WrapLogger adds a logger Wrapper to a list of options passed into the logger
|
||||
func WrapLogger(w Wrapper) Option {
|
||||
return func(o *Options) {
|
||||
o.Wrappers = append(o.Wrappers, w)
|
||||
}
|
||||
}
|
||||
|
68
logger/wrapper.go
Normal file
68
logger/wrapper.go
Normal file
@ -0,0 +1,68 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
||||
)
|
||||
|
||||
// LogFunc function used for Log method
|
||||
type LogFunc func(ctx context.Context, level Level, args ...interface{})
|
||||
|
||||
// LogfFunc function used for Logf method
|
||||
type LogfFunc func(ctx context.Context, level Level, msg string, args ...interface{})
|
||||
|
||||
type Wrapper interface {
|
||||
// Log logs message with needed level
|
||||
Log(LogFunc) LogFunc
|
||||
// Log(ctx context.Context, level Level, args ...interface{})
|
||||
// Logf logs message with needed level
|
||||
Logf(LogfFunc) LogfFunc
|
||||
//Logf(ctx context.Context, level Level, msg string, args ...interface{})
|
||||
}
|
||||
|
||||
type OmitWrapper struct{}
|
||||
|
||||
func NewOmitWrapper() Wrapper {
|
||||
return &OmitWrapper{}
|
||||
}
|
||||
|
||||
func getArgs(args []interface{}) []interface{} {
|
||||
nargs := make([]interface{}, 0, len(args))
|
||||
var err error
|
||||
for _, arg := range args {
|
||||
val := reflect.ValueOf(arg)
|
||||
switch val.Kind() {
|
||||
case reflect.Ptr:
|
||||
val = val.Elem()
|
||||
}
|
||||
narg := arg
|
||||
if val.Kind() == reflect.Struct {
|
||||
if narg, err = rutil.Zero(arg); err == nil {
|
||||
rutil.CopyDefaults(narg, arg)
|
||||
if flds, ferr := rutil.StructFields(narg); ferr == nil {
|
||||
for _, fld := range flds {
|
||||
if tv, ok := fld.Field.Tag.Lookup("logger"); ok && tv == "omit" {
|
||||
fld.Value.Set(reflect.Zero(fld.Value.Type()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nargs = append(nargs, narg)
|
||||
}
|
||||
return nargs
|
||||
}
|
||||
|
||||
func (w *OmitWrapper) Log(fn LogFunc) LogFunc {
|
||||
return func(ctx context.Context, level Level, args ...interface{}) {
|
||||
fn(ctx, level, getArgs(args)...)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *OmitWrapper) Logf(fn LogfFunc) LogfFunc {
|
||||
return func(ctx context.Context, level Level, msg string, args ...interface{}) {
|
||||
fn(ctx, level, msg, getArgs(args)...)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user