logger/unwrap: check nested in case of Tagged #181
| @@ -46,14 +46,14 @@ var ( | |||||||
| 	closeMapBytes      = []byte("}") | 	closeMapBytes      = []byte("}") | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type unwrap struct { | type Wrapper struct { | ||||||
| 	val              interface{} | 	val              interface{} | ||||||
| 	s                fmt.State | 	s                fmt.State | ||||||
| 	pointers         map[uintptr]int | 	pointers         map[uintptr]int | ||||||
| 	opts             *Options | 	opts             *Options | ||||||
| 	depth            int | 	depth            int | ||||||
| 	ignoreNextType   bool | 	ignoreNextType   bool | ||||||
| 	takeAll          bool | 	takeAll          map[int]bool | ||||||
| 	protoWrapperType bool | 	protoWrapperType bool | ||||||
| 	sqlWrapperType   bool | 	sqlWrapperType   bool | ||||||
| } | } | ||||||
| @@ -109,14 +109,14 @@ func Tagged(b bool) Option { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func Unwrap(val interface{}, opts ...Option) *unwrap { | func Unwrap(val interface{}, opts ...Option) *Wrapper { | ||||||
| 	options := NewOptions(opts...) | 	options := NewOptions(opts...) | ||||||
| 	return &unwrap{val: val, opts: &options, pointers: make(map[uintptr]int)} | 	return &Wrapper{val: val, opts: &options, pointers: make(map[uintptr]int), takeAll: make(map[int]bool)} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *unwrap) unpackValue(v reflect.Value) reflect.Value { | func (w *Wrapper) unpackValue(v reflect.Value) reflect.Value { | ||||||
| 	if v.Kind() == reflect.Interface { | 	if v.Kind() == reflect.Interface { | ||||||
| 		f.ignoreNextType = false | 		w.ignoreNextType = false | ||||||
| 		if !v.IsNil() { | 		if !v.IsNil() { | ||||||
| 			v = v.Elem() | 			v = v.Elem() | ||||||
| 		} | 		} | ||||||
| @@ -125,19 +125,19 @@ func (f *unwrap) unpackValue(v reflect.Value) reflect.Value { | |||||||
| } | } | ||||||
|  |  | ||||||
| // formatPtr handles formatting of pointers by indirecting them as necessary. | // formatPtr handles formatting of pointers by indirecting them as necessary. | ||||||
| func (f *unwrap) formatPtr(v reflect.Value) { | func (w *Wrapper) formatPtr(v reflect.Value) { | ||||||
| 	// Display nil if top level pointer is nil. | 	// Display nil if top level pointer is nil. | ||||||
| 	showTypes := f.s.Flag('#') | 	showTypes := w.s.Flag('#') | ||||||
| 	if v.IsNil() && (!showTypes || f.ignoreNextType) { | 	if v.IsNil() && (!showTypes || w.ignoreNextType) { | ||||||
| 		_, _ = f.s.Write(nilAngleBytes) | 		_, _ = w.s.Write(nilAngleBytes) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Remove pointers at or below the current depth from map used to detect | 	// Remove pointers at or below the current depth from map used to detect | ||||||
| 	// circular refs. | 	// circular refs. | ||||||
| 	for k, depth := range f.pointers { | 	for k, depth := range w.pointers { | ||||||
| 		if depth >= f.depth { | 		if depth >= w.depth { | ||||||
| 			delete(f.pointers, k) | 			delete(w.pointers, k) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -159,12 +159,12 @@ func (f *unwrap) formatPtr(v reflect.Value) { | |||||||
| 		indirects++ | 		indirects++ | ||||||
| 		addr := ve.Pointer() | 		addr := ve.Pointer() | ||||||
| 		pointerChain = append(pointerChain, addr) | 		pointerChain = append(pointerChain, addr) | ||||||
| 		if pd, ok := f.pointers[addr]; ok && pd < f.depth { | 		if pd, ok := w.pointers[addr]; ok && pd < w.depth { | ||||||
| 			cycleFound = true | 			cycleFound = true | ||||||
| 			indirects-- | 			indirects-- | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 		f.pointers[addr] = f.depth | 		w.pointers[addr] = w.depth | ||||||
|  |  | ||||||
| 		ve = ve.Elem() | 		ve = ve.Elem() | ||||||
| 		if ve.Kind() == reflect.Interface { | 		if ve.Kind() == reflect.Interface { | ||||||
| @@ -177,49 +177,49 @@ func (f *unwrap) formatPtr(v reflect.Value) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Display type or indirection level depending on flags. | 	// Display type or indirection level depending on flags. | ||||||
| 	if showTypes && !f.ignoreNextType { | 	if showTypes && !w.ignoreNextType { | ||||||
| 		if f.depth > 0 { | 		if w.depth > 0 { | ||||||
| 			_, _ = f.s.Write(openParenBytes) | 			_, _ = w.s.Write(openParenBytes) | ||||||
| 		} | 		} | ||||||
| 		if f.depth > 0 { | 		if w.depth > 0 { | ||||||
| 			_, _ = f.s.Write(bytes.Repeat(asteriskBytes, indirects)) | 			_, _ = w.s.Write(bytes.Repeat(asteriskBytes, indirects)) | ||||||
| 		} else { | 		} else { | ||||||
| 			_, _ = f.s.Write(bytes.Repeat(ampBytes, indirects)) | 			_, _ = w.s.Write(bytes.Repeat(ampBytes, indirects)) | ||||||
| 		} | 		} | ||||||
| 		_, _ = f.s.Write([]byte(ve.Type().String())) | 		_, _ = w.s.Write([]byte(ve.Type().String())) | ||||||
| 		if f.depth > 0 { | 		if w.depth > 0 { | ||||||
| 			_, _ = f.s.Write(closeParenBytes) | 			_, _ = w.s.Write(closeParenBytes) | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		if nilFound || cycleFound { | 		if nilFound || cycleFound { | ||||||
| 			indirects += strings.Count(ve.Type().String(), "*") | 			indirects += strings.Count(ve.Type().String(), "*") | ||||||
| 		} | 		} | ||||||
| 		_, _ = f.s.Write(openAngleBytes) | 		_, _ = w.s.Write(openAngleBytes) | ||||||
| 		_, _ = f.s.Write([]byte(strings.Repeat("*", indirects))) | 		_, _ = w.s.Write([]byte(strings.Repeat("*", indirects))) | ||||||
| 		_, _ = f.s.Write(closeAngleBytes) | 		_, _ = w.s.Write(closeAngleBytes) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Display pointer information depending on flags. | 	// Display pointer information depending on flags. | ||||||
| 	if f.s.Flag('+') && (len(pointerChain) > 0) { | 	if w.s.Flag('+') && (len(pointerChain) > 0) { | ||||||
| 		_, _ = f.s.Write(openParenBytes) | 		_, _ = w.s.Write(openParenBytes) | ||||||
| 		for i, addr := range pointerChain { | 		for i, addr := range pointerChain { | ||||||
| 			if i > 0 { | 			if i > 0 { | ||||||
| 				_, _ = f.s.Write(pointerChainBytes) | 				_, _ = w.s.Write(pointerChainBytes) | ||||||
| 			} | 			} | ||||||
| 			getHexPtr(f.s, addr) | 			getHexPtr(w.s, addr) | ||||||
| 		} | 		} | ||||||
| 		_, _ = f.s.Write(closeParenBytes) | 		_, _ = w.s.Write(closeParenBytes) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Display dereferenced value. | 	// Display dereferenced value. | ||||||
| 	switch { | 	switch { | ||||||
| 	case nilFound: | 	case nilFound: | ||||||
| 		_, _ = f.s.Write(nilAngleBytes) | 		_, _ = w.s.Write(nilAngleBytes) | ||||||
| 	case cycleFound: | 	case cycleFound: | ||||||
| 		_, _ = f.s.Write(circularShortBytes) | 		_, _ = w.s.Write(circularShortBytes) | ||||||
| 	default: | 	default: | ||||||
| 		f.ignoreNextType = true | 		w.ignoreNextType = true | ||||||
| 		f.format(ve) | 		w.format(ve) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -227,20 +227,24 @@ func (f *unwrap) formatPtr(v reflect.Value) { | |||||||
| // uses the passed reflect value to figure out what kind of object we are | // uses the passed reflect value to figure out what kind of object we are | ||||||
| // dealing with and formats it appropriately.  It is a recursive function, | // dealing with and formats it appropriately.  It is a recursive function, | ||||||
| // however circular data structures are detected and handled properly. | // however circular data structures are detected and handled properly. | ||||||
| func (f *unwrap) format(v reflect.Value) { | func (w *Wrapper) format(v reflect.Value) { | ||||||
| 	if f.opts.Codec != nil { | 	if w.opts.Codec != nil { | ||||||
| 		buf, err := f.opts.Codec.Marshal(v.Interface()) | 		buf, err := w.opts.Codec.Marshal(v.Interface()) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			_, _ = f.s.Write(invalidAngleBytes) | 			_, _ = w.s.Write(invalidAngleBytes) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		_, _ = f.s.Write(buf) | 		_, _ = w.s.Write(buf) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	if w.opts.Tagged { | ||||||
|  | 		w.checkTakeAll(v, 1) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// Handle invalid reflect values immediately. | 	// Handle invalid reflect values immediately. | ||||||
| 	kind := v.Kind() | 	kind := v.Kind() | ||||||
| 	if kind == reflect.Invalid { | 	if kind == reflect.Invalid { | ||||||
| 		_, _ = f.s.Write(invalidAngleBytes) | 		_, _ = w.s.Write(invalidAngleBytes) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -249,46 +253,46 @@ func (f *unwrap) format(v reflect.Value) { | |||||||
| 	case reflect.Ptr: | 	case reflect.Ptr: | ||||||
| 		if !v.IsZero() { | 		if !v.IsZero() { | ||||||
| 			if strings.HasPrefix(reflect.Indirect(v).Type().String(), "wrapperspb.") { | 			if strings.HasPrefix(reflect.Indirect(v).Type().String(), "wrapperspb.") { | ||||||
| 				f.protoWrapperType = true | 				w.protoWrapperType = true | ||||||
| 			} else if strings.HasPrefix(reflect.Indirect(v).Type().String(), "sql.Null") { | 			} else if strings.HasPrefix(reflect.Indirect(v).Type().String(), "sql.Null") { | ||||||
| 				f.sqlWrapperType = true | 				w.sqlWrapperType = true | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		f.formatPtr(v) | 		w.formatPtr(v) | ||||||
| 		return | 		return | ||||||
| 	case reflect.Struct: | 	case reflect.Struct: | ||||||
| 		if !v.IsZero() { | 		if !v.IsZero() { | ||||||
| 			if strings.HasPrefix(reflect.Indirect(v).Type().String(), "sql.Null") { | 			if strings.HasPrefix(reflect.Indirect(v).Type().String(), "sql.Null") { | ||||||
| 				f.sqlWrapperType = true | 				w.sqlWrapperType = true | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// get type information unless already handled elsewhere. | 	// get type information unless already handled elsewhere. | ||||||
| 	if !f.ignoreNextType && f.s.Flag('#') { | 	if !w.ignoreNextType && w.s.Flag('#') { | ||||||
| 		if v.Type().Kind() != reflect.Map && | 		if v.Type().Kind() != reflect.Map && | ||||||
| 			v.Type().Kind() != reflect.String && | 			v.Type().Kind() != reflect.String && | ||||||
| 			v.Type().Kind() != reflect.Array && | 			v.Type().Kind() != reflect.Array && | ||||||
| 			v.Type().Kind() != reflect.Slice { | 			v.Type().Kind() != reflect.Slice { | ||||||
| 			_, _ = f.s.Write(openParenBytes) | 			_, _ = w.s.Write(openParenBytes) | ||||||
| 		} | 		} | ||||||
| 		if v.Kind() != reflect.String { | 		if v.Kind() != reflect.String { | ||||||
| 			_, _ = f.s.Write([]byte(v.Type().String())) | 			_, _ = w.s.Write([]byte(v.Type().String())) | ||||||
| 		} | 		} | ||||||
| 		if v.Type().Kind() != reflect.Map && | 		if v.Type().Kind() != reflect.Map && | ||||||
| 			v.Type().Kind() != reflect.String && | 			v.Type().Kind() != reflect.String && | ||||||
| 			v.Type().Kind() != reflect.Array && | 			v.Type().Kind() != reflect.Array && | ||||||
| 			v.Type().Kind() != reflect.Slice { | 			v.Type().Kind() != reflect.Slice { | ||||||
| 			_, _ = f.s.Write(closeParenBytes) | 			_, _ = w.s.Write(closeParenBytes) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	f.ignoreNextType = false | 	w.ignoreNextType = false | ||||||
|  |  | ||||||
| 	// 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 w.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(w.opts, w.s, v); handled { | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -296,48 +300,48 @@ func (f *unwrap) format(v reflect.Value) { | |||||||
|  |  | ||||||
| 	switch kind { | 	switch kind { | ||||||
| 	case reflect.Invalid: | 	case reflect.Invalid: | ||||||
| 		_, _ = f.s.Write(invalidAngleBytes) | 		_, _ = w.s.Write(invalidAngleBytes) | ||||||
| 	case reflect.Bool: | 	case reflect.Bool: | ||||||
| 		getBool(f.s, v.Bool()) | 		getBool(w.s, v.Bool()) | ||||||
| 	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: | 	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: | ||||||
| 		getInt(f.s, v.Int(), 10) | 		getInt(w.s, v.Int(), 10) | ||||||
| 	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: | 	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: | ||||||
| 		getUint(f.s, v.Uint(), 10) | 		getUint(w.s, v.Uint(), 10) | ||||||
| 	case reflect.Float32: | 	case reflect.Float32: | ||||||
| 		getFloat(f.s, v.Float(), 32) | 		getFloat(w.s, v.Float(), 32) | ||||||
| 	case reflect.Float64: | 	case reflect.Float64: | ||||||
| 		getFloat(f.s, v.Float(), 64) | 		getFloat(w.s, v.Float(), 64) | ||||||
| 	case reflect.Complex64: | 	case reflect.Complex64: | ||||||
| 		getComplex(f.s, v.Complex(), 32) | 		getComplex(w.s, v.Complex(), 32) | ||||||
| 	case reflect.Complex128: | 	case reflect.Complex128: | ||||||
| 		getComplex(f.s, v.Complex(), 64) | 		getComplex(w.s, v.Complex(), 64) | ||||||
| 	case reflect.Slice: | 	case reflect.Slice: | ||||||
| 		if v.IsNil() { | 		if v.IsNil() { | ||||||
| 			_, _ = f.s.Write(nilAngleBytes) | 			_, _ = w.s.Write(nilAngleBytes) | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 		fallthrough | 		fallthrough | ||||||
| 	case reflect.Array: | 	case reflect.Array: | ||||||
| 		_, _ = f.s.Write(openBraceBytes) | 		_, _ = w.s.Write(openBraceBytes) | ||||||
| 		f.depth++ | 		w.depth++ | ||||||
| 		numEntries := v.Len() | 		numEntries := v.Len() | ||||||
| 		for i := 0; i < numEntries; i++ { | 		for i := 0; i < numEntries; i++ { | ||||||
| 			if i > 0 { | 			if i > 0 { | ||||||
| 				_, _ = f.s.Write(commaBytes) | 				_, _ = w.s.Write(commaBytes) | ||||||
| 				_, _ = f.s.Write(spaceBytes) | 				_, _ = w.s.Write(spaceBytes) | ||||||
| 			} | 			} | ||||||
| 			f.ignoreNextType = true | 			w.ignoreNextType = true | ||||||
| 			f.format(f.unpackValue(v.Index(i))) | 			w.format(w.unpackValue(v.Index(i))) | ||||||
| 		} | 		} | ||||||
| 		f.depth-- | 		w.depth-- | ||||||
| 		_, _ = f.s.Write(closeBraceBytes) | 		_, _ = w.s.Write(closeBraceBytes) | ||||||
| 	case reflect.String: | 	case reflect.String: | ||||||
| 		_, _ = f.s.Write([]byte(`"` + v.String() + `"`)) | 		_, _ = w.s.Write([]byte(`"` + v.String() + `"`)) | ||||||
| 	case reflect.Interface: | 	case reflect.Interface: | ||||||
| 		// The only time we should get here is for nil interfaces due to | 		// The only time we should get here is for nil interfaces due to | ||||||
| 		// unpackValue calls. | 		// unpackValue calls. | ||||||
| 		if v.IsNil() { | 		if v.IsNil() { | ||||||
| 			_, _ = f.s.Write(nilAngleBytes) | 			_, _ = w.s.Write(nilAngleBytes) | ||||||
| 		} | 		} | ||||||
| 	case reflect.Ptr: | 	case reflect.Ptr: | ||||||
| 		// Do nothing.  We should never get here since pointers have already | 		// Do nothing.  We should never get here since pointers have already | ||||||
| @@ -345,38 +349,39 @@ func (f *unwrap) format(v reflect.Value) { | |||||||
| 	case reflect.Map: | 	case reflect.Map: | ||||||
| 		// nil maps should be indicated as different than empty maps | 		// nil maps should be indicated as different than empty maps | ||||||
| 		if v.IsNil() { | 		if v.IsNil() { | ||||||
| 			_, _ = f.s.Write(nilAngleBytes) | 			_, _ = w.s.Write(nilAngleBytes) | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 		_, _ = f.s.Write(openMapBytes) | 		_, _ = w.s.Write(openMapBytes) | ||||||
| 		f.depth++ | 		w.depth++ | ||||||
| 		keys := v.MapKeys() | 		keys := v.MapKeys() | ||||||
| 		for i, key := range keys { | 		for i, key := range keys { | ||||||
| 			if i > 0 { | 			if i > 0 { | ||||||
| 				_, _ = f.s.Write(spaceBytes) | 				_, _ = w.s.Write(spaceBytes) | ||||||
| 			} | 			} | ||||||
| 			f.ignoreNextType = true | 			w.ignoreNextType = true | ||||||
| 			f.format(f.unpackValue(key)) | 			w.format(w.unpackValue(key)) | ||||||
| 			_, _ = f.s.Write(colonBytes) | 			_, _ = w.s.Write(colonBytes) | ||||||
| 			f.ignoreNextType = true | 			w.ignoreNextType = true | ||||||
| 			f.format(f.unpackValue(v.MapIndex(key))) | 			w.format(w.unpackValue(v.MapIndex(key))) | ||||||
| 		} | 		} | ||||||
| 		f.depth-- | 		w.depth-- | ||||||
| 		_, _ = f.s.Write(closeMapBytes) | 		_, _ = w.s.Write(closeMapBytes) | ||||||
| 	case reflect.Struct: | 	case reflect.Struct: | ||||||
|  |  | ||||||
| 		numFields := v.NumField() | 		numFields := v.NumField() | ||||||
| 		numWritten := 0 | 		numWritten := 0 | ||||||
| 		_, _ = f.s.Write(openBraceBytes) | 		_, _ = w.s.Write(openBraceBytes) | ||||||
| 		f.depth++ | 		w.depth++ | ||||||
|  |  | ||||||
| 		vt := v.Type() | 		vt := v.Type() | ||||||
| 		prevSkip := false | 		prevSkip := false | ||||||
|  |  | ||||||
| 		for i := 0; i < numFields; i++ { | 		for i := 0; i < numFields; i++ { | ||||||
| 			f.takeAll = false | 			if w.protoWrapperType && !vt.Field(i).IsExported() { | ||||||
| 			if f.protoWrapperType && !vt.Field(i).IsExported() { |  | ||||||
| 				prevSkip = true | 				prevSkip = true | ||||||
| 				continue | 				continue | ||||||
| 			} else if f.sqlWrapperType && vt.Field(i).Name == "Valid" { | 			} else if w.sqlWrapperType && vt.Field(i).Name == "Valid" { | ||||||
| 				prevSkip = true | 				prevSkip = true | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| @@ -390,9 +395,9 @@ func (f *unwrap) format(v reflect.Value) { | |||||||
| 				case "take": | 				case "take": | ||||||
| 					break | 					break | ||||||
| 				} | 				} | ||||||
| 			case f.takeAll: | 			case w.takeAll[w.depth]: | ||||||
| 				break | 				break | ||||||
| 			case !ok && f.opts.Tagged: | 			case !ok && w.opts.Tagged: | ||||||
| 				prevSkip = true | 				prevSkip = true | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| @@ -402,52 +407,53 @@ func (f *unwrap) format(v reflect.Value) { | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if numWritten > 0 { | 			if numWritten > 0 { | ||||||
| 				_, _ = f.s.Write(commaBytes) | 				_, _ = w.s.Write(commaBytes) | ||||||
| 				_, _ = f.s.Write(spaceBytes) | 				_, _ = w.s.Write(spaceBytes) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			vtf := vt.Field(i) | 			vt := vt.Field(i) | ||||||
| 			if f.s.Flag('+') || f.s.Flag('#') { | 			if w.s.Flag('+') || w.s.Flag('#') { | ||||||
| 				_, _ = f.s.Write([]byte(vtf.Name)) | 				_, _ = w.s.Write([]byte(vt.Name)) | ||||||
| 				_, _ = f.s.Write(colonBytes) | 				_, _ = w.s.Write(colonBytes) | ||||||
| 			} | 			} | ||||||
| 			unpackValue := f.unpackValue(v.Field(i)) | 			unpackValue := w.unpackValue(v.Field(i)) | ||||||
| 			f.takeAll = f.checkTakeAll(unpackValue) | 			w.checkTakeAll(unpackValue, w.depth) | ||||||
| 			f.format(unpackValue) | 			w.format(unpackValue) | ||||||
| 			numWritten++ | 			numWritten++ | ||||||
| 		} | 		} | ||||||
| 		f.depth-- | 		w.depth-- | ||||||
| 		if numWritten == 0 && f.depth < 0 { |  | ||||||
| 			_, _ = f.s.Write(filteredBytes) | 		if numWritten == 0 && w.depth < 0 { | ||||||
|  | 			_, _ = w.s.Write(filteredBytes) | ||||||
| 		} | 		} | ||||||
| 		_, _ = f.s.Write(closeBraceBytes) | 		_, _ = w.s.Write(closeBraceBytes) | ||||||
| 	case reflect.Uintptr: | 	case reflect.Uintptr: | ||||||
| 		getHexPtr(f.s, uintptr(v.Uint())) | 		getHexPtr(w.s, uintptr(v.Uint())) | ||||||
| 	case reflect.UnsafePointer, reflect.Chan, reflect.Func: | 	case reflect.UnsafePointer, reflect.Chan, reflect.Func: | ||||||
| 		getHexPtr(f.s, v.Pointer()) | 		getHexPtr(w.s, v.Pointer()) | ||||||
| 	// There were not any other types at the time this code was written, but | 	// There were not any other types at the time this code was written, but | ||||||
| 	// fall back to letting the default fmt package handle it if any get added. | 	// fall back to letting the default fmt package handle it if any get added. | ||||||
| 	default: | 	default: | ||||||
| 		format := f.buildDefaultFormat() | 		format := w.buildDefaultFormat() | ||||||
| 		if v.CanInterface() { | 		if v.CanInterface() { | ||||||
| 			_, _ = fmt.Fprintf(f.s, format, v.Interface()) | 			_, _ = fmt.Fprintf(w.s, format, v.Interface()) | ||||||
| 		} else { | 		} else { | ||||||
| 			_, _ = fmt.Fprintf(f.s, format, v.String()) | 			_, _ = fmt.Fprintf(w.s, format, v.String()) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *unwrap) Format(s fmt.State, verb rune) { | func (w *Wrapper) Format(s fmt.State, verb rune) { | ||||||
| 	f.s = s | 	w.s = s | ||||||
|  |  | ||||||
| 	// Use standard formatting for verbs that are not v. | 	// Use standard formatting for verbs that are not v. | ||||||
| 	if verb != 'v' { | 	if verb != 'v' { | ||||||
| 		format := f.constructOrigFormat(verb) | 		format := w.constructOrigFormat(verb) | ||||||
| 		_, _ = fmt.Fprintf(s, format, f.val) | 		_, _ = fmt.Fprintf(s, format, w.val) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if f.val == nil { | 	if w.val == nil { | ||||||
| 		if s.Flag('#') { | 		if s.Flag('#') { | ||||||
| 			_, _ = s.Write(interfaceBytes) | 			_, _ = s.Write(interfaceBytes) | ||||||
| 		} | 		} | ||||||
| @@ -455,7 +461,7 @@ func (f *unwrap) Format(s fmt.State, verb rune) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	f.format(reflect.ValueOf(f.val)) | 	w.format(reflect.ValueOf(w.val)) | ||||||
| } | } | ||||||
|  |  | ||||||
| // handle special methods like error.Error() or fmt.Stringer interface | // handle special methods like error.Error() or fmt.Stringer interface | ||||||
| @@ -571,11 +577,11 @@ func catchPanic(w io.Writer, _ reflect.Value) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *unwrap) buildDefaultFormat() (format string) { | func (w *Wrapper) buildDefaultFormat() (format string) { | ||||||
| 	buf := bytes.NewBuffer(percentBytes) | 	buf := bytes.NewBuffer(percentBytes) | ||||||
|  |  | ||||||
| 	for _, flag := range sf { | 	for _, flag := range sf { | ||||||
| 		if f.s.Flag(int(flag)) { | 		if w.s.Flag(int(flag)) { | ||||||
| 			_, _ = buf.WriteRune(flag) | 			_, _ = buf.WriteRune(flag) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -586,43 +592,48 @@ func (f *unwrap) buildDefaultFormat() (format string) { | |||||||
| 	return format | 	return format | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *unwrap) constructOrigFormat(verb rune) (format string) { | func (w *Wrapper) constructOrigFormat(verb rune) string { | ||||||
| 	buf := bytes.NewBuffer(percentBytes) | 	buf := bytes.NewBuffer(percentBytes) | ||||||
|  |  | ||||||
| 	for _, flag := range sf { | 	for _, flag := range sf { | ||||||
| 		if f.s.Flag(int(flag)) { | 		if w.s.Flag(int(flag)) { | ||||||
| 			_, _ = buf.WriteRune(flag) | 			_, _ = buf.WriteRune(flag) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if width, ok := f.s.Width(); ok { | 	if width, ok := w.s.Width(); ok { | ||||||
| 		_, _ = buf.WriteString(strconv.Itoa(width)) | 		_, _ = buf.WriteString(strconv.Itoa(width)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if precision, ok := f.s.Precision(); ok { | 	if precision, ok := w.s.Precision(); ok { | ||||||
| 		_, _ = buf.Write(precisionBytes) | 		_, _ = buf.Write(precisionBytes) | ||||||
| 		_, _ = buf.WriteString(strconv.Itoa(precision)) | 		_, _ = buf.WriteString(strconv.Itoa(precision)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_, _ = buf.WriteRune(verb) | 	_, _ = buf.WriteRune(verb) | ||||||
|  |  | ||||||
| 	format = buf.String() | 	return buf.String() | ||||||
| 	return format |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *unwrap) checkTakeAll(v reflect.Value) bool { | func (w *Wrapper) checkTakeAll(v reflect.Value, depth int) { | ||||||
| 	takeAll := true | 	if _, ok := w.takeAll[depth]; ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if !v.IsValid() || v.IsZero() { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
| 	switch v.Kind() { | 	switch v.Kind() { | ||||||
| 	case reflect.Struct: | 	case reflect.Struct: | ||||||
| 		break | 		break | ||||||
| 	case reflect.Ptr: | 	case reflect.Ptr: | ||||||
| 		v = v.Elem() | 		v = v.Elem() | ||||||
| 		if v.Kind() != reflect.Struct { | 		if v.Kind() != reflect.Struct { | ||||||
| 			return true | 			w.takeAll[depth] = true | ||||||
|  | 			return | ||||||
| 		} | 		} | ||||||
| 	default: | 	default: | ||||||
| 		return true | 		w.takeAll[depth] = true | ||||||
|  | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	vt := v.Type() | 	vt := v.Type() | ||||||
| @@ -630,10 +641,8 @@ func (f *unwrap) checkTakeAll(v reflect.Value) bool { | |||||||
| 	for i := 0; i < v.NumField(); i++ { | 	for i := 0; i < v.NumField(); i++ { | ||||||
| 		sv, ok := vt.Field(i).Tag.Lookup("logger") | 		sv, ok := vt.Field(i).Tag.Lookup("logger") | ||||||
| 		if ok && sv == "take" { | 		if ok && sv == "take" { | ||||||
| 			return false | 			w.takeAll[depth] = false | ||||||
| 		} | 		} | ||||||
| 		takeAll = f.checkTakeAll(v.Field(i)) | 		w.checkTakeAll(v.Field(i), depth+1) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return takeAll |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user