1
0
Fork 0

initial commit

This commit is contained in:
Sangbum Kim 2017-11-06 22:24:08 +09:00
commit 0d92295142
162 changed files with 19868 additions and 0 deletions

120
.gitignore vendored Normal file
View File

@ -0,0 +1,120 @@
# Created by https://www.gitignore.io/api/intellij,go,linux,osx,windows
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
.idea
*.iml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Go ###
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
### Linux ###
*~
*.swp
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
### OSX ###
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Windows ###
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk

33
Gopkg.lock generated Normal file
View File

@ -0,0 +1,33 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "go.uber.org/atomic"
packages = ["."]
revision = "4e336646b2ef9fc6e47be8e21594178f98e5ebcf"
version = "v1.2.0"
[[projects]]
name = "go.uber.org/multierr"
packages = ["."]
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
version = "v1.1.0"
[[projects]]
name = "go.uber.org/zap"
packages = [".","buffer","internal/bufferpool","internal/color","internal/exit","zapcore"]
revision = "35aad584952c3e7020db7b839f6b102de6271f89"
version = "v1.7.1"
[[projects]]
name = "gopkg.in/natefinch/lumberjack.v2"
packages = ["."]
revision = "a96e63847dc3c67d17befa69c303767e2f84e54f"
version = "v2.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "4e56bae68db45690431363f15d1dcc7b8a412c4522bab27b460e3f0797d4b1f1"
solver-name = "gps-cdcl"
solver-version = 1

30
Gopkg.toml Normal file
View File

@ -0,0 +1,30 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "go.uber.org/zap"
version = "1.7.1"
[[constraint]]
name = "gopkg.in/natefinch/lumberjack.v2"
version = "2.1.0"

6
Makefile Normal file
View File

@ -0,0 +1,6 @@
# Builds the project
setup:
go get -u github.com/golang/dep/cmd/dep
${GOPATH}/bin/dep ensure -v
.PHONY: clean install

51
rotater/global.go Normal file
View File

@ -0,0 +1,51 @@
package rotater
import (
"os"
"path"
"log"
)
var loggers RotateSyncerSet
func NewLogWriter(FileName string, MaxSizeMb, MaxBackup, MaxDay int, logDir string) RotateSyncer {
switch FileName {
case "Stdout":
return newLocked(os.Stdout)
case "Stderr":
return newLocked(os.Stderr)
default:
logpath := FileName
if logDir != "" {
logpath = path.Join(logDir, FileName)
}
log.Println(" Attention!! log writes to ", logpath)
logWriter := newRotater(
logpath,
MaxSizeMb, // megabytes
MaxBackup,
MaxDay, //days
)
loggers.Store(logWriter)
logWriter.SetOnClose(func() { loggers.Delete(logWriter) })
return logWriter
}
}
func Rotate() {
loggers.Range(func(rotater RotateSyncer) {
rotater.Sync()
rotater.Rotate()
})
log.Println("rotated")
}
func Close() {
loggers.Range(func(rotater RotateSyncer) {
rotater.Sync()
rotater.Close()
})
log.Println("end of log")
}

46
rotater/set_logcore.go Normal file
View File

@ -0,0 +1,46 @@
package rotater
import (
"sync"
"sync/atomic"
)
/**
logger set
*/
type RotateSyncerSet struct {
storage sync.Map
}
func (s *RotateSyncerSet) Delete(key RotateSyncer) {
s.storage.Delete(key)
}
func (s *RotateSyncerSet) Exist(key RotateSyncer) (ok bool) {
_, ok = s.storage.Load(key)
return
}
func (s *RotateSyncerSet) SetNx(key RotateSyncer) (bool) {
_, exist := s.storage.LoadOrStore(key, 0)
return !exist
}
func (s *RotateSyncerSet) Range(f func(key RotateSyncer)) {
s.storage.Range(s.rangeWrap(f))
}
func (s *RotateSyncerSet) Store(key RotateSyncer) {
s.storage.Store(key, 0)
}
func (s *RotateSyncerSet) rangeWrap(f func(key RotateSyncer)) func(key, value interface{}) bool {
ok := true
return func(key, value interface{}) bool {
f(key.(RotateSyncer))
return ok
}
}
func (s *RotateSyncerSet) Len() int {
var count uint64
s.Range(func(conn RotateSyncer) {
atomic.AddUint64(&count, 1)
})
return int(count)
}

38
rotater/wrapped.go Normal file
View File

@ -0,0 +1,38 @@
package rotater
import (
"sync"
)
type LockedWriteSyncer struct {
sync.Mutex
ws WriteSyncer
}
// Lock wraps a WriteSyncer in a mutex to make it safe for concurrent use. In
// particular, *os.Files must be locked before use.
func newLocked(ws WriteSyncer) RotateSyncer {
if lws, ok := ws.(*LockedWriteSyncer); ok {
// no need to layer on another lock
return lws
}
return &LockedWriteSyncer{ws: ws}
}
func (s *LockedWriteSyncer) Write(bs []byte) (int, error) {
s.Lock()
n, err := s.ws.Write(bs)
s.Unlock()
return n, err
}
func (s *LockedWriteSyncer) Sync() error {
s.Lock()
err := s.ws.Sync()
s.Unlock()
return err
}
func (r *LockedWriteSyncer) SetOnClose(closeFunc CloseFunc) {}
func (r *LockedWriteSyncer) Rotate() (err error) { return }
func (r *LockedWriteSyncer) Close() (err error) { return }

66
rotater/writeRotater.go Normal file
View File

@ -0,0 +1,66 @@
package rotater
import (
"gopkg.in/natefinch/lumberjack.v2"
"io"
"sync"
)
type CloseFunc func()
type WriteSyncer interface {
io.Writer
Sync() error
}
type RotateSyncer interface {
io.WriteCloser
SetOnClose(CloseFunc)
Rotate() error
Sync() error
}
type rotateSyncer struct {
setOnceOnclose *sync.Once
onClose CloseFunc
lumberjack.Logger
}
func newRotater(filename string, maxSize, maxBackup, maxDay int) RotateSyncer {
return &rotateSyncer{
setOnceOnclose: &sync.Once{},
Logger: lumberjack.Logger{
Filename: filename,
MaxSize: maxSize, // megabytes
MaxBackups: maxBackup,
MaxAge: maxDay, //days
LocalTime: false,
Compress: false,
},
}
}
func (r *rotateSyncer) SetOnClose(closeFunc CloseFunc) {
r.setOnceOnclose.Do(func() {
r.onClose = closeFunc
})
}
func (r *rotateSyncer) Rotate() error {
return r.Logger.Rotate()
}
func (r *rotateSyncer) Close() error {
defer func() {
if r.onClose != nil {
r.onClose()
}
}()
return r.Logger.Close()
}
func (r *rotateSyncer) Sync() error {
return nil
}
func (s *rotateSyncer) Write(bs []byte) (int, error) {
return s.Logger.Write(bs)
}

View File

