Skip func type value in fields.

We skip those unprintable fields and an error field
instead of dropping the whole trace.

Fixes #642
This commit is contained in:
David Bariod 2018-09-30 22:51:02 +02:00
parent a67f783a38
commit 7b467df697
5 changed files with 79 additions and 11 deletions

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"os" "os"
"reflect"
"sync" "sync"
"time" "time"
) )
@ -43,6 +44,9 @@ type Entry struct {
// When formatter is called in entry.log(), a Buffer may be set to entry // When formatter is called in entry.log(), a Buffer may be set to entry
Buffer *bytes.Buffer Buffer *bytes.Buffer
// err may contain a field formatting error
err string
} }
func NewEntry(logger *Logger) *Entry { func NewEntry(logger *Logger) *Entry {
@ -80,10 +84,18 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
for k, v := range entry.Data { for k, v := range entry.Data {
data[k] = v data[k] = v
} }
var field_err string
for k, v := range fields { for k, v := range fields {
data[k] = v if t := reflect.TypeOf(v); t != nil && t.Kind() == reflect.Func {
field_err = fmt.Sprintf("can not add field %q", k)
if entry.err != "" {
field_err = entry.err + ", " + field_err
}
} else {
data[k] = v
}
} }
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time} return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: field_err}
} }
// Overrides the time of the Entry. // Overrides the time of the Entry.

View File

@ -2,7 +2,14 @@ package logrus
import "time" import "time"
const defaultTimestampFormat = time.RFC3339 // Default key names for the default fields
const (
defaultTimestampFormat = time.RFC3339
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
FieldKeyLogrusError = "logrus_error"
)
// The Formatter interface is used to implement a custom Formatter. It takes an // The Formatter interface is used to implement a custom Formatter. It takes an
// `Entry`. It exposes all the fields, including the default ones: // `Entry`. It exposes all the fields, including the default ones:
@ -48,4 +55,10 @@ func prefixFieldClashes(data Fields, fieldMap FieldMap) {
data["fields."+levelKey] = l data["fields."+levelKey] = l
delete(data, levelKey) delete(data, levelKey)
} }
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
if l, ok := data[logrusErrKey]; ok {
data["fields."+logrusErrKey] = l
delete(data, logrusErrKey)
}
} }

View File

@ -11,13 +11,6 @@ type fieldKey string
// FieldMap allows customization of the key names for default fields. // FieldMap allows customization of the key names for default fields.
type FieldMap map[fieldKey]string type FieldMap map[fieldKey]string
// Default key names for the default fields
const (
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
)
func (f FieldMap) resolve(key fieldKey) string { func (f FieldMap) resolve(key fieldKey) string {
if k, ok := f[key]; ok { if k, ok := f[key]; ok {
return k return k
@ -79,6 +72,9 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat = defaultTimestampFormat timestampFormat = defaultTimestampFormat
} }
if entry.err != "" {
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
}
if !f.DisableTimestamp { if !f.DisableTimestamp {
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
} }

42
logger_test.go Normal file
View File

@ -0,0 +1,42 @@
package logrus
import (
"bytes"
"encoding/json"
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
func TestFieldValueError(t *testing.T) {
buf := &bytes.Buffer{}
l := &Logger{
Out: buf,
Formatter: new(JSONFormatter),
Hooks: make(LevelHooks),
Level: DebugLevel,
}
l.WithField("func", func() {}).Info("test")
fmt.Println(buf.String())
var data map[string]interface{}
json.Unmarshal(buf.Bytes(), &data)
_, ok := data[FieldKeyLogrusError]
require.True(t, ok)
}
func TestNoFieldValueError(t *testing.T) {
buf := &bytes.Buffer{}
l := &Logger{
Out: buf,
Formatter: new(JSONFormatter),
Hooks: make(LevelHooks),
Level: DebugLevel,
}
l.WithField("str", "str").Info("test")
fmt.Println(buf.String())
var data map[string]interface{}
json.Unmarshal(buf.Bytes(), &data)
_, ok := data[FieldKeyLogrusError]
require.False(t, ok)
}

View File

@ -114,7 +114,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
keys = append(keys, k) keys = append(keys, k)
} }
fixedKeys := make([]string, 0, 3+len(entry.Data)) fixedKeys := make([]string, 0, 4+len(entry.Data))
if !f.DisableTimestamp { if !f.DisableTimestamp {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
} }
@ -122,6 +122,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
if entry.Message != "" { if entry.Message != "" {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
} }
if entry.err != "" {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
}
if !f.DisableSorting { if !f.DisableSorting {
if f.SortingFunc == nil { if f.SortingFunc == nil {
@ -164,6 +167,8 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
value = entry.Level.String() value = entry.Level.String()
case f.FieldMap.resolve(FieldKeyMsg): case f.FieldMap.resolve(FieldKeyMsg):
value = entry.Message value = entry.Message
case f.FieldMap.resolve(FieldKeyLogrusError):
value = entry.err
default: default:
value = entry.Data[key] value = entry.Data[key]
} }