Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for providing custom logger name encoders #465

Merged
merged 5 commits into from
Jul 22, 2017
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion zapcore/console_encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,15 @@ func (c consoleEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer,
c.EncodeLevel(ent.Level, arr)
}
if ent.LoggerName != "" && c.NameKey != "" {
arr.AppendString(ent.LoggerName)
nameEncoder := c.EncodeName

// if no name encoder provided, fall back to FullNameEncoder for backwards
// compatibility
if nameEncoder == nil {
nameEncoder = FullNameEncoder
}

nameEncoder(ent.LoggerName, arr)
}
if ent.Caller.Defined && c.CallerKey != "" && c.EncodeCaller != nil {
c.EncodeCaller(ent.Caller, arr)
Expand Down
23 changes: 22 additions & 1 deletion zapcore/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,24 @@ func (e *CallerEncoder) UnmarshalText(text []byte) error {
return nil
}

// A NameEncoder serializes a LoggerName to a primitive type.
type NameEncoder func(string, PrimitiveArrayEncoder)

// FullNameEncoder serializes a logger name as is
func FullNameEncoder(loggerName string, enc PrimitiveArrayEncoder) {
enc.AppendString(loggerName)
}

// UnmarshalText unmarshals text to a NameEncoder. everything is unmarshaled to
// FullNameEncoder.
func (e *NameEncoder) UnmarshalText(text []byte) error {
switch string(text) {
default:
*e = FullNameEncoder
}
return nil
}

// An EncoderConfig allows users to configure the concrete encoders supplied by
// zapcore.
type EncoderConfig struct {
Expand All @@ -210,11 +228,14 @@ type EncoderConfig struct {
LineEnding string `json:"lineEnding" yaml:"lineEnding"`
// 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.
// seconds since epoch, while others may prefer ISO8601 strings. EncodeName
// is optional - initializing it to nil will fall back to printing the logger
// name as is (using FullNameEncoder)
EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"`
EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"`
EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"`
EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
}

// ObjectEncoder is a strongly-typed, encoding-agnostic interface for adding a
Expand Down
65 changes: 65 additions & 0 deletions zapcore/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package zapcore_test

import (
"strings"
"testing"
"time"

Expand Down Expand Up @@ -74,6 +75,11 @@ func withConsoleEncoder(f func(Encoder)) {
f(NewConsoleEncoder(humanEncoderConfig()))
}

// capitalNameEncoder serializes a logger name in all caps
func capitalNameEncoder(loggerName string, enc PrimitiveArrayEncoder) {
enc.AppendString(strings.ToUpper(loggerName))
}

func TestEncoderConfiguration(t *testing.T) {
base := testEncoderConfig()

Expand Down Expand Up @@ -293,6 +299,25 @@ func TestEncoderConfiguration(t *testing.T) {
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 EncodeName",
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,
EncodeName: capitalNameEncoder,
},
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{
Expand Down Expand Up @@ -393,6 +418,25 @@ func TestEncoderConfiguration(t *testing.T) {
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 EncodeName",
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,
EncodeName: 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{
Expand Down Expand Up @@ -559,6 +603,27 @@ func TestCallerEncoders(t *testing.T) {
}
}

func TestNameEncoders(t *testing.T) {
tests := []struct {
name string
expected interface{} // output of encoding InfoLevel
}{
{"", "main"},
{"something-random", "main"},
}

for _, tt := range tests {
var ne NameEncoder
require.NoError(t, ne.UnmarshalText([]byte(tt.name)), "Unexpected error unmarshaling %q.", tt.name)
assertAppended(
t,
tt.expected,
func(arr ArrayEncoder) { ne("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 {
Expand Down
16 changes: 15 additions & 1 deletion zapcore/json_encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,21 @@ 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()
nameEncoder := final.EncodeName

// if no name encoder provided, fall back to FullNameEncoder for backwards
// compatibility
if nameEncoder == nil {
nameEncoder = FullNameEncoder
}

nameEncoder(ent.LoggerName, final)
if cur == final.buf.Len() {
// User-supplied EncodeName 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)
Expand Down