@ -0,0 +1,8 @@
Before opening your pull request, please make sure that you've:
- [ ] [signed Uber's Contributor License Agreement](https://docs.google.com/a/uber.com/forms/d/1pAwS_-dA1KhPlfxzYLBqK6rsSWwRwH95OCCZrcsY5rk/viewform);
- [ ] added tests to cover your changes;
- [ ] run the test suite locally (`make test`); and finally,
- [ ] run the linters locally (`make lint`).
Thanks for your contribution!

11
vendor/go.uber.org/atomic/.gitignore generated vendored Normal file
View File

@ -0,0 +1,11 @@
.DS_Store
/vendor
/cover
cover.out
lint.log
# Binaries
*.test
# Profiling output
*.prof

21
vendor/go.uber.org/atomic/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,21 @@
sudo: false
language: go
go_import_path: go.uber.org/atomic
go:
- 1.5
- 1.6
- tip
cache:
directories:
- vendor
install:
- make install_ci
script:
- make test_ci
- scripts/test-ubergo.sh
- make lint
- travis_retry goveralls -coverprofile=cover.out -service=travis-ci

19
vendor/go.uber.org/atomic/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,19 @@
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.

64
vendor/go.uber.org/atomic/Makefile generated vendored Normal file
View File

@ -0,0 +1,64 @@
PACKAGES := $(shell glide nv)
# Many Go tools take file globs or directories as arguments instead of packages.
PACKAGE_FILES ?= *.go
# The linting tools evolve with each Go version, so run them only on the latest
# stable release.
GO_VERSION := $(shell go version | cut -d " " -f 3)
GO_MINOR_VERSION := $(word 2,$(subst ., ,$(GO_VERSION)))
LINTABLE_MINOR_VERSIONS := 7 8
ifneq ($(filter $(LINTABLE_MINOR_VERSIONS),$(GO_MINOR_VERSION)),)
SHOULD_LINT := true
endif
export GO15VENDOREXPERIMENT=1
.PHONY: build
build:
go build -i $(PACKAGES)
.PHONY: install
install:
glide --version || go get github.com/Masterminds/glide
glide install
.PHONY: test
test:
go test -cover -race $(PACKAGES)
.PHONY: install_ci
install_ci: install
go get github.com/wadey/gocovmerge
go get github.com/mattn/goveralls
go get golang.org/x/tools/cmd/cover
ifdef SHOULD_LINT
go get github.com/golang/lint/golint
endif
.PHONY: lint
lint:
ifdef SHOULD_LINT
@rm -rf lint.log
@echo "Checking formatting..."
@gofmt -d -s $(PACKAGE_FILES) 2>&1 | tee lint.log
@echo "Checking vet..."
@$(foreach dir,$(PACKAGE_FILES),go tool vet $(dir) 2>&1 | tee -a lint.log;)
@echo "Checking lint..."
@$(foreach dir,$(PKGS),golint $(dir) 2>&1 | tee -a lint.log;)
@echo "Checking for unresolved FIXMEs..."
@git grep -i fixme | grep -v -e vendor -e Makefile | tee -a lint.log
@[ ! -s lint.log ]
else
@echo "Skipping linters on" $(GO_VERSION)
endif
.PHONY: test_ci
test_ci: install_ci build
./scripts/cover.sh $(shell go list $(PACKAGES))

34
vendor/go.uber.org/atomic/README.md generated vendored Normal file
View File

@ -0,0 +1,34 @@
# atomic [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Simple wrappers for primitive types to enforce atomic access.
## Installation
`go get -u go.uber.org/atomic`
## Usage
The standard library's `sync/atomic` is powerful, but it's easy to forget which
variables must be accessed atomically. `go.uber.org/atomic` preserves all the
functionality of the standard library, but wraps the primitive types to
provide a safer, more convenient API.
```go
var atom atomic.Uint32
atom.Store(42)
atom.Sub(2)
atom.CAS(40, 11)
```
See the [documentation][doc] for a complete API specification.
## Development Status
Stable.
<hr>
Released under the [MIT License](LICENSE.txt).
[doc-img]: https://godoc.org/github.com/uber-go/atomic?status.svg
[doc]: https://godoc.org/go.uber.org/atomic
[ci-img]: https://travis-ci.org/uber-go/atomic.svg?branch=master
[ci]: https://travis-ci.org/uber-go/atomic
[cov-img]: https://coveralls.io/repos/github/uber-go/atomic/badge.svg?branch=master
[cov]: https://coveralls.io/github/uber-go/atomic?branch=master

304
vendor/go.uber.org/atomic/atomic.go generated vendored Normal file
View File

@ -0,0 +1,304 @@
// 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 atomic provides simple wrappers around numerics to enforce atomic
// access.
package atomic
import (
"math"
"sync/atomic"
)
// Int32 is an atomic wrapper around an int32.
type Int32 struct{ v int32 }
// NewInt32 creates an Int32.
func NewInt32(i int32) *Int32 {
return &Int32{i}
}
// Load atomically loads the wrapped value.
func (i *Int32) Load() int32 {
return atomic.LoadInt32(&i.v)
}
// Add atomically adds to the wrapped int32 and returns the new value.
func (i *Int32) Add(n int32) int32 {
return atomic.AddInt32(&i.v, n)
}
// Sub atomically subtracts from the wrapped int32 and returns the new value.
func (i *Int32) Sub(n int32) int32 {
return atomic.AddInt32(&i.v, -n)
}
// Inc atomically increments the wrapped int32 and returns the new value.
func (i *Int32) Inc() int32 {
return i.Add(1)
}
// Dec atomically decrements the wrapped int32 and returns the new value.
func (i *Int32) Dec() int32 {
return i.Sub(1)
}
// CAS is an atomic compare-and-swap.
func (i *Int32) CAS(old, new int32) bool {
return atomic.CompareAndSwapInt32(&i.v, old, new)
}
// Store atomically stores the passed value.
func (i *Int32) Store(n int32) {
atomic.StoreInt32(&i.v, n)
}
// Swap atomically swaps the wrapped int32 and returns the old value.
func (i *Int32) Swap(n int32) int32 {
return atomic.SwapInt32(&i.v, n)
}
// Int64 is an atomic wrapper around an int64.
type Int64 struct{ v int64 }
// NewInt64 creates an Int64.
func NewInt64(i int64) *Int64 {
return &Int64{i}
}
// Load atomically loads the wrapped value.
func (i *Int64) Load() int64 {
return atomic.LoadInt64(&i.v)
}
// Add atomically adds to the wrapped int64 and returns the new value.
func (i *Int64) Add(n int64) int64 {
return atomic.AddInt64(&i.v, n)
}
// Sub atomically subtracts from the wrapped int64 and returns the new value.
func (i *Int64) Sub(n int64) int64 {
return atomic.AddInt64(&i.v, -n)
}
// Inc atomically increments the wrapped int64 and returns the new value.
func (i *Int64) Inc() int64 {
return i.Add(1)
}
// Dec atomically decrements the wrapped int64 and returns the new value.
func (i *Int64) Dec() int64 {
return i.Sub(1)
}
// CAS is an atomic compare-and-swap.
func (i *Int64) CAS(old, new int64) bool {
return atomic.CompareAndSwapInt64(&i.v, old, new)
}
// Store atomically stores the passed value.
func (i *Int64) Store(n int64) {
atomic.StoreInt64(&i.v, n)
}
// Swap atomically swaps the wrapped int64 and returns the old value.
func (i *Int64) Swap(n int64) int64 {
return atomic.SwapInt64(&i.v, n)
}
// Uint32 is an atomic wrapper around an uint32.
type Uint32 struct{ v uint32 }
// NewUint32 creates a Uint32.
func NewUint32(i uint32) *Uint32 {
return &Uint32{i}
}
// Load atomically loads the wrapped value.
func (i *Uint32) Load() uint32 {
return atomic.LoadUint32(&i.v)
}
// Add atomically adds to the wrapped uint32 and returns the new value.
func (i *Uint32) Add(n uint32) uint32 {
return atomic.AddUint32(&i.v, n)
}
// Sub atomically subtracts from the wrapped uint32 and returns the new value.
func (i *Uint32) Sub(n uint32) uint32 {
return atomic.AddUint32(&i.v, ^(n - 1))
}
// Inc atomically increments the wrapped uint32 and returns the new value.
func (i *Uint32) Inc() uint32 {
return i.Add(1)
}
// Dec atomically decrements the wrapped int32 and returns the new value.
func (i *Uint32) Dec() uint32 {
return i.Sub(1)
}
// CAS is an atomic compare-and-swap.
func (i *Uint32) CAS(old, new uint32) bool {
return atomic.CompareAndSwapUint32(&i.v, old, new)
}
// Store atomically stores the passed value.
func (i *Uint32) Store(n uint32) {
atomic.StoreUint32(&i.v, n)
}
// Swap atomically swaps the wrapped uint32 and returns the old value.
func (i *Uint32) Swap(n uint32) uint32 {
return atomic.SwapUint32(&i.v, n)
}
// Uint64 is an atomic wrapper around a uint64.
type Uint64 struct{ v uint64 }
// NewUint64 creates a Uint64.
func NewUint64(i uint64) *Uint64 {
return &Uint64{i}
}
// Load atomically loads the wrapped value.
func (i *Uint64) Load() uint64 {
return atomic.LoadUint64(&i.v)
}
// Add atomically adds to the wrapped uint64 and returns the new value.
func (i *Uint64) Add(n uint64) uint64 {
return atomic.AddUint64(&i.v, n)
}
// Sub atomically subtracts from the wrapped uint64 and returns the new value.
func (i *Uint64) Sub(n uint64) uint64 {
return atomic.AddUint64(&i.v, ^(n - 1))
}
// Inc atomically increments the wrapped uint64 and returns the new value.
func (i *Uint64) Inc() uint64 {
return i.Add(1)
}
// Dec atomically decrements the wrapped uint64 and returns the new value.
func (i *Uint64) Dec() uint64 {
return i.Sub(1)
}
// CAS is an atomic compare-and-swap.
func (i *Uint64) CAS(old, new uint64) bool {
return atomic.CompareAndSwapUint64(&i.v, old, new)
}
// Store atomically stores the passed value.
func (i *Uint64) Store(n uint64) {
atomic.StoreUint64(&i.v, n)
}
// Swap atomically swaps the wrapped uint64 and returns the old value.
func (i *Uint64) Swap(n uint64) uint64 {
return atomic.SwapUint64(&i.v, n)
}
// Bool is an atomic Boolean.
type Bool struct{ v uint32 }
// NewBool creates a Bool.
func NewBool(initial bool) *Bool {
return &Bool{boolToInt(initial)}
}
// Load atomically loads the Boolean.
func (b *Bool) Load() bool {
return truthy(atomic.LoadUint32(&b.v))
}
// Store atomically stores the passed value.
func (b *Bool) Store(new bool) {
atomic.StoreUint32(&b.v, boolToInt(new))
}
// Swap sets the given value and returns the previous value.
func (b *Bool) Swap(new bool) bool {
return truthy(atomic.SwapUint32(&b.v, boolToInt(new)))
}
// Toggle atomically negates the Boolean and returns the previous value.
func (b *Bool) Toggle() bool {
return truthy(atomic.AddUint32(&b.v, 1) - 1)
}
func truthy(n uint32) bool {
return n&1 == 1
}
func boolToInt(b bool) uint32 {
if b {
return 1
}
return 0
}
// Float64 is an atomic wrapper around float64.
type Float64 struct {
v uint64
}
// NewFloat64 creates a Float64.
func NewFloat64(f float64) *Float64 {
return &Float64{math.Float64bits(f)}
}
// Load atomically loads the wrapped value.
func (f *Float64) Load() float64 {
return math.Float64frombits(atomic.LoadUint64(&f.v))
}
// Store atomically stores the passed value.
func (f *Float64) Store(s float64) {
atomic.StoreUint64(&f.v, math.Float64bits(s))
}
// Add atomically adds to the wrapped float64 and returns the new value.
func (f *Float64) Add(s float64) float64 {
for {
old := f.Load()
new := old + s
if f.CAS(old, new) {
return new
}
}
}
// Sub atomically subtracts from the wrapped float64 and returns the new value.
func (f *Float64) Sub(s float64) float64 {
return f.Add(-s)
}
// CAS is an atomic compare-and-swap.
func (f *Float64) CAS(old, new float64) bool {
return atomic.CompareAndSwapUint64(&f.v, math.Float64bits(old), math.Float64bits(new))
}
// Value shadows the type of the same name from sync/atomic
// https://godoc.org/sync/atomic#Value
type Value struct{ atomic.Value }

147
vendor/go.uber.org/atomic/atomic_test.go generated vendored Normal file
View File

@ -0,0 +1,147 @@
// 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 atomic
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestInt32(t *testing.T) {
atom := NewInt32(42)
require.Equal(t, int32(42), atom.Load(), "Load didn't work.")
require.Equal(t, int32(46), atom.Add(4), "Add didn't work.")
require.Equal(t, int32(44), atom.Sub(2), "Sub didn't work.")
require.Equal(t, int32(45), atom.Inc(), "Inc didn't work.")
require.Equal(t, int32(44), atom.Dec(), "Dec didn't work.")
require.True(t, atom.CAS(44, 0), "CAS didn't report a swap.")
require.Equal(t, int32(0), atom.Load(), "CAS didn't set the correct value.")
require.Equal(t, int32(0), atom.Swap(1), "Swap didn't return the old value.")
require.Equal(t, int32(1), atom.Load(), "Swap didn't set the correct value.")
atom.Store(42)
require.Equal(t, int32(42), atom.Load(), "Store didn't set the correct value.")
}
func TestInt64(t *testing.T) {
atom := NewInt64(42)
require.Equal(t, int64(42), atom.Load(), "Load didn't work.")
require.Equal(t, int64(46), atom.Add(4), "Add didn't work.")
require.Equal(t, int64(44), atom.Sub(2), "Sub didn't work.")
require.Equal(t, int64(45), atom.Inc(), "Inc didn't work.")
require.Equal(t, int64(44), atom.Dec(), "Dec didn't work.")
require.True(t, atom.CAS(44, 0), "CAS didn't report a swap.")
require.Equal(t, int64(0), atom.Load(), "CAS didn't set the correct value.")
require.Equal(t, int64(0), atom.Swap(1), "Swap didn't return the old value.")
require.Equal(t, int64(1), atom.Load(), "Swap didn't set the correct value.")
atom.Store(42)
require.Equal(t, int64(42), atom.Load(), "Store didn't set the correct value.")
}
func TestUint32(t *testing.T) {
atom := NewUint32(42)
require.Equal(t, uint32(42), atom.Load(), "Load didn't work.")
require.Equal(t, uint32(46), atom.Add(4), "Add didn't work.")
require.Equal(t, uint32(44), atom.Sub(2), "Sub didn't work.")
require.Equal(t, uint32(45), atom.Inc(), "Inc didn't work.")
require.Equal(t, uint32(44), atom.Dec(), "Dec didn't work.")
require.True(t, atom.CAS(44, 0), "CAS didn't report a swap.")
require.Equal(t, uint32(0), atom.Load(), "CAS didn't set the correct value.")
require.Equal(t, uint32(0), atom.Swap(1), "Swap didn't return the old value.")
require.Equal(t, uint32(1), atom.Load(), "Swap didn't set the correct value.")
atom.Store(42)
require.Equal(t, uint32(42), atom.Load(), "Store didn't set the correct value.")
}
func TestUint64(t *testing.T) {
atom := NewUint64(42)
require.Equal(t, uint64(42), atom.Load(), "Load didn't work.")
require.Equal(t, uint64(46), atom.Add(4), "Add didn't work.")
require.Equal(t, uint64(44), atom.Sub(2), "Sub didn't work.")
require.Equal(t, uint64(45), atom.Inc(), "Inc didn't work.")
require.Equal(t, uint64(44), atom.Dec(), "Dec didn't work.")
require.True(t, atom.CAS(44, 0), "CAS didn't report a swap.")
require.Equal(t, uint64(0), atom.Load(), "CAS didn't set the correct value.")
require.Equal(t, uint64(0), atom.Swap(1), "Swap didn't return the old value.")
require.Equal(t, uint64(1), atom.Load(), "Swap didn't set the correct value.")
atom.Store(42)
require.Equal(t, uint64(42), atom.Load(), "Store didn't set the correct value.")
}
func TestBool(t *testing.T) {
atom := NewBool(false)
require.False(t, atom.Toggle(), "Expected swap to return previous value.")
require.True(t, atom.Load(), "Unexpected state after swap.")
atom.Store(false)
require.False(t, atom.Load(), "Unexpected state after store.")
prev := atom.Swap(false)
require.False(t, prev, "Expected Swap to return previous value.")
prev = atom.Swap(true)
require.False(t, prev, "Expected Swap to return previous value.")
}
func TestFloat64(t *testing.T) {
atom := NewFloat64(4.2)
require.Equal(t, float64(4.2), atom.Load(), "Load didn't work.")
require.True(t, atom.CAS(4.2, 0.5), "CAS didn't report a swap.")
require.Equal(t, float64(0.5), atom.Load(), "CAS didn't set the correct value.")
require.False(t, atom.CAS(0.0, 1.5), "CAS reported a swap.")
atom.Store(42.0)
require.Equal(t, float64(42.0), atom.Load(), "Store didn't set the correct value.")
require.Equal(t, float64(42.5), atom.Add(0.5), "Add didn't work.")
require.Equal(t, float64(42.0), atom.Sub(0.5), "Sub didn't work.")
}
func TestValue(t *testing.T) {
var v Value
assert.Nil(t, v.Load(), "initial Value is not nil")
v.Store(42)
assert.Equal(t, 42, v.Load())
v.Store(84)
assert.Equal(t, 84, v.Load())
assert.Panics(t, func() { v.Store("foo") })
}

43
vendor/go.uber.org/atomic/example_test.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
// 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 atomic_test
import (
"fmt"
"go.uber.org/atomic"
)
func Example() {
// Uint32 is a thin wrapper around the primitive uint32 type.
var atom atomic.Uint32
// The wrapper ensures that all operations are atomic.
atom.Store(42)
fmt.Println(atom.Inc())
fmt.Println(atom.CAS(43, 0))
fmt.Println(atom.Load())
// Output:
// 43
// true
// 0
}

17
vendor/go.uber.org/atomic/glide.lock generated vendored Normal file
View File

@ -0,0 +1,17 @@
hash: f14d51408e3e0e4f73b34e4039484c78059cd7fc5f4996fdd73db20dc8d24f53
updated: 2016-10-27T00:10:51.16960137-07:00
imports: []
testImports:
- name: github.com/davecgh/go-spew
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
subpackages:
- spew
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/stretchr/testify
version: d77da356e56a7428ad25149ca77381849a6a5232
subpackages:
- assert
- require

6
vendor/go.uber.org/atomic/glide.yaml generated vendored Normal file
View File

@ -0,0 +1,6 @@
package: go.uber.org/atomic
testImport:
- package: github.com/stretchr/testify
subpackages:
- assert
- require

40
vendor/go.uber.org/atomic/scripts/cover.sh generated vendored Executable file
View File

@ -0,0 +1,40 @@
#!/bin/bash
set -e
COVER=cover
ROOT_PKG=go.uber.org/atomic
if [[ -d "$COVER" ]]; then
rm -rf "$COVER"
fi
mkdir -p "$COVER"
i=0
for pkg in "$@"; do
i=$((i + 1))
extracoverpkg=""
if [[ -f "$GOPATH/src/$pkg/.extra-coverpkg" ]]; then
extracoverpkg=$( \
sed -e "s|^|$pkg/|g" < "$GOPATH/src/$pkg/.extra-coverpkg" \
| tr '\n' ',')
fi
coverpkg=$(go list -json "$pkg" | jq -r '
.Deps
| map(select(startswith("'"$ROOT_PKG"'")))
| map(select(contains("/vendor/") | not))
| . + ["'"$pkg"'"]
| join(",")
')
if [[ -n "$extracoverpkg" ]]; then
coverpkg="$extracoverpkg$coverpkg"
fi
go test \
-coverprofile "$COVER/cover.${i}.out" -coverpkg "$coverpkg" \
-v "$pkg"
done
gocovmerge "$COVER"/*.out > cover.out

26
vendor/go.uber.org/atomic/scripts/test-ubergo.sh generated vendored Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash
set -euox pipefail
IFS=$'\n\t'
# This script creates a fake GOPATH, symlinks in the current
# directory as uber-go/atomic and verifies that tests still pass.
WORK_DIR=`mktemp -d`
function cleanup {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
export GOPATH="$WORK_DIR"
PKG_PARENT="$WORK_DIR/src/github.com/uber-go"
PKG_DIR="$PKG_PARENT/atomic"
mkdir -p "$PKG_PARENT"
cp -R `pwd` "$PKG_DIR"
cd "$PKG_DIR"
# The example imports go.uber.org, fix the import.
sed -e 's/go.uber.org\/atomic/github.com\/uber-go\/atomic/' -i="" example_test.go
make test

140
vendor/go.uber.org/atomic/stress_test.go generated vendored Normal file
View File

@ -0,0 +1,140 @@
// 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 atomic
import (
"runtime"
"sync"
"testing"
)
const (
_parallelism = 4
_iterations = 1000
)
func runStress(f func()) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(_parallelism))
var wg sync.WaitGroup
wg.Add(_parallelism)
for i := 0; i < _parallelism; i++ {
go func() {
defer wg.Done()
for j := 0; j < _iterations; j++ {
f()
}
}()
}
wg.Wait()
}
func TestStressInt32(t *testing.T) {
var atom Int32
runStress(func() {
atom.Load()
atom.Add(1)
atom.Sub(2)
atom.Inc()
atom.Dec()
atom.CAS(1, 0)
atom.Swap(5)
atom.Store(1)
})
}
func TestStressInt64(t *testing.T) {
var atom Int64
runStress(func() {
atom.Load()
atom.Add(1)
atom.Sub(2)
atom.Inc()
atom.Dec()
atom.CAS(1, 0)
atom.Swap(5)
atom.Store(1)
})
}
func TestStressUint32(t *testing.T) {
var atom Uint32
runStress(func() {
atom.Load()
atom.Add(1)
atom.Sub(2)
atom.Inc()
atom.Dec()
atom.CAS(1, 0)
atom.Swap(5)
atom.Store(1)
})
}
func TestStressUint64(t *testing.T) {
var atom Uint64
runStress(func() {
atom.Load()
atom.Add(1)
atom.Sub(2)
atom.Inc()
atom.Dec()
atom.CAS(1, 0)
atom.Swap(5)
atom.Store(1)
})
}
func TestStressFloat64(t *testing.T) {
var atom Float64
runStress(func() {
atom.Load()
atom.CAS(1.0, 0.1)
atom.Add(1.1)
atom.Sub(0.2)
atom.Store(1.0)
})
}
func TestStressBool(t *testing.T) {
var atom Bool
runStress(func() {
atom.Load()
atom.Store(false)
atom.Swap(true)
atom.Load()
atom.Toggle()
atom.Toggle()
})
}
func TestStressString(t *testing.T) {
var atom String
runStress(func() {
atom.Load()
atom.Store("abc")
atom.Load()
atom.Store("def")
})
}

51
vendor/go.uber.org/atomic/string.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
// 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 atomic
import "sync/atomic"
// String is an atomic type-safe wrapper around atomic.Value for strings.
type String struct{ v atomic.Value }
// NewString creates a String.
func NewString(str string) *String {
s := &String{}
if str != "" {
s.Store(str)
}
return s
}
// Load atomically loads the wrapped string.
func (s *String) Load() string {
v := s.v.Load()
if v == nil {
return ""
}
return v.(string)
}
// Store atomically stores the passed string.
// Note: Converting the string to an interface{} to store in the atomic.Value
// requires an allocation.
func (s *String) Store(str string) {
s.v.Store(str)
}

43
vendor/go.uber.org/atomic/string_test.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
// 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 atomic
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestStringNoInitialValue(t *testing.T) {
atom := &String{}
require.Equal(t, "", atom.Load(), "Initial value should be blank string")
}
func TestString(t *testing.T) {
atom := NewString("")
require.Equal(t, "", atom.Load(), "Expected Load to return initialized value")
atom.Store("abc")
require.Equal(t, "abc", atom.Load(), "Unexpected value after Store")
atom = NewString("bcd")
require.Equal(t, "bcd", atom.Load(), "Expected Load to return initialized value")
}

15
vendor/go.uber.org/multierr/.codecov.yml generated vendored Normal file
View File

@ -0,0 +1,15 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 100 # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure

1
vendor/go.uber.org/multierr/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
/vendor

33
vendor/go.uber.org/multierr/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,33 @@
sudo: false
language: go
go_import_path: go.uber.org/multierr
env:
global:
- GO15VENDOREXPERIMENT=1
go:
- 1.7
- 1.8
- tip
cache:
directories:
- vendor
before_install:
- go version
install:
- |
set -e
make install_ci
script:
- |
set -e
make lint
make test_ci
after_success:
- bash <(curl -s https://codecov.io/bash)

28
vendor/go.uber.org/multierr/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,28 @@
Releases
========
v1.1.0 (2017-06-30)
===================
- Added an `Errors(error) []error` function to extract the underlying list of
errors for a multierr error.
v1.0.0 (2017-05-31)
===================
No changes since v0.2.0. This release is committing to making no breaking
changes to the current API in the 1.X series.
v0.2.0 (2017-04-11)
===================
- Repeatedly appending to the same error is now faster due to fewer
allocations.
v0.1.0 (2017-31-03)
===================
- Initial release

19
vendor/go.uber.org/multierr/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2017 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.

74
vendor/go.uber.org/multierr/Makefile generated vendored Normal file
View File

@ -0,0 +1,74 @@
export GO15VENDOREXPERIMENT=1
PACKAGES := $(shell glide nv)
GO_FILES := $(shell \
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
-o -name '*.go' -print | cut -b3-)
.PHONY: install
install:
glide --version || go get github.com/Masterminds/glide
glide install
.PHONY: build
build:
go build -i $(PACKAGES)
.PHONY: test
test:
go test -cover -race $(PACKAGES)
.PHONY: gofmt
gofmt:
$(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX))
@gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true
@[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" | cat - $(FMT_LOG) && false)
.PHONY: govet
govet:
$(eval VET_LOG := $(shell mktemp -t govet.XXXXX))
@go vet $(PACKAGES) 2>&1 \
| grep -v '^exit status' > $(VET_LOG) || true
@[ ! -s "$(VET_LOG)" ] || (echo "govet failed:" | cat - $(VET_LOG) && false)
.PHONY: golint
golint:
@go get github.com/golang/lint/golint
$(eval LINT_LOG := $(shell mktemp -t golint.XXXXX))
@cat /dev/null > $(LINT_LOG)
@$(foreach pkg, $(PACKAGES), golint $(pkg) >> $(LINT_LOG) || true;)
@[ ! -s "$(LINT_LOG)" ] || (echo "golint failed:" | cat - $(LINT_LOG) && false)
.PHONY: staticcheck
staticcheck:
@go get honnef.co/go/tools/cmd/staticcheck
$(eval STATICCHECK_LOG := $(shell mktemp -t staticcheck.XXXXX))
@staticcheck $(PACKAGES) 2>&1 > $(STATICCHECK_LOG) || true
@[ ! -s "$(STATICCHECK_LOG)" ] || (echo "staticcheck failed:" | cat - $(STATICCHECK_LOG) && false)
.PHONY: lint
lint: gofmt govet golint staticcheck
.PHONY: cover
cover:
./scripts/cover.sh $(shell go list $(PACKAGES))
go tool cover -html=cover.out -o cover.html
update-license:
@go get go.uber.org/tools/update-license
@update-license \
$(shell go list -json $(PACKAGES) | \
jq -r '.Dir + "/" + (.GoFiles | .[])')
##############################################################################
.PHONY: install_ci
install_ci: install
go get github.com/wadey/gocovmerge
go get github.com/mattn/goveralls
go get golang.org/x/tools/cmd/cover
.PHONY: test_ci
test_ci: install_ci
./scripts/cover.sh $(shell go list $(PACKAGES))

23
vendor/go.uber.org/multierr/README.md generated vendored Normal file
View File

@ -0,0 +1,23 @@
# multierr [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
`multierr` allows combining one or more Go `error`s together.
## Installation
go get -u go.uber.org/multierr
## Status
Stable: No breaking changes will be made before 2.0.
-------------------------------------------------------------------------------
Released under the [MIT License].
[MIT License]: LICENSE.txt
[doc-img]: https://godoc.org/go.uber.org/multierr?status.svg
[doc]: https://godoc.org/go.uber.org/multierr
[ci-img]: https://travis-ci.org/uber-go/multierr.svg?branch=master
[cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg
[ci]: https://travis-ci.org/uber-go/multierr
[cov]: https://codecov.io/gh/uber-go/multierr

62
vendor/go.uber.org/multierr/benchmarks_test.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
// Copyright (c) 2017 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 multierr
import (
"errors"
"fmt"
"testing"
)
func BenchmarkAppend(b *testing.B) {
errorTypes := []struct {
name string
err error
}{
{
name: "nil",
err: nil,
},
{
name: "single error",
err: errors.New("test"),
},
{
name: "multiple errors",
err: appendN(nil, errors.New("err"), 10),
},
}
for _, initial := range errorTypes {
for _, v := range errorTypes {
msg := fmt.Sprintf("append %v to %v", v.name, initial.name)
b.Run(msg, func(b *testing.B) {
for _, appends := range []int{1, 2, 10} {
b.Run(fmt.Sprint(appends), func(b *testing.B) {
for i := 0; i < b.N; i++ {
appendN(initial.err, v.err, appends)
}
})
}
})
}
}
}

401
vendor/go.uber.org/multierr/error.go generated vendored Normal file
View File

@ -0,0 +1,401 @@
// Copyright (c) 2017 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 multierr allows combining one or more errors together.
//
// Overview
//
// Errors can be combined with the use of the Combine function.
//
// multierr.Combine(
// reader.Close(),
// writer.Close(),
// conn.Close(),
// )
//
// If only two errors are being combined, the Append function may be used
// instead.
//
// err = multierr.Combine(reader.Close(), writer.Close())
//
// This makes it possible to record resource cleanup failures from deferred
// blocks with the help of named return values.
//
// func sendRequest(req Request) (err error) {
// conn, err := openConnection()
// if err != nil {
// return err
// }
// defer func() {
// err = multierr.Append(err, conn.Close())
// }()
// // ...
// }
//
// The underlying list of errors for a returned error object may be retrieved
// with the Errors function.
//
// errors := multierr.Errors(err)
// if len(errors) > 0 {
// fmt.Println("The following errors occurred:")
// }
//
// Advanced Usage
//
// Errors returned by Combine and Append MAY implement the following
// interface.
//
// type errorGroup interface {
// // Returns a slice containing the underlying list of errors.
// //
// // This slice MUST NOT be modified by the caller.
// Errors() []error
// }
//
// Note that if you need access to list of errors behind a multierr error, you
// should prefer using the Errors function. That said, if you need cheap
// read-only access to the underlying errors slice, you can attempt to cast
// the error to this interface. You MUST handle the failure case gracefully
// because errors returned by Combine and Append are not guaranteed to
// implement this interface.
//
// var errors []error
// group, ok := err.(errorGroup)
// if ok {
// errors = group.Errors()
// } else {
// errors = []error{err}
// }
package multierr // import "go.uber.org/multierr"
import (
"bytes"
"fmt"
"io"
"strings"
"sync"
"go.uber.org/atomic"
)
var (
// Separator for single-line error messages.
_singlelineSeparator = []byte("; ")
_newline = []byte("\n")
// Prefix for multi-line messages
_multilinePrefix = []byte("the following errors occurred:")
// Prefix for the first and following lines of an item in a list of
// multi-line error messages.
//
// For example, if a single item is:
//
// foo
// bar
//
// It will become,
//
// - foo
// bar
_multilineSeparator = []byte("\n - ")
_multilineIndent = []byte(" ")
)
// _bufferPool is a pool of bytes.Buffers.
var _bufferPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
type errorGroup interface {
Errors() []error
}
// Errors returns a slice containing zero or more errors that the supplied
// error is composed of. If the error is nil, the returned slice is empty.
//
// err := multierr.Append(r.Close(), w.Close())
// errors := multierr.Errors(err)
//
// If the error is not composed of other errors, the returned slice contains
// just the error that was passed in.
//
// Callers of this function are free to modify the returned slice.
func Errors(err error) []error {
if err == nil {
return nil
}
// Note that we're casting to multiError, not errorGroup. Our contract is
// that returned errors MAY implement errorGroup. Errors, however, only
// has special behavior for multierr-specific error objects.
//
// This behavior can be expanded in the future but I think it's prudent to
// start with as little as possible in terms of contract and possibility
// of misuse.
eg, ok := err.(*multiError)
if !ok {
return []error{err}
}
errors := eg.Errors()
result := make([]error, len(errors))
copy(result, errors)
return result
}
// multiError is an error that holds one or more errors.
//
// An instance of this is guaranteed to be non-empty and flattened. That is,
// none of the errors inside multiError are other multiErrors.
//
// multiError formats to a semi-colon delimited list of error messages with
// %v and with a more readable multi-line format with %+v.
type multiError struct {
copyNeeded atomic.Bool
errors []error
}
var _ errorGroup = (*multiError)(nil)
// Errors returns the list of underlying errors.
//
// This slice MUST NOT be modified.
func (merr *multiError) Errors() []error {
if merr == nil {
return nil
}
return merr.errors
}
func (merr *multiError) Error() string {
if merr == nil {
return ""
}
buff := _bufferPool.Get().(*bytes.Buffer)
buff.Reset()
merr.writeSingleline(buff)
result := buff.String()
_bufferPool.Put(buff)
return result
}
func (merr *multiError) Format(f fmt.State, c rune) {
if c == 'v' && f.Flag('+') {
merr.writeMultiline(f)
} else {
merr.writeSingleline(f)
}
}
func (merr *multiError) writeSingleline(w io.Writer) {
first := true
for _, item := range merr.errors {
if first {
first = false
} else {
w.Write(_singlelineSeparator)
}
io.WriteString(w, item.Error())
}
}
func (merr *multiError) writeMultiline(w io.Writer) {
w.Write(_multilinePrefix)
for _, item := range merr.errors {
w.Write(_multilineSeparator)
writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item))
}
}
// Writes s to the writer with the given prefix added before each line after
// the first.
func writePrefixLine(w io.Writer, prefix []byte, s string) {
first := true
for len(s) > 0 {
if first {
first = false
} else {
w.Write(prefix)
}
idx := strings.IndexByte(s, '\n')
if idx < 0 {
idx = len(s) - 1
}
io.WriteString(w, s[:idx+1])
s = s[idx+1:]
}
}
type inspectResult struct {
// Number of top-level non-nil errors
Count int
// Total number of errors including multiErrors
Capacity int
// Index of the first non-nil error in the list. Value is meaningless if
// Count is zero.
FirstErrorIdx int
// Whether the list contains at least one multiError
ContainsMultiError bool
}
// Inspects the given slice of errors so that we can efficiently allocate
// space for it.
func inspect(errors []error) (res inspectResult) {
first := true
for i, err := range errors {
if err == nil {
continue
}
res.Count++
if first {
first = false
res.FirstErrorIdx = i
}
if merr, ok := err.(*multiError); ok {
res.Capacity += len(merr.errors)
res.ContainsMultiError = true
} else {
res.Capacity++
}
}
return
}
// fromSlice converts the given list of errors into a single error.
func fromSlice(errors []error) error {
res := inspect(errors)
switch res.Count {
case 0:
return nil
case 1:
// only one non-nil entry
return errors[res.FirstErrorIdx]
case len(errors):
if !res.ContainsMultiError {
// already flat
return &multiError{errors: errors}
}
}
nonNilErrs := make([]error, 0, res.Capacity)
for _, err := range errors[res.FirstErrorIdx:] {
if err == nil {
continue
}
if nested, ok := err.(*multiError); ok {
nonNilErrs = append(nonNilErrs, nested.errors...)
} else {
nonNilErrs = append(nonNilErrs, err)
}
}
return &multiError{errors: nonNilErrs}
}
// Combine combines the passed errors into a single error.
//
// If zero arguments were passed or if all items are nil, a nil error is
// returned.
//
// Combine(nil, nil) // == nil
//
// If only a single error was passed, it is returned as-is.
//
// Combine(err) // == err
//
// Combine skips over nil arguments so this function may be used to combine
// together errors from operations that fail independently of each other.
//
// multierr.Combine(
// reader.Close(),
// writer.Close(),
// pipe.Close(),
// )
//
// If any of the passed errors is a multierr error, it will be flattened along
// with the other errors.
//
// multierr.Combine(multierr.Combine(err1, err2), err3)
// // is the same as
// multierr.Combine(err1, err2, err3)
//
// The returned error formats into a readable multi-line error message if
// formatted with %+v.
//
// fmt.Sprintf("%+v", multierr.Combine(err1, err2))
func Combine(errors ...error) error {
return fromSlice(errors)
}
// Append appends the given errors together. Either value may be nil.
//
// This function is a specialization of Combine for the common case where
// there are only two errors.
//
// err = multierr.Append(reader.Close(), writer.Close())
//
// The following pattern may also be used to record failure of deferred
// operations without losing information about the original error.
//
// func doSomething(..) (err error) {
// f := acquireResource()
// defer func() {
// err = multierr.Append(err, f.Close())
// }()
func Append(left error, right error) error {
switch {
case left == nil:
return right
case right == nil:
return left
}
if _, ok := right.(*multiError); !ok {
if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) {
// Common case where the error on the left is constantly being
// appended to.
errs := append(l.errors, right)
return &multiError{errors: errs}
} else if !ok {
// Both errors are single errors.
return &multiError{errors: []error{left, right}}
}
}
// Either right or both, left and right, are multiErrors. Rely on usual
// expensive logic.
errors := [2]error{left, right}
return fromSlice(errors[0:])
}

511
vendor/go.uber.org/multierr/error_test.go generated vendored Normal file
View File

@ -0,0 +1,511 @@
// Copyright (c) 2017 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 multierr
import (
"errors"
"fmt"
"io"
"sync"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// richFormatError is an error that prints a different output depending on
// whether %v or %+v was used.
type richFormatError struct{}
func (r richFormatError) Error() string {
return fmt.Sprint(r)
}
func (richFormatError) Format(f fmt.State, c rune) {
if c == 'v' && f.Flag('+') {
io.WriteString(f, "multiline\nmessage\nwith plus")
} else {
io.WriteString(f, "without plus")
}
}
func appendN(initial, err error, n int) error {
errs := initial
for i := 0; i < n; i++ {
errs = Append(errs, err)
}
return errs
}
func newMultiErr(errors ...error) error {
return &multiError{errors: errors}
}
func TestCombine(t *testing.T) {
tests := []struct {
// Input
giveErrors []error
// Resulting error
wantError error
// %+v and %v string representations
wantMultiline string
wantSingleline string
}{
{
giveErrors: nil,
wantError: nil,
},
{
giveErrors: []error{},
wantError: nil,
},
{
giveErrors: []error{
errors.New("foo"),
nil,
newMultiErr(
errors.New("bar"),
),
nil,
},
wantError: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
wantMultiline: "the following errors occurred:\n" +
" - foo\n" +
" - bar",
wantSingleline: "foo; bar",
},
{
giveErrors: []error{
errors.New("foo"),
newMultiErr(
errors.New("bar"),
),
},
wantError: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
wantMultiline: "the following errors occurred:\n" +
" - foo\n" +
" - bar",
wantSingleline: "foo; bar",
},
{
giveErrors: []error{errors.New("great sadness")},
wantError: errors.New("great sadness"),
wantMultiline: "great sadness",
wantSingleline: "great sadness",
},
{
giveErrors: []error{
errors.New("foo"),
errors.New("bar"),
},
wantError: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
wantMultiline: "the following errors occurred:\n" +
" - foo\n" +
" - bar",
wantSingleline: "foo; bar",
},
{
giveErrors: []error{
errors.New("great sadness"),
errors.New("multi\n line\nerror message"),
errors.New("single line error message"),
},
wantError: newMultiErr(
errors.New("great sadness"),
errors.New("multi\n line\nerror message"),
errors.New("single line error message"),
),
wantMultiline: "the following errors occurred:\n" +
" - great sadness\n" +
" - multi\n" +
" line\n" +
" error message\n" +
" - single line error message",
wantSingleline: "great sadness; " +
"multi\n line\nerror message; " +
"single line error message",
},
{
giveErrors: []error{
errors.New("foo"),
newMultiErr(
errors.New("bar"),
errors.New("baz"),
),
errors.New("qux"),
},
wantError: newMultiErr(
errors.New("foo"),
errors.New("bar"),
errors.New("baz"),
errors.New("qux"),
),
wantMultiline: "the following errors occurred:\n" +
" - foo\n" +
" - bar\n" +
" - baz\n" +
" - qux",
wantSingleline: "foo; bar; baz; qux",
},
{
giveErrors: []error{
errors.New("foo"),
nil,
newMultiErr(
errors.New("bar"),
),
nil,
},
wantError: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
wantMultiline: "the following errors occurred:\n" +
" - foo\n" +
" - bar",
wantSingleline: "foo; bar",
},
{
giveErrors: []error{
errors.New("foo"),
newMultiErr(
errors.New("bar"),
),
},
wantError: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
wantMultiline: "the following errors occurred:\n" +
" - foo\n" +
" - bar",
wantSingleline: "foo; bar",
},
{
giveErrors: []error{
errors.New("foo"),
richFormatError{},
errors.New("bar"),
},
wantError: newMultiErr(
errors.New("foo"),
richFormatError{},
errors.New("bar"),
),
wantMultiline: "the following errors occurred:\n" +
" - foo\n" +
" - multiline\n" +
" message\n" +
" with plus\n" +
" - bar",
wantSingleline: "foo; without plus; bar",
},
}
for i, tt := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
err := Combine(tt.giveErrors...)
require.Equal(t, tt.wantError, err)
if tt.wantMultiline != "" {
t.Run("Sprintf/multiline", func(t *testing.T) {
assert.Equal(t, tt.wantMultiline, fmt.Sprintf("%+v", err))
})
}
if tt.wantSingleline != "" {
t.Run("Sprintf/singleline", func(t *testing.T) {
assert.Equal(t, tt.wantSingleline, fmt.Sprintf("%v", err))
})
t.Run("Error()", func(t *testing.T) {
assert.Equal(t, tt.wantSingleline, err.Error())
})
if s, ok := err.(fmt.Stringer); ok {
t.Run("String()", func(t *testing.T) {
assert.Equal(t, tt.wantSingleline, s.String())
})
}
}
})
}
}
func TestCombineDoesNotModifySlice(t *testing.T) {
errors := []error{
errors.New("foo"),
nil,
errors.New("bar"),
}
assert.NotNil(t, Combine(errors...))
assert.Len(t, errors, 3)
assert.Nil(t, errors[1], 3)
}
func TestAppend(t *testing.T) {
tests := []struct {
left error
right error
want error
}{
{
left: nil,
right: nil,
want: nil,
},
{
left: nil,
right: errors.New("great sadness"),
want: errors.New("great sadness"),
},
{
left: errors.New("great sadness"),
right: nil,
want: errors.New("great sadness"),
},
{
left: errors.New("foo"),
right: errors.New("bar"),
want: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
},
{
left: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
right: errors.New("baz"),
want: newMultiErr(
errors.New("foo"),
errors.New("bar"),
errors.New("baz"),
),
},
{
left: errors.New("baz"),
right: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
want: newMultiErr(
errors.New("baz"),
errors.New("foo"),
errors.New("bar"),
),
},
{
left: newMultiErr(
errors.New("foo"),
),
right: newMultiErr(
errors.New("bar"),
),
want: newMultiErr(
errors.New("foo"),
errors.New("bar"),
),
},
}
for _, tt := range tests {
assert.Equal(t, tt.want, Append(tt.left, tt.right))
}
}
type notMultiErr struct{}
var _ errorGroup = notMultiErr{}
func (notMultiErr) Error() string {
return "great sadness"
}
func (notMultiErr) Errors() []error {
return []error{errors.New("great sadness")}
}
func TestErrors(t *testing.T) {
tests := []struct {
give error
want []error
// Don't attempt to cast to errorGroup or *multiError
dontCast bool
}{
{dontCast: true}, // nil
{
give: errors.New("hi"),
want: []error{errors.New("hi")},
dontCast: true,
},
{
// We don't yet support non-multierr errors.
give: notMultiErr{},
want: []error{notMultiErr{}},
dontCast: true,
},
{
give: Combine(
errors.New("foo"),
errors.New("bar"),
),
want: []error{
errors.New("foo"),
errors.New("bar"),
},
},
{
give: Append(
errors.New("foo"),
errors.New("bar"),
),
want: []error{
errors.New("foo"),
errors.New("bar"),
},
},
{
give: Append(
errors.New("foo"),
Combine(
errors.New("bar"),
),
),
want: []error{
errors.New("foo"),
errors.New("bar"),
},
},
{
give: Combine(
errors.New("foo"),
Append(
errors.New("bar"),
errors.New("baz"),
),
errors.New("qux"),
),
want: []error{
errors.New("foo"),
errors.New("bar"),
errors.New("baz"),
errors.New("qux"),
},
},
}
for i, tt := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
t.Run("Errors()", func(t *testing.T) {
require.Equal(t, tt.want, Errors(tt.give))
})
if tt.dontCast {
return
}
t.Run("multiError", func(t *testing.T) {
require.Equal(t, tt.want, tt.give.(*multiError).Errors())
})
t.Run("errorGroup", func(t *testing.T) {
require.Equal(t, tt.want, tt.give.(errorGroup).Errors())
})
})
}
}
func createMultiErrWithCapacity() error {
// Create a multiError that has capacity for more errors so Append will
// modify the underlying array that may be shared.
return appendN(nil, errors.New("append"), 50)
}
func TestAppendDoesNotModify(t *testing.T) {
initial := createMultiErrWithCapacity()
err1 := Append(initial, errors.New("err1"))
err2 := Append(initial, errors.New("err2"))
// Make sure the error messages match, since we do modify the copyNeeded
// atomic, the values cannot be compared.
assert.EqualError(t, initial, createMultiErrWithCapacity().Error(), "Initial should not be modified")
assert.EqualError(t, err1, Append(createMultiErrWithCapacity(), errors.New("err1")).Error())
assert.EqualError(t, err2, Append(createMultiErrWithCapacity(), errors.New("err2")).Error())
}
func TestAppendRace(t *testing.T) {
initial := createMultiErrWithCapacity()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
err := initial
for j := 0; j < 10; j++ {
err = Append(err, errors.New("err"))
}
}()
}
wg.Wait()
}
func TestErrorsSliceIsImmutable(t *testing.T) {
err1 := errors.New("err1")
err2 := errors.New("err2")
err := Append(err1, err2)
gotErrors := Errors(err)
require.Equal(t, []error{err1, err2}, gotErrors, "errors must match")
gotErrors[0] = nil
gotErrors[1] = errors.New("err3")
require.Equal(t, []error{err1, err2}, Errors(err),
"errors must match after modification")
}
func TestNilMultierror(t *testing.T) {
// For safety, all operations on multiError should be safe even if it is
// nil.
var err *multiError
require.Empty(t, err.Error())
require.Empty(t, err.Errors())
}

72
vendor/go.uber.org/multierr/example_test.go generated vendored Normal file
View File

@ -0,0 +1,72 @@
// Copyright (c) 2017 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 multierr_test
import (
"errors"
"fmt"
"go.uber.org/multierr"
)
func ExampleCombine() {
err := multierr.Combine(
errors.New("call 1 failed"),
nil, // successful request
errors.New("call 3 failed"),
nil, // successful request
errors.New("call 5 failed"),
)
fmt.Printf("%+v", err)
// Output:
// the following errors occurred:
// - call 1 failed
// - call 3 failed
// - call 5 failed
}
func ExampleAppend() {
var err error
err = multierr.Append(err, errors.New("call 1 failed"))
err = multierr.Append(err, errors.New("call 2 failed"))
fmt.Println(err)
// Output:
// call 1 failed; call 2 failed
}
func ExampleErrors() {
err := multierr.Combine(
nil, // successful request
errors.New("call 2 failed"),
errors.New("call 3 failed"),
)
err = multierr.Append(err, nil) // successful request
err = multierr.Append(err, errors.New("call 5 failed"))
errors := multierr.Errors(err)
for _, err := range errors {
fmt.Println(err)
}
// Output:
// call 2 failed
// call 3 failed
// call 5 failed
}

19
vendor/go.uber.org/multierr/glide.lock generated vendored Normal file
View File

@ -0,0 +1,19 @@
hash: b53b5e9a84b9cb3cc4b2d0499e23da2feca1eec318ce9bb717ecf35bf24bf221
updated: 2017-04-10T13:34:45.671678062-07:00
imports:
- name: go.uber.org/atomic
version: 3b8db5e93c4c02efbc313e17b2e796b0914a01fb
testImports:
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
- spew
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
subpackages:
- assert
- require

8
vendor/go.uber.org/multierr/glide.yaml generated vendored Normal file
View File

@ -0,0 +1,8 @@
package: go.uber.org/multierr
import:
- package: go.uber.org/atomic
version: ^1
testImport:
- package: github.com/stretchr/testify
subpackages:
- assert

40
vendor/go.uber.org/multierr/scripts/cover.sh generated vendored Executable file
View File

@ -0,0 +1,40 @@
#!/bin/bash -e
COVER=cover
ROOT_PKG=go.uber.org/multierr
if [[ -d "$COVER" ]]; then
rm -rf "$COVER"
fi
mkdir -p "$COVER"
i=0
for pkg in "$@"; do
i=$((i + 1))
extracoverpkg=""
if [[ -f "$GOPATH/src/$pkg/.extra-coverpkg" ]]; then
extracoverpkg=$( \
sed -e "s|^|$pkg/|g" < "$GOPATH/src/$pkg/.extra-coverpkg" \
| tr '\n' ',')
fi
coverpkg=$(go list -json "$pkg" | jq -r '
.Deps
| . + ["'"$pkg"'"]
| map
( select(startswith("'"$ROOT_PKG"'"))
| select(contains("/vendor/") | not)
)
| join(",")
')
if [[ -n "$extracoverpkg" ]]; then
coverpkg="$extracoverpkg$coverpkg"
fi
go test \
-coverprofile "$COVER/cover.${i}.out" -coverpkg "$coverpkg" \
-v "$pkg"
done
gocovmerge "$COVER"/*.out > cover.out

17
vendor/go.uber.org/zap/.codecov.yml generated vendored Normal file
View File

@ -0,0 +1,17 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 95% # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure
ignore:
- internal/readme/readme.go

28
vendor/go.uber.org/zap/.gitignore generated vendored Normal file
View File

@ -0,0 +1,28 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
vendor
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*.pprof
*.out
*.log

108
vendor/go.uber.org/zap/.readme.tmpl generated vendored Normal file
View File

@ -0,0 +1,108 @@
# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Blazing fast, structured, leveled logging in Go.
## Installation
`go get -u go.uber.org/zap`
Note that zap only supports the two most recent minor versions of Go.
## Quick Start
In contexts where performance is nice, but not critical, use the
`SugaredLogger`. It's 4-10x faster than than other structured logging
packages and includes both structured and `printf`-style APIs.
```go
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
```
When performance and type safety are critical, use the `Logger`. It's even
faster than the `SugaredLogger` and allocates far less, but it only supports
structured logging.
```go
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
```
See the [documentation][doc] and [FAQ](FAQ.md) for more details.
## Performance
For applications that log in the hot path, reflection-based serialization and
string formatting are prohibitively expensive &mdash; they're CPU-intensive
and make many small allocations. Put differently, using `encoding/json` and
`fmt.Fprintf` to log tons of `interface{}`s makes your application slow.
Zap takes a different approach. It includes a reflection-free, zero-allocation
JSON encoder, and the base `Logger` strives to avoid serialization overhead
and allocations wherever possible. By building the high-level `SugaredLogger`
on that foundation, zap lets users *choose* when they need to count every
allocation and when they'd prefer a more familiar, loosely typed API.
As measured by its own [benchmarking suite][], not only is zap more performant
than comparable structured logging packages &mdash; it's also faster than the
standard library. Like all benchmarks, take these with a grain of salt.<sup
id="anchor-versions">[1](#footnote-versions)</sup>
Log a message and 10 fields:
{{.BenchmarkAddingFields}}
Log a message with a logger that already has 10 fields of context:
{{.BenchmarkAccumulatedContext}}
Log a static string, without any context or `printf`-style templating:
{{.BenchmarkWithoutFields}}
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
zap to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors &mdash;
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on
issues and pull requests, but you can also report any negative conduct to
oss-conduct@uber.com. That email list is a private, safe space; even the zap
maintainers don't have access, so don't hesitate to hold us to a high
standard.
<hr>
Released under the [MIT License](LICENSE.txt).
<sup id="footnote-versions">1</sup> In particular, keep in mind that we may be
benchmarking against slightly older versions of other packages. Versions are
pinned in zap's [glide.lock][] file. [↩](#anchor-versions)
[doc-img]: https://godoc.org/go.uber.org/zap?status.svg
[doc]: https://godoc.org/go.uber.org/zap
[ci-img]: https://travis-ci.org/uber-go/zap.svg?branch=master
[ci]: https://travis-ci.org/uber-go/zap
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/zap
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
[glide.lock]: https://github.com/uber-go/zap/blob/master/glide.lock

23
vendor/go.uber.org/zap/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,23 @@
language: go
sudo: false
go:
- 1.7
- 1.8
- 1.9
go_import_path: go.uber.org/zap
env:
global:
- GO15VENDOREXPERIMENT=1
- TEST_TIMEOUT_SCALE=10
cache:
directories:
- vendor
install:
- make dependencies
script:
- make lint
- make test
- make bench
after_success:
- make cover
- bash <(curl -s https://codecov.io/bash)

270
vendor/go.uber.org/zap/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,270 @@
# Changelog
## v1.7.1 (25 Sep 2017)
Bugfixes:
* [#504][]: Store strings when using AddByteString with the map encoder.
## v1.7.0 (21 Sep 2017)
Enhancements:
* [#487][]: Add `NewStdLogAt`, which extends `NewStdLog` by allowing the user
to specify the level of the logged messages.
## v1.6.0 (30 Aug 2017)
Enhancements:
* [#491][]: Omit zap stack frames from stacktraces.
* [#490][]: Add a `ContextMap` method to observer logs for simpler
field validation in tests.
## v1.5.0 (22 Jul 2017)
Enhancements:
* [#460][] and [#470][]: Support errors produced by `go.uber.org/multierr`.
* [#465][]: Support user-supplied encoders for logger names.
Bugfixes:
* [#477][]: Fix a bug that incorrectly truncated deep stacktraces.
Thanks to @richard-tunein and @pavius for their contributions to this release.
## v1.4.1 (08 Jun 2017)
This release fixes two bugs.
Bugfixes:
* [#435][]: Support a variety of case conventions when unmarshaling levels.
* [#444][]: Fix a panic in the observer.
## v1.4.0 (12 May 2017)
This release adds a few small features and is fully backward-compatible.
Enhancements:
* [#424][]: Add a `LineEnding` field to `EncoderConfig`, allowing users to
override the Unix-style default.
* [#425][]: Preserve time zones when logging times.
* [#431][]: Make `zap.AtomicLevel` implement `fmt.Stringer`, which makes a
variety of operations a bit simpler.
## v1.3.0 (25 Apr 2017)
This release adds an enhancement to zap's testing helpers as well as the
ability to marshal an AtomicLevel. It is fully backward-compatible.
Enhancements:
* [#415][]: Add a substring-filtering helper to zap's observer. This is
particularly useful when testing the `SugaredLogger`.
* [#416][]: Make `AtomicLevel` implement `encoding.TextMarshaler`.
## v1.2.0 (13 Apr 2017)
This release adds a gRPC compatibility wrapper. It is fully backward-compatible.
Enhancements:
* [#402][]: Add a `zapgrpc` package that wraps zap's Logger and implements
`grpclog.Logger`.
## v1.1.0 (31 Mar 2017)
This release fixes two bugs and adds some enhancements to zap's testing helpers.
It is fully backward-compatible.
Bugfixes:
* [#385][]: Fix caller path trimming on Windows.
* [#396][]: Fix a panic when attempting to use non-existent directories with
zap's configuration struct.
Enhancements:
* [#386][]: Add filtering helpers to zaptest's observing logger.
Thanks to @moitias for contributing to this release.
## v1.0.0 (14 Mar 2017)
This is zap's first stable release. All exported APIs are now final, and no
further breaking changes will be made in the 1.x release series. Anyone using a
semver-aware dependency manager should now pin to `^1`.
Breaking changes:
* [#366][]: Add byte-oriented APIs to encoders to log UTF-8 encoded text without
casting from `[]byte` to `string`.
* [#364][]: To support buffering outputs, add `Sync` methods to `zapcore.Core`,
`zap.Logger`, and `zap.SugaredLogger`.
* [#371][]: Rename the `testutils` package to `zaptest`, which is less likely to
clash with other testing helpers.
Bugfixes:
* [#362][]: Make the ISO8601 time formatters fixed-width, which is friendlier
for tab-separated console output.
* [#369][]: Remove the automatic locks in `zapcore.NewCore`, which allows zap to
work with concurrency-safe `WriteSyncer` implementations.
* [#347][]: Stop reporting errors when trying to `fsync` standard out on Linux
systems.
* [#373][]: Report the correct caller from zap's standard library
interoperability wrappers.
Enhancements:
* [#348][]: Add a registry allowing third-party encodings to work with zap's
built-in `Config`.
* [#327][]: Make the representation of logger callers configurable (like times,
levels, and durations).
* [#376][]: Allow third-party encoders to use their own buffer pools, which
removes the last performance advantage that zap's encoders have over plugins.
* [#346][]: Add `CombineWriteSyncers`, a convenience function to tee multiple
`WriteSyncer`s and lock the result.
* [#365][]: Make zap's stacktraces compatible with mid-stack inlining (coming in
Go 1.9).
* [#372][]: Export zap's observing logger as `zaptest/observer`. This makes it
easier for particularly punctilious users to unit test their application's
logging.
Thanks to @suyash, @htrendev, @flisky, @Ulexus, and @skipor for their
contributions to this release.
## v1.0.0-rc.3 (7 Mar 2017)
This is the third release candidate for zap's stable release. There are no
breaking changes.
Bugfixes:
* [#339][]: Byte slices passed to `zap.Any` are now correctly treated as binary blobs
rather than `[]uint8`.
Enhancements:
* [#307][]: Users can opt into colored output for log levels.
* [#353][]: In addition to hijacking the output of the standard library's
package-global logging functions, users can now construct a zap-backed
`log.Logger` instance.
* [#311][]: Frames from common runtime functions and some of zap's internal
machinery are now omitted from stacktraces.
Thanks to @ansel1 and @suyash for their contributions to this release.
## v1.0.0-rc.2 (21 Feb 2017)
This is the second release candidate for zap's stable release. It includes two
breaking changes.
Breaking changes:
* [#316][]: Zap's global loggers are now fully concurrency-safe
(previously, users had to ensure that `ReplaceGlobals` was called before the
loggers were in use). However, they must now be accessed via the `L()` and
`S()` functions. Users can update their projects with
```
gofmt -r "zap.L -> zap.L()" -w .
gofmt -r "zap.S -> zap.S()" -w .
```
* [#309][] and [#317][]: RC1 was mistakenly shipped with invalid
JSON and YAML struct tags on all config structs. This release fixes the tags
and adds static analysis to prevent similar bugs in the future.
Bugfixes:
* [#321][]: Redirecting the standard library's `log` output now
correctly reports the logger's caller.
Enhancements:
* [#325][] and [#333][]: Zap now transparently supports non-standard, rich
errors like those produced by `github.com/pkg/errors`.
* [#326][]: Though `New(nil)` continues to return a no-op logger, `NewNop()` is
now preferred. Users can update their projects with `gofmt -r 'zap.New(nil) ->
zap.NewNop()' -w .`.
* [#300][]: Incorrectly importing zap as `github.com/uber-go/zap` now returns a
more informative error.
Thanks to @skipor and @chapsuk for their contributions to this release.
## v1.0.0-rc.1 (14 Feb 2017)
This is the first release candidate for zap's stable release. There are multiple
breaking changes and improvements from the pre-release version. Most notably:
* **Zap's import path is now "go.uber.org/zap"** &mdash; all users will
need to update their code.
* User-facing types and functions remain in the `zap` package. Code relevant
largely to extension authors is now in the `zapcore` package.
* The `zapcore.Core` type makes it easy for third-party packages to use zap's
internals but provide a different user-facing API.
* `Logger` is now a concrete type instead of an interface.
* A less verbose (though slower) logging API is included by default.
* Package-global loggers `L` and `S` are included.
* A human-friendly console encoder is included.
* A declarative config struct allows common logger configurations to be managed
as configuration instead of code.
* Sampling is more accurate, and doesn't depend on the standard library's shared
timer heap.
## v0.1.0-beta.1 (6 Feb 2017)
This is a minor version, tagged to allow users to pin to the pre-1.0 APIs and
upgrade at their leisure. Since this is the first tagged release, there are no
backward compatibility concerns and all functionality is new.
Early zap adopters should pin to the 0.1.x minor version until they're ready to
upgrade to the upcoming stable release.
[#316]: https://github.com/uber-go/zap/pull/316
[#309]: https://github.com/uber-go/zap/pull/309
[#317]: https://github.com/uber-go/zap/pull/317
[#321]: https://github.com/uber-go/zap/pull/321
[#325]: https://github.com/uber-go/zap/pull/325
[#333]: https://github.com/uber-go/zap/pull/333
[#326]: https://github.com/uber-go/zap/pull/326
[#300]: https://github.com/uber-go/zap/pull/300
[#339]: https://github.com/uber-go/zap/pull/339
[#307]: https://github.com/uber-go/zap/pull/307
[#353]: https://github.com/uber-go/zap/pull/353
[#311]: https://github.com/uber-go/zap/pull/311
[#366]: https://github.com/uber-go/zap/pull/366
[#364]: https://github.com/uber-go/zap/pull/364
[#371]: https://github.com/uber-go/zap/pull/371
[#362]: https://github.com/uber-go/zap/pull/362
[#369]: https://github.com/uber-go/zap/pull/369
[#347]: https://github.com/uber-go/zap/pull/347
[#373]: https://github.com/uber-go/zap/pull/373
[#348]: https://github.com/uber-go/zap/pull/348
[#327]: https://github.com/uber-go/zap/pull/327
[#376]: https://github.com/uber-go/zap/pull/376
[#346]: https://github.com/uber-go/zap/pull/346
[#365]: https://github.com/uber-go/zap/pull/365
[#372]: https://github.com/uber-go/zap/pull/372
[#385]: https://github.com/uber-go/zap/pull/385
[#396]: https://github.com/uber-go/zap/pull/396
[#386]: https://github.com/uber-go/zap/pull/386
[#402]: https://github.com/uber-go/zap/pull/402
[#415]: https://github.com/uber-go/zap/pull/415
[#416]: https://github.com/uber-go/zap/pull/416
[#424]: https://github.com/uber-go/zap/pull/424
[#425]: https://github.com/uber-go/zap/pull/425
[#431]: https://github.com/uber-go/zap/pull/431
[#435]: https://github.com/uber-go/zap/pull/435
[#444]: https://github.com/uber-go/zap/pull/444
[#477]: https://github.com/uber-go/zap/pull/477
[#465]: https://github.com/uber-go/zap/pull/465
[#460]: https://github.com/uber-go/zap/pull/460
[#470]: https://github.com/uber-go/zap/pull/470
[#487]: https://github.com/uber-go/zap/pull/487
[#490]: https://github.com/uber-go/zap/pull/490
[#491]: https://github.com/uber-go/zap/pull/491
[#491]: https://github.com/uber-go/zap/pull/439
[#504]: https://github.com/uber-go/zap/pull/504

75
vendor/go.uber.org/zap/CODE_OF_CONDUCT.md generated vendored Normal file
View File

@ -0,0 +1,75 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age,
body size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual
identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an
appointed representative at an online or offline event. Representation of a
project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at oss-conduct@uber.com. The project
team will review and investigate all complaints, and will respond in a way
that it deems appropriate to the circumstances. The project team is obligated
to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
[http://contributor-covenant.org/version/1/4][version].
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

81
vendor/go.uber.org/zap/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,81 @@
# Contributing
We'd love your help making zap the very best structured logging library in Go!
If you'd like to add new exported APIs, please [open an issue][open-issue]
describing your proposal &mdash; discussing API changes ahead of time makes
pull request review much smoother. In your issue, pull request, and any other
communications, please remember to treat your fellow contributors with
respect! We take our [code of conduct](CODE_OF_CONDUCT.md) seriously.
Note that you'll need to sign [Uber's Contributor License Agreement][cla]
before we can accept any of your contributions. If necessary, a bot will remind
you to accept the CLA when you open your pull request.
## Setup
[Fork][fork], then clone the repository:
```
mkdir -p $GOPATH/src/go.uber.org
cd $GOPATH/src/go.uber.org
git clone git@github.com:your_github_username/zap.git
cd zap
git remote add upstream https://github.com/uber-go/zap.git
git fetch upstream
```
Install zap's dependencies:
```
make dependencies
```
Make sure that the tests and the linters pass:
```
make test
make lint
```
If you're not using the minor version of Go specified in the Makefile's
`LINTABLE_MINOR_VERSIONS` variable, `make lint` doesn't do anything. This is
fine, but it means that you'll only discover lint failures after you open your
pull request.
## Making Changes
Start by creating a new branch for your changes:
```
cd $GOPATH/src/go.uber.org/zap
git checkout master
git fetch upstream
git rebase upstream/master
git checkout -b cool_new_feature
```
Make your changes, then ensure that `make lint` and `make test` still pass. If
you're satisfied with your changes, push them to your fork.
```
git push origin cool_new_feature
```
Then use the GitHub UI to open a pull request.
At this point, you're waiting on us to review your changes. We *try* to respond
to issues and pull requests within a few business days, and we may suggest some
improvements or alternatives. Once your changes are approved, one of the
project maintainers will merge them.
We're much more likely to approve your changes if you:
* Add tests for new functionality.
* Write a [good commit message][commit-message].
* Maintain backward compatibility.
[fork]: https://github.com/uber-go/zap/fork
[open-issue]: https://github.com/uber-go/zap/issues/new
[cla]: https://cla-assistant.io/uber-go/zap
[commit-message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html

140
vendor/go.uber.org/zap/FAQ.md generated vendored Normal file
View File

@ -0,0 +1,140 @@
# Frequently Asked Questions
## Design
### Why spend so much effort on logger performance?
Of course, most applications won't notice the impact of a slow logger: they
already take tens or hundreds of milliseconds for each operation, so an extra
millisecond doesn't matter.
On the other hand, why *not* make structured logging fast? The `SugaredLogger`
isn't any harder to use than other logging packages, and the `Logger` makes
structured logging possible in performance-sensitive contexts. Across a fleet
of Go microservices, making each application even slightly more efficient adds
up quickly.
### Why aren't `Logger` and `SugaredLogger` interfaces?
Unlike the familiar `io.Writer` and `http.Handler`, `Logger` and
`SugaredLogger` interfaces would include *many* methods. As [Rob Pike points
out][go-proverbs], "The bigger the interface, the weaker the abstraction."
Interfaces are also rigid &mdash; *any* change requires releasing a new major
version, since it breaks all third-party implementations.
Making the `Logger` and `SugaredLogger` concrete types doesn't sacrifice much
abstraction, and it lets us add methods without introducing breaking changes.
Your applications should define and depend upon an interface that includes
just the methods you use.
### Why sample application logs?
Applications often experience runs of errors, either because of a bug or
because of a misbehaving user. Logging errors is usually a good idea, but it
can easily make this bad situation worse: not only is your application coping
with a flood of errors, it's also spending extra CPU cycles and I/O logging
those errors. Since writes are typically serialized, logging limits throughput
when you need it most.
Sampling fixes this problem by dropping repetitive log entries. Under normal
conditions, your application writes out every entry. When similar entries are
logged hundreds or thousands of times each second, though, zap begins dropping
duplicates to preserve throughput.
### Why do the structured logging APIs take a message in addition to fields?
Subjectively, we find it helpful to accompany structured context with a brief
description. This isn't critical during development, but it makes debugging
and operating unfamiliar systems much easier.
More concretely, zap's sampling algorithm uses the message to identify
duplicate entries. In our experience, this is a practical middle ground
between random sampling (which often drops the exact entry that you need while
debugging) and hashing the complete entry (which is prohibitively expensive).
### Why include package-global loggers?
Since so many other logging packages include a global logger, many
applications aren't designed to accept loggers as explicit parameters.
Changing function signatures is often a breaking change, so zap includes
global loggers to simplify migration.
Avoid them where possible.
### Why include dedicated Panic and Fatal log levels?
In general, application code should handle errors gracefully instead of using
`panic` or `os.Exit`. However, every rule has exceptions, and it's common to
crash when an error is truly unrecoverable. To avoid losing any information
&mdash; especially the reason for the crash &mdash; the logger must flush any
buffered entries before the process exits.
Zap makes this easy by offering `Panic` and `Fatal` logging methods that
automatically flush before exiting. Of course, this doesn't guarantee that
logs will never be lost, but it eliminates a common error.
See the discussion in uber-go/zap#207 for more details.
### What's `DPanic`?
`DPanic` stands for "panic in development." In development, it logs at
`PanicLevel`; otherwise, it logs at `ErrorLevel`. `DPanic` makes it easier to
catch errors that are theoretically possible, but shouldn't actually happen,
*without* crashing in production.
If you've ever written code like this, you need `DPanic`:
```go
if err != nil {
panic(fmt.Sprintf("shouldn't ever get here: %v", err))
}
```
## Installation
### What does the error `expects import "go.uber.org/zap"` mean?
Either zap was installed incorrectly or you're referencing the wrong package
name in your code.
Zap's source code happens to be hosted on GitHub, but the [import
path][import-path] is `go.uber.org/zap`. This gives us, the project
maintainers, the freedom to move the source code if necessary. However, it
means that you need to take a little care when installing and using the
package.
If you follow two simple rules, everything should work: install zap with `go
get -u go.uber.org/zap`, and always import it in your code with `import
"go.uber.org/zap"`. Your code shouldn't contain *any* references to
`github.com/uber-go/zap`.
## Usage
### Does zap support log rotation?
Zap doesn't natively support rotating log files, since we prefer to leave this
to an external program like `logrotate`.
However, it's easy to integrate a log rotation package like
[`gopkg.in/natefinch/lumberjack.v2`][lumberjack] as a `zapcore.WriteSyncer`.
```go
// lumberjack.Logger is already safe for concurrent use, so we don't need to
// lock it.
w := zapcore.AddSync(&lumberjack.Logger{
Filename: "/var/log/myapp/foo.log",
MaxSize: 500, // megabytes
MaxBackups: 3,
MaxAge: 28, // days
})
core := zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
w,
zap.InfoLevel,
)
logger := zap.New(core)
```
[go-proverbs]: https://go-proverbs.github.io/
[import-path]: https://golang.org/cmd/go/#hdr-Remote_import_paths
[lumberjack]: https://godoc.org/gopkg.in/natefinch/lumberjack.v2

19
vendor/go.uber.org/zap/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2016-2017 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.

76
vendor/go.uber.org/zap/Makefile generated vendored Normal file
View File

@ -0,0 +1,76 @@
export GO15VENDOREXPERIMENT=1
BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem
PKGS ?= $(shell glide novendor)
# Many Go tools take file globs or directories as arguments instead of packages.
PKG_FILES ?= *.go zapcore benchmarks buffer zapgrpc zaptest zaptest/observer internal/bufferpool internal/exit internal/color
# The linting tools evolve with each Go version, so run them only on the latest
# stable release.
GO_VERSION := $(shell go version | cut -d " " -f 3)
GO_MINOR_VERSION := $(word 2,$(subst ., ,$(GO_VERSION)))
LINTABLE_MINOR_VERSIONS := 8
ifneq ($(filter $(LINTABLE_MINOR_VERSIONS),$(GO_MINOR_VERSION)),)
SHOULD_LINT := true
endif
.PHONY: all
all: lint test
.PHONY: dependencies
dependencies:
@echo "Installing Glide and locked dependencies..."
glide --version || go get -u -f github.com/Masterminds/glide
glide install
@echo "Installing test dependencies..."
go install ./vendor/github.com/axw/gocov/gocov
go install ./vendor/github.com/mattn/goveralls
ifdef SHOULD_LINT
@echo "Installing golint..."
go install ./vendor/github.com/golang/lint/golint
else
@echo "Not installing golint, since we don't expect to lint on" $(GO_VERSION)
endif
# Disable printf-like invocation checking due to testify.assert.Error()
VET_RULES := -printf=false
.PHONY: lint
lint:
ifdef SHOULD_LINT
@rm -rf lint.log
@echo "Checking formatting..."
@gofmt -d -s $(PKG_FILES) 2>&1 | tee lint.log
@echo "Installing test dependencies for vet..."
@go test -i $(PKGS)
@echo "Checking vet..."
@$(foreach dir,$(PKG_FILES),go tool vet $(VET_RULES) $(dir) 2>&1 | tee -a lint.log;)
@echo "Checking lint..."
@$(foreach dir,$(PKGS),golint $(dir) 2>&1 | tee -a lint.log;)
@echo "Checking for unresolved FIXMEs..."
@git grep -i fixme | grep -v -e vendor -e Makefile | tee -a lint.log
@echo "Checking for license headers..."
@./check_license.sh | tee -a lint.log
@[ ! -s lint.log ]
else
@echo "Skipping linters on" $(GO_VERSION)
endif
.PHONY: test
test:
go test -race $(PKGS)
.PHONY: cover
cover:
./scripts/cover.sh $(PKGS)
.PHONY: bench
BENCH ?= .
bench:
@$(foreach pkg,$(PKGS),go test -bench=$(BENCH) -run="^$$" $(BENCH_FLAGS) $(pkg);)
.PHONY: updatereadme
updatereadme:
rm -f README.md
cat .readme.tmpl | go run internal/readme/readme.go > README.md

136
vendor/go.uber.org/zap/README.md generated vendored Normal file
View File

@ -0,0 +1,136 @@
# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Blazing fast, structured, leveled logging in Go.
## Installation
`go get -u go.uber.org/zap`
Note that zap only supports the two most recent minor versions of Go.
## Quick Start
In contexts where performance is nice, but not critical, use the
`SugaredLogger`. It's 4-10x faster than than other structured logging
packages and includes both structured and `printf`-style APIs.
```go
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
```
When performance and type safety are critical, use the `Logger`. It's even
faster than the `SugaredLogger` and allocates far less, but it only supports
structured logging.
```go
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
```
See the [documentation][doc] and [FAQ](FAQ.md) for more details.
## Performance
For applications that log in the hot path, reflection-based serialization and
string formatting are prohibitively expensive &mdash; they're CPU-intensive
and make many small allocations. Put differently, using `encoding/json` and
`fmt.Fprintf` to log tons of `interface{}`s makes your application slow.
Zap takes a different approach. It includes a reflection-free, zero-allocation
JSON encoder, and the base `Logger` strives to avoid serialization overhead
and allocations wherever possible. By building the high-level `SugaredLogger`
on that foundation, zap lets users *choose* when they need to count every
allocation and when they'd prefer a more familiar, loosely typed API.
As measured by its own [benchmarking suite][], not only is zap more performant
than comparable structured logging packages &mdash; it's also faster than the
standard library. Like all benchmarks, take these with a grain of salt.<sup
id="anchor-versions">[1](#footnote-versions)</sup>
Log a message and 10 fields:
| Package | Time | Objects Allocated |
| :--- | :---: | :---: |
| :zap: zap | 3131 ns/op | 5 allocs/op |
| :zap: zap (sugared) | 4173 ns/op | 21 allocs/op |
| zerolog | 16154 ns/op | 90 allocs/op |
| lion | 16341 ns/op | 111 allocs/op |
| go-kit | 17049 ns/op | 126 allocs/op |
| logrus | 23662 ns/op | 142 allocs/op |
| log15 | 36351 ns/op | 149 allocs/op |
| apex/log | 42530 ns/op | 126 allocs/op |
Log a message with a logger that already has 10 fields of context:
| Package | Time | Objects Allocated |
| :--- | :---: | :---: |
| :zap: zap | 380 ns/op | 0 allocs/op |
| :zap: zap (sugared) | 564 ns/op | 2 allocs/op |
| zerolog | 321 ns/op | 0 allocs/op |
| lion | 7092 ns/op | 39 allocs/op |
| go-kit | 20226 ns/op | 115 allocs/op |
| logrus | 22312 ns/op | 130 allocs/op |
| log15 | 28788 ns/op | 79 allocs/op |
| apex/log | 42063 ns/op | 115 allocs/op |
Log a static string, without any context or `printf`-style templating:
| Package | Time | Objects Allocated |
| :--- | :---: | :---: |
| :zap: zap | 361 ns/op | 0 allocs/op |
| :zap: zap (sugared) | 534 ns/op | 2 allocs/op |
| zerolog | 323 ns/op | 0 allocs/op |
| standard library | 575 ns/op | 2 allocs/op |
| go-kit | 922 ns/op | 13 allocs/op |
| lion | 1413 ns/op | 10 allocs/op |
| logrus | 2291 ns/op | 27 allocs/op |
| apex/log | 3690 ns/op | 11 allocs/op |
| log15 | 5954 ns/op | 26 allocs/op |
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
zap to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors &mdash;
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on
issues and pull requests, but you can also report any negative conduct to
oss-conduct@uber.com. That email list is a private, safe space; even the zap
maintainers don't have access, so don't hesitate to hold us to a high
standard.
<hr>
Released under the [MIT License](LICENSE.txt).
<sup id="footnote-versions">1</sup> In particular, keep in mind that we may be
benchmarking against slightly older versions of other packages. Versions are
pinned in zap's [glide.lock][] file. [](#anchor-versions)
[doc-img]: https://godoc.org/go.uber.org/zap?status.svg
[doc]: https://godoc.org/go.uber.org/zap
[ci-img]: https://travis-ci.org/uber-go/zap.svg?branch=master
[ci]: https://travis-ci.org/uber-go/zap
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/zap
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
[glide.lock]: https://github.com/uber-go/zap/blob/master/glide.lock

320
vendor/go.uber.org/zap/array.go generated vendored Normal file
View File

@ -0,0 +1,320 @@
// 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 (
"time"
"go.uber.org/zap/zapcore"
)
// Array constructs a field with the given key and ArrayMarshaler. It provides
// a flexible, but still type-safe and efficient, way to add array-like types
// to the logging context. The struct's MarshalLogArray method is called lazily.
func Array(key string, val zapcore.ArrayMarshaler) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.ArrayMarshalerType, Interface: val}
}
// Bools constructs a field that carries a slice of bools.
func Bools(key string, bs []bool) zapcore.Field {
return Array(key, bools(bs))
}
// ByteStrings constructs a field that carries a slice of []byte, each of which
// must be UTF-8 encoded text.
func ByteStrings(key string, bss [][]byte) zapcore.Field {
return Array(key, byteStringsArray(bss))
}
// Complex128s constructs a field that carries a slice of complex numbers.
func Complex128s(key string, nums []complex128) zapcore.Field {
return Array(key, complex128s(nums))
}
// Complex64s constructs a field that carries a slice of complex numbers.
func Complex64s(key string, nums []complex64) zapcore.Field {
return Array(key, complex64s(nums))
}
// Durations constructs a field that carries a slice of time.Durations.
func Durations(key string, ds []time.Duration) zapcore.Field {
return Array(key, durations(ds))
}
// Float64s constructs a field that carries a slice of floats.
func Float64s(key string, nums []float64) zapcore.Field {
return Array(key, float64s(nums))
}
// Float32s constructs a field that carries a slice of floats.
func Float32s(key string, nums []float32) zapcore.Field {
return Array(key, float32s(nums))
}
// Ints constructs a field that carries a slice of integers.
func Ints(key string, nums []int) zapcore.Field {
return Array(key, ints(nums))
}
// Int64s constructs a field that carries a slice of integers.
func Int64s(key string, nums []int64) zapcore.Field {
return Array(key, int64s(nums))
}
// Int32s constructs a field that carries a slice of integers.
func Int32s(key string, nums []int32) zapcore.Field {
return Array(key, int32s(nums))
}
// Int16s constructs a field that carries a slice of integers.
func Int16s(key string, nums []int16) zapcore.Field {
return Array(key, int16s(nums))
}
// Int8s constructs a field that carries a slice of integers.
func Int8s(key string, nums []int8) zapcore.Field {
return Array(key, int8s(nums))
}
// Strings constructs a field that carries a slice of strings.
func Strings(key string, ss []string) zapcore.Field {
return Array(key, stringArray(ss))
}
// Times constructs a field that carries a slice of time.Times.
func Times(key string, ts []time.Time) zapcore.Field {
return Array(key, times(ts))
}
// Uints constructs a field that carries a slice of unsigned integers.
func Uints(key string, nums []uint) zapcore.Field {
return Array(key, uints(nums))
}
// Uint64s constructs a field that carries a slice of unsigned integers.
func Uint64s(key string, nums []uint64) zapcore.Field {
return Array(key, uint64s(nums))
}
// Uint32s constructs a field that carries a slice of unsigned integers.
func Uint32s(key string, nums []uint32) zapcore.Field {
return Array(key, uint32s(nums))
}
// Uint16s constructs a field that carries a slice of unsigned integers.
func Uint16s(key string, nums []uint16) zapcore.Field {
return Array(key, uint16s(nums))
}
// Uint8s constructs a field that carries a slice of unsigned integers.
func Uint8s(key string, nums []uint8) zapcore.Field {
return Array(key, uint8s(nums))
}
// Uintptrs constructs a field that carries a slice of pointer addresses.
func Uintptrs(key string, us []uintptr) zapcore.Field {
return Array(key, uintptrs(us))
}
// Errors constructs a field that carries a slice of errors.
func Errors(key string, errs []error) zapcore.Field {
return Array(key, errArray(errs))
}
type bools []bool
func (bs bools) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range bs {
arr.AppendBool(bs[i])
}
return nil
}
type byteStringsArray [][]byte
func (bss byteStringsArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range bss {
arr.AppendByteString(bss[i])
}
return nil
}
type complex128s []complex128
func (nums complex128s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendComplex128(nums[i])
}
return nil
}
type complex64s []complex64
func (nums complex64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendComplex64(nums[i])
}
return nil
}
type durations []time.Duration
func (ds durations) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ds {
arr.AppendDuration(ds[i])
}
return nil
}
type float64s []float64
func (nums float64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendFloat64(nums[i])
}
return nil
}
type float32s []float32
func (nums float32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendFloat32(nums[i])
}
return nil
}
type ints []int
func (nums ints) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt(nums[i])
}
return nil
}
type int64s []int64
func (nums int64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt64(nums[i])
}
return nil
}
type int32s []int32
func (nums int32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt32(nums[i])
}
return nil
}
type int16s []int16
func (nums int16s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt16(nums[i])
}
return nil
}
type int8s []int8
func (nums int8s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt8(nums[i])
}
return nil
}
type stringArray []string
func (ss stringArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ss {
arr.AppendString(ss[i])
}
return nil
}
type times []time.Time
func (ts times) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ts {
arr.AppendTime(ts[i])
}
return nil
}
type uints []uint
func (nums uints) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint(nums[i])
}
return nil
}
type uint64s []uint64
func (nums uint64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint64(nums[i])
}
return nil
}
type uint32s []uint32
func (nums uint32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint32(nums[i])
}
return nil
}
type uint16s []uint16
func (nums uint16s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint16(nums[i])
}
return nil
}
type uint8s []uint8
func (nums uint8s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint8(nums[i])
}
return nil
}
type uintptrs []uintptr
func (nums uintptrs) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUintptr(nums[i])
}
return nil
}

107
vendor/go.uber.org/zap/array_test.go generated vendored Normal file
View File

@ -0,0 +1,107 @@
// 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"
"time"
"go.uber.org/zap/zapcore"
"github.com/stretchr/testify/assert"
)
func BenchmarkBoolsArrayMarshaler(b *testing.B) {
// Keep this benchmark here to capture the overhead of the ArrayMarshaler
// wrapper.
bs := make([]bool, 50)
enc := zapcore.NewJSONEncoder(zapcore.EncoderConfig{})
b.ResetTimer()
for i := 0; i < b.N; i++ {
Bools("array", bs).AddTo(enc.Clone())
}
}
func BenchmarkBoolsReflect(b *testing.B) {
bs := make([]bool, 50)
enc := zapcore.NewJSONEncoder(zapcore.EncoderConfig{})
b.ResetTimer()
for i := 0; i < b.N; i++ {
Reflect("array", bs).AddTo(enc.Clone())
}
}
func TestArrayWrappers(t *testing.T) {
tests := []struct {
desc string
field zapcore.Field
expected []interface{}
}{
{"empty bools", Bools("", []bool{}), []interface{}(nil)},
{"empty byte strings", ByteStrings("", [][]byte{}), []interface{}(nil)},
{"empty complex128s", Complex128s("", []complex128{}), []interface{}(nil)},
{"empty complex64s", Complex64s("", []complex64{}), []interface{}(nil)},
{"empty durations", Durations("", []time.Duration{}), []interface{}(nil)},
{"empty float64s", Float64s("", []float64{}), []interface{}(nil)},
{"empty float32s", Float32s("", []float32{}), []interface{}(nil)},
{"empty ints", Ints("", []int{}), []interface{}(nil)},
{"empty int64s", Int64s("", []int64{}), []interface{}(nil)},
{"empty int32s", Int32s("", []int32{}), []interface{}(nil)},
{"empty int16s", Int16s("", []int16{}), []interface{}(nil)},
{"empty int8s", Int8s("", []int8{}), []interface{}(nil)},
{"empty strings", Strings("", []string{}), []interface{}(nil)},
{"empty times", Times("", []time.Time{}), []interface{}(nil)},
{"empty uints", Uints("", []uint{}), []interface{}(nil)},
{"empty uint64s", Uint64s("", []uint64{}), []interface{}(nil)},
{"empty uint32s", Uint32s("", []uint32{}), []interface{}(nil)},
{"empty uint16s", Uint16s("", []uint16{}), []interface{}(nil)},
{"empty uint8s", Uint8s("", []uint8{}), []interface{}(nil)},
{"empty uintptrs", Uintptrs("", []uintptr{}), []interface{}(nil)},
{"bools", Bools("", []bool{true, false}), []interface{}{true, false}},
{"byte strings", ByteStrings("", [][]byte{{1, 2}, {3, 4}}), []interface{}{[]byte{1, 2}, []byte{3, 4}}},
{"complex128s", Complex128s("", []complex128{1 + 2i, 3 + 4i}), []interface{}{1 + 2i, 3 + 4i}},
{"complex64s", Complex64s("", []complex64{1 + 2i, 3 + 4i}), []interface{}{complex64(1 + 2i), complex64(3 + 4i)}},
{"durations", Durations("", []time.Duration{1, 2}), []interface{}{time.Nanosecond, 2 * time.Nanosecond}},
{"float64s", Float64s("", []float64{1.2, 3.4}), []interface{}{1.2, 3.4}},
{"float32s", Float32s("", []float32{1.2, 3.4}), []interface{}{float32(1.2), float32(3.4)}},
{"ints", Ints("", []int{1, 2}), []interface{}{1, 2}},
{"int64s", Int64s("", []int64{1, 2}), []interface{}{int64(1), int64(2)}},
{"int32s", Int32s("", []int32{1, 2}), []interface{}{int32(1), int32(2)}},
{"int16s", Int16s("", []int16{1, 2}), []interface{}{int16(1), int16(2)}},
{"int8s", Int8s("", []int8{1, 2}), []interface{}{int8(1), int8(2)}},
{"strings", Strings("", []string{"foo", "bar"}), []interface{}{"foo", "bar"}},
{"times", Times("", []time.Time{time.Unix(0, 0), time.Unix(0, 0)}), []interface{}{time.Unix(0, 0), time.Unix(0, 0)}},
{"uints", Uints("", []uint{1, 2}), []interface{}{uint(1), uint(2)}},
{"uint64s", Uint64s("", []uint64{1, 2}), []interface{}{uint64(1), uint64(2)}},
{"uint32s", Uint32s("", []uint32{1, 2}), []interface{}{uint32(1), uint32(2)}},
{"uint16s", Uint16s("", []uint16{1, 2}), []interface{}{uint16(1), uint16(2)}},
{"uint8s", Uint8s("", []uint8{1, 2}), []interface{}{uint8(1), uint8(2)}},
{"uintptrs", Uintptrs("", []uintptr{1, 2}), []interface{}{uintptr(1), uintptr(2)}},
}
for _, tt := range tests {
enc := zapcore.NewMapObjectEncoder()
tt.field.Key = "k"
tt.field.AddTo(enc)
assert.Equal(t, tt.expected, enc.Fields["k"], "%s: unexpected map contents.", tt.desc)
assert.Equal(t, 1, len(enc.Fields), "%s: found extra keys in map: %v", tt.desc, enc.Fields)
}
}

57
vendor/go.uber.org/zap/benchmarks/apex_test.go generated vendored Normal file
View File

@ -0,0 +1,57 @@
// 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 benchmarks
import (
"io/ioutil"
"github.com/apex/log"
"github.com/apex/log/handlers/json"
)
func newDisabledApexLog() *log.Logger {
return &log.Logger{
Handler: json.New(ioutil.Discard),
Level: log.ErrorLevel,
}
}
func newApexLog() *log.Logger {
return &log.Logger{
Handler: json.New(ioutil.Discard),
Level: log.DebugLevel,
}
}
func fakeApexFields() log.Fields {
return log.Fields{
"int": _tenInts[0],
"ints": _tenInts,
"string": _tenStrings[0],
"strings": _tenStrings,
"time": _tenTimes[0],
"times": _tenTimes,
"user1": _oneUser,
"user2": _oneUser,
"users": _tenUsers,
"error": errExample,
}
}

23
vendor/go.uber.org/zap/benchmarks/doc.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
// 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 benchmarks contains only benchmarks comparing zap to other
// structured logging libraries.
package benchmarks

31
vendor/go.uber.org/zap/benchmarks/kit_test.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
// 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 benchmarks
import (
"io/ioutil"
"github.com/go-kit/kit/log"
)
func newKitLog(fields ...interface{}) log.Logger {
return log.With(log.NewJSONLogger(ioutil.Discard), fields...)
}

31
vendor/go.uber.org/zap/benchmarks/lion_test.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
// 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 benchmarks
import (
"io/ioutil"
"go.pedge.io/lion"
)
func newLion() lion.Logger {
return lion.NewLogger(lion.NewJSONWritePusher(ioutil.Discard))
}

33
vendor/go.uber.org/zap/benchmarks/log15_test.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
// 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 benchmarks
import (
"io/ioutil"
"gopkg.in/inconshreveable/log15.v2"
)
func newLog15() log15.Logger {
logger := log15.New()
logger.SetHandler(log15.StreamHandler(ioutil.Discard, log15.JsonFormat()))
return logger
}

57
vendor/go.uber.org/zap/benchmarks/logrus_test.go generated vendored Normal file
View File

@ -0,0 +1,57 @@
// 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 benchmarks
import (
"io/ioutil"
"github.com/sirupsen/logrus"
)
func newDisabledLogrus() *logrus.Logger {
logger := newLogrus()
logger.Level = logrus.ErrorLevel
return logger
}
func newLogrus() *logrus.Logger {
return &logrus.Logger{
Out: ioutil.Discard,
Formatter: new(logrus.JSONFormatter),
Hooks: make(logrus.LevelHooks),
Level: logrus.DebugLevel,
}
}
func fakeLogrusFields() logrus.Fields {
return logrus.Fields{
"int": _tenInts[0],
"ints": _tenInts,
"string": _tenStrings[0],
"strings": _tenStrings,
"time": _tenTimes[0],
"times": _tenTimes,
"user1": _oneUser,
"user2": _oneUser,
"users": _tenUsers,
"error": errExample,
}
}

View File

@ -0,0 +1,614 @@
// 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 benchmarks
import (
"io/ioutil"
"log"
"testing"
"go.uber.org/zap"
)
func BenchmarkDisabledWithoutFields(b *testing.B) {
b.Logf("Logging at a disabled level without any structured context.")
b.Run("Zap", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("Zap.Check", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if m := logger.Check(zap.InfoLevel, getMessage(0)); m != nil {
m.Write()
}
}
})
})
b.Run("Zap.Sugar", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("Zap.SugarFormatting", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Infof("%v %v %v %s %v %v %v %v %v %s\n", fakeFmtArgs()...)
}
})
})
b.Run("apex/log", func(b *testing.B) {
logger := newDisabledApexLog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("sirupsen/logrus", func(b *testing.B) {
logger := newDisabledLogrus()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("rs/zerolog", func(b *testing.B) {
logger := newDisabledZerolog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msg(getMessage(0))
}
})
})
}
func BenchmarkDisabledAccumulatedContext(b *testing.B) {
b.Logf("Logging at a disabled level with some accumulated context.")
b.Run("Zap", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel).With(fakeFields()...)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("Zap.Check", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel).With(fakeFields()...)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if m := logger.Check(zap.InfoLevel, getMessage(0)); m != nil {
m.Write()
}
}
})
})
b.Run("Zap.Sugar", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel).With(fakeFields()...).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("Zap.SugarFormatting", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel).With(fakeFields()...).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Infof("%v %v %v %s %v %v %v %v %v %s\n", fakeFmtArgs()...)
}
})
})
b.Run("apex/log", func(b *testing.B) {
logger := newDisabledApexLog().WithFields(fakeApexFields())
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("sirupsen/logrus", func(b *testing.B) {
logger := newDisabledLogrus().WithFields(fakeLogrusFields())
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("rs/zerolog", func(b *testing.B) {
logger := fakeZerologContext(newDisabledZerolog().With()).Logger()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msg(getMessage(0))
}
})
})
}
func BenchmarkDisabledAddingFields(b *testing.B) {
b.Logf("Logging at a disabled level, adding context at each log site.")
b.Run("Zap", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0), fakeFields()...)
}
})
})
b.Run("Zap.Check", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if m := logger.Check(zap.InfoLevel, getMessage(0)); m != nil {
m.Write(fakeFields()...)
}
}
})
})
b.Run("Zap.Sugar", func(b *testing.B) {
logger := newZapLogger(zap.ErrorLevel).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Infow(getMessage(0), fakeSugarFields()...)
}
})
})
b.Run("apex/log", func(b *testing.B) {
logger := newDisabledApexLog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.WithFields(fakeApexFields()).Info(getMessage(0))
}
})
})
b.Run("sirupsen/logrus", func(b *testing.B) {
logger := newDisabledLogrus()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.WithFields(fakeLogrusFields()).Info(getMessage(0))
}
})
})
b.Run("rs/zerolog", func(b *testing.B) {
logger := newDisabledZerolog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
fakeZerologFields(logger.Info()).Msg(getMessage(0))
}
})
})
}
func BenchmarkWithoutFields(b *testing.B) {
b.Logf("Logging without any structured context.")
b.Run("Zap", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("Zap.Check", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if ce := logger.Check(zap.InfoLevel, getMessage(0)); ce != nil {
ce.Write()
}
}
})
})
b.Run("Zap.CheckSampled", func(b *testing.B) {
logger := newSampledLogger(zap.DebugLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
i++
if ce := logger.Check(zap.InfoLevel, getMessage(i)); ce != nil {
ce.Write()
}
}
})
})
b.Run("Zap.Sugar", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("Zap.SugarFormatting", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Infof("%v %v %v %s %v %v %v %v %v %s\n", fakeFmtArgs()...)
}
})
})
b.Run("apex/log", func(b *testing.B) {
logger := newApexLog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("go-kit/kit/log", func(b *testing.B) {
logger := newKitLog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Log(getMessage(0), getMessage(1))
}
})
})
b.Run("inconshreveable/log15", func(b *testing.B) {
logger := newLog15()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("sirupsen/logrus", func(b *testing.B) {
logger := newLogrus()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("go.pedge.io/lion", func(b *testing.B) {
logger := newLion()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Printf(getMessage(0))
}
})
})
b.Run("stdlib.Println", func(b *testing.B) {
logger := log.New(ioutil.Discard, "", log.LstdFlags)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Println(getMessage(0))
}
})
})
b.Run("stdlib.Printf", func(b *testing.B) {
logger := log.New(ioutil.Discard, "", log.LstdFlags)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Printf("%v %v %v %s %v %v %v %v %v %s\n", fakeFmtArgs()...)
}
})
})
b.Run("rs/zerolog", func(b *testing.B) {
logger := newZerolog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msg(getMessage(0))
}
})
})
b.Run("rs/zerolog.Formatting", func(b *testing.B) {
logger := newZerolog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msgf("%v %v %v %s %v %v %v %v %v %s\n", fakeFmtArgs()...)
}
})
})
b.Run("rs/zerolog.Check", func(b *testing.B) {
logger := newZerolog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if e := logger.Info(); e.Enabled() {
e.Msg(getMessage(0))
}
}
})
})
}
func BenchmarkAccumulatedContext(b *testing.B) {
b.Logf("Logging with some accumulated context.")
b.Run("Zap", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel).With(fakeFields()...)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("Zap.Check", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel).With(fakeFields()...)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if ce := logger.Check(zap.InfoLevel, getMessage(0)); ce != nil {
ce.Write()
}
}
})
})
b.Run("Zap.CheckSampled", func(b *testing.B) {
logger := newSampledLogger(zap.DebugLevel).With(fakeFields()...)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
i++
if ce := logger.Check(zap.InfoLevel, getMessage(i)); ce != nil {
ce.Write()
}
}
})
})
b.Run("Zap.Sugar", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel).With(fakeFields()...).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("Zap.SugarFormatting", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel).With(fakeFields()...).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Infof("%v %v %v %s %v %v %v %v %v %s\n", fakeFmtArgs()...)
}
})
})
b.Run("apex/log", func(b *testing.B) {
logger := newApexLog().WithFields(fakeApexFields())
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("go-kit/kit/log", func(b *testing.B) {
logger := newKitLog(fakeSugarFields()...)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Log(getMessage(0), getMessage(1))
}
})
})
b.Run("inconshreveable/log15", func(b *testing.B) {
logger := newLog15().New(fakeSugarFields())
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("sirupsen/logrus", func(b *testing.B) {
logger := newLogrus().WithFields(fakeLogrusFields())
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0))
}
})
})
b.Run("go.pedge.io/lion", func(b *testing.B) {
logger := newLion().WithFields(fakeLogrusFields())
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Infof(getMessage(0))
}
})
})
b.Run("rs/zerolog", func(b *testing.B) {
logger := fakeZerologContext(newZerolog().With()).Logger()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msg(getMessage(0))
}
})
})
b.Run("rs/zerolog.Check", func(b *testing.B) {
logger := fakeZerologContext(newZerolog().With()).Logger()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if e := logger.Info(); e.Enabled() {
e.Msg(getMessage(0))
}
}
})
})
b.Run("rs/zerolog.Formatting", func(b *testing.B) {
logger := fakeZerologContext(newZerolog().With()).Logger()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msgf("%v %v %v %s %v %v %v %v %v %s\n", fakeFmtArgs()...)
}
})
})
}
func BenchmarkAddingFields(b *testing.B) {
b.Logf("Logging with additional context at each log site.")
b.Run("Zap", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0), fakeFields()...)
}
})
})
b.Run("Zap.Check", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if ce := logger.Check(zap.InfoLevel, getMessage(0)); ce != nil {
ce.Write(fakeFields()...)
}
}
})
})
b.Run("Zap.CheckSampled", func(b *testing.B) {
logger := newSampledLogger(zap.DebugLevel)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
i++
if ce := logger.Check(zap.InfoLevel, getMessage(i)); ce != nil {
ce.Write(fakeFields()...)
}
}
})
})
b.Run("Zap.Sugar", func(b *testing.B) {
logger := newZapLogger(zap.DebugLevel).Sugar()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Infow(getMessage(0), fakeSugarFields()...)
}
})
})
b.Run("apex/log", func(b *testing.B) {
logger := newApexLog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.WithFields(fakeApexFields()).Info(getMessage(0))
}
})
})
b.Run("go-kit/kit/log", func(b *testing.B) {
logger := newKitLog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Log(fakeSugarFields()...)
}
})
})
b.Run("inconshreveable/log15", func(b *testing.B) {
logger := newLog15()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info(getMessage(0), fakeSugarFields()...)
}
})
})
b.Run("sirupsen/logrus", func(b *testing.B) {
logger := newLogrus()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.WithFields(fakeLogrusFields()).Info(getMessage(0))
}
})
})
b.Run("go.pedge.io/lion", func(b *testing.B) {
logger := newLion()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.WithFields(fakeLogrusFields()).Infof(getMessage(0))
}
})
})
b.Run("rs/zerolog", func(b *testing.B) {
logger := newZerolog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
fakeZerologFields(logger.Info()).Msg(getMessage(0))
}
})
})
b.Run("rs/zerolog.Check", func(b *testing.B) {
logger := newZerolog()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if e := logger.Info(); e.Enabled() {
fakeZerologFields(e).Msg(getMessage(0))
}
}
})
})
}

172
vendor/go.uber.org/zap/benchmarks/zap_test.go generated vendored Normal file
View File

@ -0,0 +1,172 @@
// 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 benchmarks
import (
"errors"
"fmt"
"time"
"go.uber.org/multierr"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest"
)
var (
errExample = errors.New("fail")
_messages = fakeMessages(1000)
_tenInts = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
_tenStrings = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"}
_tenTimes = []time.Time{
time.Unix(0, 0),
time.Unix(1, 0),
time.Unix(2, 0),
time.Unix(3, 0),
time.Unix(4, 0),
time.Unix(5, 0),
time.Unix(6, 0),
time.Unix(7, 0),
time.Unix(8, 0),
time.Unix(9, 0),
}
_oneUser = &user{
Name: "Jane Doe",
Email: "jane@test.com",
CreatedAt: time.Date(1980, 1, 1, 12, 0, 0, 0, time.UTC),
}
_tenUsers = users{
_oneUser,
_oneUser,
_oneUser,
_oneUser,
_oneUser,
_oneUser,
_oneUser,
_oneUser,
_oneUser,
_oneUser,
}
)
func fakeMessages(n int) []string {
messages := make([]string, n)
for i := range messages {
messages[i] = fmt.Sprintf("Test logging, but use a somewhat realistic message length. (#%v)", i)
}
return messages
}
func getMessage(iter int) string {
return _messages[iter%1000]
}
type users []*user
func (uu users) MarshalLogArray(arr zapcore.ArrayEncoder) error {
var err error
for i := range uu {
err = multierr.Append(err, arr.AppendObject(uu[i]))
}
return err
}
type user struct {
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func (u *user) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("name", u.Name)
enc.AddString("email", u.Email)
enc.AddInt64("createdAt", u.CreatedAt.UnixNano())
return nil
}
func newZapLogger(lvl zapcore.Level) *zap.Logger {
ec := zap.NewProductionEncoderConfig()
ec.EncodeDuration = zapcore.NanosDurationEncoder
ec.EncodeTime = zapcore.EpochNanosTimeEncoder
enc := zapcore.NewJSONEncoder(ec)
return zap.New(zapcore.NewCore(
enc,
&zaptest.Discarder{},
lvl,
))
}
func newSampledLogger(lvl zapcore.Level) *zap.Logger {
return zap.New(zapcore.NewSampler(
newZapLogger(zap.DebugLevel).Core(),
100*time.Millisecond,
10, // first
10, // thereafter
))
}
func fakeFields() []zapcore.Field {
return []zapcore.Field{
zap.Int("int", _tenInts[0]),
zap.Ints("ints", _tenInts),
zap.String("string", _tenStrings[0]),
zap.Strings("strings", _tenStrings),
zap.Time("time", _tenTimes[0]),
zap.Times("times", _tenTimes),
zap.Object("user1", _oneUser),
zap.Object("user2", _oneUser),
zap.Array("users", _tenUsers),
zap.Error(errExample),
}
}
func fakeSugarFields() []interface{} {
return []interface{}{
"int", _tenInts[0],
"ints", _tenInts,
"string", _tenStrings[0],
"strings", _tenStrings,
"time", _tenTimes[0],
"times", _tenTimes,
"user1", _oneUser,
"user2", _oneUser,
"users", _tenUsers,
"error", errExample,
}
}
func fakeFmtArgs() []interface{} {
// Need to keep this a function instead of a package-global var so that we
// pay the cast-to-interface{} penalty on each call.
return []interface{}{
_tenInts[0],
_tenInts,
_tenStrings[0],
_tenStrings,
_tenTimes[0],
_tenTimes,
_oneUser,
_oneUser,
_tenUsers,
errExample,
}
}

63
vendor/go.uber.org/zap/benchmarks/zerolog_test.go generated vendored Normal file
View File

@ -0,0 +1,63 @@
// 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 benchmarks
import (
"io/ioutil"
"github.com/rs/zerolog"
)
func newZerolog() zerolog.Logger {
return zerolog.New(ioutil.Discard).With().Timestamp().Logger()
}
func newDisabledZerolog() zerolog.Logger {
return newZerolog().Level(zerolog.Disabled)
}
func fakeZerologFields(e *zerolog.Event) *zerolog.Event {
return e.
Int("int", _tenInts[0]).
Interface("ints", _tenInts).
Str("string", _tenStrings[0]).
Interface("strings", _tenStrings).
Time("time", _tenTimes[0]).
Interface("times", _tenTimes).
Interface("user1", _oneUser).
Interface("user2", _oneUser).
Interface("users", _tenUsers).
Err(errExample)
}
func fakeZerologContext(c zerolog.Context) zerolog.Context {
return c.
Int("int", _tenInts[0]).
Interface("ints", _tenInts).
Str("string", _tenStrings[0]).
Interface("strings", _tenStrings).
Time("time", _tenTimes[0]).
Interface("times", _tenTimes).
Interface("user1", _oneUser).
Interface("user2", _oneUser).
Interface("users", _tenUsers).
Err(errExample)
}

106
vendor/go.uber.org/zap/buffer/buffer.go generated vendored Normal file
View File

@ -0,0 +1,106 @@
// 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 buffer provides a thin wrapper around a byte slice. Unlike the
// standard library's bytes.Buffer, it supports a portion of the strconv
// package's zero-allocation formatters.
package buffer
import "strconv"
const _size = 1024 // by default, create 1 KiB buffers
// Buffer is a thin wrapper around a byte slice. It's intended to be pooled, so
// the only way to construct one is via a Pool.
type Buffer struct {
bs []byte
pool Pool
}
// AppendByte writes a single byte to the Buffer.
func (b *Buffer) AppendByte(v byte) {
b.bs = append(b.bs, v)
}
// AppendString writes a string to the Buffer.
func (b *Buffer) AppendString(s string) {
b.bs = append(b.bs, s...)
}
// AppendInt appends an integer to the underlying buffer (assuming base 10).
func (b *Buffer) AppendInt(i int64) {
b.bs = strconv.AppendInt(b.bs, i, 10)
}
// AppendUint appends an unsigned integer to the underlying buffer (assuming
// base 10).
func (b *Buffer) AppendUint(i uint64) {
b.bs = strconv.AppendUint(b.bs, i, 10)
}
// AppendBool appends a bool to the underlying buffer.
func (b *Buffer) AppendBool(v bool) {
b.bs = strconv.AppendBool(b.bs, v)
}
// AppendFloat appends a float to the underlying buffer. It doesn't quote NaN
// or +/- Inf.
func (b *Buffer) AppendFloat(f float64, bitSize int) {
b.bs = strconv.AppendFloat(b.bs, f, 'f', -1, bitSize)
}
// Len returns the length of the underlying byte slice.
func (b *Buffer) Len() int {
return len(b.bs)
}
// Cap returns the capacity of the underlying byte slice.
func (b *Buffer) Cap() int {
return cap(b.bs)
}
// Bytes returns a mutable reference to the underlying byte slice.
func (b *Buffer) Bytes() []byte {
return b.bs
}
// String returns a string copy of the underlying byte slice.
func (b *Buffer) String() string {
return string(b.bs)
}
// Reset resets the underlying byte slice. Subsequent writes re-use the slice's
// backing array.
func (b *Buffer) Reset() {
b.bs = b.bs[:0]
}
// Write implements io.Writer.
func (b *Buffer) Write(bs []byte) (int, error) {
b.bs = append(b.bs, bs...)
return len(bs), nil
}
// Free returns the Buffer to its Pool.
//
// Callers must not retain references to the Buffer after calling Free.
func (b *Buffer) Free() {
b.pool.put(b)
}

91
vendor/go.uber.org/zap/buffer/buffer_test.go generated vendored Normal file
View File

@ -0,0 +1,91 @@
// 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 buffer
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestBufferWrites(t *testing.T) {
buf := NewPool().Get()
tests := []struct {
desc string
f func()
want string
}{
{"AppendByte", func() { buf.AppendByte('v') }, "v"},
{"AppendString", func() { buf.AppendString("foo") }, "foo"},
{"AppendIntPositive", func() { buf.AppendInt(42) }, "42"},
{"AppendIntNegative", func() { buf.AppendInt(-42) }, "-42"},
{"AppendUint", func() { buf.AppendUint(42) }, "42"},
{"AppendBool", func() { buf.AppendBool(true) }, "true"},
{"AppendFloat64", func() { buf.AppendFloat(3.14, 64) }, "3.14"},
// Intenationally introduce some floating-point error.
{"AppendFloat32", func() { buf.AppendFloat(float64(float32(3.14)), 32) }, "3.14"},
{"AppendWrite", func() { buf.Write([]byte("foo")) }, "foo"},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
buf.Reset()
tt.f()
assert.Equal(t, tt.want, buf.String(), "Unexpected buffer.String().")
assert.Equal(t, tt.want, string(buf.Bytes()), "Unexpected string(buffer.Bytes()).")
assert.Equal(t, len(tt.want), buf.Len(), "Unexpected buffer length.")
// We're not writing more than a kibibyte in tests.
assert.Equal(t, _size, buf.Cap(), "Expected buffer capacity to remain constant.")
})
}
}
func BenchmarkBuffers(b *testing.B) {
// Because we use the strconv.AppendFoo functions so liberally, we can't
// use the standard library's bytes.Buffer anyways (without incurring a
// bunch of extra allocations). Nevertheless, let's make sure that we're
// not losing any precious nanoseconds.
str := strings.Repeat("a", 1024)
slice := make([]byte, 1024)
buf := bytes.NewBuffer(slice)
custom := NewPool().Get()
b.Run("ByteSlice", func(b *testing.B) {
for i := 0; i < b.N; i++ {
slice = append(slice, str...)
slice = slice[:0]
}
})
b.Run("BytesBuffer", func(b *testing.B) {
for i := 0; i < b.N; i++ {
buf.WriteString(str)
buf.Reset()
}
})
b.Run("CustomBuffer", func(b *testing.B) {
for i := 0; i < b.N; i++ {
custom.AppendString(str)
custom.Reset()
}
})
}

49
vendor/go.uber.org/zap/buffer/pool.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
// 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 buffer
import "sync"
// A Pool is a type-safe wrapper around a sync.Pool.
type Pool struct {
p *sync.Pool
}
// NewPool constructs a new Pool.
func NewPool() Pool {
return Pool{p: &sync.Pool{
New: func() interface{} {
return &Buffer{bs: make([]byte, 0, _size)}
},
}}
}
// Get retrieves a Buffer from the pool, creating one if necessary.
func (p Pool) Get() *Buffer {
buf := p.p.Get().(*Buffer)
buf.Reset()
buf.pool = p
return buf
}
func (p Pool) put(buf *Buffer) {
p.p.Put(buf)
}

52
vendor/go.uber.org/zap/buffer/pool_test.go generated vendored Normal file
View File

@ -0,0 +1,52 @@
// 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 buffer
import (
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
func TestBuffers(t *testing.T) {
const dummyData = "dummy data"
p := NewPool()
var wg sync.WaitGroup
for g := 0; g < 10; g++ {
wg.Add(1)
go func() {
for i := 0; i < 100; i++ {
buf := p.Get()
assert.Zero(t, buf.Len(), "Expected truncated buffer")
assert.NotZero(t, buf.Cap(), "Expected non-zero capacity")
buf.AppendString(dummyData)
assert.Equal(t, buf.Len(), len(dummyData), "Expected buffer to contain dummy data")
buf.Free()
}
wg.Done()
}()
}
wg.Wait()
}

17
vendor/go.uber.org/zap/check_license.sh generated vendored Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash -e
ERROR_COUNT=0
while read -r file
do
case "$(head -1 "${file}")" in
*"Copyright (c) "*" Uber Technologies, Inc.")
# everything's cool
;;
*)
echo "$file is missing license header."
(( ERROR_COUNT++ ))
;;
esac
done < <(git ls-files "*\.go")
exit $ERROR_COUNT

57
vendor/go.uber.org/zap/common_test.go generated vendored Normal file
View File

@ -0,0 +1,57 @@
// 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 (
"sync"
"testing"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest/observer"
)
func opts(opts ...Option) []Option {
return opts
}
// Here specifically to introduce an easily-identifiable filename for testing
// stacktraces and caller skips.
func withLogger(t testing.TB, e zapcore.LevelEnabler, opts []Option, f func(*Logger, *observer.ObservedLogs)) {
fac, logs := observer.New(e)
log := New(fac, opts...)
f(log, logs)
}
func withSugar(t testing.TB, e zapcore.LevelEnabler, opts []Option, f func(*SugaredLogger, *observer.ObservedLogs)) {
withLogger(t, e, opts, func(logger *Logger, logs *observer.ObservedLogs) { f(logger.Sugar(), logs) })
}
func runConcurrently(goroutines, iterations int, wg *sync.WaitGroup, f func()) {
wg.Add(goroutines)
for g := 0; g < goroutines; g++ {
go func() {
defer wg.Done()
for i := 0; i < iterations; i++ {
f()
}
}()
}
}

243
vendor/go.uber.org/zap/config.go generated vendored Normal file
View File

@ -0,0 +1,243 @@
// 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 (
"sort"
"time"
"go.uber.org/zap/zapcore"
)
// SamplingConfig sets a sampling strategy for the logger. Sampling caps the
// global CPU and I/O load that logging puts on your process while attempting
// to preserve a representative subset of your logs.
//
// Values configured here are per-second. See zapcore.NewSampler for details.
type SamplingConfig struct {
Initial int `json:"initial" yaml:"initial"`
Thereafter int `json:"thereafter" yaml:"thereafter"`
}
// Config offers a declarative way to construct a logger. It doesn't do
// anything that can't be done with New, Options, and the various
// zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to
// toggle common options.
//
// Note that Config intentionally supports only the most common options. More
// unusual logging setups (logging to network connections or message queues,
// splitting output between multiple files, etc.) are possible, but require
// direct use of the zapcore package. For sample code, see the package-level
// BasicConfiguration and AdvancedConfiguration examples.
//
// For an example showing runtime log level changes, see the documentation for
// AtomicLevel.
type Config struct {
// Level is the minimum enabled logging level. Note that this is a dynamic
// level, so calling Config.Level.SetLevel will atomically change the log
// level of all loggers descended from this config.
Level AtomicLevel `json:"level" yaml:"level"`
// Development puts the logger in development mode, which changes the
// behavior of DPanicLevel and takes stacktraces more liberally.
Development bool `json:"development" yaml:"development"`
// DisableCaller stops annotating logs with the calling function's file
// name and line number. By default, all logs are annotated.
DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
// DisableStacktrace completely disables automatic stacktrace capturing. By
// default, stacktraces are captured for WarnLevel and above logs in
// development and ErrorLevel and above in production.
DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
// Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
// Encoding sets the logger's encoding. Valid values are "json" and
// "console", as well as any third-party encodings registered via
// RegisterEncoder.
Encoding string `json:"encoding" yaml:"encoding"`
// EncoderConfig sets options for the chosen encoder. See
// zapcore.EncoderConfig for details.
EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
// OutputPaths is a list of paths to write logging output to. See Open for
// details.
OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
// ErrorOutputPaths is a list of paths to write internal logger errors to.
// The default is standard error.
//
// Note that this setting only affects internal errors; for sample code that
// sends error-level logs to a different location from info- and debug-level
// logs, see the package-level AdvancedConfiguration example.
ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
// InitialFields is a collection of fields to add to the root logger.
InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
}
// NewProductionEncoderConfig returns an opinionated EncoderConfig for
// production environments.
func NewProductionEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
TimeKey: "ts",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.EpochTimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
}
// NewProductionConfig is a reasonable production logging configuration.
// Logging is enabled at InfoLevel and above.
//
// It uses a JSON encoder, writes to standard error, and enables sampling.
// Stacktraces are automatically included on logs of ErrorLevel and above.
func NewProductionConfig() Config {
return Config{
Level: NewAtomicLevelAt(InfoLevel),
Development: false,
Sampling: &SamplingConfig{
Initial: 100,
Thereafter: 100,
},
Encoding: "json",
EncoderConfig: NewProductionEncoderConfig(),
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
}
// NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for
// development environments.
func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
// Keys can be anything except the empty string.
TimeKey: "T",
LevelKey: "L",
NameKey: "N",
CallerKey: "C",
MessageKey: "M",
StacktraceKey: "S",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
}
// NewDevelopmentConfig is a reasonable development logging configuration.
// Logging is enabled at DebugLevel and above.
//
// It enables development mode (which makes DPanicLevel logs panic), uses a
// console encoder, writes to standard error, and disables sampling.
// Stacktraces are automatically included on logs of WarnLevel and above.
func NewDevelopmentConfig() Config {
return Config{
Level: NewAtomicLevelAt(DebugLevel),
Development: true,
Encoding: "console",
EncoderConfig: NewDevelopmentEncoderConfig(),
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
}
// Build constructs a logger from the Config and Options.
func (cfg Config) Build(opts ...Option) (*Logger, error) {
enc, err := cfg.buildEncoder()
if err != nil {
return nil, err
}
sink, errSink, err := cfg.openSinks()
if err != nil {
return nil, err
}
log := New(
zapcore.NewCore(enc, sink, cfg.Level),
cfg.buildOptions(errSink)...,
)
if len(opts) > 0 {
log = log.WithOptions(opts...)
}
return log, nil
}
func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
opts := []Option{ErrorOutput(errSink)}
if cfg.Development {
opts = append(opts, Development())
}
if !cfg.DisableCaller {
opts = append(opts, AddCaller())
}
stackLevel := ErrorLevel
if cfg.Development {
stackLevel = WarnLevel
}
if !cfg.DisableStacktrace {
opts = append(opts, AddStacktrace(stackLevel))
}
if cfg.Sampling != nil {
opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core {
return zapcore.NewSampler(core, time.Second, int(cfg.Sampling.Initial), int(cfg.Sampling.Thereafter))
}))
}
if len(cfg.InitialFields) > 0 {
fs := make([]zapcore.Field, 0, len(cfg.InitialFields))
keys := make([]string, 0, len(cfg.InitialFields))
for k := range cfg.InitialFields {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fs = append(fs, Any(k, cfg.InitialFields[k]))
}
opts = append(opts, Fields(fs...))
}
return opts
}
func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
sink, closeOut, err := Open(cfg.OutputPaths...)
if err != nil {
return nil, nil, err
}
errSink, _, err := Open(cfg.ErrorOutputPaths...)
if err != nil {
closeOut()
return nil, nil, err
}
return sink, errSink, nil
}
func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
return newEncoder(cfg.Encoding, cfg.EncoderConfig)
}

108
vendor/go.uber.org/zap/config_test.go generated vendored Normal file
View File

@ -0,0 +1,108 @@
// 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 (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestConfig(t *testing.T) {
tests := []struct {
desc string
cfg Config
expectN int64
expectRe string
}{
{
desc: "production",
cfg: NewProductionConfig(),
expectN: 2 + 100 + 1, // 2 from initial logs, 100 initial sampled logs, 1 from off-by-one in sampler
expectRe: `{"level":"info","caller":"zap/config_test.go:\d+","msg":"info","k":"v","z":"zz"}` + "\n" +
`{"level":"warn","caller":"zap/config_test.go:\d+","msg":"warn","k":"v","z":"zz"}` + "\n",
},
{
desc: "development",
cfg: NewDevelopmentConfig(),
expectN: 3 + 200, // 3 initial logs, all 200 subsequent logs
expectRe: "DEBUG\tzap/config_test.go:" + `\d+` + "\tdebug\t" + `{"k": "v", "z": "zz"}` + "\n" +
"INFO\tzap/config_test.go:" + `\d+` + "\tinfo\t" + `{"k": "v", "z": "zz"}` + "\n" +
"WARN\tzap/config_test.go:" + `\d+` + "\twarn\t" + `{"k": "v", "z": "zz"}` + "\n" +
`testing.\w+`,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
temp, err := ioutil.TempFile("", "zap-prod-config-test")
require.NoError(t, err, "Failed to create temp file.")
defer os.Remove(temp.Name())
tt.cfg.OutputPaths = []string{temp.Name()}
tt.cfg.EncoderConfig.TimeKey = "" // no timestamps in tests
tt.cfg.InitialFields = map[string]interface{}{"z": "zz", "k": "v"}
hook, count := makeCountingHook()
logger, err := tt.cfg.Build(Hooks(hook))
require.NoError(t, err, "Unexpected error constructing logger.")
logger.Debug("debug")
logger.Info("info")
logger.Warn("warn")
byteContents, err := ioutil.ReadAll(temp)
require.NoError(t, err, "Couldn't read log contents from temp file.")
logs := string(byteContents)
assert.Regexp(t, tt.expectRe, logs, "Unexpected log output.")
for i := 0; i < 200; i++ {
logger.Info("sampling")
}
assert.Equal(t, tt.expectN, count.Load(), "Hook called an unexpected number of times.")
})
}
}
func TestConfigWithInvalidPaths(t *testing.T) {
tests := []struct {
desc string
output string
errOutput string
}{
{"output directory doesn't exist", "/tmp/not-there/foo.log", "stderr"},
{"error output directory doesn't exist", "stdout", "/tmp/not-there/foo-errors.log"},
{"neither output directory exists", "/tmp/not-there/foo.log", "/tmp/not-there/foo-errors.log"},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
cfg := NewProductionConfig()
cfg.OutputPaths = []string{tt.output}
cfg.ErrorOutputPaths = []string{tt.errOutput}
_, err := cfg.Build()
assert.Error(t, err, "Expected an error opening a non-existent directory.")
})
}
}

113
vendor/go.uber.org/zap/doc.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
// 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 provides fast, structured, leveled logging.
//
// For applications that log in the hot path, reflection-based serialization
// and string formatting are prohibitively expensive - they're CPU-intensive
// and make many small allocations. Put differently, using json.Marshal and
// fmt.Fprintf to log tons of interface{} makes your application slow.
//
// Zap takes a different approach. It includes a reflection-free,
// zero-allocation JSON encoder, and the base Logger strives to avoid
// serialization overhead and allocations wherever possible. By building the
// high-level SugaredLogger on that foundation, zap lets users choose when
// they need to count every allocation and when they'd prefer a more familiar,
// loosely typed API.
//
// Choosing a Logger
//
// In contexts where performance is nice, but not critical, use the
// SugaredLogger. It's 4-10x faster than other structured logging packages and
// supports both structured and printf-style logging. Like log15 and go-kit,
// the SugaredLogger's structured logging APIs are loosely typed and accept a
// variadic number of key-value pairs. (For more advanced use cases, they also
// accept strongly typed fields - see the SugaredLogger.With documentation for
// details.)
// sugar := zap.NewExample().Sugar()
// defer sugar.Sync()
// sugar.Infow("failed to fetch URL",
// "url", "http://example.com",
// "attempt", 3,
// "backoff", time.Second,
// )
// sugar.Printf("failed to fetch URL: %s", "http://example.com")
//
// By default, loggers are unbuffered. However, since zap's low-level APIs
// allow buffering, calling Sync before letting your process exit is a good
// habit.
//
// In the rare contexts where every microsecond and every allocation matter,
// use the Logger. It's even faster than the SugaredLogger and allocates far
// less, but it only supports strongly-typed, structured logging.
// logger := zap.NewExample()
// defer logger.Sync()
// logger.Info("failed to fetch URL",
// zap.String("url", "http://example.com"),
// zap.Int("attempt", 3),
// zap.Duration("backoff", time.Second),
// )
//
// Choosing between the Logger and SugaredLogger doesn't need to be an
// application-wide decision: converting between the two is simple and
// inexpensive.
// logger := zap.NewExample()
// defer logger.Sync()
// sugar := logger.Sugar()
// plain := sugar.Desugar()
//
// Configuring Zap
//
// The simplest way to build a Logger is to use zap's opinionated presets:
// NewExample, NewProduction, and NewDevelopment. These presets build a logger
// with a single function call:
// logger, err := zap.NewProduction()
// if err != nil {
// log.Fatalf("can't initialize zap logger: %v", err)
// }
// defer logger.Sync()
//
// Presets are fine for small projects, but larger projects and organizations
// naturally require a bit more customization. For most users, zap's Config
// struct strikes the right balance between flexibility and convenience. See
// the package-level BasicConfiguration example for sample code.
//
// More unusual configurations (splitting output between files, sending logs
// to a message queue, etc.) are possible, but require direct use of
// go.uber.org/zap/zapcore. See the package-level AdvancedConfiguration
// example for sample code.
//
// Extending Zap
//
// The zap package itself is a relatively thin wrapper around the interfaces
// in go.uber.org/zap/zapcore. Extending zap to support a new encoding (e.g.,
// BSON), a new log sink (e.g., Kafka), or something more exotic (perhaps an
// exception aggregation service, like Sentry or Rollbar) typically requires
// implementing the zapcore.Encoder, zapcore.WriteSyncer, or zapcore.Core
// interfaces. See the zapcore documentation for details.
//
// Similarly, package authors can use the high-performance Encoder and Core
// implementations in the zapcore package to build their own loggers.
//
// Frequently Asked Questions
//
// An FAQ covering everything from installation errors to design decisions is
// available at https://github.com/uber-go/zap/blob/master/FAQ.md.
package zap // import "go.uber.org/zap"

75
vendor/go.uber.org/zap/encoder.go generated vendored Normal file
View File

@ -0,0 +1,75 @@
// 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 = map[string]func(zapcore.EncoderConfig) (zapcore.Encoder, error){
"console": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
return zapcore.NewConsoleEncoder(encoderConfig), nil
},
"json": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
return zapcore.NewJSONEncoder(encoderConfig), nil
},
}
_encoderMutex sync.RWMutex
)
// RegisterEncoder registers an encoder constructor, which the Config struct
// can then reference. By default, the "json" and "console" encoders are
// registered.
//
// Attempting to register an encoder whose name is already taken returns an
// error.
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 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)
}

88
vendor/go.uber.org/zap/encoder_test.go generated vendored Normal file
View File

@ -0,0 +1,88 @@
// 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), "expected to be able to register the encoder foo")
testEncodersRegistered(t, "foo")
})
}
func TestDuplicateRegisterEncoder(t *testing.T) {
testEncoders(func() {
RegisterEncoder("foo", newNilEncoder)
assert.Error(t, RegisterEncoder("foo", newNilEncoder), "expected an error when registering an encoder with the same name twice")
})
}
func TestRegisterEncoderNoName(t *testing.T) {
assert.Equal(t, errNoEncoderNameSpecified, RegisterEncoder("", newNilEncoder), "expected an error when registering an encoder with no name")
}
func TestNewEncoder(t *testing.T) {
testEncoders(func() {
RegisterEncoder("foo", newNilEncoder)
encoder, err := newEncoder("foo", zapcore.EncoderConfig{})
assert.NoError(t, err, "could not create an encoder for the registered name foo")
assert.Nil(t, encoder, "the encoder from newNilEncoder is not nil")
})
}
func TestNewEncoderNotRegistered(t *testing.T) {
_, err := newEncoder("foo", zapcore.EncoderConfig{})
assert.Error(t, err, "expected an error when trying to create an encoder of an unregistered name")
}
func TestNewEncoderNoName(t *testing.T) {
_, err := newEncoder("", zapcore.EncoderConfig{})
assert.Equal(t, errNoEncoderNameSpecified, err, "expected an error when creating an encoder with no name")
}
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), "the expected number of registered encoders does not match the actual number")
for _, name := range names {
assert.NotNil(t, _encoderNameToConstructor[name], "no encoder is registered for name %s", name)
}
}
func newNilEncoder(_ zapcore.EncoderConfig) (zapcore.Encoder, error) {
return nil, nil
}

80
vendor/go.uber.org/zap/error.go generated vendored Normal file
View File

@ -0,0 +1,80 @@
// Copyright (c) 2017 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 (
"sync"
"go.uber.org/zap/zapcore"
)
var _errArrayElemPool = sync.Pool{New: func() interface{} {
return &errArrayElem{}
}}
// Error is shorthand for the common idiom NamedError("error", err).
func Error(err error) zapcore.Field {
return NamedError("error", err)
}
// NamedError constructs a field that lazily stores err.Error() under the
// provided key. Errors which also implement fmt.Formatter (like those produced
// by github.com/pkg/errors) will also have their verbose representation stored
// under key+"Verbose". If passed a nil error, the field is a no-op.
//
// For the common case in which the key is simply "error", the Error function
// is shorter and less repetitive.
func NamedError(key string, err error) zapcore.Field {
if err == nil {
return Skip()
}
return zapcore.Field{Key: key, Type: zapcore.ErrorType, Interface: err}
}
type errArray []error
func (errs errArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range errs {
if errs[i] == nil {
continue
}
// To represent each error as an object with an "error" attribute and
// potentially an "errorVerbose" attribute, we need to wrap it in a
// type that implements LogObjectMarshaler. To prevent this from
// allocating, pool the wrapper type.
elem := _errArrayElemPool.Get().(*errArrayElem)
elem.error = errs[i]
arr.AppendObject(elem)
elem.error = nil
_errArrayElemPool.Put(elem)
}
return nil
}
type errArrayElem struct {
error
}
func (e *errArrayElem) MarshalLogObject(enc zapcore.ObjectEncoder) error {
// Re-use the error field's logic, which supports non-standard error types.
Error(e.error).AddTo(enc)
return nil
}

99
vendor/go.uber.org/zap/error_test.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
// Copyright (c) 2017 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"
"testing"
"go.uber.org/zap/zapcore"
richErrors "github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestErrorConstructors(t *testing.T) {
fail := errors.New("fail")
tests := []struct {
name string
field zapcore.Field
expect zapcore.Field
}{
{"Error", Skip(), Error(nil)},
{"Error", zapcore.Field{Key: "error", Type: zapcore.ErrorType, Interface: fail}, Error(fail)},
{"NamedError", Skip(), NamedError("foo", nil)},
{"NamedError", zapcore.Field{Key: "foo", Type: zapcore.ErrorType, Interface: fail}, NamedError("foo", fail)},
{"Any:Error", Any("k", errors.New("v")), NamedError("k", errors.New("v"))},
{"Any:Errors", Any("k", []error{errors.New("v")}), Errors("k", []error{errors.New("v")})},
}
for _, tt := range tests {
if !assert.Equal(t, tt.expect, tt.field, "Unexpected output from convenience field constructor %s.", tt.name) {
t.Logf("type expected: %T\nGot: %T", tt.expect.Interface, tt.field.Interface)
}
assertCanBeReused(t, tt.field)
}
}
func TestErrorArrayConstructor(t *testing.T) {
tests := []struct {
desc string
field zapcore.Field
expected []interface{}
}{
{"empty errors", Errors("", []error{}), []interface{}(nil)},
{
"errors",
Errors("", []error{nil, errors.New("foo"), nil, errors.New("bar")}),
[]interface{}{map[string]interface{}{"error": "foo"}, map[string]interface{}{"error": "bar"}},
},
}
for _, tt := range tests {
enc := zapcore.NewMapObjectEncoder()
tt.field.Key = "k"
tt.field.AddTo(enc)
assert.Equal(t, tt.expected, enc.Fields["k"], "%s: unexpected map contents.", tt.desc)
assert.Equal(t, 1, len(enc.Fields), "%s: found extra keys in map: %v", tt.desc, enc.Fields)
}
}
func TestErrorsArraysHandleRichErrors(t *testing.T) {
errs := []error{richErrors.New("egad")}
enc := zapcore.NewMapObjectEncoder()
Errors("k", errs).AddTo(enc)
assert.Equal(t, 1, len(enc.Fields), "Expected only top-level field.")
val := enc.Fields["k"]
arr, ok := val.([]interface{})
require.True(t, ok, "Expected top-level field to be an array.")
require.Equal(t, 1, len(arr), "Expected only one error object in array.")
serialized := arr[0]
errMap, ok := serialized.(map[string]interface{})
require.True(t, ok, "Expected serialized error to be a map, got %T.", serialized)
assert.Equal(t, "egad", errMap["error"], "Unexpected standard error string.")
assert.Contains(t, errMap["errorVerbose"], "egad", "Verbose error string should be a superset of standard error.")
assert.Contains(t, errMap["errorVerbose"], "TestErrorsArraysHandleRichErrors", "Verbose error string should contain a stacktrace.")
}

327
vendor/go.uber.org/zap/example_test.go generated vendored Normal file
View File

@ -0,0 +1,327 @@
// 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_test
import (
"encoding/json"
"io/ioutil"
"log"
"os"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func Example_presets() {
// Using zap's preset constructors is the simplest way to get a feel for the
// package, but they don't allow much customization.
logger := zap.NewExample() // or NewProduction, or NewDevelopment
defer logger.Sync()
const url = "http://example.com"
// In most circumstances, use the SugaredLogger. It's 4-10x faster than most
// other structured logging packages and has a familiar, loosely-typed API.
sugar := logger.Sugar()
sugar.Infow("Failed to fetch URL.",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
// In the unusual situations where every microsecond matters, use the
// Logger. It's even faster than the SugaredLogger, but only supports
// structured logging.
logger.Info("Failed to fetch URL.",
// Structured context as strongly typed fields.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
// Output:
// {"level":"info","msg":"Failed to fetch URL.","url":"http://example.com","attempt":3,"backoff":"1s"}
// {"level":"info","msg":"Failed to fetch URL: http://example.com"}
// {"level":"info","msg":"Failed to fetch URL.","url":"http://example.com","attempt":3,"backoff":"1s"}
}
func Example_basicConfiguration() {
// For some users, the presets offered by the NewProduction, NewDevelopment,
// and NewExample constructors won't be appropriate. For most of those
// users, the bundled Config struct offers the right balance of flexibility
// and convenience. (For more complex needs, see the AdvancedConfiguration
// example.)
//
// See the documentation for Config and zapcore.EncoderConfig for all the
// available options.
rawJSON := []byte(`{
"level": "debug",
"encoding": "json",
"outputPaths": ["stdout", "/tmp/logs"],
"errorOutputPaths": ["stderr"],
"initialFields": {"foo": "bar"},
"encoderConfig": {
"messageKey": "message",
"levelKey": "level",
"levelEncoder": "lowercase"
}
}`)
var cfg zap.Config
if err := json.Unmarshal(rawJSON, &cfg); err != nil {
panic(err)
}
logger, err := cfg.Build()
if err != nil {
panic(err)
}
defer logger.Sync()
logger.Info("logger construction succeeded")
// Output:
// {"level":"info","message":"logger construction succeeded","foo":"bar"}
}
func Example_advancedConfiguration() {
// The bundled Config struct only supports the most common configuration
// options. More complex needs, like splitting logs between multiple files
// or writing to non-file outputs, require use of the zapcore package.
//
// In this example, imagine we're both sending our logs to Kafka and writing
// them to the console. We'd like to encode the console output and the Kafka
// topics differently, and we'd also like special treatment for
// high-priority logs.
// First, define our level-handling logic.
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl >= zapcore.ErrorLevel
})
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl < zapcore.ErrorLevel
})
// Assume that we have clients for two Kafka topics. The clients implement
// zapcore.WriteSyncer and are safe for concurrent use. (If they only
// implement io.Writer, we can use zapcore.AddSync to add a no-op Sync
// method. If they're not safe for concurrent use, we can add a protecting
// mutex with zapcore.Lock.)
topicDebugging := zapcore.AddSync(ioutil.Discard)
topicErrors := zapcore.AddSync(ioutil.Discard)
// High-priority output should also go to standard error, and low-priority
// output should also go to standard out.
consoleDebugging := zapcore.Lock(os.Stdout)
consoleErrors := zapcore.Lock(os.Stderr)
// Optimize the Kafka output for machine consumption and the console output
// for human operators.
kafkaEncoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
// Join the outputs, encoders, and level-handling functions into
// zapcore.Cores, then tee the four cores together.
core := zapcore.NewTee(
zapcore.NewCore(kafkaEncoder, topicErrors, highPriority),
zapcore.NewCore(consoleEncoder, consoleErrors, highPriority),
zapcore.NewCore(kafkaEncoder, topicDebugging, lowPriority),
zapcore.NewCore(consoleEncoder, consoleDebugging, lowPriority),
)
// From a zapcore.Core, it's easy to construct a Logger.
logger := zap.New(core)
defer logger.Sync()
logger.Info("constructed a logger")
}
func ExampleNamespace() {
logger := zap.NewExample()
defer logger.Sync()
logger.With(
zap.Namespace("metrics"),
zap.Int("counter", 1),
).Info("tracked some metrics")
// Output:
// {"level":"info","msg":"tracked some metrics","metrics":{"counter":1}}
}
func ExampleNewStdLog() {
logger := zap.NewExample()
defer logger.Sync()
std := zap.NewStdLog(logger)
std.Print("standard logger wrapper")
// Output:
// {"level":"info","msg":"standard logger wrapper"}
}
func ExampleRedirectStdLog() {
logger := zap.NewExample()
defer logger.Sync()
undo := zap.RedirectStdLog(logger)
defer undo()
log.Print("redirected standard library")
// Output:
// {"level":"info","msg":"redirected standard library"}
}
func ExampleReplaceGlobals() {
logger := zap.NewExample()
defer logger.Sync()
undo := zap.ReplaceGlobals(logger)
defer undo()
zap.L().Info("replaced zap's global loggers")
// Output:
// {"level":"info","msg":"replaced zap's global loggers"}
}
func ExampleAtomicLevel() {
atom := zap.NewAtomicLevel()
// To keep the example deterministic, disable timestamps in the output.
encoderCfg := zap.NewProductionEncoderConfig()
encoderCfg.TimeKey = ""
logger := zap.New(zapcore.NewCore(
zapcore.NewJSONEncoder(encoderCfg),
zapcore.Lock(os.Stdout),
atom,
))
defer logger.Sync()
logger.Info("info logging enabled")
atom.SetLevel(zap.ErrorLevel)
logger.Info("info logging disabled")
// Output:
// {"level":"info","msg":"info logging enabled"}
}
func ExampleAtomicLevel_config() {
// The zap.Config struct includes an AtomicLevel. To use it, keep a
// reference to the Config.
rawJSON := []byte(`{
"level": "info",
"outputPaths": ["stdout"],
"errorOutputPaths": ["stderr"],
"encoding": "json",
"encoderConfig": {
"messageKey": "message",
"levelKey": "level",
"levelEncoder": "lowercase"
}
}`)
var cfg zap.Config
if err := json.Unmarshal(rawJSON, &cfg); err != nil {
panic(err)
}
logger, err := cfg.Build()
if err != nil {
panic(err)
}
defer logger.Sync()
logger.Info("info logging enabled")
cfg.Level.SetLevel(zap.ErrorLevel)
logger.Info("info logging disabled")
// Output:
// {"level":"info","message":"info logging enabled"}
}
func ExampleLogger_Check() {
logger := zap.NewExample()
defer logger.Sync()
if ce := logger.Check(zap.DebugLevel, "debugging"); ce != nil {
// If debug-level log output isn't enabled or if zap's sampling would have
// dropped this log entry, we don't allocate the slice that holds these
// fields.
ce.Write(
zap.String("foo", "bar"),
zap.String("baz", "quux"),
)
}
// Output:
// {"level":"debug","msg":"debugging","foo":"bar","baz":"quux"}
}
func ExampleLogger_Named() {
logger := zap.NewExample()
defer logger.Sync()
// By default, Loggers are unnamed.
logger.Info("no name")
// The first call to Named sets the Logger name.
main := logger.Named("main")
main.Info("main logger")
// Additional calls to Named create a period-separated path.
main.Named("subpackage").Info("sub-logger")
// Output:
// {"level":"info","msg":"no name"}
// {"level":"info","logger":"main","msg":"main logger"}
// {"level":"info","logger":"main.subpackage","msg":"sub-logger"}
}
func ExampleWrapCore_replace() {
// Replacing a Logger's core can alter fundamental behaviors. For example,
// example, it can convert a Logger to a no-op.
nop := zap.WrapCore(func(zapcore.Core) zapcore.Core {
return zapcore.NewNopCore()
})
logger := zap.NewExample()
defer logger.Sync()
logger.Info("working")
logger.WithOptions(nop).Info("no-op")
logger.Info("original logger still works")
// Output:
// {"level":"info","msg":"working"}
// {"level":"info","msg":"original logger still works"}
}
func ExampleWrapCore_wrap() {
// Wrapping a Logger's core can extend its functionality. As a trivial
// example, it can double-write all logs.
doubled := zap.WrapCore(func(c zapcore.Core) zapcore.Core {
return zapcore.NewTee(c, c)
})
logger := zap.NewExample()
defer logger.Sync()
logger.Info("single")
logger.WithOptions(doubled).Info("doubled")
// Output:
// {"level":"info","msg":"single"}
// {"level":"info","msg":"doubled"}
// {"level":"info","msg":"doubled"}
}

306
vendor/go.uber.org/zap/field.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
// 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 (
"fmt"
"math"
"time"
"go.uber.org/zap/zapcore"
)
// Skip constructs a no-op field, which is often useful when handling invalid
// inputs in other Field constructors.
func Skip() zapcore.Field {
return zapcore.Field{Type: zapcore.SkipType}
}
// Binary constructs a field that carries an opaque binary blob.
//
// Binary data is serialized in an encoding-appropriate format. For example,
// zap's JSON encoder base64-encodes binary blobs. To log UTF-8 encoded text,
// use ByteString.
func Binary(key string, val []byte) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.BinaryType, Interface: val}
}
// Bool constructs a field that carries a bool.
func Bool(key string, val bool) zapcore.Field {
var ival int64
if val {
ival = 1
}
return zapcore.Field{Key: key, Type: zapcore.BoolType, Integer: ival}
}
// ByteString constructs a field that carries UTF-8 encoded text as a []byte.
// To log opaque binary blobs (which aren't necessarily valid UTF-8), use
// Binary.
func ByteString(key string, val []byte) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.ByteStringType, Interface: val}
}
// Complex128 constructs a field that carries a complex number. Unlike most
// numeric fields, this costs an allocation (to convert the complex128 to
// interface{}).
func Complex128(key string, val complex128) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Complex128Type, Interface: val}
}
// Complex64 constructs a field that carries a complex number. Unlike most
// numeric fields, this costs an allocation (to convert the complex64 to
// interface{}).
func Complex64(key string, val complex64) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Complex64Type, Interface: val}
}
// Float64 constructs a field that carries a float64. The way the
// floating-point value is represented is encoder-dependent, so marshaling is
// necessarily lazy.
func Float64(key string, val float64) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Float64Type, Integer: int64(math.Float64bits(val))}
}
// Float32 constructs a field that carries a float32. The way the
// floating-point value is represented is encoder-dependent, so marshaling is
// necessarily lazy.
func Float32(key string, val float32) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Float32Type, Integer: int64(math.Float32bits(val))}
}
// Int constructs a field with the given key and value.
func Int(key string, val int) zapcore.Field {
return Int64(key, int64(val))
}
// Int64 constructs a field with the given key and value.
func Int64(key string, val int64) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Int64Type, Integer: val}
}
// Int32 constructs a field with the given key and value.
func Int32(key string, val int32) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Int32Type, Integer: int64(val)}
}
// Int16 constructs a field with the given key and value.
func Int16(key string, val int16) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Int16Type, Integer: int64(val)}
}
// Int8 constructs a field with the given key and value.
func Int8(key string, val int8) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Int8Type, Integer: int64(val)}
}
// String constructs a field with the given key and value.
func String(key string, val string) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.StringType, String: val}
}
// Uint constructs a field with the given key and value.
func Uint(key string, val uint) zapcore.Field {
return Uint64(key, uint64(val))
}
// Uint64 constructs a field with the given key and value.
func Uint64(key string, val uint64) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Uint64Type, Integer: int64(val)}
}
// Uint32 constructs a field with the given key and value.
func Uint32(key string, val uint32) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Uint32Type, Integer: int64(val)}
}
// Uint16 constructs a field with the given key and value.
func Uint16(key string, val uint16) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Uint16Type, Integer: int64(val)}
}
// Uint8 constructs a field with the given key and value.
func Uint8(key string, val uint8) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.Uint8Type, Integer: int64(val)}
}
// Uintptr constructs a field with the given key and value.
func Uintptr(key string, val uintptr) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.UintptrType, Integer: int64(val)}
}
// Reflect constructs a field with the given key and an arbitrary object. It uses
// an encoding-appropriate, reflection-based function to lazily serialize nearly
// any object into the logging context, but it's relatively slow and
// allocation-heavy. Outside tests, Any is always a better choice.
//
// If encoding fails (e.g., trying to serialize a map[int]string to JSON), Reflect
// includes the error message in the final log output.
func Reflect(key string, val interface{}) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.ReflectType, Interface: val}
}
// Namespace creates a named, isolated scope within the logger's context. All
// subsequent fields will be added to the new namespace.
//
// This helps prevent key collisions when injecting loggers into sub-components
// or third-party libraries.
func Namespace(key string) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.NamespaceType}
}
// Stringer constructs a field with the given key and the output of the value's
// String method. The Stringer's String method is called lazily.
func Stringer(key string, val fmt.Stringer) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.StringerType, Interface: val}
}
// Time constructs a zapcore.Field with the given key and value. The encoder
// controls how the time is serialized.
func Time(key string, val time.Time) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.TimeType, Integer: val.UnixNano(), Interface: val.Location()}
}
// Stack constructs a field that stores a stacktrace of the current goroutine
// under provided key. Keep in mind that taking a stacktrace is eager and
// expensive (relatively speaking); this function both makes an allocation and
// takes about two microseconds.
func Stack(key string) zapcore.Field {
// Returning the stacktrace as a string costs an allocation, but saves us
// from expanding the zapcore.Field union struct to include a byte slice. Since
// taking a stacktrace is already so expensive (~10us), the extra allocation
// is okay.
return String(key, takeStacktrace())
}
// Duration constructs a field with the given key and value. The encoder
// controls how the duration is serialized.
func Duration(key string, val time.Duration) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.DurationType, Integer: int64(val)}
}
// Object constructs a field with the given key and ObjectMarshaler. It
// provides a flexible, but still type-safe and efficient, way to add map- or
// struct-like user-defined types to the logging context. The struct's
// MarshalLogObject method is called lazily.
func Object(key string, val zapcore.ObjectMarshaler) zapcore.Field {
return zapcore.Field{Key: key, Type: zapcore.ObjectMarshalerType, Interface: val}
}
// Any takes a key and an arbitrary value and chooses the best way to represent
// them as a field, falling back to a reflection-based approach only if
// necessary.
//
// Since byte/uint8 and rune/int32 are aliases, Any can't differentiate between
// them. To minimize suprise, []byte values are treated as binary blobs, byte
// values are treated as uint8, and runes are always treated as integers.
func Any(key string, value interface{}) zapcore.Field {
switch val := value.(type) {
case zapcore.ObjectMarshaler:
return Object(key, val)
case zapcore.ArrayMarshaler:
return Array(key, val)
case bool:
return Bool(key, val)
case []bool:
return Bools(key, val)
case complex128:
return Complex128(key, val)
case []complex128:
return Complex128s(key, val)
case complex64:
return Complex64(key, val)
case []complex64:
return Complex64s(key, val)
case float64:
return Float64(key, val)
case []float64:
return Float64s(key, val)
case float32:
return Float32(key, val)
case []float32:
return Float32s(key, val)
case int:
return Int(key, val)
case []int:
return Ints(key, val)
case int64:
return Int64(key, val)
case []int64:
return Int64s(key, val)
case int32:
return Int32(key, val)
case []int32:
return Int32s(key, val)
case int16:
return Int16(key, val)
case []int16:
return Int16s(key, val)
case int8:
return Int8(key, val)
case []int8:
return Int8s(key, val)
case string:
return String(key, val)
case []string:
return Strings(key, val)
case uint:
return Uint(key, val)
case []uint:
return Uints(key, val)
case uint64:
return Uint64(key, val)
case []uint64:
return Uint64s(key, val)
case uint32:
return Uint32(key, val)
case []uint32:
return Uint32s(key, val)
case uint16:
return Uint16(key, val)
case []uint16:
return Uint16s(key, val)
case uint8:
return Uint8(key, val)
case []byte:
return Binary(key, val)
case uintptr:
return Uintptr(key, val)
case []uintptr:
return Uintptrs(key, val)
case time.Time:
return Time(key, val)
case []time.Time:
return Times(key, val)
case time.Duration:
return Duration(key, val)
case []time.Duration:
return Durations(key, val)
case error:
return NamedError(key, val)
case []error:
return Errors(key, val)
case fmt.Stringer:
return Stringer(key, val)
default:
return Reflect(key, val)
}
}

159
vendor/go.uber.org/zap/field_test.go generated vendored Normal file
View File

@ -0,0 +1,159 @@
// 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 (
"net"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"go.uber.org/zap/zapcore"
)
type username string
func (n username) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("username", string(n))
return nil
}
func assertCanBeReused(t testing.TB, field zapcore.Field) {
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
enc := zapcore.NewMapObjectEncoder()
// Ensure using the field in multiple encoders in separate goroutines
// does not cause any races or panics.
wg.Add(1)
go func() {
defer wg.Done()
assert.NotPanics(t, func() {
field.AddTo(enc)
}, "Reusing a field should not cause issues")
}()
}
wg.Wait()
}
func TestFieldConstructors(t *testing.T) {
// Interface types.
addr := net.ParseIP("1.2.3.4")
name := username("phil")
ints := []int{5, 6}
tests := []struct {
name string
field zapcore.Field
expect zapcore.Field
}{
{"Skip", zapcore.Field{Type: zapcore.SkipType}, Skip()},
{"Binary", zapcore.Field{Key: "k", Type: zapcore.BinaryType, Interface: []byte("ab12")}, Binary("k", []byte("ab12"))},
{"Bool", zapcore.Field{Key: "k", Type: zapcore.BoolType, Integer: 1}, Bool("k", true)},
{"Bool", zapcore.Field{Key: "k", Type: zapcore.BoolType, Integer: 1}, Bool("k", true)},
{"ByteString", zapcore.Field{Key: "k", Type: zapcore.ByteStringType, Interface: []byte("ab12")}, ByteString("k", []byte("ab12"))},
{"Complex128", zapcore.Field{Key: "k", Type: zapcore.Complex128Type, Interface: 1 + 2i}, Complex128("k", 1+2i)},
{"Complex64", zapcore.Field{Key: "k", Type: zapcore.Complex64Type, Interface: complex64(1 + 2i)}, Complex64("k", 1+2i)},
{"Duration", zapcore.Field{Key: "k", Type: zapcore.DurationType, Integer: 1}, Duration("k", 1)},
{"Int", zapcore.Field{Key: "k", Type: zapcore.Int64Type, Integer: 1}, Int("k", 1)},
{"Int64", zapcore.Field{Key: "k", Type: zapcore.Int64Type, Integer: 1}, Int64("k", 1)},
{"Int32", zapcore.Field{Key: "k", Type: zapcore.Int32Type, Integer: 1}, Int32("k", 1)},
{"Int16", zapcore.Field{Key: "k", Type: zapcore.Int16Type, Integer: 1}, Int16("k", 1)},
{"Int8", zapcore.Field{Key: "k", Type: zapcore.Int8Type, Integer: 1}, Int8("k", 1)},
{"String", zapcore.Field{Key: "k", Type: zapcore.StringType, String: "foo"}, String("k", "foo")},
{"Time", zapcore.Field{Key: "k", Type: zapcore.TimeType, Integer: 0, Interface: time.UTC}, Time("k", time.Unix(0, 0).In(time.UTC))},
{"Time", zapcore.Field{Key: "k", Type: zapcore.TimeType, Integer: 1000, Interface: time.UTC}, Time("k", time.Unix(0, 1000).In(time.UTC))},
{"Uint", zapcore.Field{Key: "k", Type: zapcore.Uint64Type, Integer: 1}, Uint("k", 1)},
{"Uint64", zapcore.Field{Key: "k", Type: zapcore.Uint64Type, Integer: 1}, Uint64("k", 1)},
{"Uint32", zapcore.Field{Key: "k", Type: zapcore.Uint32Type, Integer: 1}, Uint32("k", 1)},
{"Uint16", zapcore.Field{Key: "k", Type: zapcore.Uint16Type, Integer: 1}, Uint16("k", 1)},
{"Uint8", zapcore.Field{Key: "k", Type: zapcore.Uint8Type, Integer: 1}, Uint8("k", 1)},
{"Uintptr", zapcore.Field{Key: "k", Type: zapcore.UintptrType, Integer: 10}, Uintptr("k", 0xa)},
{"Reflect", zapcore.Field{Key: "k", Type: zapcore.ReflectType, Interface: ints}, Reflect("k", ints)},
{"Stringer", zapcore.Field{Key: "k", Type: zapcore.StringerType, Interface: addr}, Stringer("k", addr)},
{"Object", zapcore.Field{Key: "k", Type: zapcore.ObjectMarshalerType, Interface: name}, Object("k", name)},
{"Any:ObjectMarshaler", Any("k", name), Object("k", name)},
{"Any:ArrayMarshaler", Any("k", bools([]bool{true})), Array("k", bools([]bool{true}))},
{"Any:Stringer", Any("k", addr), Stringer("k", addr)},
{"Any:Bool", Any("k", true), Bool("k", true)},
{"Any:Bools", Any("k", []bool{true}), Bools("k", []bool{true})},
{"Any:Byte", Any("k", byte(1)), Uint8("k", 1)},
{"Any:Bytes", Any("k", []byte{1}), Binary("k", []byte{1})},
{"Any:Complex128", Any("k", 1+2i), Complex128("k", 1+2i)},
{"Any:Complex128s", Any("k", []complex128{1 + 2i}), Complex128s("k", []complex128{1 + 2i})},
{"Any:Complex64", Any("k", complex64(1+2i)), Complex64("k", 1+2i)},
{"Any:Complex64s", Any("k", []complex64{1 + 2i}), Complex64s("k", []complex64{1 + 2i})},
{"Any:Float64", Any("k", 3.14), Float64("k", 3.14)},
{"Any:Float64s", Any("k", []float64{3.14}), Float64s("k", []float64{3.14})},
{"Any:Float32", Any("k", float32(3.14)), Float32("k", 3.14)},
{"Any:Float32s", Any("k", []float32{3.14}), Float32s("k", []float32{3.14})},
{"Any:Int", Any("k", 1), Int("k", 1)},
{"Any:Ints", Any("k", []int{1}), Ints("k", []int{1})},
{"Any:Int64", Any("k", int64(1)), Int64("k", 1)},
{"Any:Int64s", Any("k", []int64{1}), Int64s("k", []int64{1})},
{"Any:Int32", Any("k", int32(1)), Int32("k", 1)},
{"Any:Int32s", Any("k", []int32{1}), Int32s("k", []int32{1})},
{"Any:Int16", Any("k", int16(1)), Int16("k", 1)},
{"Any:Int16s", Any("k", []int16{1}), Int16s("k", []int16{1})},
{"Any:Int8", Any("k", int8(1)), Int8("k", 1)},
{"Any:Int8s", Any("k", []int8{1}), Int8s("k", []int8{1})},
{"Any:Rune", Any("k", rune(1)), Int32("k", 1)},
{"Any:Runes", Any("k", []rune{1}), Int32s("k", []int32{1})},
{"Any:String", Any("k", "v"), String("k", "v")},
{"Any:Strings", Any("k", []string{"v"}), Strings("k", []string{"v"})},
{"Any:Uint", Any("k", uint(1)), Uint("k", 1)},
{"Any:Uints", Any("k", []uint{1}), Uints("k", []uint{1})},
{"Any:Uint64", Any("k", uint64(1)), Uint64("k", 1)},
{"Any:Uint64s", Any("k", []uint64{1}), Uint64s("k", []uint64{1})},
{"Any:Uint32", Any("k", uint32(1)), Uint32("k", 1)},
{"Any:Uint32s", Any("k", []uint32{1}), Uint32s("k", []uint32{1})},
{"Any:Uint16", Any("k", uint16(1)), Uint16("k", 1)},
{"Any:Uint16s", Any("k", []uint16{1}), Uint16s("k", []uint16{1})},
{"Any:Uint8", Any("k", uint8(1)), Uint8("k", 1)},
{"Any:Uint8s", Any("k", []uint8{1}), Binary("k", []uint8{1})},
{"Any:Uintptr", Any("k", uintptr(1)), Uintptr("k", 1)},
{"Any:Uintptrs", Any("k", []uintptr{1}), Uintptrs("k", []uintptr{1})},
{"Any:Time", Any("k", time.Unix(0, 0)), Time("k", time.Unix(0, 0))},
{"Any:Times", Any("k", []time.Time{time.Unix(0, 0)}), Times("k", []time.Time{time.Unix(0, 0)})},
{"Any:Duration", Any("k", time.Second), Duration("k", time.Second)},
{"Any:Durations", Any("k", []time.Duration{time.Second}), Durations("k", []time.Duration{time.Second})},
{"Any:Fallback", Any("k", struct{}{}), Reflect("k", struct{}{})},
{"Namespace", Namespace("k"), zapcore.Field{Key: "k", Type: zapcore.NamespaceType}},
}
for _, tt := range tests {
if !assert.Equal(t, tt.expect, tt.field, "Unexpected output from convenience field constructor %s.", tt.name) {
t.Logf("type expected: %T\nGot: %T", tt.expect.Interface, tt.field.Interface)
}
assertCanBeReused(t, tt.field)
}
}
func TestStackField(t *testing.T) {
f := Stack("stacktrace")
assert.Equal(t, "stacktrace", f.Key, "Unexpected field key.")
assert.Equal(t, zapcore.StringType, f.Type, "Unexpected field type.")
assert.Equal(t, takeStacktrace(), f.String, "Unexpected stack trace")
assertCanBeReused(t, f)
}

39
vendor/go.uber.org/zap/flag.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
// 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 (
"flag"
"go.uber.org/zap/zapcore"
)
// LevelFlag uses the standard library's flag.Var to declare a global flag
// with the specified name, default, and usage guidance. The returned value is
// a pointer to the value of the flag.
//
// If you don't want to use the flag package's global state, you can use any
// non-nil *Level as a flag.Value with your own *flag.FlagSet.
func LevelFlag(name string, defaultLevel zapcore.Level, usage string) *zapcore.Level {
lvl := defaultLevel
flag.Var(&lvl, name, usage)
return &lvl
}

102
vendor/go.uber.org/zap/flag_test.go generated vendored Normal file
View File

@ -0,0 +1,102 @@
// 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 (
"flag"
"io/ioutil"
"testing"
"go.uber.org/zap/zapcore"
"github.com/stretchr/testify/assert"
)
type flagTestCase struct {
args []string
wantLevel zapcore.Level
wantErr bool
}
func (tc flagTestCase) runImplicitSet(t testing.TB) {
origCommandLine := flag.CommandLine
flag.CommandLine = flag.NewFlagSet("test", flag.ContinueOnError)
flag.CommandLine.SetOutput(ioutil.Discard)
defer func() { flag.CommandLine = origCommandLine }()
level := LevelFlag("level", InfoLevel, "")
tc.run(t, flag.CommandLine, level)
}
func (tc flagTestCase) runExplicitSet(t testing.TB) {
var lvl zapcore.Level
set := flag.NewFlagSet("test", flag.ContinueOnError)
set.Var(&lvl, "level", "minimum enabled logging level")
tc.run(t, set, &lvl)
}
func (tc flagTestCase) run(t testing.TB, set *flag.FlagSet, actual *zapcore.Level) {
err := set.Parse(tc.args)
if tc.wantErr {
assert.Error(t, err, "Parse(%v) should fail.", tc.args)
return
}
if assert.NoError(t, err, "Parse(%v) should succeed.", tc.args) {
assert.Equal(t, tc.wantLevel, *actual, "Level mismatch.")
}
}
func TestLevelFlag(t *testing.T) {
tests := []flagTestCase{
{
args: nil,
wantLevel: zapcore.InfoLevel,
},
{
args: []string{"--level", "unknown"},
wantErr: true,
},
{
args: []string{"--level", "error"},
wantLevel: zapcore.ErrorLevel,
},
}
for _, tt := range tests {
tt.runExplicitSet(t)
tt.runImplicitSet(t)
}
}
func TestLevelFlagsAreIndependent(t *testing.T) {
origCommandLine := flag.CommandLine
flag.CommandLine = flag.NewFlagSet("test", flag.ContinueOnError)
flag.CommandLine.SetOutput(ioutil.Discard)
defer func() { flag.CommandLine = origCommandLine }()
// Make sure that these two flags are independent.
fileLevel := LevelFlag("file-level", InfoLevel, "")
consoleLevel := LevelFlag("console-level", InfoLevel, "")
assert.NoError(t, flag.CommandLine.Parse([]string{"-file-level", "debug"}), "Unexpected flag-parsing error.")
assert.Equal(t, InfoLevel, *consoleLevel, "Expected file logging level to remain unchanged.")
assert.Equal(t, DebugLevel, *fileLevel, "Expected console logging level to have changed.")
}

76
vendor/go.uber.org/zap/glide.lock generated vendored Normal file
View File

@ -0,0 +1,76 @@
hash: f073ba522c06c88ea3075bde32a8aaf0969a840a66cab6318a0897d141ffee92
updated: 2017-07-22T18:06:49.598185334-07:00
imports:
- name: go.uber.org/atomic
version: 4e336646b2ef9fc6e47be8e21594178f98e5ebcf
- name: go.uber.org/multierr
version: 3c4937480c32f4c13a875a1829af76c98ca3d40a
testImports:
- name: github.com/apex/log
version: d9b960447bfa720077b2da653cc79e533455b499
subpackages:
- handlers/json
- name: github.com/axw/gocov
version: 3a69a0d2a4ef1f263e2d92b041a69593d6964fe8
subpackages:
- gocov
- name: github.com/davecgh/go-spew
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
subpackages:
- spew
- name: github.com/fatih/color
version: 62e9147c64a1ed519147b62a56a14e83e2be02c1
- name: github.com/go-kit/kit
version: e10f5bf035be9af21fd5b2fb4469d5716c6ab07d
subpackages:
- log
- name: github.com/go-logfmt/logfmt
version: 390ab7935ee28ec6b286364bba9b4dd6410cb3d5
- name: github.com/go-stack/stack
version: 54be5f394ed2c3e19dac9134a40a95ba5a017f7b
- name: github.com/golang/lint
version: c5fb716d6688a859aae56d26d3e6070808df29f7
subpackages:
- golint
- name: github.com/kr/logfmt
version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0
- name: github.com/mattn/go-colorable
version: 3fa8c76f9daed4067e4a806fb7e4dc86455c6d6a
- name: github.com/mattn/go-isatty
version: fc9e8d8ef48496124e79ae0df75490096eccf6fe
- name: github.com/mattn/goveralls
version: 6efce81852ad1b7567c17ad71b03aeccc9dd9ae0
- name: github.com/pborman/uuid
version: e790cca94e6cc75c7064b1332e63811d4aae1a53
- name: github.com/pkg/errors
version: 645ef00459ed84a119197bfb8d8205042c6df63d
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/rs/zerolog
version: eed4c2b94d945e0b2456ad6aa518a443986b5f22
- name: github.com/satori/go.uuid
version: 5bf94b69c6b68ee1b541973bb8e1144db23a194b
- name: github.com/sirupsen/logrus
version: 7dd06bf38e1e13df288d471a57d5adbac106be9e
- name: github.com/stretchr/testify
version: f6abca593680b2315d2075e0f5e2a9751e3f431a
subpackages:
- assert
- require
- name: go.pedge.io/lion
version: 87958e8713f1fa138d993087133b97e976642159
- name: golang.org/x/sys
version: c4489faa6e5ab84c0ef40d6ee878f7a030281f0f
subpackages:
- unix
- name: golang.org/x/tools
version: 496819729719f9d07692195e0a94d6edd2251389
subpackages:
- cover
- name: gopkg.in/inconshreveable/log15.v2
version: b105bd37f74e5d9dc7b6ad7806715c7a2b83fd3f
subpackages:
- stack
- term

35
vendor/go.uber.org/zap/glide.yaml generated vendored Normal file
View File

@ -0,0 +1,35 @@
package: go.uber.org/zap
license: MIT
import:
- package: go.uber.org/atomic
version: ^1
- package: go.uber.org/multierr
version: ^1
testImport:
- package: github.com/satori/go.uuid
- package: github.com/sirupsen/logrus
- package: github.com/apex/log
subpackages:
- handlers/json
- package: github.com/go-kit/kit
subpackages:
- log
- package: github.com/stretchr/testify
subpackages:
- assert
- require
- package: gopkg.in/inconshreveable/log15.v2
- package: github.com/mattn/goveralls
- package: github.com/pborman/uuid
- package: github.com/pkg/errors
- package: go.pedge.io/lion
- package: github.com/rs/zerolog
- package: golang.org/x/tools
subpackages:
- cover
- package: github.com/golang/lint
subpackages:
- golint
- package: github.com/axw/gocov
subpackages:
- gocov

139
vendor/go.uber.org/zap/global.go generated vendored Normal file
View File

@ -0,0 +1,139 @@
// 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 (
"bytes"
"fmt"
"log"
"os"
"sync"
"go.uber.org/zap/zapcore"
)
const (
_stdLogDefaultDepth = 2
_loggerWriterDepth = 2
)
var (
_globalMu sync.RWMutex
_globalL = NewNop()
_globalS = _globalL.Sugar()
)
// L returns the global Logger, which can be reconfigured with ReplaceGlobals.
// It's safe for concurrent use.
func L() *Logger {
_globalMu.RLock()
l := _globalL
_globalMu.RUnlock()
return l
}
// S returns the global SugaredLogger, which can be reconfigured with
// ReplaceGlobals. It's safe for concurrent use.
func S() *SugaredLogger {
_globalMu.RLock()
s := _globalS
_globalMu.RUnlock()
return s
}
// ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a
// function to restore the original values. It's safe for concurrent use.
func ReplaceGlobals(logger *Logger) func() {
_globalMu.Lock()
prev := _globalL
_globalL = logger
_globalS = logger.Sugar()
_globalMu.Unlock()
return func() { ReplaceGlobals(prev) }
}
// NewStdLog returns a *log.Logger which writes to the supplied zap Logger at
// InfoLevel. To redirect the standard library's package-global logging
// functions, use RedirectStdLog instead.
func NewStdLog(l *Logger) *log.Logger {
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
f := logger.Info
return log.New(&loggerWriter{f}, "" /* prefix */, 0 /* flags */)
}
// NewStdLogAt returns *log.Logger which writes to supplied zap logger at
// required level.
func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error) {
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
var logFunc func(string, ...zapcore.Field)
switch level {
case DebugLevel:
logFunc = logger.Debug
case InfoLevel:
logFunc = logger.Info
case WarnLevel:
logFunc = logger.Warn
case ErrorLevel:
logFunc = logger.Error
case DPanicLevel:
logFunc = logger.DPanic
case PanicLevel:
logFunc = logger.Panic
case FatalLevel:
logFunc = logger.Fatal
default:
return nil, fmt.Errorf("unrecognized level: %q", level)
}
return log.New(&loggerWriter{logFunc}, "" /* prefix */, 0 /* flags */), nil
}
// RedirectStdLog redirects output from the standard library's package-global
// logger to the supplied logger at InfoLevel. Since zap already handles caller
// annotations, timestamps, etc., it automatically disables the standard
// library's annotations and prefixing.
//
// It returns a function to restore the original prefix and flags and reset the
// standard library's output to os.Stdout.
func RedirectStdLog(l *Logger) func() {
flags := log.Flags()
prefix := log.Prefix()
log.SetFlags(0)
log.SetPrefix("")
logFunc := l.WithOptions(
AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth),
).Info
log.SetOutput(&loggerWriter{logFunc})
return func() {
log.SetFlags(flags)
log.SetPrefix(prefix)
log.SetOutput(os.Stderr)
}
}
type loggerWriter struct {
logFunc func(msg string, fields ...zapcore.Field)
}
func (l *loggerWriter) Write(p []byte) (int, error) {
p = bytes.TrimSpace(p)
l.logFunc(string(p))
return len(p), nil
}

