mirror of
https://github.com/zeromicro/go-zero.git
synced 2025-02-03 00:38:40 +08:00
fix: log panic when use nil error or stringer with Field method (#4130)
This commit is contained in:
parent
9d551d507f
commit
74331a45c9
@ -6,6 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"reflect"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -153,11 +154,11 @@ func Errorw(msg string, fields ...LogField) {
|
|||||||
func Field(key string, value any) LogField {
|
func Field(key string, value any) LogField {
|
||||||
switch val := value.(type) {
|
switch val := value.(type) {
|
||||||
case error:
|
case error:
|
||||||
return LogField{Key: key, Value: val.Error()}
|
return LogField{Key: key, Value: encodeError(val)}
|
||||||
case []error:
|
case []error:
|
||||||
var errs []string
|
var errs []string
|
||||||
for _, err := range val {
|
for _, err := range val {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, encodeError(err))
|
||||||
}
|
}
|
||||||
return LogField{Key: key, Value: errs}
|
return LogField{Key: key, Value: errs}
|
||||||
case time.Duration:
|
case time.Duration:
|
||||||
@ -175,11 +176,11 @@ func Field(key string, value any) LogField {
|
|||||||
}
|
}
|
||||||
return LogField{Key: key, Value: times}
|
return LogField{Key: key, Value: times}
|
||||||
case fmt.Stringer:
|
case fmt.Stringer:
|
||||||
return LogField{Key: key, Value: val.String()}
|
return LogField{Key: key, Value: encodeStringer(val)}
|
||||||
case []fmt.Stringer:
|
case []fmt.Stringer:
|
||||||
var strs []string
|
var strs []string
|
||||||
for _, str := range val {
|
for _, str := range val {
|
||||||
strs = append(strs, str.String())
|
strs = append(strs, encodeStringer(str))
|
||||||
}
|
}
|
||||||
return LogField{Key: key, Value: strs}
|
return LogField{Key: key, Value: strs}
|
||||||
default:
|
default:
|
||||||
@ -414,6 +415,32 @@ func createOutput(path string) (io.WriteCloser, error) {
|
|||||||
return NewLogger(path, rule, options.gzipEnabled)
|
return NewLogger(path, rule, options.gzipEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func encodeError(err error) (ret string) {
|
||||||
|
return encodeWithRecover(err, func() string {
|
||||||
|
return err.Error()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeStringer(v fmt.Stringer) (ret string) {
|
||||||
|
return encodeWithRecover(v, func() string {
|
||||||
|
return v.String()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeWithRecover(arg any, fn func() string) (ret string) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() {
|
||||||
|
ret = nilAngleString
|
||||||
|
} else {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return fn()
|
||||||
|
}
|
||||||
|
|
||||||
func getWriter() Writer {
|
func getWriter() Writer {
|
||||||
w := writer.Load()
|
w := writer.Load()
|
||||||
if w == nil {
|
if w == nil {
|
||||||
|
@ -348,6 +348,25 @@ func TestStructedLogInfow(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStructedLogInfowNil(t *testing.T) {
|
||||||
|
w := new(mockWriter)
|
||||||
|
old := writer.Swap(w)
|
||||||
|
defer writer.Store(old)
|
||||||
|
|
||||||
|
assert.Panics(t, func() {
|
||||||
|
var ps panicStringer
|
||||||
|
Infow("test", Field("bb", ps))
|
||||||
|
})
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
var s *string
|
||||||
|
Infow("test", Field("bb", s))
|
||||||
|
var d *nilStringer
|
||||||
|
Infow("test", Field("bb", d))
|
||||||
|
var e *nilError
|
||||||
|
Errorw("test", Field("bb", e))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestStructedLogInfoConsoleAny(t *testing.T) {
|
func TestStructedLogInfoConsoleAny(t *testing.T) {
|
||||||
w := new(mockWriter)
|
w := new(mockWriter)
|
||||||
old := writer.Swap(w)
|
old := writer.Swap(w)
|
||||||
@ -859,3 +878,25 @@ func validateFields(t *testing.T, content string, fields map[string]any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nilError struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *nilError) Error() string {
|
||||||
|
return e.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
type nilStringer struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *nilStringer) String() string {
|
||||||
|
return s.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
type panicStringer struct{}
|
||||||
|
|
||||||
|
func (s panicStringer) String() string {
|
||||||
|
panic("panic")
|
||||||
|
}
|
||||||
|
@ -48,6 +48,7 @@ const (
|
|||||||
levelDebug = "debug"
|
levelDebug = "debug"
|
||||||
|
|
||||||
backupFileDelimiter = "-"
|
backupFileDelimiter = "-"
|
||||||
|
nilAngleString = "<nil>"
|
||||||
flags = 0x0
|
flags = 0x0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -277,6 +277,20 @@ func combineGlobalFields(fields []LogField) []LogField {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func marshalJson(t interface{}) ([]byte, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
encoder := json.NewEncoder(&buf)
|
||||||
|
encoder.SetEscapeHTML(false)
|
||||||
|
err := encoder.Encode(t)
|
||||||
|
// go 1.5+ will append a newline to the end of the json string
|
||||||
|
// https://github.com/golang/go/issues/13520
|
||||||
|
if l := buf.Len(); l > 0 && buf.Bytes()[l-1] == '\n' {
|
||||||
|
buf.Truncate(l - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
func output(writer io.Writer, level string, val any, fields ...LogField) {
|
func output(writer io.Writer, level string, val any, fields ...LogField) {
|
||||||
// only truncate string content, don't know how to truncate the values of other types.
|
// only truncate string content, don't know how to truncate the values of other types.
|
||||||
if v, ok := val.(string); ok {
|
if v, ok := val.(string); ok {
|
||||||
@ -333,7 +347,7 @@ func wrapLevelWithColor(level string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writeJson(writer io.Writer, info any) {
|
func writeJson(writer io.Writer, info any) {
|
||||||
if content, err := json.Marshal(info); err != nil {
|
if content, err := marshalJson(info); err != nil {
|
||||||
log.Printf("err: %s\n\n%s", err.Error(), debug.Stack())
|
log.Printf("err: %s\n\n%s", err.Error(), debug.Stack())
|
||||||
} else if writer == nil {
|
} else if writer == nil {
|
||||||
log.Println(string(content))
|
log.Println(string(content))
|
||||||
|
Loading…
Reference in New Issue
Block a user