From 751edf210216f0dd6d7f4d22e21a3a28522feafa Mon Sep 17 00:00:00 2001 From: Eran Date: Mon, 3 Jul 2017 22:16:12 +0300 Subject: [PATCH] added support for providing custom logger name encoders --- zapcore/console_encoder.go | 4 +- zapcore/encoder.go | 35 ++- zapcore/encoder_test.go | 472 +++++++++++++++++++++---------------- zapcore/json_encoder.go | 8 +- 4 files changed, 315 insertions(+), 204 deletions(-) diff --git a/zapcore/console_encoder.go b/zapcore/console_encoder.go index 9fc89e924..f62b48dc9 100644 --- a/zapcore/console_encoder.go +++ b/zapcore/console_encoder.go @@ -79,8 +79,8 @@ func (c consoleEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, if c.LevelKey != "" && c.EncodeLevel != nil { c.EncodeLevel(ent.Level, arr) } - if ent.LoggerName != "" && c.NameKey != "" { - arr.AppendString(ent.LoggerName) + if ent.LoggerName != "" && c.NameKey != "" && c.EncodeLoggerName != nil { + c.EncodeLoggerName(ent.LoggerName, arr) } if ent.Caller.Defined && c.CallerKey != "" && c.EncodeCaller != nil { c.EncodeCaller(ent.Caller, arr) diff --git a/zapcore/encoder.go b/zapcore/encoder.go index a026f4679..1a29f442f 100644 --- a/zapcore/encoder.go +++ b/zapcore/encoder.go @@ -21,6 +21,7 @@ package zapcore import ( + "strings" "time" "go.uber.org/zap/buffer" @@ -196,6 +197,31 @@ func (e *CallerEncoder) UnmarshalText(text []byte) error { return nil } +// A LoggerNameEncoder serializes a LoggerName to a primitive type. +type LoggerNameEncoder func(string, PrimitiveArrayEncoder) + +// FullLoggerNameEncoder serializes a logger name as is +func FullLoggerNameEncoder(loggerName string, enc PrimitiveArrayEncoder) { + enc.AppendString(loggerName) +} + +// CapitalLoggerNameEncoder serializes a logger name in all caps +func CapitalLoggerNameEncoder(loggerName string, enc PrimitiveArrayEncoder) { + enc.AppendString(strings.ToUpper(loggerName)) +} + +// UnmarshalText unmarshals text to a LoggerNameEncoder. "capital" is unmarshaled to +// CapitalLoggerNameEncoder and anything else is unmarshaled to FullLoggerNameEncoder. +func (e *LoggerNameEncoder) UnmarshalText(text []byte) error { + switch string(text) { + case "capital": + *e = CapitalLoggerNameEncoder + default: + *e = FullLoggerNameEncoder + } + return nil +} + // An EncoderConfig allows users to configure the concrete encoders supplied by // zapcore. type EncoderConfig struct { @@ -211,10 +237,11 @@ type EncoderConfig struct { // Configure the primitive representations of common complex types. For // example, some users may want all time.Times serialized as floating-point // seconds since epoch, while others may prefer ISO8601 strings. - EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"` - EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"` - EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"` - EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"` + EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"` + EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"` + EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"` + EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"` + EncodeLoggerName LoggerNameEncoder `json:"nameEncoder" yaml:"nameEncoder"` } // ObjectEncoder is a strongly-typed, encoding-agnostic interface for adding a diff --git a/zapcore/encoder_test.go b/zapcore/encoder_test.go index 0708902fa..b8f344624 100644 --- a/zapcore/encoder_test.go +++ b/zapcore/encoder_test.go @@ -44,17 +44,18 @@ var ( func testEncoderConfig() EncoderConfig { return EncoderConfig{ - MessageKey: "msg", - LevelKey: "level", - NameKey: "name", - TimeKey: "ts", - CallerKey: "caller", - StacktraceKey: "stacktrace", - LineEnding: "\n", - EncodeTime: EpochTimeEncoder, - EncodeLevel: LowercaseLevelEncoder, - EncodeDuration: SecondsDurationEncoder, - EncodeCaller: ShortCallerEncoder, + MessageKey: "msg", + LevelKey: "level", + NameKey: "name", + TimeKey: "ts", + CallerKey: "caller", + StacktraceKey: "stacktrace", + LineEnding: "\n", + EncodeTime: EpochTimeEncoder, + EncodeLevel: LowercaseLevelEncoder, + EncodeDuration: SecondsDurationEncoder, + EncodeCaller: ShortCallerEncoder, + EncodeLoggerName: FullLoggerNameEncoder, } } @@ -98,17 +99,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "use custom entry keys in JSON output and ignore them in console output", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", expectedConsole: "0\tinfo\tmain\tfoo.go:42\thello\nfake-stack\n", @@ -116,17 +118,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "skip level if LevelKey is omitted", cfg: EncoderConfig{ - LevelKey: "", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"T":0,"N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", expectedConsole: "0\tmain\tfoo.go:42\thello\nfake-stack\n", @@ -134,17 +137,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "skip timestamp if TimeKey is omitted", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", expectedConsole: "info\tmain\tfoo.go:42\thello\nfake-stack\n", @@ -152,17 +156,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "skip message if MessageKey is omitted", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","S":"fake-stack"}` + "\n", expectedConsole: "0\tinfo\tmain\tfoo.go:42\nfake-stack\n", @@ -170,17 +175,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "skip name if NameKey is omitted", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", expectedConsole: "0\tinfo\tfoo.go:42\thello\nfake-stack\n", @@ -188,17 +194,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "skip caller if CallerKey is omitted", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"N":"main","M":"hello","S":"fake-stack"}` + "\n", expectedConsole: "0\tinfo\tmain\thello\nfake-stack\n", @@ -206,17 +213,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "skip stacktrace if StacktraceKey is omitted", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello"}` + "\n", expectedConsole: "0\tinfo\tmain\tfoo.go:42\thello\n", @@ -224,17 +232,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "use the supplied EncodeTime, for both the entry and any times added", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: func(t time.Time, enc PrimitiveArrayEncoder) { enc.AppendString(t.String()) }, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: func(t time.Time, enc PrimitiveArrayEncoder) { enc.AppendString(t.String()) }, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, extra: func(enc Encoder) { enc.AddTime("extra", _epoch) @@ -251,17 +260,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "use the supplied EncodeDuration for any durations added", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: StringDurationEncoder, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: StringDurationEncoder, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, extra: func(enc Encoder) { enc.AddDuration("extra", time.Second) @@ -278,35 +288,56 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "use the supplied EncodeLevel", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: CapitalLevelEncoder, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: CapitalLevelEncoder, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"INFO","T":0,"N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", expectedConsole: "0\tINFO\tmain\tfoo.go:42\thello\nfake-stack\n", }, + { + desc: "use the supplied EncodeLoggerName", + cfg: EncoderConfig{ + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: CapitalLoggerNameEncoder, + }, + expectedJSON: `{"L":"info","T":0,"N":"MAIN","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", + expectedConsole: "0\tinfo\tMAIN\tfoo.go:42\thello\nfake-stack\n", + }, { desc: "close all open namespaces", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, extra: func(enc Encoder) { enc.OpenNamespace("outer") @@ -322,17 +353,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "handle no-op EncodeTime", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: func(time.Time, PrimitiveArrayEncoder) {}, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: func(time.Time, PrimitiveArrayEncoder) {}, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, extra: func(enc Encoder) { enc.AddTime("sometime", time.Unix(0, 100)) }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello","sometime":100,"S":"fake-stack"}` + "\n", @@ -341,17 +373,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "handle no-op EncodeDuration", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: func(time.Duration, PrimitiveArrayEncoder) {}, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: func(time.Duration, PrimitiveArrayEncoder) {}, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, extra: func(enc Encoder) { enc.AddDuration("someduration", time.Microsecond) }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello","someduration":1000,"S":"fake-stack"}` + "\n", @@ -360,17 +393,18 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "handle no-op EncodeLevel", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: func(Level, PrimitiveArrayEncoder) {}, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: func(Level, PrimitiveArrayEncoder) {}, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", expectedConsole: "0\tmain\tfoo.go:42\thello\nfake-stack\n", @@ -378,35 +412,56 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "handle no-op EncodeCaller", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: base.LineEnding, - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: func(EntryCaller, PrimitiveArrayEncoder) {}, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: func(EntryCaller, PrimitiveArrayEncoder) {}, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", expectedConsole: "0\tinfo\tmain\thello\nfake-stack\n", }, + { + desc: "handle no-op EncodeLoggerName", + cfg: EncoderConfig{ + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: base.LineEnding, + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: func(string, PrimitiveArrayEncoder) {}, + }, + expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\n", + expectedConsole: "0\tinfo\tfoo.go:42\thello\nfake-stack\n", + }, { desc: "use custom line separator", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - LineEnding: "\r\n", - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + LineEnding: "\r\n", + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + "\r\n", expectedConsole: "0\tinfo\tmain\tfoo.go:42\thello\nfake-stack\r\n", @@ -414,16 +469,17 @@ func TestEncoderConfiguration(t *testing.T) { { desc: "omit line separator definition - fall back to default", cfg: EncoderConfig{ - LevelKey: "L", - TimeKey: "T", - MessageKey: "M", - NameKey: "N", - CallerKey: "C", - StacktraceKey: "S", - EncodeTime: base.EncodeTime, - EncodeDuration: base.EncodeDuration, - EncodeLevel: base.EncodeLevel, - EncodeCaller: base.EncodeCaller, + LevelKey: "L", + TimeKey: "T", + MessageKey: "M", + NameKey: "N", + CallerKey: "C", + StacktraceKey: "S", + EncodeTime: base.EncodeTime, + EncodeDuration: base.EncodeDuration, + EncodeLevel: base.EncodeLevel, + EncodeCaller: base.EncodeCaller, + EncodeLoggerName: base.EncodeLoggerName, }, expectedJSON: `{"L":"info","T":0,"N":"main","C":"foo.go:42","M":"hello","S":"fake-stack"}` + DefaultLineEnding, expectedConsole: "0\tinfo\tmain\tfoo.go:42\thello\nfake-stack" + DefaultLineEnding, @@ -559,6 +615,28 @@ func TestCallerEncoders(t *testing.T) { } } +func TestLoggerNameEncoders(t *testing.T) { + tests := []struct { + name string + expected interface{} // output of encoding InfoLevel + }{ + {"capital", "MAIN"}, + {"", "main"}, + {"something-random", "main"}, + } + + for _, tt := range tests { + var lne LoggerNameEncoder + require.NoError(t, lne.UnmarshalText([]byte(tt.name)), "Unexpected error unmarshaling %q.", tt.name) + assertAppended( + t, + tt.expected, + func(arr ArrayEncoder) { lne("main", arr) }, + "Unexpected output serializing logger name with %q.", tt.name, + ) + } +} + func assertAppended(t testing.TB, expected interface{}, f func(ArrayEncoder), msgAndArgs ...interface{}) { mem := NewMapObjectEncoder() mem.AddArray("k", ArrayMarshalerFunc(func(arr ArrayEncoder) error { diff --git a/zapcore/json_encoder.go b/zapcore/json_encoder.go index 7d4a22c8d..7a1690bda 100644 --- a/zapcore/json_encoder.go +++ b/zapcore/json_encoder.go @@ -302,7 +302,13 @@ func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, } if ent.LoggerName != "" && final.NameKey != "" { final.addKey(final.NameKey) - final.AppendString(ent.LoggerName) + cur := final.buf.Len() + final.EncodeLoggerName(ent.LoggerName, final) + if cur == final.buf.Len() { + // User-supplied EncodeLoggerName was a no-op. Fall back to strings to + // keep output JSON valid. + final.AppendString(ent.LoggerName) + } } if ent.Caller.Defined && final.CallerKey != "" { final.addKey(final.CallerKey)