189
vendor/go.uber.org/zap/global_test.go generated vendored Normal file
View File

@ -0,0 +1,189 @@
// 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 (
"log"
"sync"
"testing"
"time"
"go.uber.org/zap/internal/exit"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest"
"go.uber.org/zap/zaptest/observer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/atomic"
)
func TestReplaceGlobals(t *testing.T) {
initialL := *L()
initialS := *S()
withLogger(t, DebugLevel, nil, func(l *Logger, logs *observer.ObservedLogs) {
L().Info("no-op")
S().Info("no-op")
assert.Equal(t, 0, logs.Len(), "Expected initial logs to go to default no-op global.")
defer ReplaceGlobals(l)()
L().Info("captured")
S().Info("captured")
expected := observer.LoggedEntry{
Entry: zapcore.Entry{Message: "captured"},
Context: []zapcore.Field{},
}
assert.Equal(
t,
[]observer.LoggedEntry{expected, expected},
logs.AllUntimed(),
"Unexpected global log output.",
)
})
assert.Equal(t, initialL, *L(), "Expected func returned from ReplaceGlobals to restore initial L.")
assert.Equal(t, initialS, *S(), "Expected func returned from ReplaceGlobals to restore initial S.")
}
func TestGlobalsConcurrentUse(t *testing.T) {
var (
stop atomic.Bool
wg sync.WaitGroup
)
for i := 0; i < 100; i++ {
wg.Add(2)
go func() {
for !stop.Load() {
ReplaceGlobals(NewNop())
}
wg.Done()
}()
go func() {
for !stop.Load() {
L().With(Int("foo", 42)).Named("main").WithOptions(Development()).Info("")
S().Info("")
}
wg.Done()
}()
}
zaptest.Sleep(100 * time.Millisecond)
stop.Toggle()
wg.Wait()
}
func TestNewStdLog(t *testing.T) {
withLogger(t, DebugLevel, []Option{AddCaller()}, func(l *Logger, logs *observer.ObservedLogs) {
std := NewStdLog(l)
std.Print("redirected")
checkStdLogMessage(t, "redirected", logs)
})
}
func TestNewStdLogAt(t *testing.T) {
// include DPanicLevel here, but do not include Development in options
levels := []zapcore.Level{DebugLevel, InfoLevel, WarnLevel, ErrorLevel, DPanicLevel}
for _, level := range levels {
withLogger(t, DebugLevel, []Option{AddCaller()}, func(l *Logger, logs *observer.ObservedLogs) {
std, err := NewStdLogAt(l, level)
require.NoError(t, err, "Unexpected error.")
std.Print("redirected")
checkStdLogMessage(t, "redirected", logs)
})
}
}
func TestNewStdLogAtPanics(t *testing.T) {
// include DPanicLevel here and enable Development in options
levels := []zapcore.Level{DPanicLevel, PanicLevel}
for _, level := range levels {
withLogger(t, DebugLevel, []Option{AddCaller(), Development()}, func(l *Logger, logs *observer.ObservedLogs) {
std, err := NewStdLogAt(l, level)
require.NoError(t, err, "Unexpected error")
assert.Panics(t, func() { std.Print("redirected") }, "Expected log to panic.")
checkStdLogMessage(t, "redirected", logs)
})
}
}
func TestNewStdLogAtFatal(t *testing.T) {
withLogger(t, DebugLevel, []Option{AddCaller()}, func(l *Logger, logs *observer.ObservedLogs) {
stub := exit.WithStub(func() {
std, err := NewStdLogAt(l, FatalLevel)
require.NoError(t, err, "Unexpected error.")
std.Print("redirected")
checkStdLogMessage(t, "redirected", logs)
})
assert.True(t, true, stub.Exited, "Expected Fatal logger call to terminate process.")
stub.Unstub()
})
}
func TestNewStdLogAtInvalid(t *testing.T) {
_, err := NewStdLogAt(NewNop(), zapcore.Level(99))
assert.Error(t, err, "Expected to get error.")
assert.Contains(t, err.Error(), "99", "Expected level code in error message")
}
func TestRedirectStdLog(t *testing.T) {
initialFlags := log.Flags()
initialPrefix := log.Prefix()
withLogger(t, DebugLevel, nil, func(l *Logger, logs *observer.ObservedLogs) {
defer RedirectStdLog(l)()
log.Print("redirected")
assert.Equal(t, []observer.LoggedEntry{{
Entry: zapcore.Entry{Message: "redirected"},
Context: []zapcore.Field{},
}}, logs.AllUntimed(), "Unexpected global log output.")
})
assert.Equal(t, initialFlags, log.Flags(), "Expected to reset initial flags.")
assert.Equal(t, initialPrefix, log.Prefix(), "Expected to reset initial prefix.")
}
func TestRedirectStdLogCaller(t *testing.T) {
withLogger(t, DebugLevel, []Option{AddCaller()}, func(l *Logger, logs *observer.ObservedLogs) {
defer RedirectStdLog(l)()
log.Print("redirected")
entries := logs.All()
require.Len(t, entries, 1, "Unexpected number of logs.")
assert.Contains(t, entries[0].Entry.Caller.File, "global_test.go", "Unexpected caller annotation.")
})
}
func checkStdLogMessage(t *testing.T, msg string, logs *observer.ObservedLogs) {
require.Equal(t, 1, logs.Len(), "Expected exactly one entry to be logged")
entry := logs.AllUntimed()[0]
assert.Equal(t, []zapcore.Field{}, entry.Context, "Unexpected entry context.")
assert.Equal(t, "redirected", entry.Entry.Message, "Unexpected entry message.")
assert.Regexp(
t,
`go.uber.org/zap/global_test.go:\d+$`,
entry.Entry.Caller.String(),
"Unexpected caller annotation.",
)
}

