forked from mirror/logrus
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:
parent
a67f783a38
commit
7b467df697
16
entry.go
16
entry.go
|
@ -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.
|
||||||
|
|
15
formatter.go
15
formatter.go
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue