Skip to content

Commit

Permalink
Merge e3b9d4f into 179e456
Browse files Browse the repository at this point in the history
  • Loading branch information
bufdev committed Mar 9, 2017
2 parents 179e456 + e3b9d4f commit 5f41b27
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 8 deletions.
9 changes: 1 addition & 8 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
package zap

import (
"fmt"
"sort"
"time"

Expand Down Expand Up @@ -229,11 +228,5 @@ func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error)
}

func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
switch cfg.Encoding {
case "json":
return zapcore.NewJSONEncoder(cfg.EncoderConfig), nil
case "console":
return zapcore.NewConsoleEncoder(cfg.EncoderConfig), nil
}
return nil, fmt.Errorf("unknown encoding %q", cfg.Encoding)
return newEncoder(cfg.Encoding, cfg.EncoderConfig)
}
90 changes: 90 additions & 0 deletions encoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zap

import (
"errors"
"fmt"
"sync"

"go.uber.org/zap/zapcore"
)

var (
errNoEncoderNameSpecified = errors.New("no encoder name specified ")
encoderNameToConstructor = make(map[string]func(zapcore.EncoderConfig) (zapcore.Encoder, error))
encoderMutex sync.RWMutex
)

func init() {
registerDefaultEncoders()
}

// MustRegisterEncoder registers an encoder constructor for the given name.
//
// If an encoder with the same name already exists, this will panic.
// By default, the encoders "json" and "console" are registered.
func MustRegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) {
if err := RegisterEncoder(name, constructor); err != nil {
panic(err.Error())
}
}

// RegisterEncoder registers an encoder constructor for the given name.
//
// If an encoder with the same name already exists, this will return an error.
// By default, the encoders "json" and "console" are registered.
func RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) error {
encoderMutex.Lock()
defer encoderMutex.Unlock()
if name == "" {
return errNoEncoderNameSpecified
}
if _, ok := encoderNameToConstructor[name]; ok {
return fmt.Errorf("encoder already registered for name %q", name)
}
encoderNameToConstructor[name] = constructor
return nil
}

func registerDefaultEncoders() {
MustRegisterEncoder("console", wrapEncoderConstructorNoError(zapcore.NewConsoleEncoder))
MustRegisterEncoder("json", wrapEncoderConstructorNoError(zapcore.NewJSONEncoder))
}

func newEncoder(name string, encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
encoderMutex.RLock()
defer encoderMutex.RUnlock()
if name == "" {
return nil, errNoEncoderNameSpecified
}
constructor, ok := encoderNameToConstructor[name]
if !ok {
return nil, fmt.Errorf("no encoder registered for name %q", name)
}
return constructor(encoderConfig)
}

func wrapEncoderConstructorNoError(constructor func(zapcore.EncoderConfig) zapcore.Encoder) func(zapcore.EncoderConfig) (zapcore.Encoder, error) {
return func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
return constructor(encoderConfig), nil
}
}
97 changes: 97 additions & 0 deletions encoder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zap

import (
"testing"

"go.uber.org/zap/zapcore"

"github.com/stretchr/testify/assert"
)

func TestRegisterDefaultEncoders(t *testing.T) {
testEncodersRegistered(t, "console", "json")
}

func TestRegisterEncoder(t *testing.T) {
testEncoders(func() {
assert.NoError(t, RegisterEncoder("foo", newNilEncoder))
testEncodersRegistered(t, "foo")
})
}

func TestDuplicateRegisterEncoder(t *testing.T) {
testEncoders(func() {
RegisterEncoder("foo", newNilEncoder)
assert.Error(t, RegisterEncoder("foo", newNilEncoder))
})
}

func TestDuplicateMustRegisterEncoder(t *testing.T) {
testEncoders(func() {
RegisterEncoder("foo", newNilEncoder)
assert.Panics(t, func() {
MustRegisterEncoder("foo", newNilEncoder)
})
})
}

func TestRegisterEncoderNoName(t *testing.T) {
assert.Equal(t, errNoEncoderNameSpecified, RegisterEncoder("", newNilEncoder))
}

func TestNewEncoder(t *testing.T) {
testEncoders(func() {
RegisterEncoder("foo", newNilEncoder)
encoder, err := newEncoder("foo", zapcore.EncoderConfig{})
assert.NoError(t, err)
assert.Nil(t, encoder)
})
}

func TestNewEncoderNotRegistered(t *testing.T) {
_, err := newEncoder("foo", zapcore.EncoderConfig{})
assert.Error(t, err)
}

func TestNewEncoderNoName(t *testing.T) {
_, err := newEncoder("", zapcore.EncoderConfig{})
assert.Equal(t, errNoEncoderNameSpecified, err)
}

func testEncoders(f func()) {
existing := encoderNameToConstructor
encoderNameToConstructor = make(map[string]func(zapcore.EncoderConfig) (zapcore.Encoder, error))
defer func() { encoderNameToConstructor = existing }()
f()
}

func testEncodersRegistered(t *testing.T, names ...string) {
assert.Len(t, encoderNameToConstructor, len(names))
for _, name := range names {
assert.NotNil(t, encoderNameToConstructor[name])
}
}

func newNilEncoder(_ zapcore.EncoderConfig) (zapcore.Encoder, error) {
return nil, nil
}

0 comments on commit 5f41b27

Please sign in to comment.