81
vendor/go.uber.org/zap/http_handler.go generated vendored Normal file
View File

@ -0,0 +1,81 @@
// 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 (
"encoding/json"
"fmt"
"net/http"
"go.uber.org/zap/zapcore"
)
// ServeHTTP is a simple JSON endpoint that can report on or change the current
// logging level.
//
// GET requests return a JSON description of the current logging level. PUT
// requests change the logging level and expect a payload like:
// {"level":"info"}
//
// It's perfectly safe to change the logging level while a program is running.
func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request) {
type errorResponse struct {
Error string `json:"error"`
}
type payload struct {
Level *zapcore.Level `json:"level"`
}
enc := json.NewEncoder(w)
switch r.Method {
case "GET":
current := lvl.Level()
enc.Encode(payload{Level: &current})
case "PUT":
var req payload
if errmess := func() string {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return fmt.Sprintf("Request body must be well-formed JSON: %v", err)
}
if req.Level == nil {
return "Must specify a logging level."
}
return ""
}(); errmess != "" {
w.WriteHeader(http.StatusBadRequest)
enc.Encode(errorResponse{Error: errmess})
return
}
lvl.SetLevel(*req.Level)
enc.Encode(req)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
enc.Encode(errorResponse{
Error: "Only GET and PUT are supported.",
})
}
}

