logger/unwrap: fix Tagged option #163
@ -35,6 +35,7 @@ var (
|
|||||||
nilAngleBytes = []byte("<nil>")
|
nilAngleBytes = []byte("<nil>")
|
||||||
circularShortBytes = []byte("<shown>")
|
circularShortBytes = []byte("<shown>")
|
||||||
invalidAngleBytes = []byte("<invalid>")
|
invalidAngleBytes = []byte("<invalid>")
|
||||||
|
filteredBytes = []byte("<filtered>")
|
||||||
openBracketBytes = []byte("[")
|
openBracketBytes = []byte("[")
|
||||||
closeBracketBytes = []byte("]")
|
closeBracketBytes = []byte("]")
|
||||||
percentBytes = []byte("%")
|
percentBytes = []byte("%")
|
||||||
@ -48,12 +49,13 @@ var (
|
|||||||
type unwrap struct {
|
type unwrap struct {
|
||||||
val interface{}
|
val interface{}
|
||||||
s fmt.State
|
s fmt.State
|
||||||
depth int
|
|
||||||
pointers map[uintptr]int
|
pointers map[uintptr]int
|
||||||
opts *Options
|
opts *Options
|
||||||
|
depth int
|
||||||
ignoreNextType bool
|
ignoreNextType bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Options struct
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Codec codec.Codec
|
Codec codec.Codec
|
||||||
Indent string
|
Indent string
|
||||||
@ -61,6 +63,7 @@ type Options struct {
|
|||||||
Tagged bool
|
Tagged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewOptions creates new Options struct via provided args
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Indent: " ",
|
Indent: " ",
|
||||||
@ -72,26 +75,31 @@ func NewOptions(opts ...Option) Options {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Option func signature
|
||||||
type Option func(*Options)
|
type Option func(*Options)
|
||||||
|
|
||||||
|
// Indent option specify indent level
|
||||||
func Indent(f string) Option {
|
func Indent(f string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Indent = f
|
o.Indent = f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Methods option toggles fmt.Stringer methods
|
||||||
func Methods(b bool) Option {
|
func Methods(b bool) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Methods = b
|
o.Methods = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Codec option automatic marshal arg via specified codec and write it to log
|
||||||
func Codec(c codec.Codec) Option {
|
func Codec(c codec.Codec) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Codec = c
|
o.Codec = c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tagged option toggles output only logger:"take" fields
|
||||||
func Tagged(b bool) Option {
|
func Tagged(b bool) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Tagged = b
|
o.Tagged = b
|
||||||
@ -204,10 +212,8 @@ func (f *unwrap) formatPtr(v reflect.Value) {
|
|||||||
switch {
|
switch {
|
||||||
case nilFound:
|
case nilFound:
|
||||||
_, _ = f.s.Write(nilAngleBytes)
|
_, _ = f.s.Write(nilAngleBytes)
|
||||||
|
|
||||||
case cycleFound:
|
case cycleFound:
|
||||||
_, _ = f.s.Write(circularShortBytes)
|
_, _ = f.s.Write(circularShortBytes)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
f.ignoreNextType = true
|
f.ignoreNextType = true
|
||||||
f.format(ve)
|
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
|
// Call Stringer/error interfaces if they exist and the handle methods
|
||||||
// flag is enabled.
|
// flag is enabled.
|
||||||
if !f.opts.Methods {
|
if f.opts.Methods {
|
||||||
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
||||||
if handled := handleMethods(f.opts, f.s, v); handled {
|
if handled := handleMethods(f.opts, f.s, v); handled {
|
||||||
return
|
return
|
||||||
@ -342,6 +348,7 @@ func (f *unwrap) format(v reflect.Value) {
|
|||||||
_, _ = f.s.Write(closeMapBytes)
|
_, _ = f.s.Write(closeMapBytes)
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
numFields := v.NumField()
|
numFields := v.NumField()
|
||||||
|
numWritten := 0
|
||||||
_, _ = f.s.Write(openBraceBytes)
|
_, _ = f.s.Write(openBraceBytes)
|
||||||
f.depth++
|
f.depth++
|
||||||
vt := v.Type()
|
vt := v.Type()
|
||||||
@ -349,9 +356,12 @@ func (f *unwrap) format(v reflect.Value) {
|
|||||||
for i := 0; i < numFields; i++ {
|
for i := 0; i < numFields; i++ {
|
||||||
sv, ok := vt.Field(i).Tag.Lookup("logger")
|
sv, ok := vt.Field(i).Tag.Lookup("logger")
|
||||||
if ok {
|
if ok {
|
||||||
if sv == "omit" {
|
switch sv {
|
||||||
|
case "omit":
|
||||||
prevSkip = true
|
prevSkip = true
|
||||||
continue
|
continue
|
||||||
|
case "take":
|
||||||
|
break
|
||||||
}
|
}
|
||||||
} else if f.opts.Tagged {
|
} else if f.opts.Tagged {
|
||||||
prevSkip = true
|
prevSkip = true
|
||||||
@ -370,8 +380,12 @@ func (f *unwrap) format(v reflect.Value) {
|
|||||||
_, _ = f.s.Write(colonBytes)
|
_, _ = f.s.Write(colonBytes)
|
||||||
}
|
}
|
||||||
f.format(f.unpackValue(v.Field(i)))
|
f.format(f.unpackValue(v.Field(i)))
|
||||||
|
numWritten++
|
||||||
}
|
}
|
||||||
f.depth--
|
f.depth--
|
||||||
|
if numWritten == 0 && f.depth < 0 {
|
||||||
|
_, _ = f.s.Write(filteredBytes)
|
||||||
|
}
|
||||||
_, _ = f.s.Write(closeBraceBytes)
|
_, _ = f.s.Write(closeBraceBytes)
|
||||||
case reflect.Uintptr:
|
case reflect.Uintptr:
|
||||||
getHexPtr(f.s, uintptr(v.Uint()))
|
getHexPtr(f.s, uintptr(v.Uint()))
|
||||||
|
@ -57,10 +57,11 @@ func TestOmit(t *testing.T) {
|
|||||||
type val struct {
|
type val struct {
|
||||||
Key1 string `logger:"omit"`
|
Key1 string `logger:"omit"`
|
||||||
Key2 string `logger:"take"`
|
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))
|
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)
|
t.Fatalf("not proper written %s", buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,3 +78,23 @@ func TestTagged(t *testing.T) {
|
|||||||
t.Fatalf("not proper written %s", buf)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user