From 421842315f753129c78916c707ab619577cae869 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Thu, 29 Dec 2022 23:16:58 +0300 Subject: [PATCH] logger/unwrap: fix Tagged option Signed-off-by: Vasiliy Tolstov --- logger/unwrap/unwrap.go | 24 +++++++++++++++++++----- logger/unwrap/unwrap_test.go | 25 +++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/logger/unwrap/unwrap.go b/logger/unwrap/unwrap.go index 30c647e1..16f6b41d 100644 --- a/logger/unwrap/unwrap.go +++ b/logger/unwrap/unwrap.go @@ -35,6 +35,7 @@ var ( nilAngleBytes = []byte("") circularShortBytes = []byte("") invalidAngleBytes = []byte("") + filteredBytes = []byte("") openBracketBytes = []byte("[") closeBracketBytes = []byte("]") percentBytes = []byte("%") @@ -48,12 +49,13 @@ var ( type unwrap struct { val interface{} s fmt.State - depth int pointers map[uintptr]int opts *Options + depth int ignoreNextType bool } +// Options struct type Options struct { Codec codec.Codec Indent string @@ -61,6 +63,7 @@ type Options struct { Tagged bool } +// NewOptions creates new Options struct via provided args func NewOptions(opts ...Option) Options { options := Options{ Indent: " ", @@ -72,26 +75,31 @@ func NewOptions(opts ...Option) Options { return options } +// Option func signature type Option func(*Options) +// Indent option specify indent level func Indent(f string) Option { return func(o *Options) { o.Indent = f } } +// Methods option toggles fmt.Stringer methods func Methods(b bool) Option { return func(o *Options) { o.Methods = b } } +// Codec option automatic marshal arg via specified codec and write it to log func Codec(c codec.Codec) Option { return func(o *Options) { o.Codec = c } } +// Tagged option toggles output only logger:"take" fields func Tagged(b bool) Option { return func(o *Options) { o.Tagged = b @@ -204,10 +212,8 @@ func (f *unwrap) formatPtr(v reflect.Value) { switch { case nilFound: _, _ = f.s.Write(nilAngleBytes) - case cycleFound: _, _ = f.s.Write(circularShortBytes) - default: f.ignoreNextType = true f.format(ve) @@ -263,7 +269,7 @@ func (f *unwrap) format(v reflect.Value) { // Call Stringer/error interfaces if they exist and the handle methods // flag is enabled. - if !f.opts.Methods { + if f.opts.Methods { if (kind != reflect.Invalid) && (kind != reflect.Interface) { if handled := handleMethods(f.opts, f.s, v); handled { return @@ -342,6 +348,7 @@ func (f *unwrap) format(v reflect.Value) { _, _ = f.s.Write(closeMapBytes) case reflect.Struct: numFields := v.NumField() + numWritten := 0 _, _ = f.s.Write(openBraceBytes) f.depth++ vt := v.Type() @@ -349,9 +356,12 @@ func (f *unwrap) format(v reflect.Value) { for i := 0; i < numFields; i++ { sv, ok := vt.Field(i).Tag.Lookup("logger") if ok { - if sv == "omit" { + switch sv { + case "omit": prevSkip = true continue + case "take": + break } } else if f.opts.Tagged { prevSkip = true @@ -370,8 +380,12 @@ func (f *unwrap) format(v reflect.Value) { _, _ = f.s.Write(colonBytes) } f.format(f.unpackValue(v.Field(i))) + numWritten++ } f.depth-- + if numWritten == 0 && f.depth < 0 { + _, _ = f.s.Write(filteredBytes) + } _, _ = f.s.Write(closeBraceBytes) case reflect.Uintptr: getHexPtr(f.s, uintptr(v.Uint())) diff --git a/logger/unwrap/unwrap_test.go b/logger/unwrap/unwrap_test.go index b24fe0e9..3161c342 100644 --- a/logger/unwrap/unwrap_test.go +++ b/logger/unwrap/unwrap_test.go @@ -57,10 +57,11 @@ func TestOmit(t *testing.T) { type val struct { Key1 string `logger:"omit"` Key2 string `logger:"take"` + Key3 string } - v1 := &val{Key1: "val1", Key2: "val2"} + v1 := &val{Key1: "val1", Key2: "val2", Key3: "val3"} buf := fmt.Sprintf("%#v", Unwrap(v1)) - if strings.Compare(buf, `&unwrap.val{Key2:"val2"}`) != 0 { + if strings.Compare(buf, `&unwrap.val{Key2:"val2", Key3:"val3"}`) != 0 { t.Fatalf("not proper written %s", buf) } } @@ -77,3 +78,23 @@ func TestTagged(t *testing.T) { t.Fatalf("not proper written %s", buf) } } + +func TestTaggedNested(t *testing.T) { + type val struct { + key string `logger:"take"` + val string `logger:"omit"` + unk string + } + type str struct { + key string `logger:"omit"` + val *val `logger:"take"` + } + + var iface interface{} + v := &str{val: &val{key: "test", unk: "unk"}} + iface = v + buf := fmt.Sprintf("%#v", Unwrap(iface, Tagged(true))) + if strings.Compare(buf, `&unwrap.str{val:(*unwrap.val){key:"test"}}`) != 0 { + t.Fatalf("not proper written %s", buf) + } +}