131
vendor/go.uber.org/zap/http_handler_test.go generated vendored Normal file
View File

@ -0,0 +1,131 @@
// 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_test
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
. "go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func newHandler() (AtomicLevel, *Logger) {
lvl := NewAtomicLevel()
logger := New(zapcore.NewNopCore())
return lvl, logger
}
func assertCodeOK(t testing.TB, code int) {
assert.Equal(t, http.StatusOK, code, "Unexpected response status code.")
}
func assertCodeBadRequest(t testing.TB, code int) {
assert.Equal(t, http.StatusBadRequest, code, "Unexpected response status code.")
}
func assertCodeMethodNotAllowed(t testing.TB, code int) {
assert.Equal(t, http.StatusMethodNotAllowed, code, "Unexpected response status code.")
}
func assertResponse(t testing.TB, expectedLevel zapcore.Level, actualBody string) {
assert.Equal(t, fmt.Sprintf(`{"level":"%s"}`, expectedLevel)+"\n", actualBody, "Unexpected response body.")
}
func assertJSONError(t testing.TB, body string) {
// Don't need to test exact error message, but one should be present.
var payload map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(body), &payload), "Expected error response to be JSON.")
msg, ok := payload["error"]
require.True(t, ok, "Error message is an unexpected type.")
assert.NotEqual(t, "", msg, "Expected an error message in response.")
}
func makeRequest(t testing.TB, method string, handler http.Handler, reader io.Reader) (int, string) {
ts := httptest.NewServer(handler)
defer ts.Close()
req, err := http.NewRequest(method, ts.URL, reader)
require.NoError(t, err, "Error constructing %s request.", method)
res, err := http.DefaultClient.Do(req)
require.NoError(t, err, "Error making %s request.", method)
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
require.NoError(t, err, "Error reading request body.")
return res.StatusCode, string(body)
}
func TestHTTPHandlerGetLevel(t *testing.T) {
lvl, _ := newHandler()
code, body := makeRequest(t, "GET", lvl, nil)
assertCodeOK(t, code)
assertResponse(t, lvl.Level(), body)
}
func TestHTTPHandlerPutLevel(t *testing.T) {
lvl, _ := newHandler()
code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{"level":"warn"}`))
assertCodeOK(t, code)
assertResponse(t, lvl.Level(), body)
}
func TestHTTPHandlerPutUnrecognizedLevel(t *testing.T) {
lvl, _ := newHandler()
code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{"level":"unrecognized-level"}`))
assertCodeBadRequest(t, code)
assertJSONError(t, body)
}
func TestHTTPHandlerNotJSON(t *testing.T) {
lvl, _ := newHandler()
code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{`))
assertCodeBadRequest(t, code)
assertJSONError(t, body)
}
func TestHTTPHandlerNoLevelSpecified(t *testing.T) {
lvl, _ := newHandler()
code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{}`))
assertCodeBadRequest(t, code)
assertJSONError(t, body)
}
func TestHTTPHandlerMethodNotAllowed(t *testing.T) {
lvl, _ := newHandler()
code, body := makeRequest(t, "POST", lvl, strings.NewReader(`{`))
assertCodeMethodNotAllowed(t, code)
assertJSONError(t, body)
}

