logger/unwrap: fix Tagged option

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2022-12-29 23:16:58 +03:00
parent 25350a6531
commit 421842315f
2 changed files with 42 additions and 7 deletions

View File

@ -35,6 +35,7 @@ var (
nilAngleBytes = []byte("<nil>")
circularShortBytes = []byte("<shown>")
invalidAngleBytes = []byte("<invalid>")
filteredBytes = []byte("<filtered>")
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()))

View File

@ -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)
}
}