View File

@ -0,0 +1,31 @@
// 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 bufferpool houses zap's shared internal buffer pool. Third-party
// packages can recreate the same functionality with buffers.NewPool.
package bufferpool
import "go.uber.org/zap/buffer"
var (
_pool = buffer.NewPool()
// Get retrieves a buffer from the pool, creating one if necessary.
Get = _pool.Get
)

44
vendor/go.uber.org/zap/internal/color/color.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
// 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 color adds coloring functionality for TTY output.
package color
import "fmt"
// Foreground colors.
const (
Black Color = iota + 30
Red
Green
Yellow
Blue
Magenta
Cyan
White
)
// Color represents a text color.
type Color uint8
// Add adds the coloring to the given string.
func (c Color) Add(s string) string {
return fmt.Sprintf("\x1b[%dm%s\x1b[0m", uint8(c), s)
}

36
vendor/go.uber.org/zap/internal/color/color_test.go generated vendored Normal file
View File

@ -0,0 +1,36 @@
// 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 color
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestColorFormatting(t *testing.T) {
assert.Equal(
t,
"\x1b[31mfoo\x1b[0m",
Red.Add("foo"),
"Unexpected colored output.",
)
}

64
vendor/go.uber.org/zap/internal/exit/exit.go generated vendored Normal file
View File

@ -0,0 +1,64 @@
// 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 exit provides stubs so that unit tests can exercise code that calls
// os.Exit(1).
package exit
import "os"
var real = func() { os.Exit(1) }
// Exit normally terminates the process by calling os.Exit(1). If the package
// is stubbed, it instead records a call in the testing spy.
func Exit() {
real()
}
// A StubbedExit is a testing fake for os.Exit.
type StubbedExit struct {
Exited bool
prev func()
}
// Stub substitutes a fake for the call to os.Exit(1).
func Stub() *StubbedExit {
s := &StubbedExit{prev: real}
real = s.exit
return s
}
// WithStub runs the supplied function with Exit stubbed. It returns the stub
// used, so that users can test whether the process would have crashed.
func WithStub(f func()) *StubbedExit {
s := Stub()
defer s.Unstub()
f()
return s
}
// Unstub restores the previous exit function.
func (se *StubbedExit) Unstub() {
real = se.prev
}
func (se *StubbedExit) exit() {
se.Exited = true
}

42
vendor/go.uber.org/zap/internal/exit/exit_test.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
// 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 exit
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestStub(t *testing.T) {
tests := []struct {
f func()
want bool
}{
{Exit, true},
{func() {}, false},
}
for _, tt := range tests {
s := WithStub(tt.f)
assert.Equal(t, tt.want, s.Exited, "Stub captured unexpected exit value.")
}
}

212
vendor/go.uber.org/zap/internal/readme/readme.go generated vendored Normal file
View File

@ -0,0 +1,212 @@
// 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 main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"sort"
"strconv"
"strings"
"text/template"
"time"
)
var (
libraryNameToMarkdownName = map[string]string{
"Zap": ":zap: zap",
"Zap.Sugar": ":zap: zap (sugared)",
"stdlib.Println": "standard library",
"sirupsen/logrus": "logrus",
"go-kit/kit/log": "go-kit",
"inconshreveable/log15": "log15",
"apex/log": "apex/log",
"go.pedge.io/lion": "lion",
"rs/zerolog": "zerolog",
}
)
func main() {
flag.Parse()
if err := do(); err != nil {
log.Fatal(err)
}
}
func do() error {
tmplData, err := getTmplData()
if err != nil {
return err
}
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
}
t, err := template.New("tmpl").Parse(string(data))
if err != nil {
return err
}
if err := t.Execute(os.Stdout, tmplData); err != nil {
return err
}
return nil
}
func getTmplData() (*tmplData, error) {
tmplData := &tmplData{}
rows, err := getBenchmarkRows("BenchmarkAddingFields")
if err != nil {
return nil, err
}
tmplData.BenchmarkAddingFields = rows
rows, err = getBenchmarkRows("BenchmarkAccumulatedContext")
if err != nil {
return nil, err
}
tmplData.BenchmarkAccumulatedContext = rows
rows, err = getBenchmarkRows("BenchmarkWithoutFields")
if err != nil {
return nil, err
}
tmplData.BenchmarkWithoutFields = rows
return tmplData, nil
}
func getBenchmarkRows(benchmarkName string) (string, error) {
benchmarkOutput, err := getBenchmarkOutput(benchmarkName)
if err != nil {
return "", err
}
var benchmarkRows []*benchmarkRow
for libraryName := range libraryNameToMarkdownName {
benchmarkRow, err := getBenchmarkRow(benchmarkOutput, benchmarkName, libraryName)
if err != nil {
return "", err
}
if benchmarkRow == nil {
continue
}
benchmarkRows = append(benchmarkRows, benchmarkRow)
}
sort.Sort(benchmarkRowsByTime(benchmarkRows))
rows := []string{
"| Package | Time | Objects Allocated |",
"| :--- | :---: | :---: |",
}
for _, benchmarkRow := range benchmarkRows {
rows = append(rows, benchmarkRow.String())
}
return strings.Join(rows, "\n"), nil
}
func getBenchmarkRow(input []string, benchmarkName string, libraryName string) (*benchmarkRow, error) {
line, err := findUniqueSubstring(input, fmt.Sprintf("%s/%s-", benchmarkName, libraryName))
if err != nil {
return nil, err
}
if line == "" {
return nil, nil
}
split := strings.Split(line, "\t")
if len(split) < 5 {
return nil, fmt.Errorf("unknown benchmark line: %s", line)
}
duration, err := time.ParseDuration(strings.Replace(strings.TrimSuffix(strings.TrimSpace(split[2]), "/op"), " ", "", -1))
if err != nil {
return nil, err
}
allocatedBytes, err := strconv.Atoi(strings.TrimSuffix(strings.TrimSpace(split[3]), " B/op"))
if err != nil {
return nil, err
}
allocatedObjects, err := strconv.Atoi(strings.TrimSuffix(strings.TrimSpace(split[4]), " allocs/op"))
if err != nil {
return nil, err
}
return &benchmarkRow{
libraryNameToMarkdownName[libraryName],
duration,
allocatedBytes,
allocatedObjects,
}, nil
}
func findUniqueSubstring(input []string, substring string) (string, error) {
var output string
for _, line := range input {
if strings.Contains(line, substring) {
if output != "" {
return "", fmt.Errorf("input has duplicate substring %s", substring)
}
output = line
}
}
return output, nil
}
func getBenchmarkOutput(benchmarkName string) ([]string, error) {
return getOutput("go", "test", fmt.Sprintf("-bench=%s", benchmarkName), "-benchmem", "./benchmarks")
}
func getOutput(name string, arg ...string) ([]string, error) {
output, err := exec.Command(name, arg...).CombinedOutput()
if err != nil {
return nil, fmt.Errorf("error running %s %s: %v\n%s", name, strings.Join(arg, " "), err, string(output))
}
return strings.Split(string(output), "\n"), nil
}
type tmplData struct {
BenchmarkAddingFields string
BenchmarkAccumulatedContext string
BenchmarkWithoutFields string
}
type benchmarkRow struct {
Name string
Time time.Duration
AllocatedBytes int
AllocatedObjects int
}
func (b *benchmarkRow) String() string {
return fmt.Sprintf("| %s | %d ns/op | %d allocs/op |", b.Name, b.Time.Nanoseconds(), b.AllocatedObjects)
}
type benchmarkRowsByTime []*benchmarkRow
func (b benchmarkRowsByTime) Len() int { return len(b) }
func (b benchmarkRowsByTime) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b benchmarkRowsByTime) Less(i, j int) bool {
left, right := b[i], b[j]
leftZap, rightZap := strings.Contains(left.Name, "zap"), strings.Contains(right.Name, "zap")
// If neither benchmark is for zap or both are, sort by time.
if !(leftZap || rightZap) || (leftZap && rightZap) {
return left.Time.Nanoseconds() < right.Time.Nanoseconds()
}
// Sort zap benchmark first.
return leftZap
}

132
vendor/go.uber.org/zap/level.go generated vendored Normal file
View File

@ -0,0 +1,132 @@
// 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 (
"go.uber.org/atomic"
"go.uber.org/zap/zapcore"
)
const (
// DebugLevel logs are typically voluminous, and are usually disabled in
// production.
DebugLevel = zapcore.DebugLevel
// InfoLevel is the default logging priority.
InfoLevel = zapcore.InfoLevel
// WarnLevel logs are more important than Info, but don't need individual
// human review.
WarnLevel = zapcore.WarnLevel
// ErrorLevel logs are high-priority. If an application is running smoothly,
// it shouldn't generate any error-level logs.
ErrorLevel = zapcore.ErrorLevel
// DPanicLevel logs are particularly important errors. In development the
// logger panics after writing the message.
DPanicLevel = zapcore.DPanicLevel
// PanicLevel logs a message, then panics.
PanicLevel = zapcore.PanicLevel
// FatalLevel logs a message, then calls os.Exit(1).
FatalLevel = zapcore.FatalLevel
)
// LevelEnablerFunc is a convenient way to implement zapcore.LevelEnabler with
// an anonymous function.
//
// It's particularly useful when splitting log output between different
// outputs (e.g., standard error and standard out). For sample code, see the
// package-level AdvancedConfiguration example.
type LevelEnablerFunc func(zapcore.Level) bool
// Enabled calls the wrapped function.
func (f LevelEnablerFunc) Enabled(lvl zapcore.Level) bool { return f(lvl) }
// An AtomicLevel is an atomically changeable, dynamic logging level. It lets
// you safely change the log level of a tree of loggers (the root logger and
// any children created by adding context) at runtime.
//
// The AtomicLevel itself is an http.Handler that serves a JSON endpoint to
// alter its level.
//
// AtomicLevels must be created with the NewAtomicLevel constructor to allocate
// their internal atomic pointer.
type AtomicLevel struct {
l *atomic.Int32
}
// NewAtomicLevel creates an AtomicLevel with InfoLevel and above logging
// enabled.
func NewAtomicLevel() AtomicLevel {
return AtomicLevel{
l: atomic.NewInt32(int32(InfoLevel)),
}
}
// NewAtomicLevelAt is a convienence function that creates an AtomicLevel
// and then calls SetLevel with the given level.
func NewAtomicLevelAt(l zapcore.Level) AtomicLevel {
a := NewAtomicLevel()
a.SetLevel(l)
return a
}
// Enabled implements the zapcore.LevelEnabler interface, which allows the
// AtomicLevel to be used in place of traditional static levels.
func (lvl AtomicLevel) Enabled(l zapcore.Level) bool {
return lvl.Level().Enabled(l)
}
// Level returns the minimum enabled log level.
func (lvl AtomicLevel) Level() zapcore.Level {
return zapcore.Level(int8(lvl.l.Load()))
}
// SetLevel alters the logging level.
func (lvl AtomicLevel) SetLevel(l zapcore.Level) {
lvl.l.Store(int32(l))
}
// String returns the string representation of the underlying Level.
func (lvl AtomicLevel) String() string {
return lvl.Level().String()
}
// UnmarshalText unmarshals the text to an AtomicLevel. It uses the same text
// representations as the static zapcore.Levels ("debug", "info", "warn",
// "error", "dpanic", "panic", and "fatal").
func (lvl *AtomicLevel) UnmarshalText(text []byte) error {
if lvl.l == nil {
lvl.l = &atomic.Int32{}
}
var l zapcore.Level
if err := l.UnmarshalText(text); err != nil {
return err
}
lvl.SetLevel(l)
return nil
}
// MarshalText marshals the AtomicLevel to a byte slice. It uses the same
// text representation as the static zapcore.Levels ("debug", "info", "warn",
// "error", "dpanic", "panic", and "fatal").
func (lvl AtomicLevel) MarshalText() (text []byte, err error) {
return lvl.Level().MarshalText()
}

117
vendor/go.uber.org/zap/level_test.go generated vendored Normal file
View File

@ -0,0 +1,117 @@
// 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 (
"sync"
"testing"
"go.uber.org/zap/zapcore"
"github.com/stretchr/testify/assert"
)
func TestLevelEnablerFunc(t *testing.T) {
enab := LevelEnablerFunc(func(l zapcore.Level) bool { return l == zapcore.InfoLevel })
tests := []struct {
level zapcore.Level
enabled bool
}{
{DebugLevel, false},
{InfoLevel, true},
{WarnLevel, false},
{ErrorLevel, false},
{DPanicLevel, false},
{PanicLevel, false},
{FatalLevel, false},
}
for _, tt := range tests {
assert.Equal(t, tt.enabled, enab.Enabled(tt.level), "Unexpected result applying LevelEnablerFunc to %s", tt.level)
}
}
func TestNewAtomicLevel(t *testing.T) {
lvl := NewAtomicLevel()
assert.Equal(t, InfoLevel, lvl.Level(), "Unexpected initial level.")
lvl.SetLevel(ErrorLevel)
assert.Equal(t, ErrorLevel, lvl.Level(), "Unexpected level after SetLevel.")
lvl = NewAtomicLevelAt(WarnLevel)
assert.Equal(t, WarnLevel, lvl.Level(), "Unexpected level after SetLevel.")
}
func TestAtomicLevelMutation(t *testing.T) {
lvl := NewAtomicLevel()
lvl.SetLevel(WarnLevel)
// Trigger races for non-atomic level mutations.
proceed := make(chan struct{})
wg := &sync.WaitGroup{}
runConcurrently(10, 100, wg, func() {
<-proceed
assert.Equal(t, WarnLevel, lvl.Level())
})
runConcurrently(10, 100, wg, func() {
<-proceed
lvl.SetLevel(WarnLevel)
})
close(proceed)
wg.Wait()
}
func TestAtomicLevelText(t *testing.T) {
tests := []struct {
text string
expect zapcore.Level
err bool
}{
{"debug", DebugLevel, false},
{"info", InfoLevel, false},
{"", InfoLevel, false},
{"warn", WarnLevel, false},
{"error", ErrorLevel, false},
{"dpanic", DPanicLevel, false},
{"panic", PanicLevel, false},
{"fatal", FatalLevel, false},
{"foobar", InfoLevel, true},
}
for _, tt := range tests {
var lvl AtomicLevel
// Test both initial unmarshaling and overwriting existing value.
for i := 0; i < 2; i++ {
if tt.err {
assert.Error(t, lvl.UnmarshalText([]byte(tt.text)), "Expected unmarshaling %q to fail.", tt.text)
} else {
assert.NoError(t, lvl.UnmarshalText([]byte(tt.text)), "Expected unmarshaling %q to succeed.", tt.text)
}
assert.Equal(t, tt.expect, lvl.Level(), "Unexpected level after unmarshaling.")
lvl.SetLevel(InfoLevel)
}
// Test marshalling
if tt.text != "" && !tt.err {
lvl.SetLevel(tt.expect)
marshaled, err := lvl.MarshalText()
assert.NoError(t, err, `Unexpected error marshalling level "%v" to text.`, tt.expect)
assert.Equal(t, tt.text, string(marshaled), "Expected marshaled text to match")
assert.Equal(t, tt.text, lvl.String(), "Expected Stringer call to match")
}
}
}

305
vendor/go.uber.org/zap/logger.go generated vendored Normal file
View File

@ -0,0 +1,305 @@
// 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 (
"fmt"
"io/ioutil"
"os"
"runtime"
"strings"
"time"
"go.uber.org/zap/zapcore"
)
// A Logger provides fast, leveled, structured logging. All methods are safe
// for concurrent use.
//
// The Logger is designed for contexts in which every microsecond and every
// allocation matters, so its API intentionally favors performance and type
// safety over brevity. For most applications, the SugaredLogger strikes a
// better balance between performance and ergonomics.
type Logger struct {
core zapcore.Core
development bool
name string
errorOutput zapcore.WriteSyncer
addCaller bool
addStack zapcore.LevelEnabler
callerSkip int
}
// New constructs a new Logger from the provided zapcore.Core and Options. If
// the passed zapcore.Core is nil, it falls back to using a no-op
// implementation.
//
// This is the most flexible way to construct a Logger, but also the most
// verbose. For typical use cases, the highly-opinionated presets
// (NewProduction, NewDevelopment, and NewExample) or the Config struct are
// more convenient.
//
// For sample code, see the package-level AdvancedConfiguration example.
func New(core zapcore.Core, options ...Option) *Logger {
if core == nil {
return NewNop()
}
log := &Logger{
core: core,
errorOutput: zapcore.Lock(os.Stderr),
addStack: zapcore.FatalLevel + 1,
}
return log.WithOptions(options...)
}
// NewNop returns a no-op Logger. It never writes out logs or internal errors,
// and it never runs user-defined hooks.
//
// Using WithOptions to replace the Core or error output of a no-op Logger can
// re-enable logging.
func NewNop() *Logger {
return &Logger{
core: zapcore.NewNopCore(),
errorOutput: zapcore.AddSync(ioutil.Discard),
addStack: zapcore.FatalLevel + 1,
}
}
// NewProduction builds a sensible production Logger that writes InfoLevel and
// above logs to standard error as JSON.
//
// It's a shortcut for NewProductionConfig().Build(...Option).
func NewProduction(options ...Option) (*Logger, error) {
return NewProductionConfig().Build(options...)
}
// NewDevelopment builds a development Logger that writes DebugLevel and above
// logs to standard error in a human-friendly format.
//
// It's a shortcut for NewDevelopmentConfig().Build(...Option).
func NewDevelopment(options ...Option) (*Logger, error) {
return NewDevelopmentConfig().Build(options...)
}
// NewExample builds a Logger that's designed for use in zap's testable
// examples. It writes DebugLevel and above logs to standard out as JSON, but
// omits the timestamp and calling function to keep example output
// short and deterministic.
func NewExample(options ...Option) *Logger {
encoderCfg := zapcore.EncoderConfig{
MessageKey: "msg",
LevelKey: "level",
NameKey: "logger",
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
}
core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), os.Stdout, DebugLevel)
return New(core).WithOptions(options...)
}
// Sugar wraps the Logger to provide a more ergonomic, but slightly slower,
// API. Sugaring a Logger is quite inexpensive, so it's reasonable for a
// single application to use both Loggers and SugaredLoggers, converting
// between them on the boundaries of performance-sensitive code.
func (log *Logger) Sugar() *SugaredLogger {
core := log.clone()
core.callerSkip += 2
return &SugaredLogger{core}
}
// Named adds a new path segment to the logger's name. Segments are joined by
// periods. By default, Loggers are unnamed.
func (log *Logger) Named(s string) *Logger {
if s == "" {
return log
}
l := log.clone()
if log.name == "" {
l.name = s
} else {
l.name = strings.Join([]string{l.name, s}, ".")
}
return l
}
// WithOptions clones the current Logger, applies the supplied Options, and
// returns the resulting Logger. It's safe to use concurrently.
func (log *Logger) WithOptions(opts ...Option) *Logger {
c := log.clone()
for _, opt := range opts {
opt.apply(c)
}
return c
}
// With creates a child logger and adds structured context to it. Fields added
// to the child don't affect the parent, and vice versa.
func (log *Logger) With(fields ...zapcore.Field) *Logger {
if len(fields) == 0 {
return log
}
l := log.clone()
l.core = l.core.With(fields)
return l
}
// Check returns a CheckedEntry if logging a message at the specified level
// is enabled. It's a completely optional optimization; in high-performance
// applications, Check can help avoid allocating a slice to hold fields.
func (log *Logger) Check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
return log.check(lvl, msg)
}
// Debug logs a message at DebugLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Debug(msg string, fields ...zapcore.Field) {
if ce := log.check(DebugLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Info logs a message at InfoLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Info(msg string, fields ...zapcore.Field) {
if ce := log.check(InfoLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Warn logs a message at WarnLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Warn(msg string, fields ...zapcore.Field) {
if ce := log.check(WarnLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Error logs a message at ErrorLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Error(msg string, fields ...zapcore.Field) {
if ce := log.check(ErrorLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// DPanic logs a message at DPanicLevel. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
//
// If the logger is in development mode, it then panics (DPanic means
// "development panic"). This is useful for catching errors that are
// recoverable, but shouldn't ever happen.
func (log *Logger) DPanic(msg string, fields ...zapcore.Field) {
if ce := log.check(DPanicLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Panic logs a message at PanicLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then panics, even if logging at PanicLevel is disabled.
func (log *Logger) Panic(msg string, fields ...zapcore.Field) {
if ce := log.check(PanicLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Fatal logs a message at FatalLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then calls os.Exit(1), even if logging at FatalLevel is
// disabled.
func (log *Logger) Fatal(msg string, fields ...zapcore.Field) {
if ce := log.check(FatalLevel, msg); ce != nil {
ce.Write(fields...)
}
}
// Sync calls the underlying Core's Sync method, flushing any buffered log
// entries. Applications should take care to call Sync before exiting.
func (log *Logger) Sync() error {
return log.core.Sync()
}
// Core returns the Logger's underlying zapcore.Core.
func (log *Logger) Core() zapcore.Core {
return log.core
}
func (log *Logger) clone() *Logger {
copy := *log
return &copy
}
func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
// check must always be called directly by a method in the Logger interface
// (e.g., Check, Info, Fatal).
const callerSkipOffset = 2
// Create basic checked entry thru the core; this will be non-nil if the
// log message will actually be written somewhere.
ent := zapcore.Entry{
LoggerName: log.name,
Time: time.Now(),
Level: lvl,
Message: msg,
}
ce := log.core.Check(ent, nil)
willWrite := ce != nil
// Set up any required terminal behavior.
switch ent.Level {
case zapcore.PanicLevel:
ce = ce.Should(ent, zapcore.WriteThenPanic)
case zapcore.FatalLevel:
ce = ce.Should(ent, zapcore.WriteThenFatal)
case zapcore.DPanicLevel:
if log.development {
ce = ce.Should(ent, zapcore.WriteThenPanic)
}
}
// Only do further annotation if we're going to write this message; checked
// entries that exist only for terminal behavior don't benefit from
// annotation.
if !willWrite {
return ce
}
// Thread the error output through to the CheckedEntry.
ce.ErrorOutput = log.errorOutput
if log.addCaller {
ce.Entry.Caller = zapcore.NewEntryCaller(runtime.Caller(log.callerSkip + callerSkipOffset))
if !ce.Entry.Caller.Defined {
fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC())
log.errorOutput.Sync()
}
}
if log.addStack.Enabled(ce.Entry.Level) {
ce.Entry.Stack = Stack("").String
}
return ce
}

222
vendor/go.uber.org/zap/logger_bench_test.go generated vendored Normal file
View File

@ -0,0 +1,222 @@
// 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"
"testing"
"time"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest"
)
type user struct {
Name string
Email string
CreatedAt time.Time
}
func (u *user) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("name", u.Name)
enc.AddString("email", u.Email)
enc.AddInt64("created_at", u.CreatedAt.UnixNano())
return nil
}
var _jane = &user{
Name: "Jane Doe",
Email: "jane@test.com",
CreatedAt: time.Date(1980, 1, 1, 12, 0, 0, 0, time.UTC),
}
func withBenchedLogger(b *testing.B, f func(*Logger)) {
logger := New(
zapcore.NewCore(
zapcore.NewJSONEncoder(NewProductionConfig().EncoderConfig),
&zaptest.Discarder{},
DebugLevel,
))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
f(logger)
}
})
}
func BenchmarkNoContext(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("No context.")
})
}
func BenchmarkBoolField(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Boolean.", Bool("foo", true))
})
}
func BenchmarkByteStringField(b *testing.B) {
val := []byte("bar")
withBenchedLogger(b, func(log *Logger) {
log.Info("ByteString.", ByteString("foo", val))
})
}
func BenchmarkFloat64Field(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Floating point.", Float64("foo", 3.14))
})
}
func BenchmarkIntField(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Integer.", Int("foo", 42))
})
}
func BenchmarkInt64Field(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("64-bit integer.", Int64("foo", 42))
})
}
func BenchmarkStringField(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Strings.", String("foo", "bar"))
})
}
func BenchmarkStringerField(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Level.", Stringer("foo", InfoLevel))
})
}
func BenchmarkTimeField(b *testing.B) {
t := time.Unix(0, 0)
withBenchedLogger(b, func(log *Logger) {
log.Info("Time.", Time("foo", t))
})
}
func BenchmarkDurationField(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Duration", Duration("foo", time.Second))
})
}
func BenchmarkErrorField(b *testing.B) {
err := errors.New("egad")
withBenchedLogger(b, func(log *Logger) {
log.Info("Error.", Error(err))
})
}
func BenchmarkErrorsField(b *testing.B) {
errs := []error{
errors.New("egad"),
errors.New("oh no"),
errors.New("dear me"),
errors.New("such fail"),
}
withBenchedLogger(b, func(log *Logger) {
log.Info("Errors.", Errors("errors", errs))
})
}
func BenchmarkStackField(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Error.", Stack("stacktrace"))
})
}
func BenchmarkObjectField(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Arbitrary ObjectMarshaler.", Object("user", _jane))
})
}
func BenchmarkReflectField(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Reflection-based serialization.", Reflect("user", _jane))
})
}
func BenchmarkAddCallerHook(b *testing.B) {
logger := New(
zapcore.NewCore(
zapcore.NewJSONEncoder(NewProductionConfig().EncoderConfig),
&zaptest.Discarder{},
InfoLevel,
),
AddCaller(),
)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info("Caller.")
}
})
}
func Benchmark10Fields(b *testing.B) {
withBenchedLogger(b, func(log *Logger) {
log.Info("Ten fields, passed at the log site.",
Int("one", 1),
Int("two", 2),
Int("three", 3),
Int("four", 4),
Int("five", 5),
Int("six", 6),
Int("seven", 7),
Int("eight", 8),
Int("nine", 9),
Int("ten", 10),
)
})
}
func Benchmark100Fields(b *testing.B) {
const batchSize = 50
logger := New(zapcore.NewCore(
zapcore.NewJSONEncoder(NewProductionConfig().EncoderConfig),
&zaptest.Discarder{},
DebugLevel,
))
// Don't include allocating these helper slices in the benchmark. Since
// access to them isn't synchronized, we can't run the benchmark in
// parallel.
first := make([]zapcore.Field, batchSize)
second := make([]zapcore.Field, batchSize)
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i := 0; i < batchSize; i++ {
// We're duplicating keys, but that doesn't affect performance.
first[i] = Int("foo", i)
second[i] = Int("foo", i+batchSize)
}
logger.With(first...).Info("Child loggers with lots of context.", second...)
}
}

432
vendor/go.uber.org/zap/logger_test.go generated vendored Normal file
View File

@ -0,0 +1,432 @@
// 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"
"sync"
"testing"
"go.uber.org/zap/internal/exit"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest"
"go.uber.org/zap/zaptest/observer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/atomic"
)
func makeCountingHook() (func(zapcore.Entry) error, *atomic.Int64) {
count := &atomic.Int64{}
h := func(zapcore.Entry) error {
count.Inc()
return nil
}
return h, count
}
func TestLoggerAtomicLevel(t *testing.T) {
// Test that the dynamic level applies to all ancestors and descendants.
dl := NewAtomicLevel()
withLogger(t, dl, nil, func(grandparent *Logger, _ *observer.ObservedLogs) {
parent := grandparent.With(Int("generation", 1))
child := parent.With(Int("generation", 2))
tests := []struct {
setLevel zapcore.Level
testLevel zapcore.Level
enabled bool
}{
{DebugLevel, DebugLevel, true},
{InfoLevel, DebugLevel, false},
{WarnLevel, PanicLevel, true},
}
for _, tt := range tests {
dl.SetLevel(tt.setLevel)
for _, logger := range []*Logger{grandparent, parent, child} {
if tt.enabled {
assert.NotNil(
t,
logger.Check(tt.testLevel, ""),
"Expected level %s to be enabled after setting level %s.", tt.testLevel, tt.setLevel,
)
} else {
assert.Nil(
t,
logger.Check(tt.testLevel, ""),
"Expected level %s to be enabled after setting level %s.", tt.testLevel, tt.setLevel,
)
}
}
}
})
}
func TestLoggerInitialFields(t *testing.T) {
fieldOpts := opts(Fields(Int("foo", 42), String("bar", "baz")))
withLogger(t, DebugLevel, fieldOpts, func(logger *Logger, logs *observer.ObservedLogs) {
logger.Info("")
assert.Equal(
t,
observer.LoggedEntry{Context: []zapcore.Field{Int("foo", 42), String("bar", "baz")}},
logs.AllUntimed()[0],
"Unexpected output with initial fields set.",
)
})
}
func TestLoggerWith(t *testing.T) {
fieldOpts := opts(Fields(Int("foo", 42)))
withLogger(t, DebugLevel, fieldOpts, func(logger *Logger, logs *observer.ObservedLogs) {
// Child loggers should have copy-on-write semantics, so two children
// shouldn't stomp on each other's fields or affect the parent's fields.
logger.With(String("one", "two")).Info("")
logger.With(String("three", "four")).Info("")
logger.Info("")
assert.Equal(t, []observer.LoggedEntry{
{Context: []zapcore.Field{Int("foo", 42), String("one", "two")}},
{Context: []zapcore.Field{Int("foo", 42), String("three", "four")}},
{Context: []zapcore.Field{Int("foo", 42)}},
}, logs.AllUntimed(), "Unexpected cross-talk between child loggers.")
})
}
func TestLoggerLogPanic(t *testing.T) {
for _, tt := range []struct {
do func(*Logger)
should bool
expected string
}{
{func(logger *Logger) { logger.Check(PanicLevel, "bar").Write() }, true, "bar"},
{func(logger *Logger) { logger.Panic("baz") }, true, "baz"},
} {
withLogger(t, DebugLevel, nil, func(logger *Logger, logs *observer.ObservedLogs) {
if tt.should {
assert.Panics(t, func() { tt.do(logger) }, "Expected panic")
} else {
assert.NotPanics(t, func() { tt.do(logger) }, "Expected no panic")
}
output := logs.AllUntimed()
assert.Equal(t, 1, len(output), "Unexpected number of logs.")
assert.Equal(t, 0, len(output[0].Context), "Unexpected context on first log.")
assert.Equal(
t,
zapcore.Entry{Message: tt.expected, Level: PanicLevel},
output[0].Entry,
"Unexpected output from panic-level Log.",
)
})
}
}
func TestLoggerLogFatal(t *testing.T) {
for _, tt := range []struct {
do func(*Logger)
expected string
}{
{func(logger *Logger) { logger.Check(FatalLevel, "bar").Write() }, "bar"},
{func(logger *Logger) { logger.Fatal("baz") }, "baz"},
} {
withLogger(t, DebugLevel, nil, func(logger *Logger, logs *observer.ObservedLogs) {
stub := exit.WithStub(func() {
tt.do(logger)
})
assert.True(t, stub.Exited, "Expected Fatal logger call to terminate process.")
output := logs.AllUntimed()
assert.Equal(t, 1, len(output), "Unexpected number of logs.")
assert.Equal(t, 0, len(output[0].Context), "Unexpected context on first log.")
assert.Equal(
t,
zapcore.Entry{Message: tt.expected, Level: FatalLevel},
output[0].Entry,
"Unexpected output from fatal-level Log.",
)
})
}
}
func TestLoggerLeveledMethods(t *testing.T) {
withLogger(t, DebugLevel, nil, func(logger *Logger, logs *observer.ObservedLogs) {
tests := []struct {
method func(string, ...zapcore.Field)
expectedLevel zapcore.Level
}{
{logger.Debug, DebugLevel},
{logger.Info, InfoLevel},
{logger.Warn, WarnLevel},
{logger.Error, ErrorLevel},
{logger.DPanic, DPanicLevel},
}
for i, tt := range tests {
tt.method("")
output := logs.AllUntimed()
assert.Equal(t, i+1, len(output), "Unexpected number of logs.")
assert.Equal(t, 0, len(output[i].Context), "Unexpected context on first log.")
assert.Equal(
t,
zapcore.Entry{Level: tt.expectedLevel},
output[i].Entry,
"Unexpected output from %s-level logger method.", tt.expectedLevel)
}
})
}
func TestLoggerAlwaysPanics(t *testing.T) {
// Users can disable writing out panic-level logs, but calls to logger.Panic()
// should still call panic().
withLogger(t, FatalLevel, nil, func(logger *Logger, logs *observer.ObservedLogs) {
msg := "Even if output is disabled, logger.Panic should always panic."
assert.Panics(t, func() { logger.Panic("foo") }, msg)
assert.Panics(t, func() {
if ce := logger.Check(PanicLevel, "foo"); ce != nil {
ce.Write()
}
}, msg)
assert.Equal(t, 0, logs.Len(), "Panics shouldn't be written out if PanicLevel is disabled.")
})
}
func TestLoggerAlwaysFatals(t *testing.T) {
// Users can disable writing out fatal-level logs, but calls to logger.Fatal()
// should still terminate the process.
withLogger(t, FatalLevel+1, nil, func(logger *Logger, logs *observer.ObservedLogs) {
stub := exit.WithStub(func() { logger.Fatal("") })
assert.True(t, stub.Exited, "Expected calls to logger.Fatal to terminate process.")
stub = exit.WithStub(func() {
if ce := logger.Check(FatalLevel, ""); ce != nil {
ce.Write()
}
})
assert.True(t, stub.Exited, "Expected calls to logger.Check(FatalLevel, ...) to terminate process.")
assert.Equal(t, 0, logs.Len(), "Shouldn't write out logs when fatal-level logging is disabled.")
})
}
func TestLoggerDPanic(t *testing.T) {
withLogger(t, DebugLevel, nil, func(logger *Logger, logs *observer.ObservedLogs) {
assert.NotPanics(t, func() { logger.DPanic("") })
assert.Equal(
t,
[]observer.LoggedEntry{{Entry: zapcore.Entry{Level: DPanicLevel}, Context: []zapcore.Field{}}},
logs.AllUntimed(),
"Unexpected log output from DPanic in production mode.",
)
})
withLogger(t, DebugLevel, opts(Development()), func(logger *Logger, logs *observer.ObservedLogs) {
assert.Panics(t, func() { logger.DPanic("") })
assert.Equal(
t,
[]observer.LoggedEntry{{Entry: zapcore.Entry{Level: DPanicLevel}, Context: []zapcore.Field{}}},
logs.AllUntimed(),
"Unexpected log output from DPanic in development mode.",
)
})
}
func TestLoggerNoOpsDisabledLevels(t *testing.T) {
withLogger(t, WarnLevel, nil, func(logger *Logger, logs *observer.ObservedLogs) {
logger.Info("silence!")
assert.Equal(
t,
[]observer.LoggedEntry{},
logs.AllUntimed(),
"Expected logging at a disabled level to produce no output.",
)
})
}
func TestLoggerNames(t *testing.T) {
tests := []struct {
names []string
expected string
}{
{nil, ""},
{[]string{""}, ""},
{[]string{"foo"}, "foo"},
{[]string{"foo", ""}, "foo"},
{[]string{"foo", "bar"}, "foo.bar"},
{[]string{"foo.bar", "baz"}, "foo.bar.baz"},
// Garbage in, garbage out.
{[]string{"foo.", "bar"}, "foo..bar"},
{[]string{"foo", ".bar"}, "foo..bar"},
{[]string{"foo.", ".bar"}, "foo...bar"},
}
for _, tt := range tests {
withLogger(t, DebugLevel, nil, func(log *Logger, logs *observer.ObservedLogs) {
for _, n := range tt.names {
log = log.Named(n)
}
log.Info("")
require.Equal(t, 1, logs.Len(), "Expected only one log entry to be written.")
assert.Equal(t, tt.expected, logs.AllUntimed()[0].Entry.LoggerName, "Unexpected logger name.")
})
withSugar(t, DebugLevel, nil, func(log *SugaredLogger, logs *observer.ObservedLogs) {
for _, n := range tt.names {
log = log.Named(n)
}
log.Infow("")
require.Equal(t, 1, logs.Len(), "Expected only one log entry to be written.")
assert.Equal(t, tt.expected, logs.AllUntimed()[0].Entry.LoggerName, "Unexpected logger name.")
})
}
}
func TestLoggerWriteFailure(t *testing.T) {
errSink := &zaptest.Buffer{}
logger := New(
zapcore.NewCore(
zapcore.NewJSONEncoder(NewProductionConfig().EncoderConfig),
zapcore.Lock(zapcore.AddSync(zaptest.FailWriter{})),
DebugLevel,
),
ErrorOutput(errSink),
)
logger.Info("foo")
// Should log the error.
assert.Regexp(t, `write error: failed`, errSink.Stripped(), "Expected to log the error to the error output.")
assert.True(t, errSink.Called(), "Expected logging an internal error to call Sync the error sink.")
}
func TestLoggerSync(t *testing.T) {
withLogger(t, DebugLevel, nil, func(logger *Logger, _ *observer.ObservedLogs) {
assert.NoError(t, logger.Sync(), "Expected syncing a test logger to succeed.")
assert.NoError(t, logger.Sugar().Sync(), "Expected syncing a sugared logger to succeed.")
})
}
func TestLoggerSyncFail(t *testing.T) {
noSync := &zaptest.Buffer{}
err := errors.New("fail")
noSync.SetError(err)
logger := New(zapcore.NewCore(
zapcore.NewJSONEncoder(zapcore.EncoderConfig{}),
noSync,
DebugLevel,
))
assert.Equal(t, err, logger.Sync(), "Expected Logger.Sync to propagate errors.")
assert.Equal(t, err, logger.Sugar().Sync(), "Expected SugaredLogger.Sync to propagate errors.")
}
func TestLoggerAddCaller(t *testing.T) {
tests := []struct {
options []Option
pat string
}{
{opts(AddCaller()), `.+/logger_test.go:[\d]+$`},
{opts(AddCaller(), AddCallerSkip(1), AddCallerSkip(-1)), `.+/zap/logger_test.go:[\d]+$`},
{opts(AddCaller(), AddCallerSkip(1)), `.+/zap/common_test.go:[\d]+$`},
{opts(AddCaller(), AddCallerSkip(1), AddCallerSkip(3)), `.+/src/runtime/.*:[\d]+$`},
}
for _, tt := range tests {
withLogger(t, DebugLevel, tt.options, func(logger *Logger, logs *observer.ObservedLogs) {
// Make sure that sugaring and desugaring resets caller skip properly.
logger = logger.Sugar().Desugar()
logger.Info("")
output := logs.AllUntimed()
assert.Equal(t, 1, len(output), "Unexpected number of logs written out.")
assert.Regexp(
t,
tt.pat,
output[0].Entry.Caller,
"Expected to find package name and file name in output.",
)
})
}
}
func TestLoggerAddCallerFail(t *testing.T) {
errBuf := &zaptest.Buffer{}
withLogger(t, DebugLevel, opts(AddCaller(), ErrorOutput(errBuf)), func(log *Logger, logs *observer.ObservedLogs) {
log.callerSkip = 1e3
log.Info("Failure.")
assert.Regexp(
t,
`Logger.check error: failed to get caller`,
errBuf.String(),
"Didn't find expected failure message.",
)
assert.Equal(
t,
logs.AllUntimed()[0].Entry.Message,
"Failure.",
"Expected original message to survive failures in runtime.Caller.")
})
}
func TestLoggerReplaceCore(t *testing.T) {
replace := WrapCore(func(zapcore.Core) zapcore.Core {
return zapcore.NewNopCore()
})
withLogger(t, DebugLevel, opts(replace), func(logger *Logger, logs *observer.ObservedLogs) {
logger.Debug("")
logger.Info("")
logger.Warn("")
assert.Equal(t, 0, logs.Len(), "Expected no-op core to write no logs.")
})
}
func TestLoggerHooks(t *testing.T) {
hook, seen := makeCountingHook()
withLogger(t, DebugLevel, opts(Hooks(hook)), func(logger *Logger, logs *observer.ObservedLogs) {
logger.Debug("")
logger.Info("")
})
assert.Equal(t, int64(2), seen.Load(), "Hook saw an unexpected number of logs.")
}
func TestLoggerConcurrent(t *testing.T) {
withLogger(t, DebugLevel, nil, func(logger *Logger, logs *observer.ObservedLogs) {
child := logger.With(String("foo", "bar"))
wg := &sync.WaitGroup{}
runConcurrently(5, 10, wg, func() {
logger.Info("", String("foo", "bar"))
})
runConcurrently(5, 10, wg, func() {
child.Info("")
})
wg.Wait()
// Make sure the output doesn't contain interspersed entries.
assert.Equal(t, 100, logs.Len(), "Unexpected number of logs written out.")
for _, obs := range logs.AllUntimed() {
assert.Equal(
t,
observer.LoggedEntry{
Entry: zapcore.Entry{Level: InfoLevel},
Context: []zapcore.Field{String("foo", "bar")},
},
obs,
"Unexpected log output.",
)
}
})
}

109
vendor/go.uber.org/zap/options.go generated vendored Normal file
View File

@ -0,0 +1,109 @@
// 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 "go.uber.org/zap/zapcore"
// An Option configures a Logger.
type Option interface {
apply(*Logger)
}
// optionFunc wraps a func so it satisfies the Option interface.
type optionFunc func(*Logger)
func (f optionFunc) apply(log *Logger) {
f(log)
}
// WrapCore wraps or replaces the Logger's underlying zapcore.Core.
func WrapCore(f func(zapcore.Core) zapcore.Core) Option {
return optionFunc(func(log *Logger) {
log.core = f(log.core)
})
}
// Hooks registers functions which will be called each time the Logger writes
// out an Entry. Repeated use of Hooks is additive.
//
// Hooks are useful for simple side effects, like capturing metrics for the
// number of emitted logs. More complex side effects, including anything that
// requires access to the Entry's structured fields, should be implemented as
// a zapcore.Core instead. See zapcore.RegisterHooks for details.
func Hooks(hooks ...func(zapcore.Entry) error) Option {
return optionFunc(func(log *Logger) {
log.core = zapcore.RegisterHooks(log.core, hooks...)
})
}
// Fields adds fields to the Logger.
func Fields(fs ...zapcore.Field) Option {
return optionFunc(func(log *Logger) {
log.core = log.core.With(fs)
})
}
// ErrorOutput sets the destination for errors generated by the Logger. Note
// that this option only affects internal errors; for sample code that sends
// error-level logs to a different location from info- and debug-level logs,
// see the package-level AdvancedConfiguration example.
//
// The supplied WriteSyncer must be safe for concurrent use. The Open and
// zapcore.Lock functions are the simplest ways to protect files with a mutex.
func ErrorOutput(w zapcore.WriteSyncer) Option {
return optionFunc(func(log *Logger) {
log.errorOutput = w
})
}
// Development puts the logger in development mode, which makes DPanic-level
// logs panic instead of simply logging an error.
func Development() Option {
return optionFunc(func(log *Logger) {
log.development = true
})
}
// AddCaller configures the Logger to annotate each message with the filename
// and line number of zap's caller.
func AddCaller() Option {
return optionFunc(func(log *Logger) {
log.addCaller = true
})
}
// AddCallerSkip increases the number of callers skipped by caller annotation
// (as enabled by the AddCaller option). When building wrappers around the
// Logger and SugaredLogger, supplying this Option prevents zap from always
// reporting the wrapper code as the caller.
func AddCallerSkip(skip int) Option {
return optionFunc(func(log *Logger) {
log.callerSkip += skip
})
}
// AddStacktrace configures the Logger to record a stack trace for all messages at
// or above a given level.
func AddStacktrace(lvl zapcore.LevelEnabler) Option {
return optionFunc(func(log *Logger) {
log.addStack = lvl
})
}

12
vendor/go.uber.org/zap/scripts/cover.sh generated vendored Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e
echo "" > cover.out
for d in $(go list $@); do
go test -race -coverprofile=profile.out $d
if [ -f profile.out ]; then
cat profile.out >> cover.out
rm profile.out
fi
done

126
vendor/go.uber.org/zap/stacktrace.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
// 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 (
"runtime"
"strings"
"sync"
"go.uber.org/zap/internal/bufferpool"
)
const _zapPackage = "go.uber.org/zap"
var (
_stacktracePool = sync.Pool{
New: func() interface{} {
return newProgramCounters(64)
},
}
// We add "." and "/" suffixes to the package name to ensure we only match
// the exact package and not any package with the same prefix.
_zapStacktracePrefixes = addPrefix(_zapPackage, ".", "/")
_zapStacktraceVendorContains = addPrefix("/vendor/", _zapStacktracePrefixes...)
)
func takeStacktrace() string {
buffer := bufferpool.Get()
defer buffer.Free()
programCounters := _stacktracePool.Get().(*programCounters)
defer _stacktracePool.Put(programCounters)
var numFrames int
for {
// Skip the call to runtime.Counters and takeStacktrace so that the
// program counters start at the caller of takeStacktrace.
numFrames = runtime.Callers(2, programCounters.pcs)
if numFrames < len(programCounters.pcs) {
break
}
// Don't put the too-short counter slice back into the pool; this lets
// the pool adjust if we consistently take deep stacktraces.
programCounters = newProgramCounters(len(programCounters.pcs) * 2)
}
i := 0
skipZapFrames := true // skip all consecutive zap frames at the beginning.
frames := runtime.CallersFrames(programCounters.pcs[:numFrames])
// Note: On the last iteration, frames.Next() returns false, with a valid
// frame, but we ignore this frame. The last frame is a a runtime frame which
// adds noise, since it's only either runtime.main or runtime.goexit.
for frame, more := frames.Next(); more; frame, more = frames.Next() {
if skipZapFrames && isZapFrame(frame.Function) {
continue
} else {
skipZapFrames = false
}
if i != 0 {
buffer.AppendByte('\n')
}
i++
buffer.AppendString(frame.Function)
buffer.AppendByte('\n')
buffer.AppendByte('\t')
buffer.AppendString(frame.File)
buffer.AppendByte(':')
buffer.AppendInt(int64(frame.Line))
}
return buffer.String()
}
func isZapFrame(function string) bool {
for _, prefix := range _zapStacktracePrefixes {
if strings.HasPrefix(function, prefix) {
return true
}
}
// We can't use a prefix match here since the location of the vendor
// directory affects the prefix. Instead we do a contains match.
for _, contains := range _zapStacktraceVendorContains {
if strings.Contains(function, contains) {
return true
}
}
return false
}
type programCounters struct {
pcs []uintptr
}
func newProgramCounters(size int) *programCounters {
return &programCounters{make([]uintptr, size)}
}
func addPrefix(prefix string, ss ...string) []string {
withPrefix := make([]string, len(ss))
for i, s := range ss {
withPrefix[i] = prefix + s
}
return withPrefix
}

161
vendor/go.uber.org/zap/stacktrace_ext_test.go generated vendored Normal file
View File

@ -0,0 +1,161 @@
// Copyright (c) 2016, 2017 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_test
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// _zapPackages are packages that we search for in the logging output to match a
// zap stack frame. It is different from _zapStacktracePrefixes which is only
// intended to match on the function name, while this is on the full output
// which includes filenames.
var _zapPackages = []string{
"go.uber.org/zap.",
"go.uber.org/zap/zapcore.",
}
func TestStacktraceFiltersZapLog(t *testing.T) {
withLogger(t, func(logger *zap.Logger, out *bytes.Buffer) {
logger.Error("test log")
logger.Sugar().Error("sugar test log")
require.Contains(t, out.String(), "TestStacktraceFiltersZapLog", "Should not strip out non-zap import")
verifyNoZap(t, out.String())
})
}
func TestStacktraceFiltersZapMarshal(t *testing.T) {
withLogger(t, func(logger *zap.Logger, out *bytes.Buffer) {
marshal := func(enc zapcore.ObjectEncoder) error {
logger.Warn("marshal caused warn")
enc.AddString("f", "v")
return nil
}
logger.Error("test log", zap.Object("obj", zapcore.ObjectMarshalerFunc(marshal)))
logs := out.String()
// The marshal function (which will be under the test function) should not be stripped.
const marshalFnPrefix = "TestStacktraceFiltersZapMarshal."
require.Contains(t, logs, marshalFnPrefix, "Should not strip out marshal call")
// There should be no zap stack traces before that point.
marshalIndex := strings.Index(logs, marshalFnPrefix)
verifyNoZap(t, logs[:marshalIndex])
// After that point, there should be zap stack traces - we don't want to strip out
// the Marshal caller information.
for _, fnPrefix := range _zapPackages {
require.Contains(t, logs[marshalIndex:], fnPrefix, "Missing zap caller stack for Marshal")
}
})
}
func TestStacktraceFiltersVendorZap(t *testing.T) {
// We need to simulate a zap as a vendor library, so we're going to create a fake GOPATH
// and run the above test which will contain zap in the vendor directory.
withGoPath(t, func(goPath string) {
curDir, err := os.Getwd()
require.NoError(t, err, "Failed to get current directory")
testDir := filepath.Join(goPath, "src/go.uber.org/zap_test/")
vendorDir := filepath.Join(testDir, "vendor")
require.NoError(t, os.MkdirAll(testDir, 0777), "Failed to create source director")
curFile := getSelfFilename(t)
//copyFile(t, curFile, filepath.Join(testDir, curFile))
setupSymlink(t, curFile, filepath.Join(testDir, curFile))
// Set up symlinks for zap, and for any test dependencies.
setupSymlink(t, curDir, filepath.Join(vendorDir, "go.uber.org/zap"))
for _, testDep := range []string{"github.com/stretchr/testify"} {
setupSymlink(t, filepath.Join(curDir, "vendor", testDep), filepath.Join(vendorDir, testDep))
}
// Now run the above test which ensures we filter out zap stacktraces, but this time
// zap is in a vendor
cmd := exec.Command("go", "test", "-v", "-run", "TestStacktraceFiltersZap")
cmd.Dir = testDir
out, err := cmd.CombinedOutput()
require.NoError(t, err, "Failed to run test in vendor directory, output: %s", out)
assert.Contains(t, string(out), "PASS")
})
}
// withLogger sets up a logger with a real encoder set up, so that any marshal functions are called.
// The inbuilt observer does not call Marshal for objects/arrays, which we need for some tests.
func withLogger(t *testing.T, fn func(logger *zap.Logger, out *bytes.Buffer)) {
buf := &bytes.Buffer{}
encoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
core := zapcore.NewCore(encoder, zapcore.AddSync(buf), zapcore.DebugLevel)
logger := zap.New(core, zap.AddStacktrace(zap.DebugLevel))
fn(logger, buf)
}
func verifyNoZap(t *testing.T, logs string) {
for _, fnPrefix := range _zapPackages {
require.NotContains(t, logs, fnPrefix, "Should not strip out marshal call")
}
}
func withGoPath(t *testing.T, f func(goPath string)) {
goPath, err := ioutil.TempDir("", "gopath")
require.NoError(t, err, "Failed to create temporary directory for GOPATH")
//defer os.RemoveAll(goPath)
os.Setenv("GOPATH", goPath)
defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
f(goPath)
}
func getSelfFilename(t *testing.T) string {
_, file, _, ok := runtime.Caller(0)
require.True(t, ok, "Failed to get caller information to identify local file")
return filepath.Base(file)
}
func setupSymlink(t *testing.T, src, dst string) {
// Make sure the destination directory exists.
os.MkdirAll(filepath.Dir(dst), 0777)
// Get absolute path of the source for the symlink, otherwise we can create a symlink
// that uses relative paths.
srcAbs, err := filepath.Abs(src)
require.NoError(t, err, "Failed to get absolute path")
require.NoError(t, os.Symlink(srcAbs, dst), "Failed to set up symlink")
}

75
vendor/go.uber.org/zap/stacktrace_test.go generated vendored Normal file
View File

@ -0,0 +1,75 @@
// 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 (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTakeStacktrace(t *testing.T) {
trace := takeStacktrace()
lines := strings.Split(trace, "\n")
require.True(t, len(lines) > 0, "Expected stacktrace to have at least one frame.")
assert.Contains(
t,
lines[0],
"testing.",
"Expected stacktrace to start with the test runner (zap frames are filtered out) %s.", lines[0],
)
}
func TestIsZapFrame(t *testing.T) {
zapFrames := []string{
"go.uber.org/zap.Stack",
"go.uber.org/zap.(*SugaredLogger).log",
"go.uber.org/zap/zapcore.(ArrayMarshalerFunc).MarshalLogArray",
"github.com/uber/tchannel-go/vendor/go.uber.org/zap.Stack",
"github.com/uber/tchannel-go/vendor/go.uber.org/zap.(*SugaredLogger).log",
"github.com/uber/tchannel-go/vendor/go.uber.org/zap/zapcore.(ArrayMarshalerFunc).MarshalLogArray",
}
nonZapFrames := []string{
"github.com/uber/tchannel-go.NewChannel",
"go.uber.org/not-zap.New",
"go.uber.org/zapext.ctx",
"go.uber.org/zap_ext/ctx.New",
}
t.Run("zap frames", func(t *testing.T) {
for _, f := range zapFrames {
require.True(t, isZapFrame(f), f)
}
})
t.Run("non-zap frames", func(t *testing.T) {
for _, f := range nonZapFrames {
require.False(t, isZapFrame(f), f)
}
})
}
func BenchmarkTakeStacktrace(b *testing.B) {
for i := 0; i < b.N; i++ {
takeStacktrace()
}
}

Some files were not shown because too many files have changed in this diff Show More