infra
/
goutils
Archived
1
0
Fork 0

logrotator 교체

This commit is contained in:
Sangbum Kim 2018-06-12 08:45:20 +09:00
parent b1f49e40e7
commit fba6751e05
175 changed files with 24446 additions and 53 deletions

92
Gopkg.lock generated Normal file
View File

@ -0,0 +1,92 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/NebulousLabs/fastrand"
packages = ["."]
revision = "3cf7173006a0b7d2371fa1a220da7f9d48c7827c"
[[projects]]
branch = "master"
name = "github.com/benburkert/dns"
packages = ["."]
revision = "737ce0376169e5410fb2a4ae066d5aabbb71648c"
[[projects]]
name = "github.com/lestrrat-go/file-rotatelogs"
packages = [
".",
"internal/option"
]
revision = "3b4f34a036f374c18d604e1b8006d9fbb9593c06"
version = "v2.2.0"
[[projects]]
branch = "master"
name = "github.com/lestrrat-go/strftime"
packages = ["."]
revision = "59966ecb6d84ec0010de6a5b8deae0299ce5b549"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[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 = "eeedf312bc6c57391d84767a4cd413f02a917974"
version = "v1.8.0"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["blake2b"]
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["cpu"]
revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb"
[[projects]]
name = "golang.org/x/text"
packages = [
"internal/gen",
"internal/triegen",
"internal/ucd",
"transform",
"unicode/cldr",
"width"
]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "6efd7212bdd402a83d3371c761b44b92ba0a2dfb54708f3fe576e5fd1ed5bade"
solver-name = "gps-cdcl"
solver-version = 1

50
Gopkg.toml Normal file
View File

@ -0,0 +1,50 @@
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# 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"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/NebulousLabs/fastrand"
[[constraint]]
branch = "master"
name = "github.com/benburkert/dns"
[[constraint]]
name = "go.uber.org/zap"
version = "1.8.0"
[[constraint]]
name = "golang.org/x/text"
version = "0.3.0"
[[constraint]]
name = "gopkg.in/natefinch/lumberjack.v2"
version = "2.1.0"
[prune]
go-tests = true
unused-packages = true

View File

@ -9,29 +9,25 @@ import (
var loggers RotateSyncerSet
func NewLogWriter(FileName string, MaxSizeMb, MaxBackup, MaxDay int, logDir string) logger.RotateSyncer {
func NewLogWriter(FileName string, logDir string, options ...Option) (logger.RotateSyncer, error) {
switch FileName {
case "Stdout":
return NewLocked(os.Stdout)
return NewLocked(os.Stdout), nil
case "Stderr":
return NewLocked(os.Stderr)
return NewLocked(os.Stderr), nil
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
if logWriter, err := NewRotater(logpath, options...); err != nil {
return nil, err
} else {
loggers.Store(logWriter)
logWriter.SetOnClose(func() { loggers.Delete(logWriter) })
return logWriter, nil
}
}
}

View File

@ -34,6 +34,6 @@ func (s *LockedWriteSyncer) Sync() error {
return err
}
func (r *LockedWriteSyncer) SetOnClose(closeFunc logger.CloseFunc) {}
func (r *LockedWriteSyncer) Rotate() (err error) { return }
func (r *LockedWriteSyncer) Close() (err error) { return }
func (r *LockedWriteSyncer) SetOnClose(closeFunc func()) {}
func (r *LockedWriteSyncer) Rotate() (err error) { return }
func (r *LockedWriteSyncer) Close() (err error) { return }

View File

@ -3,26 +3,25 @@ package rotater
import (
"sync"
"amuz.es/src/infra/goutils/logger"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
"github.com/lestrrat-go/file-rotatelogs"
)
type Option = rotatelogs.Option
type rotateSyncer struct {
setOnceOnclose *sync.Once
onClose func()
lumberjack.Logger
*rotatelogs.RotateLogs
}
func NewRotater(filename string, maxSize, maxBackup, maxDay int) logger.RotateSyncer {
return &rotateSyncer{
setOnceOnclose: &sync.Once{},
Logger: lumberjack.Logger{
Filename: filename,
MaxSize: maxSize, // megabytes
MaxBackups: maxBackup,
MaxAge: maxDay, //days
LocalTime: false,
Compress: false,
},
func NewRotater(filename string, options ...Option) (logger.RotateSyncer, error) {
if rotateLogger, err := rotatelogs.New(filename, options...); err != nil {
return nil, err
} else {
return &rotateSyncer{
setOnceOnclose: &sync.Once{},
RotateLogs: rotateLogger,
}, nil
}
}
func (r *rotateSyncer) SetOnClose(closeFunc func()) {
@ -32,7 +31,7 @@ func (r *rotateSyncer) SetOnClose(closeFunc func()) {
}
func (r *rotateSyncer) Rotate() error {
return r.Logger.Rotate()
return r.RotateLogs.Rotate()
}
func (r *rotateSyncer) Close() error {
defer func() {
@ -40,7 +39,7 @@ func (r *rotateSyncer) Close() error {
r.onClose()
}
}()
return r.Logger.Close()
return r.RotateLogs.Close()
}
func (r *rotateSyncer) Sync() error {
@ -48,5 +47,5 @@ func (r *rotateSyncer) Sync() error {
}
func (s *rotateSyncer) Write(bs []byte) (int, error) {
return s.Logger.Write(bs)
return s.RotateLogs.Write(bs)
}

View File

@ -5,6 +5,7 @@ import (
"go.uber.org/zap/zapcore"
"amuz.es/src/infra/goutils/logger"
"amuz.es/src/infra/goutils/logger/rotater"
)
var (
@ -26,25 +27,27 @@ func Init(
verbose bool,
formatter zapcore.Encoder,
mainLogName, logFilename, logDir string,
maxSizeMb, maxBackup, maxDay int,
rotateOption []rotater.Option,
logLevel zapcore.Level,
additionalOptions ...zap.Option,
) *zap.SugaredLogger {
) (*zap.SugaredLogger, error) {
level := zap.NewAtomicLevelAt(logLevel)
defaultWriter = rotater.NewLogWriter(logFilename, maxSizeMb, maxBackup, maxDay, logDir)
if defaultWriter, err := rotater.NewLogWriter(logFilename, logDir, rotateOption...); err != nil {
return nil, err
} else {
defaultErrorOutputOptions = []zap.Option{zap.ErrorOutput(defaultWriter)}
options := defaultErrorOutputOptions
if verbose {
options = append(options, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.PanicLevel)))
}
// reset log option slice
options = append(options, additionalOptions...)
defaultErrorOutputOptions = []zap.Option{zap.ErrorOutput(defaultWriter)}
options := defaultErrorOutputOptions
if verbose {
options = append(options, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.PanicLevel)))
log := initLogger(defaultWriter, mainLogName, formatter, level, options...)
replaceGlobalLogger(log)
return log.Sugar(), nil
}
// reset log option slice
options = append(options, additionalOptions...)
log := initLogger(defaultWriter, mainLogName, formatter, level, options...)
replaceGlobalLogger(log)
return log.Sugar()
}
func New(parent *zap.SugaredLogger, moduleName string, options ...zap.Option) *zap.SugaredLogger {
@ -63,12 +66,15 @@ func New(parent *zap.SugaredLogger, moduleName string, options ...zap.Option) *z
func NewOtherLogger(
formatter zapcore.Encoder,
moduleName, logFilename, logDir string,
maxSizeMb, maxBackup, maxDay int,
rotateOption []rotater.Option,
logLevel zapcore.Level,
fields ...zapcore.Field,
) (logger *zap.SugaredLogger, closer func() error) {
) (logger *zap.SugaredLogger, closer func() error, err error) {
loglevel := zap.NewAtomicLevelAt(logLevel)
logWriter := rotater.NewLogWriter(logFilename, maxSizeMb, maxBackup, maxDay, logDir)
logWriter, err := rotater.NewLogWriter(logFilename, logDir, rotateOption...)
if err != nil {
return
}
core := zapcore.NewCore(formatter, logWriter, loglevel)
closer = logWriter.Close
logger = zap.New(core, defaultErrorOutputOptions...).
@ -79,13 +85,16 @@ func NewOtherLogger(
func NewOtherLoggerWithOption(
formatter zapcore.Encoder,
moduleName, logFilename, logDir string,
maxSizeMb, maxBackup, maxDay int,
rotateOption []rotater.Option,
logLevel zapcore.Level,
options []zap.Option,
fields ...zapcore.Field,
) (logger *zap.SugaredLogger, closer func() error) {
) (logger *zap.SugaredLogger, closer func() error, err error) {
loglevel := zap.NewAtomicLevelAt(logLevel)
logWriter := rotater.NewLogWriter(logFilename, maxSizeMb, maxBackup, maxDay, logDir)
logWriter, err := rotater.NewLogWriter(logFilename, logDir, rotateOption...)
if err != nil {
return
}
core := zapcore.NewCore(formatter, logWriter, loglevel)
closer = logWriter.Close
options = append(defaultErrorOutputOptions, options...)

21
vendor/github.com/NebulousLabs/fastrand/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Nebulous 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.

55
vendor/github.com/NebulousLabs/fastrand/README.md generated vendored Normal file
View File

@ -0,0 +1,55 @@
fastrand
--------
[![GoDoc](https://godoc.org/github.com/NebulousLabs/fastrand?status.svg)](https://godoc.org/github.com/NebulousLabs/fastrand)
[![Go Report Card](http://goreportcard.com/badge/github.com/NebulousLabs/fastrand)](https://goreportcard.com/report/github.com/NebulousLabs/fastrand)
```
go get github.com/NebulousLabs/fastrand
```
`fastrand` implements a cryptographically secure pseudorandom number generator.
The generator is seeded using the system's default entropy source, and
thereafter produces random values via repeated hashing. As a result, `fastrand`
can generate randomness much faster than `crypto/rand`, and generation cannot
fail beyond a potential panic during `init()`.
`fastrand` also scales better than `crypto/rand` and `math/rand` when called in
parallel. In fact, `fastrand` can even outperform `math/rand` when using enough threads.
## Benchmarks ##
```
// 32 byte reads
BenchmarkRead32 10000000 175 ns/op 181.86 MB/s
BenchmarkReadCrypto32 500000 2733 ns/op 11.71 MB/s
// 512 kb reads
BenchmarkRead512kb 1000 1336217 ns/op 383.17 MB/s
BenchmarkReadCrypto512kb 50 33423693 ns/op 15.32 MB/s
// 32 byte reads using 4 threads
BenchmarkRead4Threads32 3000000 392 ns/op 326.46 MB/s
BenchmarkReadCrypto4Threads32 200000 7579 ns/op 16.89 MB/s
// 512 kb reads using 4 threads
BenchmarkRead4Threads512kb 1000 1899048 ns/op 1078.43 MB/s
BenchmarkReadCrypto4Threads512kb 20 97423380 ns/op 21.02 MB/s
```
## Security ##
`fastrand` uses an algorithm similar to Fortuna, which is the basis for the
`/dev/random` device in FreeBSD. However, although the techniques used by
`fastrand` are known to be secure, the specific implementation has not been
reviewed by a security professional. Use with caution.
The general strategy is to use `crypto/rand` at init to get 32 bytes of strong
entropy. From there, the entropy is concatenated to a counter and hashed
repeatedly, providing 64 bytes of random output each time the counter is
incremented. The counter is 16 bytes, which provides strong guarantees that a
cycle will not be seen throughout the lifetime of the program.
The `sync/atomic` package is used to ensure that multiple threads calling
`fastrand` concurrently are always guaranteed to end up with unique counters.

174
vendor/github.com/NebulousLabs/fastrand/fastrand.go generated vendored Normal file
View File

@ -0,0 +1,174 @@
// Package fastrand implements a cryptographically secure pseudorandom number
// generator. The generator is seeded using the system's default entropy source,
// and thereafter produces random values via repeated hashing. As a result,
// fastrand can generate randomness much faster than crypto/rand, and generation
// cannot fail beyond a potential panic at init.
//
// The method used in this package is similar to the Fortuna algorithm, which is
// used in used in FreeBSD for /dev/urandom. This package uses techniques that
// are known to be secure, however the exact implementation has not been heavily
// reviewed by cryptographers.
package fastrand
import (
"crypto/rand"
"encoding/binary"
"io"
"math"
"math/big"
"strconv"
"sync/atomic"
"unsafe"
"golang.org/x/crypto/blake2b"
)
// A randReader produces random values via repeated hashing. The entropy field
// is the concatenation of an initial seed and a 128-bit counter. Each time
// the entropy is hashed, the counter is incremented.
type randReader struct {
counter uint64 // First 64 bits of the counter.
counterExtra uint64 // Second 64 bits of the counter.
entropy [32]byte
}
// Reader is a global, shared instance of a cryptographically strong pseudo-
// random generator. It uses blake2b as its hashing function. Reader is safe
// for concurrent use by multiple goroutines.
var Reader io.Reader
// init provides the initial entropy for the reader that will seed all numbers
// coming out of fastrand.
func init() {
r := &randReader{}
n, err := rand.Read(r.entropy[:])
if err != nil || n != len(r.entropy) {
panic("not enough entropy to fill fastrand reader at startup")
}
Reader = r
}
// Read fills b with random data. It always returns len(b), nil.
func (r *randReader) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
// Grab a unique counter from the reader, while atomically updating the
// counter so that concurrent callers also end up with unique values.
counter := atomic.AddUint64(&r.counter, 1)
counterExtra := atomic.LoadUint64(&r.counterExtra)
// Increment counterExtra when counter is close to overflowing. We cannot
// wait until counter == math.MaxUint64 to increment counterExtra, because
// another goroutine could call Read, overflowing counter to 0 before the
// first goroutine increments counterExtra. The second goroutine would then
// be reusing the counter pair (0, 0). Instead, we increment at 1<<63 so
// that there is little risk of an overflow.
//
// There is still a potential overlap near 1<<63, though, because another
// goroutine could see counter == 1<<63+1 before the first goroutine
// increments counterExtra. The counter pair (1<<63+1, 1) would then be
// reused. To prevent this, we also increment at math.MaxUint64. This means
// that in order for an overlap to occur, 1<<63 goroutine would need to
// increment counter before the first goroutine increments counterExtra.
//
// This strategy means that many counters will be omitted, and that the
// total space cycle time is potentially as low as 2^126. This is fine
// however, as the security model merely mandates that no counter is ever
// used twice.
if counter == 1<<63 || counter == math.MaxUint64 {
atomic.AddUint64(&r.counterExtra, 1)
}
// Copy the counter and entropy into a separate slice, so that the result
// may be used in isolation of the other threads. The counter ensures that
// the result is unique to this thread.
seed := make([]byte, 64)
binary.LittleEndian.PutUint64(seed[0:8], counter)
binary.LittleEndian.PutUint64(seed[8:16], counterExtra)
// Leave 16 bytes for the inner counter.
copy(seed[32:], r.entropy[:])
// Set up an inner counter, that can be incremented to produce unique
// entropy within this thread.
n := 0
innerCounter := uint64(0)
innerCounterExtra := uint64(0)
for n < len(b) {
// Copy in the inner counter values.
binary.LittleEndian.PutUint64(seed[16:24], innerCounter)
binary.LittleEndian.PutUint64(seed[24:32], innerCounterExtra)
// Hash the seed to produce the next set of entropy.
result := blake2b.Sum512(seed)
n += copy(b[n:], result[:])
// Increment the inner counter. Because we are the only thread accessing
// the counter, we can wait until the first 64 bits have reached their
// maximum value before incrementing the next 64 bits.
innerCounter++
if innerCounter == math.MaxUint64 {
innerCounterExtra++
}
}
return n, nil
}
// Read is a helper function that calls Reader.Read on b. It always fills b
// completely.
func Read(b []byte) { Reader.Read(b) }
// Bytes is a helper function that returns n bytes of random data.
func Bytes(n int) []byte {
b := make([]byte, n)
Read(b)
return b
}
// Uint64n returns a uniform random uint64 in [0,n). It panics if n == 0.
func Uint64n(n uint64) uint64 {
if n == 0 {
panic("fastrand: argument to Uint64n is 0")
}
// To eliminate modulo bias, keep selecting at random until we fall within
// a range that is evenly divisible by n.
// NOTE: since n is at most math.MaxUint64, max is minimized when:
// n = math.MaxUint64/2 + 1 -> max = math.MaxUint64 - math.MaxUint64/2
// This gives an expected 2 tries before choosing a value < max.
max := math.MaxUint64 - math.MaxUint64%n
b := Bytes(8)
r := *(*uint64)(unsafe.Pointer(&b[0]))
for r >= max {
Read(b)
r = *(*uint64)(unsafe.Pointer(&b[0]))
}
return r % n
}
// Intn returns a uniform random int in [0,n). It panics if n <= 0.
func Intn(n int) int {
if n <= 0 {
panic("fastrand: argument to Intn is <= 0: " + strconv.Itoa(n))
}
// NOTE: since n is at most math.MaxUint64/2, max is minimized when:
// n = math.MaxUint64/4 + 1 -> max = math.MaxUint64 - math.MaxUint64/4
// This gives an expected 1.333 tries before choosing a value < max.
return int(Uint64n(uint64(n)))
}
// BigIntn returns a uniform random *big.Int in [0,n). It panics if n <= 0.
func BigIntn(n *big.Int) *big.Int {
i, _ := rand.Int(Reader, n)
return i
}
// Perm returns a random permutation of the integers [0,n).
func Perm(n int) []int {
m := make([]int, n)
for i := 1; i < n; i++ {
j := Intn(i + 1)
m[i] = m[j]
m[j] = i
}
return m
}

6
vendor/github.com/benburkert/dns/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,6 @@
language: go
sudo: false
go:
- 1.9
- tip
script: "go test -v -race ./..."

21
vendor/github.com/benburkert/dns/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Ben Burkert
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.

3
vendor/github.com/benburkert/dns/README.md generated vendored Normal file
View File

@ -0,0 +1,3 @@
# dns [![GoDoc](https://godoc.org/github.com/benburkert/dns?status.svg)](https://godoc.org/github.com/benburkert/dns) [![Build Status](https://travis-ci.org/benburkert/dns.svg)](https://travis-ci.org/benburkert/dns) [![Go Report Card](https://goreportcard.com/badge/github.com/benburkert/dns)](https://goreportcard.com/report/github.com/benburkert/dns)
DNS client and server package. [See godoc for details & examples.](https://godoc.org/github.com/benburkert/dns)

155
vendor/github.com/benburkert/dns/cache.go generated vendored Normal file
View File

@ -0,0 +1,155 @@
package dns
import (
"context"
"math/rand"
"sync"
"time"
)
// Cache is a DNS query cache handler.
type Cache struct {
mu sync.RWMutex
cache map[Question]*Message
}
// ServeDNS answers query questions from a local cache, and forwards unanswered
// questions upstream, then caches the answers from the response.
func (c *Cache) ServeDNS(ctx context.Context, w MessageWriter, r *Query) {
var (
miss bool
now = time.Now()
)
c.mu.RLock()
for _, q := range r.Questions {
if hit := c.lookup(q, w, now); !hit {
miss = true
}
}
c.mu.RUnlock()
if !miss {
return
}
msg, err := w.Recur(ctx)
if err != nil || msg == nil {
w.Status(ServFail)
return
}
if msg.RCode == NoError {
c.insert(msg, now)
}
writeMessage(w, msg)
}
// c.mu.RLock held
func (c *Cache) lookup(q Question, w MessageWriter, now time.Time) bool {
msg, ok := c.cache[q]
if !ok {
return false
}
var answers, authorities, additionals []Resource
for _, res := range msg.Answers {
if res.TTL = cacheTTL(res.TTL, now); res.TTL <= 0 {
return false
}
answers = append(answers, res)
}
for _, res := range msg.Authorities {
if res.TTL = cacheTTL(res.TTL, now); res.TTL <= 0 {
return false
}
authorities = append(authorities, res)
}
for _, res := range msg.Additionals {
if res.TTL = cacheTTL(res.TTL, now); res.TTL <= 0 {
return false
}
additionals = append(additionals, res)
}
randomize(answers)
for _, res := range answers {
w.Answer(res.Name, res.TTL, res.Record)
}
for _, res := range authorities {
w.Authority(res.Name, res.TTL, res.Record)
}
for _, res := range additionals {
w.Additional(res.Name, res.TTL, res.Record)
}
return true
}
func (c *Cache) insert(msg *Message, now time.Time) {
cache := make(map[Question]*Message, len(msg.Questions))
for _, q := range msg.Questions {
m := new(Message)
for _, res := range msg.Answers {
res.TTL = cacheEpoch(res.TTL, now)
m.Answers = append(m.Answers, res)
}
for _, res := range msg.Authorities {
res.TTL = cacheEpoch(res.TTL, now)
m.Authorities = append(m.Authorities, res)
}
for _, res := range msg.Additionals {
res.TTL = cacheEpoch(res.TTL, now)
m.Additionals = append(m.Additionals, res)
}
cache[q] = m
}
c.mu.Lock()
defer c.mu.Unlock()
if c.cache == nil {
c.cache = cache
return
}
for q, m := range cache {
c.cache[q] = m
}
}
func cacheEpoch(ttl time.Duration, now time.Time) time.Duration {
return time.Duration(now.Add(ttl).UnixNano())
}
func cacheTTL(epoch time.Duration, now time.Time) time.Duration {
return time.Unix(0, int64(epoch)).Sub(now)
}
// randomize shuffles contigous groups of resourcesfor the same name.
func randomize(s []Resource) {
var low, high int
for low = 0; low < len(s)-1; low++ {
for high = low + 1; high < len(s) && s[low].Name == s[high].Name; high++ {
}
shuffle(s[low:high])
low = high
}
}
func shuffle(s []Resource) {
if len(s) < 2 {
return
}
for i := len(s) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
s[i], s[j] = s[j], s[i]
}
}

219
vendor/github.com/benburkert/dns/client.go generated vendored Normal file
View File

@ -0,0 +1,219 @@
package dns
import (
"context"
"net"
"sync/atomic"
)
// Client is a DNS client.
type Client struct {
// Transport manages connections to DNS servers.
Transport AddrDialer
// Resolver is a handler that may answer all or portions of a query.
// Any questions answered by the handler are not sent to the upstream
// server.
Resolver Handler
id uint32
}
// Dial dials a DNS server and returns a net Conn that reads and writes DNS
// messages.
func (c *Client) Dial(ctx context.Context, network, address string) (net.Conn, error) {
switch network {
case "tcp", "tcp4", "tcp6":
addr, err := net.ResolveTCPAddr(network, address)
if err != nil {
return nil, err
}
conn, err := c.dial(ctx, addr)
if err != nil {
return nil, err
}
return &streamSession{
session: session{
Conn: conn,
addr: addr,
client: c,
msgerrc: make(chan msgerr),
},
}, nil
case "udp", "udp4", "udp6":
addr, err := net.ResolveUDPAddr(network, address)
if err != nil {
return nil, err
}
conn, err := c.dial(ctx, addr)
if err != nil {
return nil, err
}
return &packetSession{
session: session{
Conn: conn,
addr: addr,
client: c,
msgerrc: make(chan msgerr),
},
}, nil
default:
return nil, ErrUnsupportedNetwork
}
}
// Do sends a DNS query to a server and returns the response message.
func (c *Client) Do(ctx context.Context, query *Query) (*Message, error) {
conn, err := c.dial(ctx, query.RemoteAddr)
if err != nil {
return nil, err
}
if t, ok := ctx.Deadline(); ok {
if err := conn.SetDeadline(t); err != nil {
return nil, err
}
}
return c.do(ctx, conn, query)
}
func (c *Client) dial(ctx context.Context, addr net.Addr) (Conn, error) {
tport := c.Transport
if tport == nil {
tport = new(Transport)
}
return tport.DialAddr(ctx, addr)
}
func (c *Client) do(ctx context.Context, conn Conn, query *Query) (*Message, error) {
if c.Resolver == nil {
return c.roundtrip(conn, query)
}
w := &clientWriter{
messageWriter: &messageWriter{
msg: response(query.Message),
},
req: request(query.Message),
addr: query.RemoteAddr,
conn: conn,
roundtrip: c.roundtrip,
}
c.Resolver.ServeDNS(ctx, w, query)
if w.err != nil {
return nil, w.err
}
return response(w.msg), nil
}
func (c *Client) roundtrip(conn Conn, query *Query) (*Message, error) {
id := query.ID
msg := *query.Message
msg.ID = c.nextID()
if err := conn.Send(&msg); err != nil {
return nil, err
}
if err := conn.Recv(&msg); err != nil {
return nil, err
}
msg.ID = id
return &msg, nil
}
const idMask = (1 << 16) - 1
func (c *Client) nextID() int {
return int(atomic.AddUint32(&c.id, 1) & idMask)
}
type clientWriter struct {
*messageWriter
req *Message
err error
addr net.Addr
conn Conn
roundtrip func(Conn, *Query) (*Message, error)
}
func (w *clientWriter) Recur(context.Context) (*Message, error) {
qs := make([]Question, 0, len(w.req.Questions))
for _, q := range w.req.Questions {
if !questionMatched(q, w.msg) {
qs = append(qs, q)
}
}
w.req.Questions = qs
req := &Query{
Message: w.req,
RemoteAddr: w.addr,
}
msg, err := w.roundtrip(w.conn, req)
if err != nil {
w.err = err
}
return msg, err
}
func (w *clientWriter) Reply(context.Context) error {
return ErrUnsupportedOp
}
func request(msg *Message) *Message {
req := new(Message)
*req = *msg // shallow copy
return req
}
func questionMatched(q Question, msg *Message) bool {
mrs := [3][]Resource{
msg.Answers,
msg.Authorities,
msg.Additionals,
}
for _, rs := range mrs {
for _, res := range rs {
if res.Name == q.Name {
return true
}
}
}
return false
}
func writeMessage(w MessageWriter, msg *Message) {
w.Status(msg.RCode)
w.Authoritative(msg.Authoritative)
w.Recursion(msg.RecursionAvailable)
for _, res := range msg.Answers {
w.Answer(res.Name, res.TTL, res.Record)
}
for _, res := range msg.Authorities {
w.Authority(res.Name, res.TTL, res.Record)
}
for _, res := range msg.Additionals {
w.Additional(res.Name, res.TTL, res.Record)
}
}

177
vendor/github.com/benburkert/dns/compression.go generated vendored Normal file
View File

@ -0,0 +1,177 @@
package dns
import (
"strings"
)
// Compressor encodes domain names.
type Compressor interface {
Length(...string) int
Pack([]byte, string) ([]byte, error)
}
// Decompressor decodes domain names.
type Decompressor interface {
Unpack([]byte) (string, []byte, error)
}
type compressor struct {
tbl map[string]int
offset int
}
func (c compressor) Length(names ...string) int {
var visited map[string]struct{}
if c.tbl != nil {
visited = make(map[string]struct{})
}
var n int
for _, name := range names {
n += c.length(name, visited)
}
return n
}
func (c compressor) length(name string, visited map[string]struct{}) int {
if name == "." || name == "" {
return 1
}
if c.tbl != nil {
if _, ok := c.tbl[name]; ok {
return 2
}
if _, ok := visited[name]; ok {
return 2
}
visited[name] = struct{}{}
}
pvt := strings.IndexByte(name, '.')
return pvt + 1 + c.length(name[pvt+1:], visited)
}
func (c compressor) Pack(b []byte, fqdn string) ([]byte, error) {
if fqdn == "." || fqdn == "" {
return append(b, 0x00), nil
}
if c.tbl != nil {
if idx, ok := c.tbl[fqdn]; ok {
ptr, err := pointerTo(idx)
if err != nil {
return nil, err
}
return append(b, ptr...), nil
}
}
pvt := strings.IndexByte(fqdn, '.')
if pvt == 0 {
return nil, errZeroSegLen
}
if pvt > 63 {
return nil, errSegTooLong
}
if c.tbl != nil {
idx := len(b) - c.offset
if int(uint16(idx)) != idx {
return nil, errInvalidPtr
}
c.tbl[fqdn] = idx
}
b = append(b, byte(pvt))
b = append(b, fqdn[:pvt]...)
return c.Pack(b, fqdn[pvt+1:])
}
type decompressor []byte
func (d decompressor) Unpack(b []byte) (string, []byte, error) {
name, b, err := d.unpack(make([]byte, 0, 32), b, nil)
if err != nil {
return "", nil, err
}
return string(name), b, nil
}
func (d decompressor) unpack(name, b []byte, visited []int) ([]byte, []byte, error) {
lenb := len(b)
if lenb == 0 {
return nil, nil, errBaseLen
}
if b[0] == 0x00 {
if len(name) == 0 {
return append(name, '.'), b[1:], nil
}
return name, b[1:], nil
}
if lenb < 2 {
return nil, nil, errBaseLen
}
if isPointer(b[0]) {
if d == nil {
return nil, nil, errBaseLen
}
ptr := nbo.Uint16(b[:2])
name, err := d.deref(name, ptr, visited)
if err != nil {
return nil, nil, err
}
return name, b[2:], nil
}
lenl, b := int(b[0]), b[1:]
if len(b) < lenl {
return nil, nil, errCalcLen
}
name = append(name, b[:lenl]...)
name = append(name, '.')
return d.unpack(name, b[lenl:], visited)
}
func (d decompressor) deref(name []byte, ptr uint16, visited []int) ([]byte, error) {
idx := int(ptr & 0x3FFF)
if len(d) < idx {
return nil, errInvalidPtr
}
if isPointer(d[idx]) {
return nil, errInvalidPtr
}
for _, v := range visited {
if idx == v {
return nil, errPtrCycle
}
}
name, _, err := d.unpack(name, d[idx:], append(visited, idx))
return name, err
}
func isPointer(b byte) bool { return b&0xC0 > 0 }
func pointerTo(idx int) ([]byte, error) {
ptr := uint16(idx)
if int(ptr) != idx {
return nil, errInvalidPtr
}
ptr |= 0xC000
buf := [2]byte{}
nbo.PutUint16(buf[:], ptr)
return buf[:], nil
}

113
vendor/github.com/benburkert/dns/conn.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
package dns
import (
"io"
"net"
)
// Conn is a network connection to a DNS resolver.
type Conn interface {
net.Conn
// Recv reads a DNS message from the connection.
Recv(msg *Message) error
// Send writes a DNS message to the connection.
Send(msg *Message) error
}
// PacketConn is a packet-oriented network connection to a DNS resolver that
// expects transmitted messages to adhere to RFC 1035 Section 4.2.1. "UDP
// usage".
type PacketConn struct {
net.Conn
rbuf, wbuf []byte
}
// Recv reads a DNS message from the underlying connection.
func (c *PacketConn) Recv(msg *Message) error {
if len(c.rbuf) != maxPacketLen {
c.rbuf = make([]byte, maxPacketLen)
}
n, err := c.Read(c.rbuf)
if err != nil {
return err
}
_, err = msg.Unpack(c.rbuf[:n])
return err
}
// Send writes a DNS message to the underlying connection.
func (c *PacketConn) Send(msg *Message) error {
if len(c.wbuf) != maxPacketLen {
c.wbuf = make([]byte, maxPacketLen)
}
var err error
if c.wbuf, err = msg.Pack(c.wbuf[:0], true); err != nil {
return err
}
if len(c.wbuf) > maxPacketLen {
return ErrOversizedMessage
}
_, err = c.Write(c.wbuf)
return err
}
// StreamConn is a stream-oriented network connection to a DNS resolver that
// expects transmitted messages to adhere to RFC 1035 Section 4.2.2. "TCP
// usage".
type StreamConn struct {
net.Conn
rbuf, wbuf []byte
}
// Recv reads a DNS message from the underlying connection.
func (c *StreamConn) Recv(msg *Message) error {
if len(c.rbuf) < 2 {
c.rbuf = make([]byte, 1280)
}
if _, err := io.ReadFull(c, c.rbuf[:2]); err != nil {
return err
}
mlen := nbo.Uint16(c.rbuf[:2])
if len(c.rbuf) < int(mlen) {
c.rbuf = make([]byte, mlen)
}
if _, err := io.ReadFull(c, c.rbuf[:mlen]); err != nil {
return err
}
_, err := msg.Unpack(c.rbuf[:mlen])
return err
}
// Send writes a DNS message to the underlying connection.
func (c *StreamConn) Send(msg *Message) error {
if len(c.wbuf) < 2 {
c.wbuf = make([]byte, 1024)
}
b, err := msg.Pack(c.wbuf[2:2], true)
if err != nil {
return err
}
mlen := uint16(len(b))
if int(mlen) != len(b) {
return ErrOversizedMessage
}
nbo.PutUint16(c.wbuf[:2], mlen)
_, err = c.Write(c.wbuf[:len(b)+2])
return err
}

60
vendor/github.com/benburkert/dns/dns.go generated vendored Normal file
View File

@ -0,0 +1,60 @@
package dns
import (
"context"
"errors"
"net"
)
var (
// ErrConflictingID is a pipelining error due to the same message ID being
// used for more than one inflight query.
ErrConflictingID = errors.New("conflicting message id")
// ErrOversizedMessage is an error returned when attempting to send a
// message that is longer than the maximum allowed number of bytes.
ErrOversizedMessage = errors.New("oversized message")
// ErrTruncatedMessage indicates the response message has been truncated.
ErrTruncatedMessage = errors.New("truncated message")
// ErrUnsupportedNetwork is returned when DialAddr is called with an
// unknown network.
ErrUnsupportedNetwork = errors.New("unsupported network")
// ErrUnsupportedOp indicates the operation is not supported by callee.
ErrUnsupportedOp = errors.New("unsupported operation")
)
// AddrDialer dials a net Addr.
type AddrDialer interface {
DialAddr(context.Context, net.Addr) (Conn, error)
}
// Query is a DNS request message bound for a DNS resolver.
type Query struct {
*Message
// RemoteAddr is the address of a DNS resolver.
RemoteAddr net.Addr
}
// OverTLSAddr indicates the remote DNS service implements DNS-over-TLS as
// defined in RFC 7858.
type OverTLSAddr struct {
net.Addr
}
// Network returns the address's network name with a "-tls" suffix.
func (a OverTLSAddr) Network() string {
return a.Addr.Network() + "-tls"
}
// ProxyFunc modifies the address of a DNS server.
type ProxyFunc func(context.Context, net.Addr) (net.Addr, error)
// RoundTripper is an interface representing the ability to execute a single
// DNS transaction, obtaining a response Message for a given Query.
type RoundTripper interface {
Do(context.Context, *Query) (*Message, error)
}

76
vendor/github.com/benburkert/dns/doc.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
/*
Package dns provides DNS client and server implementations.
A client can handle queries for a net.Dialer:
dialer := &net.Dialer{
Resolver: &net.Resolver{
PreferGo: true,
Dial: new(dns.Client).Dial,
},
}
conn, err := dialer.DialContext(ctx, "tcp", "example.com:80")
It can also query a remote DNS server directly:
client := new(dns.Client)
query := &dns.Query{
RemoteAddr: &net.TCPAddr{IP: net.IPv4(8, 8, 8, 8), Port: 53},
Message: &dns.Message{
Questions: []dns.Question{
{
Name: "example.com.",
Type: dns.TypeA,
Class: dns.ClassIN,
},
{
Name: "example.com.",
Type: dns.TypeAAAA,
Class: dns.ClassIN,
},
},
},
}
msg, err := client.Do(ctx, query)
A handler answers queries for a server or a local resolver for a client:
zone := &dns.Zone{
Origin: "localhost.",
TTL: 5 * time.Minute,
RRs: dns.RRSet{
"alpha": []dns.Record{
&dns.A{net.IPv4(127, 0, 0, 42).To4()},
&dns.AAAA{net.ParseIP("::42")},
},
},
}
srv := &dns.Server{
Addr: ":53",
Handler: zone,
}
go srv.ListenAndServe(ctx)
mux := new(dns.ResolveMux)
mux.Handle(dns.TypeANY, zone.Origin, zone)
client := &dns.Client{
Resolver: mux,
}
net.DefaultResolver = &net.Resolver{
PreferGo: true,
Dial: client.Dial,
}
addrs, err := net.LookupHost("alpha.localhost")
*/
package dns

247
vendor/github.com/benburkert/dns/handler.go generated vendored Normal file
View File

@ -0,0 +1,247 @@
package dns
import (
"context"
"strings"
)
// Handler responds to a DNS query.
//
// ServeDNS should build the reply message using the MessageWriter, and may
// optionally call the Reply method. Returning signals that the request is
// finished and the response is ready to send.
//
// A recursive handler may call the Recur method of the MessageWriter to send
// an query upstream. Only unanswered questions are included in the upstream
// query.
type Handler interface {
ServeDNS(context.Context, MessageWriter, *Query)
}
// The HandlerFunc type is an adapter to allow the use of ordinary functions as
// DNS handlers. If f is a function with the appropriate signature,
// HandlerFunc(f) is a Handler that calls f.
type HandlerFunc func(context.Context, MessageWriter, *Query)
// ServeDNS calls f(w, r).
func (f HandlerFunc) ServeDNS(ctx context.Context, w MessageWriter, r *Query) {
f(ctx, w, r)
}
// Recursor forwards a query and copies the response.
func Recursor(ctx context.Context, w MessageWriter, r *Query) {
msg, err := w.Recur(ctx)
if err != nil {
w.Status(ServFail)
return
}
writeMessage(w, msg)
}
// Refuse responds to all queries with a "Query Refused" message.
func Refuse(ctx context.Context, w MessageWriter, r *Query) {
w.Status(Refused)
}
// ResolveMux is a DNS query multiplexer. It matches a question type and name
// suffix to a Handler.
type ResolveMux struct {
tbl []muxEntry
}
type muxEntry struct {
typ Type
suffix string
h Handler
}
// Handle registers the handler for the given question type and name suffix.
func (m *ResolveMux) Handle(typ Type, suffix string, h Handler) {
m.tbl = append(m.tbl, muxEntry{typ: typ, suffix: suffix, h: h})
}
// ServeDNS dispatches the query to the handler(s) whose pattern most closely
// matches each question.
func (m *ResolveMux) ServeDNS(ctx context.Context, w MessageWriter, r *Query) {
var muxw *muxWriter
for _, q := range r.Questions {
h := m.lookup(q)
muxm := new(Message)
*muxm = *r.Message
muxm.Questions = []Question{q}
muxr := new(Query)
*muxr = *r
muxr.Message = muxm
muxw = &muxWriter{
messageWriter: &messageWriter{
msg: response(muxr.Message),
},
recurc: make(chan msgerr),
replyc: make(chan msgerr),
next: muxw,
}
go m.serveMux(ctx, h, muxw, muxr)
}
if me, ok := <-muxw.recurc; ok {
writeMessage(w, me.msg)
msg, err := w.Recur(ctx)
muxw.recurc <- msgerr{msg, err}
}
me := <-muxw.replyc
writeMessage(w, me.msg)
if err := w.Reply(ctx); err != nil {
muxw.replyc <- msgerr{nil, err}
}
}
var recursiveHandler = HandlerFunc(func(ctx context.Context, w MessageWriter, r *Query) {
msg, err := w.Recur(ctx)
if err != nil {
w.Status(ServFail)
return
}
w.Status(msg.RCode)
w.Authoritative(msg.Authoritative)
w.Recursion(msg.RecursionAvailable)
for _, rec := range msg.Answers {
w.Answer(rec.Name, rec.TTL, rec.Record)
}
for _, rec := range msg.Authorities {
w.Authority(rec.Name, rec.TTL, rec.Record)
}
for _, rec := range msg.Additionals {
w.Additional(rec.Name, rec.TTL, rec.Record)
}
})
func (m *ResolveMux) lookup(q Question) Handler {
for _, e := range m.tbl {
if e.typ != q.Type && e.typ != TypeANY {
continue
}
if strings.HasSuffix(q.Name, e.suffix) {
return e.h
}
}
return recursiveHandler
}
func (m *ResolveMux) serveMux(ctx context.Context, h Handler, w *muxWriter, r *Query) {
h.ServeDNS(ctx, w, r)
w.finish(ctx)
}
type muxWriter struct {
*messageWriter
recurc, replyc chan msgerr
next *muxWriter
}
func (w muxWriter) Recur(ctx context.Context) (*Message, error) {
var (
nextOK bool
msg = request(w.msg)
)
if w.next != nil {
var me msgerr
if me, nextOK = <-w.next.recurc; nextOK {
mergeRequests(msg, me.msg)
}
}
w.recurc <- msgerr{msg, nil}
me := <-w.recurc
if nextOK {
w.next.recurc <- me
}
if me.err != nil {
return nil, me.err
}
return responseFor(w.msg.Questions[0], me.msg), nil
}
func (w muxWriter) Reply(ctx context.Context) error {
msg := response(w.msg)
if w.next != nil {
if me, ok := <-w.next.recurc; ok {
w.recurc <- me
me = <-w.recurc
w.next.recurc <- me
}
me, ok := <-w.next.replyc
if !ok || me.err != nil {
panic("impossible")
}
mergeResponses(msg, me.msg)
}
close(w.recurc)
w.replyc <- msgerr{msg, nil}
me := <-w.replyc
if w.next != nil {
w.next.replyc <- me
}
close(w.replyc)
w.replyc = nil
return me.err
}
func (w muxWriter) finish(ctx context.Context) {
if w.replyc != nil {
w.Reply(ctx)
}
}
func mergeRequests(to, from *Message) {
if from.OpCode > to.OpCode {
to.OpCode = from.OpCode
}
to.RecursionDesired = to.RecursionDesired || from.RecursionDesired
to.Questions = append(from.Questions, to.Questions...)
}
func mergeResponses(to, from *Message) {
to.Authoritative = to.Authoritative && from.Authoritative
to.RecursionAvailable = to.RecursionAvailable || from.RecursionAvailable
if from.RCode > to.RCode {
to.RCode = from.RCode
}
to.Questions = append(from.Questions, to.Questions...)
to.Answers = append(from.Answers, to.Answers...)
to.Authorities = append(from.Authorities, to.Authorities...)
to.Additionals = append(from.Additionals, to.Additionals...)
}
func responseFor(q Question, res *Message) *Message {
msg := response(res)
var answers []Resource
for _, a := range res.Answers {
if a.Name == q.Name {
answers = append(answers, a)
}
}
msg.Answers = answers
return msg
}

819
vendor/github.com/benburkert/dns/message.go generated vendored Normal file
View File

@ -0,0 +1,819 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package dns
import (
"encoding/binary"
"errors"
"net"
"time"
)
var nbo = binary.BigEndian
// A Type is a type of DNS request and response.
type Type uint16
// A Class is a type of network.
type Class uint16
// An OpCode is a DNS operation code.
type OpCode uint16
// An RCode is a DNS response status code.
type RCode uint16
// Domain Name System (DNS) Parameters.
//
// Taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
const (
// Resource Record (RR) TYPEs
TypeA Type = 1 // [RFC1035] a host address
TypeNS Type = 2 // [RFC1035] an authoritative name server
TypeCNAME Type = 5 // [RFC1035] the canonical name for an alias
TypeSOA Type = 6 // [RFC1035] marks the start of a zone of authority
TypeWKS Type = 11 // [RFC1035] a well known service description
TypePTR Type = 12 // [RFC1035] a domain name pointer
TypeHINFO Type = 13 // [RFC1035] host information
TypeMINFO Type = 14 // [RFC1035] mailbox or mail list information
TypeMX Type = 15 // [RFC1035] mail exchange
TypeTXT Type = 16 // [RFC1035] text strings
TypeAAAA Type = 28 // [RFC3596] IP6 Address
TypeSRV Type = 33 // [RFC2782] Server Selection
TypeAXFR Type = 252 // [RFC1035][RFC5936] transfer of an entire zone
TypeALL Type = 255 // [RFC1035][RFC6895] A request for all records the server/cache has available
TypeANY Type = 0
// DNS CLASSes
ClassIN Class = 1 // [RFC1035] Internet (IN)
ClassCH Class = 3 // [] Chaos (CH)
ClassHS Class = 4 // [] Hesiod (HS)
ClassANY Class = 255 // [RFC1035] QCLASS * (ANY)
// DNS RCODEs
NoError RCode = 0 // [RFC1035] No Error
FormErr RCode = 1 // [RFC1035] Format Error
ServFail RCode = 2 // [RFC1035] Server Failure
NXDomain RCode = 3 // [RFC1035] Non-Existent Domain
NotImp RCode = 4 // [RFC1035] Not Implemented
Refused RCode = 5 // [RFC1035] Query Refused
maxPacketLen = 512
)
// NewRecordByType returns a new instance of a Record for a Type.
var NewRecordByType = map[Type]func() Record{
TypeA: func() Record { return new(A) },
TypeNS: func() Record { return new(NS) },
TypeCNAME: func() Record { return new(CNAME) },
TypeSOA: func() Record { return new(SOA) },
TypePTR: func() Record { return new(PTR) },
TypeMX: func() Record { return new(MX) },
TypeTXT: func() Record { return new(TXT) },
TypeAAAA: func() Record { return new(AAAA) },
TypeSRV: func() Record { return new(SRV) },
}
var (
// ErrNotStarted indicates that the prerequisite information isn't
// available yet because the previous records haven't been appropriately
// parsed or skipped.
ErrNotStarted = errors.New("parsing of this type isn't available yet")
// ErrSectionDone indicated that all records in the section have been
// parsed.
ErrSectionDone = errors.New("parsing of this section has completed")
errBaseLen = errors.New("insufficient data for base length type")
errCalcLen = errors.New("insufficient data for calculated length type")
errReserved = errors.New("segment prefix is reserved")
errPtrCycle = errors.New("pointer cycle")
errInvalidPtr = errors.New("invalid pointer")
errResourceLen = errors.New("insufficient data for resource body length")
errSegTooLong = errors.New("segment length too long")
errZeroSegLen = errors.New("zero length segment")
errResTooLong = errors.New("resource length too long")
errTooManyQuestions = errors.New("too many Questions to pack (>65535)")
errTooManyAnswers = errors.New("too many Answers to pack (>65535)")
errTooManyAuthorities = errors.New("too many Authorities to pack (>65535)")
errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)")
errFieldOverflow = errors.New("value too large for packed field")
errUnknownType = errors.New("unknown resource type")
)
// Message is a DNS message.
type Message struct {
ID int
Response bool
OpCode OpCode
Authoritative bool
Truncated bool
RecursionDesired bool
RecursionAvailable bool
RCode RCode
Questions []Question
Answers []Resource
Authorities []Resource
Additionals []Resource
}
// Pack encodes m as a byte slice. If b is not nil, m is appended into b.
// Domain name compression is enabled by setting compress.
func (m *Message) Pack(b []byte, compress bool) ([]byte, error) {
if b == nil {
b = make([]byte, 0, maxPacketLen)
}
var com Compressor
if compress {
com = compressor{tbl: make(map[string]int), offset: len(b)}
}
var err error
if b, err = m.packHeader(b); err != nil {
return nil, err
}
for _, q := range m.Questions {
if b, err = q.Pack(b, com); err != nil {
return nil, err
}
}
for _, rs := range [3][]Resource{m.Answers, m.Authorities, m.Additionals} {
for _, r := range rs {
if b, err = r.Pack(b, com); err != nil {
return nil, err
}
}
}
return b, nil
}
// Unpack decodes m from b. Unused bytes are returned.
func (m *Message) Unpack(b []byte) ([]byte, error) {
dec := decompressor(b)
var err error
if b, err = m.unpackHeader(b); err != nil {
return nil, err
}
for i := 0; i < cap(m.Questions); i++ {
var q Question
if b, err = q.Unpack(b, dec); err != nil {
return nil, err
}
m.Questions = append(m.Questions, q)
}
for i := 0; i < cap(m.Answers); i++ {
var r Resource
if b, err = r.Unpack(b, dec); err != nil {
return nil, err
}
m.Answers = append(m.Answers, r)
}
for i := 0; i < cap(m.Authorities); i++ {
var r Resource
if b, err = r.Unpack(b, dec); err != nil {
return nil, err
}
m.Authorities = append(m.Authorities, r)
}
for i := 0; i < cap(m.Additionals); i++ {
var r Resource
if b, err = r.Unpack(b, dec); err != nil {
return nil, err
}
m.Additionals = append(m.Additionals, r)
}
return b, nil
}
const (
headerBitQR = 1 << 15 // query/response (response=1)
headerBitAA = 1 << 10 // authoritative
headerBitTC = 1 << 9 // truncated
headerBitRD = 1 << 8 // recursion desired
headerBitRA = 1 << 7 // recursion available
)
func (m *Message) packHeader(b []byte) ([]byte, error) {
id := uint16(m.ID)
if int(id) != m.ID {
return nil, errFieldOverflow
}
opcode := m.OpCode & 0x0F
if opcode != m.OpCode {
return nil, errFieldOverflow
}
rcode := m.RCode & 0x0F
if rcode != m.RCode {
return nil, errFieldOverflow
}
bits := uint16(opcode)<<11 | uint16(rcode)
if m.Response {
bits |= headerBitQR
}
if m.RecursionAvailable {
bits |= headerBitRA
}
if m.RecursionDesired {
bits |= headerBitRD
}
if m.Truncated {
bits |= headerBitTC
}
if m.Authoritative {
bits |= headerBitAA
}
qdcount := uint16(len(m.Questions))
if int(qdcount) != len(m.Questions) {
return nil, errTooManyQuestions
}
ancount := uint16(len(m.Answers))
if int(ancount) != len(m.Answers) {
return nil, errTooManyAnswers
}
nscount := uint16(len(m.Authorities))
if int(nscount) != len(m.Authorities) {
return nil, errTooManyAuthorities
}
arcount := uint16(len(m.Additionals))
if int(nscount) != len(m.Authorities) {
return nil, errTooManyAuthorities
}
buf := [12]byte{}
nbo.PutUint16(buf[0:2], id)
nbo.PutUint16(buf[2:4], bits)
nbo.PutUint16(buf[4:6], qdcount)
nbo.PutUint16(buf[6:8], ancount)
nbo.PutUint16(buf[8:10], nscount)
nbo.PutUint16(buf[10:12], arcount)
return append(b, buf[:]...), nil
}
func (m *Message) unpackHeader(b []byte) ([]byte, error) {
if len(b) < 12 {
return nil, errResourceLen
}
var (
id = int(nbo.Uint16(b))
bits = nbo.Uint16(b[2:])
qdcount = nbo.Uint16(b[4:])
ancount = nbo.Uint16(b[6:])
nscount = nbo.Uint16(b[8:])
arcount = nbo.Uint16(b[10:])
)
*m = Message{
ID: id,
Response: (bits & headerBitQR) > 0,
OpCode: OpCode(bits>>11) & 0xF,
Authoritative: (bits & headerBitAA) > 0,
Truncated: (bits & headerBitTC) > 0,
RecursionDesired: (bits & headerBitRD) > 0,
RecursionAvailable: (bits & headerBitRA) > 0,
RCode: RCode(bits) & 0xF,
}
if qdcount > 0 {
m.Questions = make([]Question, 0, qdcount)
}
if ancount > 0 {
m.Answers = make([]Resource, 0, ancount)
}
if nscount > 0 {
m.Authorities = make([]Resource, 0, nscount)
}
if arcount > 0 {
m.Additionals = make([]Resource, 0, arcount)
}
return b[12:], nil
}
// A Question is a DNS query.
type Question struct {
Name string
Type Type
Class Class
}
// Pack encodes q as a byte slice. If b is not nil, m is appended into b.
func (q Question) Pack(b []byte, com Compressor) ([]byte, error) {
if com == nil {
com = compressor{}
}
var err error
if b, err = com.Pack(b, q.Name); err != nil {
return nil, err
}
buf := [4]byte{}
nbo.PutUint16(buf[:2], uint16(q.Type))
nbo.PutUint16(buf[2:4], uint16(q.Class))
return append(b, buf[:]...), nil
}
// Unpack decodes q from b.
func (q *Question) Unpack(b []byte, dec Decompressor) ([]byte, error) {
if dec == nil {
dec = decompressor(nil)
}
var err error
if q.Name, b, err = dec.Unpack(b); err != nil {
return nil, err
}
if len(b) < 4 {
return nil, errResourceLen
}
q.Type = Type(nbo.Uint16(b[:2]))
q.Class = Class(nbo.Uint16(b[2:4]))
return b[4:], nil
}
// Resource is a DNS resource record (RR).
type Resource struct {
Name string
Class Class
TTL time.Duration
Record
}
// Pack encodes r onto b.
func (r Resource) Pack(b []byte, com Compressor) ([]byte, error) {
if com == nil {
com = compressor{}
}
var err error
if b, err = com.Pack(b, r.Name); err != nil {
return nil, err
}
rtype := r.Record.Type()
ttl := uint32(r.TTL / time.Second)
if time.Duration(ttl) != r.TTL/time.Second {
return nil, errFieldOverflow
}
rlen := r.Record.Length(com)
rdatalen := uint16(rlen)
if int(rdatalen) != rlen {
return nil, errFieldOverflow
}
buf := [10]byte{}
nbo.PutUint16(buf[:2], uint16(rtype))
nbo.PutUint16(buf[2:4], uint16(r.Class))
nbo.PutUint32(buf[4:8], ttl)
nbo.PutUint16(buf[8:10], rdatalen)
b = append(b, buf[:]...)
return r.Record.Pack(b, com)
}
// Unpack decodes r from b.
func (r *Resource) Unpack(b []byte, dec Decompressor) ([]byte, error) {
var err error
if r.Name, b, err = dec.Unpack(b); err != nil {
return nil, err
}
if len(b) < 10 {
return nil, errResourceLen
}
rtype := Type(nbo.Uint16(b[:2]))
r.Class = Class(nbo.Uint16(b[2:4]))
r.TTL = time.Duration(nbo.Uint32(b[4:8])) * time.Second
rdlen, b := int(nbo.Uint16(b[8:10])), b[10:]
if len(b) < rdlen {
return nil, errResourceLen
}
newfn, ok := NewRecordByType[rtype]
if !ok {
return nil, errUnknownType
}
record := newfn()
buf, err := record.Unpack(b[:rdlen], dec)
if err != nil {
return nil, err
}
if len(buf) > 0 {
return nil, errResTooLong
}
r.Record = record
return b[rdlen:], nil
}
// Record is a DNS record.
type Record interface {
Type() Type
Length(Compressor) int
Pack([]byte, Compressor) ([]byte, error)
Unpack([]byte, Decompressor) ([]byte, error)
}
// A A is a DNS A record.
type A struct {
A net.IP
}
// Type returns the RR type identifier.
func (A) Type() Type { return TypeA }
// Length returns the encoded RDATA size.
func (A) Length(Compressor) int { return 4 }
// Pack encodes a as RDATA.
func (a A) Pack(b []byte, _ Compressor) ([]byte, error) {
if len(a.A) < 4 {
return nil, errResourceLen
}
return append(b, a.A.To4()...), nil
}
// Unpack decodes a from RDATA in b.
func (a *A) Unpack(b []byte, _ Decompressor) ([]byte, error) {
if len(b) < 4 {
return nil, errResourceLen
}
if len(a.A) != 4 {
a.A = make([]byte, 4)
}
copy(a.A, b[:4])
return b[4:], nil
}
// AAAA is a DNS AAAA record.
type AAAA struct {
AAAA net.IP
}
// Type returns the RR type identifier.
func (AAAA) Type() Type { return TypeAAAA }
// Length returns the encoded RDATA size.
func (AAAA) Length(Compressor) int { return 16 }
// Pack encodes a as RDATA.
func (a AAAA) Pack(b []byte, _ Compressor) ([]byte, error) {
if len(a.AAAA) != 16 {
return nil, errResourceLen
}
return append(b, a.AAAA...), nil
}
// Unpack decodes a from RDATA in b.
func (a *AAAA) Unpack(b []byte, _ Decompressor) ([]byte, error) {
if len(b) < 16 {
return nil, errResourceLen
}
if len(a.AAAA) != 16 {
a.AAAA = make([]byte, 16)
}
copy(a.AAAA, b[:16])
return b[16:], nil
}
// CNAME is a DNS CNAME record.
type CNAME struct {
CNAME string
}
// Type returns the RR type identifier.
func (CNAME) Type() Type { return TypeCNAME }
// Length returns the encoded RDATA size.
func (c CNAME) Length(com Compressor) int {
return com.Length(c.CNAME)
}
// Pack encodes c as RDATA.
func (c CNAME) Pack(b []byte, com Compressor) ([]byte, error) {
return com.Pack(b, c.CNAME)
}
// Unpack decodes c from RDATA in b.
func (c *CNAME) Unpack(b []byte, dec Decompressor) ([]byte, error) {
var err error
c.CNAME, b, err = dec.Unpack(b)
return b, err
}
// SOA is a DNS SOA record.
type SOA struct {
NS string
MBox string
Serial int
Refresh time.Duration
Retry time.Duration
Expire time.Duration
MinTTL time.Duration
}
// Type returns the RR type identifier.
func (SOA) Type() Type { return TypeSOA }
// Length returns the encoded RDATA size.
func (s SOA) Length(com Compressor) int {
return com.Length(s.NS, s.MBox) + 20
}
// Pack encodes s as RDATA.
func (s SOA) Pack(b []byte, com Compressor) ([]byte, error) {
var err error
if b, err = com.Pack(b, s.NS); err != nil {
return nil, err
}
if b, err = com.Pack(b, s.MBox); err != nil {
return nil, err
}
var (
serial = uint32(s.Serial)
refresh = int32(s.Refresh / time.Second)
retry = int32(s.Retry / time.Second)
expire = int32(s.Expire / time.Second)
minimum = uint32(s.MinTTL / time.Second)
)
if int(serial) != s.Serial {
return nil, errFieldOverflow
}
if time.Duration(refresh) != s.Refresh/time.Second {
return nil, errFieldOverflow
}
if time.Duration(retry) != s.Retry/time.Second {
return nil, errFieldOverflow
}
if time.Duration(expire) != s.Expire/time.Second {
return nil, errFieldOverflow
}
if time.Duration(minimum) != s.MinTTL/time.Second {
return nil, errFieldOverflow
}
buf := [20]byte{}
nbo.PutUint32(buf[:4], serial)
nbo.PutUint32(buf[4:8], uint32(refresh))
nbo.PutUint32(buf[8:12], uint32(retry))
nbo.PutUint32(buf[12:16], uint32(expire))
nbo.PutUint32(buf[16:], minimum)
return append(b, buf[:]...), nil
}
// Unpack decodes s from RDATA in b.
func (s *SOA) Unpack(b []byte, dec Decompressor) ([]byte, error) {
var err error
if s.NS, b, err = dec.Unpack(b); err != nil {
return nil, err
}
if s.MBox, b, err = dec.Unpack(b); err != nil {
return nil, err
}
if len(b) < 20 {
return nil, errResourceLen
}
var (
serial = nbo.Uint32(b[:4])
refresh = int32(nbo.Uint32(b[4:8]))
retry = int32(nbo.Uint32(b[8:12]))
expire = int32(nbo.Uint32(b[12:16]))
minimum = nbo.Uint32(b[16:20])
)
s.Serial = int(serial)
s.Refresh = time.Duration(refresh) * time.Second
s.Retry = time.Duration(retry) * time.Second
s.Expire = time.Duration(expire) * time.Second
s.MinTTL = time.Duration(minimum) * time.Second
return b[20:], nil
}
// PTR is a DNS PTR record.
type PTR struct {
PTR string
}
// Type returns the RR type identifier.
func (PTR) Type() Type { return TypePTR }
// Length returns the encoded RDATA size.
func (p PTR) Length(com Compressor) int {
return com.Length(p.PTR)
}
// Pack encodes p as RDATA.
func (p PTR) Pack(b []byte, com Compressor) ([]byte, error) {
return com.Pack(b, p.PTR)
}
// Unpack decodes p from RDATA in b.
func (p *PTR) Unpack(b []byte, dec Decompressor) ([]byte, error) {
var err error
p.PTR, b, err = dec.Unpack(b)
return b, err
}
// MX is a DNS MX record.
type MX struct {
Pref int
MX string
}
// Type returns the RR type identifier.
func (MX) Type() Type { return TypeMX }
// Length returns the encoded RDATA size.
func (m MX) Length(com Compressor) int {
return 2 + com.Length(m.MX)
}
// Pack encodes m as RDATA.
func (m MX) Pack(b []byte, com Compressor) ([]byte, error) {
pref := uint16(m.Pref)
if int(pref) != m.Pref {
return nil, errFieldOverflow
}
buf := [2]byte{}
nbo.PutUint16(buf[:], pref)
return com.Pack(append(b, buf[:]...), m.MX)
}
// Unpack decodes m from RDATA in b.
func (m *MX) Unpack(b []byte, dec Decompressor) ([]byte, error) {
if len(b) < 2 {
return nil, errResourceLen
}
m.Pref = int(nbo.Uint16(b[:2]))
var err error
m.MX, b, err = dec.Unpack(b[2:])
return b, err
}
// NS is a DNS MX record.
type NS struct {
NS string
}
// Type returns the RR type identifier.
func (NS) Type() Type { return TypeNS }
// Length returns the encoded RDATA size.
func (n NS) Length(com Compressor) int {
return com.Length(n.NS)
}
// Pack encodes n as RDATA.
func (n NS) Pack(b []byte, com Compressor) ([]byte, error) {
return com.Pack(b, n.NS)
}
// Unpack decodes n from RDATA in b.
func (n *NS) Unpack(b []byte, dec Decompressor) ([]byte, error) {
var err error
n.NS, b, err = dec.Unpack(b)
return b, err
}
// TXT is a DNS TXT record.
type TXT struct {
TXT []string
}
// Type returns the RR type identifier.
func (TXT) Type() Type { return TypeTXT }
// Length returns the encoded RDATA size.
func (t TXT) Length(_ Compressor) int {
var n int
for _, s := range t.TXT {
n += 1 + len(s)
}
return n
}
// Pack encodes t as RDATA.
func (t TXT) Pack(b []byte, _ Compressor) ([]byte, error) {
for _, s := range t.TXT {
if len(s) > 255 {
return nil, errSegTooLong
}
b = append(append(b, byte(len(s))), []byte(s)...)
}
return b, nil
}
// Unpack decodes t from RDATA in b.
func (t *TXT) Unpack(b []byte, _ Decompressor) ([]byte, error) {
var txts []string
for len(b) > 0 {
txtlen := int(b[0])
if len(b) < txtlen+1 {
return nil, errResourceLen
}
txts = append(txts, string(b[1:1+txtlen]))
b = b[1+txtlen:]
}
t.TXT = txts
return nil, nil
}
// SRV is a DNS SRV record.
type SRV struct {
Priority int
Weight int
Port int
Target string // Not compressed as per RFC 2782.
}
// Type returns the RR type identifier.
func (SRV) Type() Type { return TypeSRV }
// Length returns the encoded RDATA size.
func (s SRV) Length(_ Compressor) int {
return 6 + compressor{}.Length(s.Target)
}
// Pack encodes s as RDATA.
func (s SRV) Pack(b []byte, _ Compressor) ([]byte, error) {
var (
priority = uint16(s.Priority)
weight = uint16(s.Weight)
port = uint16(s.Port)
)
if int(priority) != s.Priority {
return nil, errFieldOverflow
}
if int(weight) != s.Weight {
return nil, errFieldOverflow
}
if int(port) != s.Port {
return nil, errFieldOverflow
}
buf := [6]byte{}
nbo.PutUint16(buf[:2], priority)
nbo.PutUint16(buf[2:4], weight)
nbo.PutUint16(buf[4:], port)
return compressor{}.Pack(append(b, buf[:]...), s.Target)
}
// Unpack decodes s from RDATA in b.
func (s *SRV) Unpack(b []byte, _ Decompressor) ([]byte, error) {
if len(b) < 6 {
return nil, errResourceLen
}
s.Priority = int(nbo.Uint16(b[:2]))
s.Weight = int(nbo.Uint16(b[2:4]))
s.Port = int(nbo.Uint16(b[4:6]))
var err error
s.Target, b, err = decompressor(nil).Unpack(b[6:])
return b, err
}

62
vendor/github.com/benburkert/dns/messagewriter.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
package dns
import (
"context"
"time"
)
// MessageWriter is used by a DNS handler to serve a DNS query.
type MessageWriter interface {
// Authoritative sets the Authoritative Answer (AA) bit of the header.
Authoritative(bool)
// Recursion sets the Recursion Available (RA) bit of the header.
Recursion(bool)
// Status sets the Response code (RCODE) bits of the header.
Status(RCode)
// Answer adds a record to the answers section.
Answer(string, time.Duration, Record)
// Authority adds a record to the authority section.
Authority(string, time.Duration, Record)
// Additional adds a record to the additional section
Additional(string, time.Duration, Record)
// Recur forwards the request query upstream, and returns the response
// message or error.
Recur(context.Context) (*Message, error)
// Reply sends the response message.
//
// For large messages sent over a UDP connection, an ErrTruncatedMessage
// error is returned if the message was truncated.
Reply(context.Context) error
}
type messageWriter struct {
msg *Message
}
func (w *messageWriter) Authoritative(aa bool) { w.msg.Authoritative = aa }
func (w *messageWriter) Recursion(ra bool) { w.msg.RecursionAvailable = ra }
func (w *messageWriter) Status(rc RCode) { w.msg.RCode = rc }
func (w *messageWriter) Answer(fqdn string, ttl time.Duration, rec Record) {
w.msg.Answers = append(w.msg.Answers, w.rr(fqdn, ttl, rec))
}
func (w *messageWriter) Authority(fqdn string, ttl time.Duration, rec Record) {
w.msg.Authorities = append(w.msg.Authorities, w.rr(fqdn, ttl, rec))
}
func (w *messageWriter) Additional(fqdn string, ttl time.Duration, rec Record) {
w.msg.Additionals = append(w.msg.Additionals, w.rr(fqdn, ttl, rec))
}
func (w *messageWriter) rr(fqdn string, ttl time.Duration, rec Record) Resource {
return Resource{
Name: fqdn,
Class: ClassIN,
TTL: ttl,
Record: rec,
}
}

78
vendor/github.com/benburkert/dns/nameservers.go generated vendored Normal file
View File

@ -0,0 +1,78 @@
package dns
import (
"context"
cryptorand "crypto/rand"
"errors"
"io"
"math/big"
"net"
"sync/atomic"
)
// NameServers is a slice of DNS nameserver addresses.
type NameServers []net.Addr
// Random picks a random Addr from s every time.
func (s NameServers) Random(rand io.Reader) ProxyFunc {
addrsByNet := s.netAddrsMap()
maxByNet := make(map[string]*big.Int, len(addrsByNet))
for network, addrs := range addrsByNet {
maxByNet[network] = big.NewInt(int64(len(addrs)))
}
return func(_ context.Context, addr net.Addr) (net.Addr, error) {
network := addr.Network()
max, ok := maxByNet[network]
if !ok {
return nil, errors.New("no nameservers for network: " + network)
}
addrs, ok := addrsByNet[network]
if !ok {
panic("impossible")
}
idx, err := cryptorand.Int(rand, max)
if err != nil {
return nil, err
}
return addrs[idx.Uint64()], nil
}
}
// RoundRobin picks the next Addr of s by index of the last pick.
func (s NameServers) RoundRobin() ProxyFunc {
addrsByNet := s.netAddrsMap()
idxByNet := make(map[string]*uint32, len(s))
for network := range addrsByNet {
idxByNet[network] = new(uint32)
}
return func(_ context.Context, addr net.Addr) (net.Addr, error) {
network := addr.Network()
idx, ok := idxByNet[network]
if !ok {
return nil, errors.New("no nameservers for network: " + network)
}
addrs, ok := addrsByNet[network]
if !ok {
panic("impossible")
}
return addrs[int(atomic.AddUint32(idx, 1)-1)%len(addrs)], nil
}
}
func (s NameServers) netAddrsMap() map[string][]net.Addr {
addrsByNet := make(map[string][]net.Addr, len(s))
for _, addr := range s {
network := addr.Network()
addrsByNet[network] = append(addrsByNet[network], addr)
}
return addrsByNet
}

158
vendor/github.com/benburkert/dns/pipeline.go generated vendored Normal file
View File

@ -0,0 +1,158 @@
package dns
import (
"io"
"sync"
"time"
)
type pipeline struct {
Conn
rmu, wmu sync.Mutex
mu sync.Mutex
inflight map[int]pipelineTx
readerr error
}
func (p *pipeline) alive() bool {
p.mu.Lock()
defer p.mu.Unlock()
return p.readerr == nil
}
func (p *pipeline) conn() Conn {
return &pipelineConn{
pipeline: p,
tx: pipelineTx{
msgerrc: make(chan msgerr),
abortc: make(chan struct{}),
},
}
}
func (p *pipeline) run() {
var err error
for {
var msg Message
p.rmu.Lock()
if err = p.Recv(&msg); err != nil {
break
}
p.rmu.Unlock()
p.mu.Lock()
tx, ok := p.inflight[msg.ID]
delete(p.inflight, msg.ID)
p.mu.Unlock()
if !ok {
continue
}
go tx.deliver(msgerr{msg: &msg})
}
p.rmu.Unlock()
p.mu.Lock()
p.readerr = err
txs := make([]pipelineTx, 0, len(p.inflight))
for _, tx := range p.inflight {
txs = append(txs, tx)
}
p.mu.Unlock()
for _, tx := range txs {
go tx.deliver(msgerr{err: err})
}
}
type pipelineConn struct {
*pipeline
aborto sync.Once
tx pipelineTx
readDeadline, writeDeadline time.Time
}
func (c *pipelineConn) Close() error {
c.aborto.Do(c.tx.abort)
return nil
}
func (c *pipelineConn) Recv(msg *Message) error {
var me msgerr
select {
case me = <-c.tx.msgerrc:
case <-c.tx.abortc:
return io.ErrUnexpectedEOF
}
if err := me.err; err != nil {
return err
}
*msg = *me.msg // shallow copy
return nil
}
func (c *pipelineConn) Send(msg *Message) error {
if err := c.register(msg); err != nil {
return err
}
c.wmu.Lock()
defer c.wmu.Unlock()
if err := c.Conn.SetWriteDeadline(c.writeDeadline); err != nil {
return err
}
return c.Conn.Send(msg)
}
func (c *pipelineConn) SetDeadline(t time.Time) error {
c.SetReadDeadline(t)
c.SetWriteDeadline(t)
return nil
}
func (c *pipelineConn) SetReadDeadline(t time.Time) error {
c.readDeadline = t
return nil
}
func (c *pipelineConn) SetWriteDeadline(t time.Time) error {
c.writeDeadline = t
return nil
}
func (c *pipelineConn) register(msg *Message) error {
c.mu.Lock()
defer c.mu.Unlock()
if _, ok := c.inflight[msg.ID]; ok {
return ErrConflictingID
}
c.inflight[msg.ID] = c.tx
return nil
}
type pipelineTx struct {
msgerrc chan msgerr
abortc chan struct{}
}
func (p pipelineTx) abort() { close(p.abortc) }
func (p pipelineTx) deliver(me msgerr) {
select {
case p.msgerrc <- me:
case <-p.abortc:
}
}

370
vendor/github.com/benburkert/dns/server.go generated vendored Normal file
View File

@ -0,0 +1,370 @@
package dns
import (
"bufio"
"context"
"crypto/tls"
"io"
"log"
"net"
"sync"
)
// A Server defines parameters for running a DNS server. The zero value for
// Server is a valid configuration.
type Server struct {
Addr string // TCP and UDP address to listen on, ":domain" if empty
Handler Handler // handler to invoke
TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS
// Forwarder relays a recursive query. If nil, recursive queries are
// answered with a "Query Refused" message.
Forwarder RoundTripper
// ErrorLog specifies an optional logger for errors accepting connections,
// reading data, and unpacking messages.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
}
// ListenAndServe listens on both the TCP and UDP network address s.Addr and
// then calls Serve or ServePacket to handle queries on incoming connections.
// If srv.Addr is blank, ":domain" is used. ListenAndServe always returns a
// non-nil error.
func (s *Server) ListenAndServe(ctx context.Context) error {
addr := s.Addr
if addr == "" {
addr = ":domain"
}
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
conn, err := net.ListenPacket("udp", addr)
if err != nil {
return err
}
errc := make(chan error, 1)
go func() { errc <- s.Serve(ctx, ln) }()
go func() { errc <- s.ServePacket(ctx, conn) }()
return <-errc
}
// ListenAndServeTLS listens on the TCP network address s.Addr and then calls
// Serve to handle requests on incoming TLS connections.
//
// If s.Addr is blank, ":853" is used.
//
// ListenAndServeTLS always returns a non-nil error.
func (s *Server) ListenAndServeTLS(ctx context.Context) error {
addr := s.Addr
if addr == "" {
addr = ":domain"
}
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return s.ServeTLS(ctx, ln)
}
// Serve accepts incoming connections on the Listener ln, creating a new
// service goroutine for each. The service goroutines read TCP encoded queries
// and then call s.Handler to reply to them.
//
// See RFC 1035, section 4.2.2 "TCP usage" for transport encoding of messages.
//
// Serve always returns a non-nil error.
func (s *Server) Serve(ctx context.Context, ln net.Listener) error {
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
return err
}
go s.serveStream(ctx, conn)
}
}
// ServePacket reads UDP encoded queries from the PacketConn conn, creating a
// new service goroutine for each. The service goroutines call s.Handler to
// reply.
//
// See RFC 1035, section 4.2.1 "UDP usage" for transport encoding of messages.
//
// ServePacket always returns a non-nil error.
func (s *Server) ServePacket(ctx context.Context, conn net.PacketConn) error {
defer conn.Close()
for {
buf := make([]byte, maxPacketLen)
n, addr, err := conn.ReadFrom(buf)
if err != nil {
return err
}
req := &Query{
Message: new(Message),
RemoteAddr: addr,
}
if buf, err = req.Message.Unpack(buf[:n]); err != nil {
s.logf("dns unpack: %s", err.Error())
continue
}
if len(buf) != 0 {
s.logf("dns unpack: malformed packet, extra message bytes")
continue
}
pw := &packetWriter{
messageWriter: &messageWriter{
msg: response(req.Message),
},
addr: addr,
conn: conn,
}
go s.handle(ctx, pw, req)
}
}
// ServeTLS accepts incoming connections on the Listener ln, creating a new
// service goroutine for each. The service goroutines read TCP encoded queries
// over a TLS channel and then call s.Handler to reply to them, in another
// service goroutine.
//
// See RFC 7858, section 3.3 for transport encoding of messages.
//
// ServeTLS always returns a non-nil error.
func (s *Server) ServeTLS(ctx context.Context, ln net.Listener) error {
ln = tls.NewListener(ln, s.TLSConfig.Clone())
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
return err
}
go func(conn net.Conn) {
if err := conn.(*tls.Conn).Handshake(); err != nil {
s.logf("dns handshake: %s", err.Error())
return
}
s.serveStream(ctx, conn)
}(conn)
}
}
func (s *Server) serveStream(ctx context.Context, conn net.Conn) {
var (
rbuf = bufio.NewReader(conn)
lbuf [2]byte
mu sync.Mutex
)
for {
if _, err := rbuf.Read(lbuf[:]); err != nil {
if err != io.EOF {
s.logf("dns read: %s", err.Error())
}
return
}
buf := make([]byte, int(nbo.Uint16(lbuf[:])))
if _, err := io.ReadFull(rbuf, buf); err != nil {
s.logf("dns read: %s", err.Error())
return
}
req := &Query{
Message: new(Message),
RemoteAddr: conn.RemoteAddr(),
}
var err error
if buf, err = req.Message.Unpack(buf); err != nil {
s.logf("dns unpack: %s", err.Error())
continue
}
if len(buf) != 0 {
s.logf("dns unpack: malformed packet, extra message bytes")
continue
}
sw := streamWriter{
messageWriter: &messageWriter{
msg: response(req.Message),
},
mu: &mu,
conn: conn,
}
go s.handle(ctx, sw, req)
}
}
func (s *Server) handle(ctx context.Context, w MessageWriter, r *Query) {
sw := &serverWriter{
MessageWriter: w,
forwarder: s.Forwarder,
query: r,
}
s.Handler.ServeDNS(ctx, sw, r)
if !sw.replied {
if err := sw.Reply(ctx); err != nil {
s.logf("dns: %s", err.Error())
}
}
}
func (s *Server) logf(format string, args ...interface{}) {
printf := log.Printf
if s.ErrorLog != nil {
printf = s.ErrorLog.Printf
}
printf(format, args...)
}
type packetWriter struct {
*messageWriter
addr net.Addr
conn net.PacketConn
}
func (w packetWriter) Recur(ctx context.Context) (*Message, error) {
return nil, ErrUnsupportedOp
}
func (w packetWriter) Reply(ctx context.Context) error {
buf, err := w.msg.Pack(nil, true)
if err != nil {
return err
}
if len(buf) > maxPacketLen {
return w.truncate(buf)
}
_, err = w.conn.WriteTo(buf, w.addr)
return err
}
func (w packetWriter) truncate(buf []byte) error {
var err error
if buf, err = truncate(buf, maxPacketLen); err != nil {
return err
}
if _, err := w.conn.WriteTo(buf, w.addr); err != nil {
return err
}
return ErrTruncatedMessage
}
type streamWriter struct {
*messageWriter
mu *sync.Mutex
conn net.Conn
}
func (w streamWriter) Recur(ctx context.Context) (*Message, error) {
return nil, ErrUnsupportedOp
}
func (w streamWriter) Reply(ctx context.Context) error {
buf, err := w.msg.Pack(make([]byte, 2), true)
if err != nil {
return err
}
blen := uint16(len(buf) - 2)
if int(blen) != len(buf)-2 {
return ErrOversizedMessage
}
nbo.PutUint16(buf[:2], blen)
w.mu.Lock()
defer w.mu.Unlock()
_, err = w.conn.Write(buf)
return err
}
type serverWriter struct {
MessageWriter
forwarder RoundTripper
query *Query
replied bool
}
func (w serverWriter) Recur(ctx context.Context) (*Message, error) {
query := &Query{
Message: request(w.query.Message),
RemoteAddr: w.query.RemoteAddr,
}
qs := make([]Question, 0, len(w.query.Questions))
for _, q := range w.query.Questions {
if !questionMatched(q, query.Message) {
qs = append(qs, q)
}
}
query.Questions = qs
return w.forward(ctx, query)
}
func (w serverWriter) Reply(ctx context.Context) error {
w.replied = true
return w.MessageWriter.Reply(ctx)
}
func response(msg *Message) *Message {
res := new(Message)
*res = *msg // shallow copy
res.Response = true
return res
}
var refuser = &Client{
Transport: nopDialer{},
Resolver: HandlerFunc(Refuse),
}
func (w serverWriter) forward(ctx context.Context, query *Query) (*Message, error) {
if w.forwarder != nil {
return w.forwarder.Do(ctx, query)
}
return refuser.Do(ctx, query)
}
type nopDialer struct{}
func (nopDialer) DialAddr(ctx context.Context, addr net.Addr) (Conn, error) {
return nil, nil
}

171
vendor/github.com/benburkert/dns/session.go generated vendored Normal file
View File

@ -0,0 +1,171 @@
package dns
import (
"context"
"io"
"net"
)
type packetSession struct {
session
}
func (s *packetSession) Read(b []byte) (int, error) {
msg, err := s.recv()
if err != nil {
return 0, err
}
buf, err := msg.Pack(b[:0:len(b)], true)
if err != nil {
return 0, err
}
if len(buf) > len(b) {
if buf, err = truncate(buf, len(b)); err != nil {
return 0, err
}
copy(b, buf)
return len(buf), nil
}
return len(buf), nil
}
func (s *packetSession) ReadFrom(b []byte) (int, net.Addr, error) {
n, err := s.Read(b)
return n, s.addr, err
}
func (s *packetSession) Write(b []byte) (int, error) {
msg := new(Message)
if _, err := msg.Unpack(b); err != nil {
return 0, err
}
query := &Query{
RemoteAddr: s.addr,
Message: msg,
}
go s.do(query)
return len(b), nil
}
func (s *packetSession) WriteTo(b []byte, addr net.Addr) (int, error) {
return s.Write(b)
}
type streamSession struct {
session
rbuf []byte
}
func (s *streamSession) Read(b []byte) (int, error) {
if len(s.rbuf) > 0 {
return s.read(b)
}
msg, err := s.recv()
if err != nil {
return 0, err
}
if s.rbuf, err = msg.Pack(s.rbuf[:0], true); err != nil {
return 0, err
}
mlen := uint16(len(s.rbuf))
if int(mlen) != len(s.rbuf) {
return 0, ErrOversizedMessage
}
nbo.PutUint16(b, mlen)
if len(b) == 2 {
return 2, nil
}
n, err := s.read(b[2:])
return 2 + n, err
}
func (s *streamSession) read(b []byte) (int, error) {
if len(s.rbuf) > len(b) {
copy(b, s.rbuf[:len(b)])
s.rbuf = s.rbuf[len(b):]
return len(b), nil
}
n := len(s.rbuf)
copy(b, s.rbuf)
s.rbuf = s.rbuf[:0]
return n, nil
}
func (s streamSession) Write(b []byte) (int, error) {
if len(b) < 2 {
return 0, io.ErrShortWrite
}
mlen := nbo.Uint16(b[:2])
buf := b[2:]
if int(mlen) != len(buf) {
return 0, io.ErrShortWrite
}
msg := new(Message)
if _, err := msg.Unpack(buf); err != nil {
return 0, err
}
query := &Query{
RemoteAddr: s.addr,
Message: msg,
}
go s.do(query)
return len(b), nil
}
type session struct {
Conn
addr net.Addr
client *Client
msgerrc chan msgerr
}
type msgerr struct {
msg *Message
err error
}
func (s session) do(query *Query) {
msg, err := s.client.do(context.Background(), s.Conn, query)
s.msgerrc <- msgerr{msg, err}
}
func (s session) recv() (*Message, error) {
me, ok := <-s.msgerrc
if !ok {
panic("impossible")
}
return me.msg, me.err
}
func truncate(buf []byte, maxPacketLength int) ([]byte, error) {
msg := new(Message)
if _, err := msg.Unpack(buf[:maxPacketLen]); err != nil {
if err != errResourceLen && err != errBaseLen {
return nil, err
}
}
msg.Truncated = true
return msg.Pack(buf[:0], true)
}

149
vendor/github.com/benburkert/dns/transport.go generated vendored Normal file
View File

@ -0,0 +1,149 @@
package dns
import (
"context"
"crypto/tls"
"net"
"strings"
"sync"
)
// Transport is an implementation of AddrDialer that manages connections to DNS
// servers. Transport may modify the sending and receiving of messages but does
// not modify messages.
type Transport struct {
TLSConfig *tls.Config // optional TLS config, used by DialAddr
// DialContext func creates the underlying net connection. The DialContext
// method of a new net.Dialer is used by default.
DialContext func(context.Context, string, string) (net.Conn, error)
// Proxy modifies the address of the DNS server to dial.
Proxy ProxyFunc
// DisablePipelining disables query pipelining for stream oriented
// connections as defined in RFC 7766, section 6.2.1.1.
DisablePipelining bool
plinemu sync.Mutex
plines map[net.Addr]*pipeline
}
// DialAddr dials a net Addr and returns a Conn.
func (t *Transport) DialAddr(ctx context.Context, addr net.Addr) (Conn, error) {
if !t.DisablePipelining {
if pline := t.getPipeline(addr); pline != nil && pline.alive() {
return pline.conn(), nil
}
}
conn, err := t.dialAddr(ctx, addr)
if err != nil {
return nil, err
}
return conn, nil
}
func (t *Transport) dialAddr(ctx context.Context, addr net.Addr) (Conn, error) {
conn, dnsOverTLS, err := t.dial(ctx, addr)
if err != nil {
return nil, err
}
if conn, ok := conn.(Conn); ok {
return conn, nil
}
if _, ok := conn.(*tls.Conn); dnsOverTLS && !ok {
ipaddr, _, err := net.SplitHostPort(addr.String())
if err != nil {
return nil, err
}
cfg := &tls.Config{ServerName: ipaddr}
if t.TLSConfig != nil {
cfg = t.TLSConfig.Clone()
}
conn = tls.Client(conn, cfg)
if err := conn.(*tls.Conn).Handshake(); err != nil {
return nil, err
}
}
if _, ok := conn.(net.PacketConn); ok {
return &PacketConn{
Conn: conn,
}, nil
}
sconn := &StreamConn{
Conn: conn,
}
if !t.DisablePipelining {
pline := t.setPipeline(addr, sconn)
return pline.conn(), nil
}
return sconn, nil
}
var defaultDialer = &net.Dialer{
Resolver: &net.Resolver{},
}
func (t *Transport) dial(ctx context.Context, addr net.Addr) (net.Conn, bool, error) {
if t.Proxy != nil {
var err error
if addr, err = t.Proxy(ctx, addr); err != nil {
return nil, false, err
}
}
network, dnsOverTLS := addr.Network(), false
if strings.HasSuffix(network, "-tls") {
network, dnsOverTLS = network[:len(network)-4], true
}
dial := t.DialContext
if dial == nil {
dial = defaultDialer.DialContext
}
conn, err := dial(ctx, network, addr.String())
if err != nil {
return nil, false, err
}
return conn, dnsOverTLS, err
}
func (t *Transport) getPipeline(addr net.Addr) *pipeline {
t.plinemu.Lock()
defer t.plinemu.Unlock()
if t.plines == nil {
t.plines = make(map[net.Addr]*pipeline)
}
return t.plines[addr]
}
func (t *Transport) setPipeline(addr net.Addr, conn Conn) *pipeline {
pline := &pipeline{
Conn: conn,
inflight: make(map[int]pipelineTx),
}
go pline.run()
t.plinemu.Lock()
defer t.plinemu.Unlock()
if t.plines == nil {
t.plines = make(map[net.Addr]*pipeline)
}
t.plines[addr] = pline
return pline
}

63
vendor/github.com/benburkert/dns/zone.go generated vendored Normal file
View File

@ -0,0 +1,63 @@
package dns
import (
"context"
"strings"
"time"
)
// RRSet is a set of resource records indexed by name and type.
type RRSet map[string]map[Type][]Record
// Zone is a contiguous set DNS records under an origin domain name.
type Zone struct {
Origin string
TTL time.Duration
SOA *SOA
RRs RRSet
}
// ServeDNS answers DNS queries in zone z.
func (z *Zone) ServeDNS(ctx context.Context, w MessageWriter, r *Query) {
w.Authoritative(true)
var found bool
for _, q := range r.Questions {
if !strings.HasSuffix(q.Name, z.Origin) {
continue
}
dn := q.Name[:len(q.Name)-len(z.Origin)-1]
rrs, ok := z.RRs[dn]
if !ok {
continue
}
for _, rr := range rrs[q.Type] {
w.Answer(q.Name, z.TTL, rr)
found = true
if r.RecursionDesired && rr.Type() == TypeCNAME {
name := rr.(*CNAME).CNAME
dn := name[:len(name)-len(z.Origin)-1]
if rrs, ok := z.RRs[dn]; ok {
for _, rr := range rrs[q.Type] {
w.Answer(name, z.TTL, rr)
}
}
}
}
}
if !found {
w.Status(NXDomain)
if z.SOA != nil {
w.Authority(z.Origin, z.TTL, z.SOA)
}
}
}

View File

@ -0,0 +1,22 @@
# 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

View File

@ -0,0 +1,5 @@
language: go
sudo: false
go:
- 1.7
- tip

20
vendor/github.com/lestrrat-go/file-rotatelogs/LICENSE generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2014 lestrrat
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.

190
vendor/github.com/lestrrat-go/file-rotatelogs/README.md generated vendored Normal file
View File

@ -0,0 +1,190 @@
file-rotatelogs
==================
Periodically rotates log files from within the application. Port of [File::RotateLogs](https://metacpan.org/release/File-RotateLogs) from Perl to Go.
[![Build Status](https://travis-ci.org/lestrrat-go/file-rotatelogs.png?branch=master)](https://travis-ci.org/lestrrat-go/file-rotatelogs)
[![GoDoc](https://godoc.org/github.com/lestrrat-go/file-rotatelogs?status.svg)](https://godoc.org/github.com/lestrrat-go/file-rotatelogs)
# SYNOPSIS
```go
import (
"log"
"net/http"
apachelog "github.com/lestrrat-go/apache-logformat"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { ... })
logf, err := rotatelogs.New(
"/path/to/access_log.%Y%m%d%H%M",
rotatelogs.WithLinkName("/path/to/access_log"),
rotatelogs.WithMaxAge(24 * time.Hour),
rotatelogs.WithRotationTime(time.Hour),
)
if err != nil {
log.Printf("failed to create rotatelogs: %s", err)
return
}
http.ListenAndServe(":8080", apachelog.Wrap(mux, logf))
}
```
# DESCRIPTION
When you integrate this to to you app, it automatically write to logs that
are rotated from within the app: No more disk-full alerts because you forgot
to setup logrotate!
To install, simply issue a `go get`:
```
go get github.com/lestrrat-go/file-rotatelogs
```
It's normally expected that this library is used with some other
logging service, such as the built-in `log` library, or loggers
such as `github.com/lestrrat-go/apache-logformat`.
```go
import(
"log"
"github.com/lestrrat-go/file-rotatelogs"
)
func main() {
rl, _ := rotatelogs.New("/path/to/access_log.%Y%m%d%H%M")
log.SetOutput(rl)
/* elsewhere ... */
log.Printf("Hello, World!")
}
```
OPTIONS
====
## Pattern (Required)
The pattern used to generate actual log file names. You should use patterns
using the strftime (3) format. For example:
```go
rotatelogs.New("/var/log/myapp/log.%Y%m%d")
```
## Clock (default: rotatelogs.Local)
You may specify an object that implements the roatatelogs.Clock interface.
When this option is supplied, it's used to determine the current time to
base all of the calculations on. For example, if you want to base your
calculations in UTC, you may specify rotatelogs.UTC
```go
rotatelogs.New(
"/var/log/myapp/log.%Y%m%d",
rotatelogs.WithClock(rotatelogs.UTC),
)
```
## Location
This is an alternative to the `WithClock` option. Instead of providing an
explicit clock, you can provide a location for you times. We will create
a Clock object that produces times in your specified location, and configure
the rotatelog to respect it.
## LinkName (default: "")
Path where a symlink for the actual log file is placed. This allows you to
always check at the same location for log files even if the logs were rotated
```go
rotatelogs.New(
"/var/log/myapp/log.%Y%m%d",
rotatelogs.WithLinkName("/var/log/myapp/current"),
)
```
```
// Else where
$ tail -f /var/log/myapp/current
```
If not provided, no link will be written.
## RotationTime (default: 86400 sec)
Interval between file rotation. By default logs are rotated every 86400 seconds.
Note: Remember to use time.Duration values.
```go
// Rotate every hour
rotatelogs.New(
"/var/log/myapp/log.%Y%m%d",
rotatelogs.WithRotationTime(time.Hour),
)
```
## MaxAge (default: 7 days)
Time to wait until old logs are purged. By default no logs are purged, which
certainly isn't what you want.
Note: Remember to use time.Duration values.
```go
// Purge logs older than 1 hour
rotatelogs.New(
"/var/log/myapp/log.%Y%m%d",
rotatelogs.WithMaxAge(time.Hour),
)
```
## RotationCount (default: -1)
The number of files should be kept. By default, this option is disabled.
Note: MaxAge should be disabled by specifing `WithMaxAge(-1)` explicitly.
```go
// Purge logs except latest 7 files
rotatelogs.New(
"/var/log/myapp/log.%Y%m%d",
rotatelogs.WithMaxAge(-1),
rotatelogs.WithRotationCount(7),
)
```
# Rotating files forcefully
If you want to rotate files forcefully before the actual rotation time has reached,
you may use the `Rotate()` method. This method forcefully rotates the logs, but
if the generated file name clashes, then a numeric suffix is added so that
the new file will forcefully appear on disk.
For example, suppose you had a pattern of '%Y.log' with a rotation time of
`86400` so that it only gets rotated every year, but for whatever reason you
wanted to rotate the logs now, you could install a signal handler to
trigger this rotation:
```go
rl := rotatelogs.New(...)
signal.Notify(ch, syscall.SIGHUP)
go func(ch chan os.Signal) {
<-ch
rl.Rotate()
}()
```
And you will get a log file name in like `2018.log.1`, `2018.log.2`, etc.

View File

@ -0,0 +1,47 @@
package rotatelogs
import (
"os"
"sync"
"time"
strftime "github.com/lestrrat-go/strftime"
)
// RotateLogs represents a log file that gets
// automatically rotated as you write to it.
type RotateLogs struct {
clock Clock
curFn string
globPattern string
generation int
linkName string
maxAge time.Duration
mutex sync.RWMutex
outFh *os.File
pattern *strftime.Strftime
rotationTime time.Duration
rotationCount uint
}
// Clock is the interface used by the RotateLogs
// object to determine the current time
type Clock interface {
Now() time.Time
}
type clockFn func() time.Time
// UTC is an object satisfying the Clock interface, which
// returns the current time in UTC
var UTC = clockFn(func() time.Time { return time.Now().UTC() })
// Local is an object satisfying the Clock interface, which
// returns the current time in the local timezone
var Local = clockFn(time.Now)
// Option is used to pass optional arguments to
// the RotateLogs constructor
type Option interface {
Name() string
Value() interface {}
}

View File

@ -0,0 +1,25 @@
package option
type Interface interface {
Name() string
Value() interface{}
}
type Option struct {
name string
value interface{}
}
func New(name string, value interface{}) *Option {
return &Option{
name: name,
value: value,
}
}
func (o *Option) Name() string {
return o.name
}
func (o *Option) Value() interface{} {
return o.value
}

View File

@ -0,0 +1,66 @@
package rotatelogs
import (
"time"
"github.com/lestrrat-go/file-rotatelogs/internal/option"
)
const (
optkeyClock = "clock"
optkeyLinkName = "link-name"
optkeyMaxAge = "max-age"
optkeyRotationTime = "rotation-time"
optkeyRotationCount = "rotation-count"
)
// WithClock creates a new Option that sets a clock
// that the RotateLogs object will use to determine
// the current time.
//
// By default rotatelogs.Local, which returns the
// current time in the local time zone, is used. If you
// would rather use UTC, use rotatelogs.UTC as the argument
// to this option, and pass it to the constructor.
func WithClock(c Clock) Option {
return option.New(optkeyClock, c)
}
// WithLocation creates a new Option that sets up a
// "Clock" interface that the RotateLogs object will use
// to determine the current time.
//
// This optin works by always returning the in the given
// location.
func WithLocation(loc *time.Location) Option {
return option.New(optkeyClock, clockFn(func() time.Time {
return time.Now().In(loc)
}))
}
// WithLinkName creates a new Option that sets the
// symbolic link name that gets linked to the current
// file name being used.
func WithLinkName(s string) Option {
return option.New(optkeyLinkName, s)
}
// WithMaxAge creates a new Option that sets the
// max age of a log file before it gets purged from
// the file system.
func WithMaxAge(d time.Duration) Option {
return option.New(optkeyMaxAge, d)
}
// WithRotationTime creates a new Option that sets the
// time between rotation.
func WithRotationTime(d time.Duration) Option {
return option.New(optkeyRotationTime, d)
}
// WithRotationCount creates a new Option that sets the
// number of files should be kept before it gets
// purged from the file system.
func WithRotationCount(n uint) Option {
return option.New(optkeyRotationCount, n)
}

View File

@ -0,0 +1,325 @@
// package rotatelogs is a port of File-RotateLogs from Perl
// (https://metacpan.org/release/File-RotateLogs), and it allows
// you to automatically rotate output files when you write to them
// according to the filename pattern that you can specify.
package rotatelogs
import (
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"time"
strftime "github.com/lestrrat-go/strftime"
"github.com/pkg/errors"
)
func (c clockFn) Now() time.Time {
return c()
}
// New creates a new RotateLogs object. A log filename pattern
// must be passed. Optional `Option` parameters may be passed
func New(p string, options ...Option) (*RotateLogs, error) {
globPattern := p
for _, re := range patternConversionRegexps {
globPattern = re.ReplaceAllString(globPattern, "*")
}
pattern, err := strftime.New(p)
if err != nil {
return nil, errors.Wrap(err, `invalid strftime pattern`)
}
var clock Clock = Local
rotationTime := 24 * time.Hour
var rotationCount uint
var linkName string
var maxAge time.Duration
for _, o := range options {
switch o.Name() {
case optkeyClock:
clock = o.Value().(Clock)
case optkeyLinkName:
linkName = o.Value().(string)
case optkeyMaxAge:
maxAge = o.Value().(time.Duration)
if maxAge < 0 {
maxAge = 0
}
case optkeyRotationTime:
rotationTime = o.Value().(time.Duration)
if rotationTime < 0 {
rotationTime = 0
}
case optkeyRotationCount:
rotationCount = o.Value().(uint)
}
}
if maxAge > 0 && rotationCount > 0 {
return nil, errors.New("options MaxAge and RotationCount cannot be both set")
}
if maxAge == 0 && rotationCount == 0 {
// if both are 0, give maxAge a sane default
maxAge = 7 * 24 * time.Hour
}
return &RotateLogs{
clock: clock,
globPattern: globPattern,
linkName: linkName,
maxAge: maxAge,
pattern: pattern,
rotationTime: rotationTime,
rotationCount: rotationCount,
}, nil
}
func (rl *RotateLogs) genFilename() string {
now := rl.clock.Now()
// XXX HACK: Truncate only happens in UTC semantics, apparently.
// observed values for truncating given time with 86400 secs:
//
// before truncation: 2018/06/01 03:54:54 2018-06-01T03:18:00+09:00
// after truncation: 2018/06/01 03:54:54 2018-05-31T09:00:00+09:00
//
// This is really annoying when we want to truncate in local time
// so we hack: we take the apparent local time in the local zone,
// and pretend that it's in UTC. do our math, and put it back to
// the local zone
var base time.Time
if now.Location() != time.UTC {
base = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), now.Nanosecond(), time.UTC)
base = base.Truncate(time.Duration(rl.rotationTime))
base = time.Date(base.Year(), base.Month(), base.Day(), base.Hour(), base.Minute(), base.Second(), base.Nanosecond(), base.Location())
} else {
base = now.Truncate(time.Duration(rl.rotationTime))
}
return rl.pattern.FormatString(base)
}
// Write satisfies the io.Writer interface. It writes to the
// appropriate file handle that is currently being used.
// If we have reached rotation time, the target file gets
// automatically rotated, and also purged if necessary.
func (rl *RotateLogs) Write(p []byte) (n int, err error) {
// Guard against concurrent writes
rl.mutex.Lock()
defer rl.mutex.Unlock()
out, err := rl.getWriter_nolock(false, false)
if err != nil {
return 0, errors.Wrap(err, `failed to acquite target io.Writer`)
}
return out.Write(p)
}
// must be locked during this operation
func (rl *RotateLogs) getWriter_nolock(bailOnRotateFail, useGenerationalNames bool) (io.Writer, error) {
generation := rl.generation
// This filename contains the name of the "NEW" filename
// to log to, which may be newer than rl.currentFilename
filename := rl.genFilename()
if rl.curFn != filename {
generation = 0
} else {
if !useGenerationalNames {
// nothing to do
return rl.outFh, nil
}
// This is used when we *REALLY* want to rotate a log.
// instead of just using the regular strftime pattern, we
// create a new file name using generational names such as
// "foo.1", "foo.2", "foo.3", etc
for {
generation++
name := fmt.Sprintf("%s.%d", filename, generation)
if _, err := os.Stat(name); err != nil {
filename = name
break
}
}
}
// if we got here, then we need to create a file
fh, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return nil, errors.Errorf("failed to open file %s: %s", rl.pattern, err)
}
if err := rl.rotate_nolock(filename); err != nil {
err = errors.Wrap(err, "failed to rotate")
if bailOnRotateFail {
// Failure to rotate is a problem, but it's really not a great
// idea to stop your application just because you couldn't rename
// your log.
// We only return this error when explicitly needed.
return nil, err
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
}
rl.outFh.Close()
rl.outFh = fh
rl.curFn = filename
rl.generation = generation
return fh, nil
}
// CurrentFileName returns the current file name that
// the RotateLogs object is writing to
func (rl *RotateLogs) CurrentFileName() string {
rl.mutex.RLock()
defer rl.mutex.RUnlock()
return rl.curFn
}
var patternConversionRegexps = []*regexp.Regexp{
regexp.MustCompile(`%[%+A-Za-z]`),
regexp.MustCompile(`\*+`),
}
type cleanupGuard struct {
enable bool
fn func()
mutex sync.Mutex
}
func (g *cleanupGuard) Enable() {
g.mutex.Lock()
defer g.mutex.Unlock()
g.enable = true
}
func (g *cleanupGuard) Run() {
g.fn()
}
// Rotate forcefully rotates the log files. If the generated file name
// clash because file already exists, a numeric suffix of the form
// ".1", ".2", ".3" and so forth are appended to the end of the log file
//
// Thie method can be used in conjunction with a signal handler so to
// emulate servers that generate new log files when they receive a
// SIGHUP
func (rl *RotateLogs) Rotate() error {
rl.mutex.Lock()
defer rl.mutex.Unlock()
if _, err := rl.getWriter_nolock(true, true); err != nil {
return err
}
return nil
}
func (rl *RotateLogs) rotate_nolock(filename string) error {
lockfn := filename + `_lock`
fh, err := os.OpenFile(lockfn, os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
// Can't lock, just return
return err
}
var guard cleanupGuard
guard.fn = func() {
fh.Close()
os.Remove(lockfn)
}
defer guard.Run()
if rl.linkName != "" {
tmpLinkName := filename + `_symlink`
if err := os.Symlink(filename, tmpLinkName); err != nil {
return errors.Wrap(err, `failed to create new symlink`)
}
if err := os.Rename(tmpLinkName, rl.linkName); err != nil {
return errors.Wrap(err, `failed to rename new symlink`)
}
}
if rl.maxAge <= 0 && rl.rotationCount <= 0 {
return errors.New("panic: maxAge and rotationCount are both set")
}
matches, err := filepath.Glob(rl.globPattern)
if err != nil {
return err
}
cutoff := rl.clock.Now().Add(-1 * rl.maxAge)
var toUnlink []string
for _, path := range matches {
// Ignore lock files
if strings.HasSuffix(path, "_lock") || strings.HasSuffix(path, "_symlink") {
continue
}
fi, err := os.Stat(path)
if err != nil {
continue
}
fl, err := os.Lstat(path)
if err != nil {
continue
}
if rl.maxAge > 0 && fi.ModTime().After(cutoff) {
continue
}
if rl.rotationCount > 0 && fl.Mode()&os.ModeSymlink == os.ModeSymlink {
continue
}
toUnlink = append(toUnlink, path)
}
if rl.rotationCount > 0 {
// Only delete if we have more than rotationCount
if rl.rotationCount >= uint(len(toUnlink)) {
return nil
}
toUnlink = toUnlink[:len(toUnlink)-int(rl.rotationCount)]
}
if len(toUnlink) <= 0 {
return nil
}
guard.Enable()
go func() {
// unlink files on a separate goroutine
for _, path := range toUnlink {
os.Remove(path)
}
}()
return nil
}
// Close satisfies the io.Closer interface. You must
// call this method if you performed any writes to
// the object.
func (rl *RotateLogs) Close() error {
rl.mutex.Lock()
defer rl.mutex.Unlock()
if rl.outFh == nil {
return nil
}
rl.outFh.Close()
rl.outFh = nil
return nil
}

24
vendor/github.com/lestrrat-go/strftime/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# 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

5
vendor/github.com/lestrrat-go/strftime/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,5 @@
language: go
sudo: false
go:
- 1.7.x
- tip

21
vendor/github.com/lestrrat-go/strftime/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 lestrrat
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.

151
vendor/github.com/lestrrat-go/strftime/README.md generated vendored Normal file
View File

@ -0,0 +1,151 @@
# strftime
Fast strftime for Go
[![Build Status](https://travis-ci.org/lestrrat-go/strftime.png?branch=master)](https://travis-ci.org/lestrrat-go/strftime)
[![GoDoc](https://godoc.org/github.com/lestrrat-go/strftime?status.svg)](https://godoc.org/github.com/lestrrat-go/strftime)
# SYNOPSIS
```go
f := strftime.New(`.... pattern ...`)
if err := f.Format(buf, time.Now()); err != nil {
log.Println(err.Error())
}
```
# DESCRIPTION
The goals for this library are
* Optimized for the same pattern being called repeatedly
* Be flexible about destination to write the results out
* Be as complete as possible in terms of conversion specifications
# API
## Format(string, time.Time) (string, error)
Takes the pattern and the time, and formats it. This function is a utility function that recompiles the pattern every time the function is called. If you know beforehand that you will be formatting the same pattern multiple times, consider using `New` to create a `Strftime` object and reuse it.
## New(string) (\*Strftime, error)
Takes the pattern and creates a new `Strftime` object.
## obj.Pattern() string
Returns the pattern string used to create this `Strftime` object
## obj.Format(io.Writer, time.Time) error
Formats the time according to the pre-compiled pattern, and writes the result to the specified `io.Writer`
## obj.FormatString(time.Time) string
Formats the time according to the pre-compiled pattern, and returns the result string.
# SUPPORTED CONVERSION SPECIFICATIONS
| pattern | description |
|:--------|:------------|
| %A | national representation of the full weekday name |
| %a | national representation of the abbreviated weekday |
| %B | national representation of the full month name |
| %b | national representation of the abbreviated month name |
| %C | (year / 100) as decimal number; single digits are preceded by a zero |
| %c | national representation of time and date |
| %D | equivalent to %m/%d/%y |
| %d | day of the month as a decimal number (01-31) |
| %e | the day of the month as a decimal number (1-31); single digits are preceded by a blank |
| %F | equivalent to %Y-%m-%d |
| %H | the hour (24-hour clock) as a decimal number (00-23) |
| %h | same as %b |
| %I | the hour (12-hour clock) as a decimal number (01-12) |
| %j | the day of the year as a decimal number (001-366) |
| %k | the hour (24-hour clock) as a decimal number (0-23); single digits are preceded by a blank |
| %l | the hour (12-hour clock) as a decimal number (1-12); single digits are preceded by a blank |
| %M | the minute as a decimal number (00-59) |
| %m | the month as a decimal number (01-12) |
| %n | a newline |
| %p | national representation of either "ante meridiem" (a.m.) or "post meridiem" (p.m.) as appropriate. |
| %R | equivalent to %H:%M |
| %r | equivalent to %I:%M:%S %p |
| %S | the second as a decimal number (00-60) |
| %T | equivalent to %H:%M:%S |
| %t | a tab |
| %U | the week number of the year (Sunday as the first day of the week) as a decimal number (00-53) |
| %u | the weekday (Monday as the first day of the week) as a decimal number (1-7) |
| %V | the week number of the year (Monday as the first day of the week) as a decimal number (01-53) |
| %v | equivalent to %e-%b-%Y |
| %W | the week number of the year (Monday as the first day of the week) as a decimal number (00-53) |
| %w | the weekday (Sunday as the first day of the week) as a decimal number (0-6) |
| %X | national representation of the time |
| %x | national representation of the date |
| %Y | the year with century as a decimal number |
| %y | the year without century as a decimal number (00-99) |
| %Z | the time zone name |
| %z | the time zone offset from UTC |
| %% | a '%' |
# PERFORMANCE / OTHER LIBRARIES
The following benchmarks were run separately because some libraries were using cgo on specific platforms (notabley, the fastly version)
```
// On my OS X 10.11.6, 2.9 GHz Intel Core i5, 16GB memory.
// go version go1.8rc1 darwin/amd64
hummingbird% go test -tags bench -benchmem -bench .
<snip>
BenchmarkTebeka-4 300000 4469 ns/op 288 B/op 21 allocs/op
BenchmarkJehiah-4 1000000 1931 ns/op 256 B/op 17 allocs/op
BenchmarkFastly-4 2000000 724 ns/op 80 B/op 5 allocs/op
BenchmarkLestrrat-4 1000000 1572 ns/op 240 B/op 3 allocs/op
BenchmarkLestrratCachedString-4 3000000 548 ns/op 128 B/op 2 allocs/op
BenchmarkLestrratCachedWriter-4 500000 2519 ns/op 192 B/op 3 allocs/op
PASS
ok github.com/lestrrat-go/strftime 22.900s
```
```
// On a host on Google Cloud Platform, machine-type: n1-standard-4 (vCPU x 4, memory: 15GB)
// Linux <snip> 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux
// go version go1.8rc1 linux/amd64
hummingbird% go test -tags bench -benchmem -bench .
<snip>
BenchmarkTebeka-4 500000 3904 ns/op 288 B/op 21 allocs/op
BenchmarkJehiah-4 1000000 1665 ns/op 256 B/op 17 allocs/op
BenchmarkFastly-4 1000000 2134 ns/op 192 B/op 13 allocs/op
BenchmarkLestrrat-4 1000000 1327 ns/op 240 B/op 3 allocs/op
BenchmarkLestrratCachedString-4 3000000 498 ns/op 128 B/op 2 allocs/op
BenchmarkLestrratCachedWriter-4 1000000 3390 ns/op 192 B/op 3 allocs/op
PASS
ok github.com/lestrrat-go/strftime 44.854s
```
This library is much faster than other libraries *IF* you can reuse the format pattern.
Here's the annotated list from the benchmark results. You can clearly see that (re)using a `Strftime` object
and producing a string is the fastest. Writing to an `io.Writer` seems a bit sluggish, but since
the one producing the string is doing almost exactly the same thing, we believe this is purely the overhead of
writing to an `io.Writer`
| Import Path | Score | Note |
|:------------------------------------|--------:|:--------------------------------|
| github.com/lestrrat-go/strftime | 3000000 | Using `FormatString()` (cached) |
| github.com/fastly/go-utils/strftime | 2000000 | Pure go version on OS X |
| github.com/lestrrat-go/strftime | 1000000 | Using `Format()` (NOT cached) |
| github.com/jehiah/go-strftime | 1000000 | |
| github.com/fastly/go-utils/strftime | 1000000 | cgo version on Linux |
| github.com/lestrrat-go/strftime | 500000 | Using `Format()` (cached) |
| github.com/tebeka/strftime | 300000 | |
However, depending on your pattern, this speed may vary. If you find a particular pattern that seems sluggish,
please send in patches or tests.
Please also note that this benchmark only uses the subset of conversion specifications that are supported by *ALL* of the libraries compared.
Somethings to consider when making performance comparisons in the future:
* Can it write to io.Writer?
* Which `%specification` does it handle?

219
vendor/github.com/lestrrat-go/strftime/strftime.go generated vendored Normal file
View File

@ -0,0 +1,219 @@
package strftime
import (
"io"
"strings"
"time"
"github.com/pkg/errors"
)
var directives = map[byte]appender{
'A': timefmt("Monday"),
'a': timefmt("Mon"),
'B': timefmt("January"),
'b': timefmt("Jan"),
'C': &century{},
'c': timefmt("Mon Jan _2 15:04:05 2006"),
'D': timefmt("01/02/06"),
'd': timefmt("02"),
'e': timefmt("_2"),
'F': timefmt("2006-01-02"),
'H': timefmt("15"),
'h': timefmt("Jan"), // same as 'b'
'I': timefmt("3"),
'j': &dayofyear{},
'k': hourwblank(false),
'l': hourwblank(true),
'M': timefmt("04"),
'm': timefmt("01"),
'n': verbatim("\n"),
'p': timefmt("PM"),
'R': timefmt("15:04"),
'r': timefmt("3:04:05 PM"),
'S': timefmt("05"),
'T': timefmt("15:04:05"),
't': verbatim("\t"),
'U': weeknumberOffset(0), // week number of the year, Sunday first
'u': weekday(1),
'V': &weeknumber{},
'v': timefmt("_2-Jan-2006"),
'W': weeknumberOffset(1), // week number of the year, Monday first
'w': weekday(0),
'X': timefmt("15:04:05"), // national representation of the time XXX is this correct?
'x': timefmt("01/02/06"), // national representation of the date XXX is this correct?
'Y': timefmt("2006"), // year with century
'y': timefmt("06"), // year w/o century
'Z': timefmt("MST"), // time zone name
'z': timefmt("-0700"), // time zone ofset from UTC
'%': verbatim("%"),
}
type combiningAppend struct {
list appenderList
prev appender
prevCanCombine bool
}
func (ca *combiningAppend) Append(w appender) {
if ca.prevCanCombine {
if wc, ok := w.(combiner); ok && wc.canCombine() {
ca.prev = ca.prev.(combiner).combine(wc)
ca.list[len(ca.list)-1] = ca.prev
return
}
}
ca.list = append(ca.list, w)
ca.prev = w
ca.prevCanCombine = false
if comb, ok := w.(combiner); ok {
if comb.canCombine() {
ca.prevCanCombine = true
}
}
}
func compile(wl *appenderList, p string) error {
var ca combiningAppend
for l := len(p); l > 0; l = len(p) {
i := strings.IndexByte(p, '%')
if i < 0 {
ca.Append(verbatim(p))
// this is silly, but I don't trust break keywords when there's a
// possibility of this piece of code being rearranged
p = p[l:]
continue
}
if i == l-1 {
return errors.New(`stray % at the end of pattern`)
}
// we found a '%'. we need the next byte to decide what to do next
// we already know that i < l - 1
// everything up to the i is verbatim
if i > 0 {
ca.Append(verbatim(p[:i]))
p = p[i:]
}
directive, ok := directives[p[1]]
if !ok {
return errors.Errorf(`unknown time format specification '%c'`, p[1])
}
ca.Append(directive)
p = p[2:]
}
*wl = ca.list
return nil
}
// Format takes the format `s` and the time `t` to produce the
// format date/time. Note that this function re-compiles the
// pattern every time it is called.
//
// If you know beforehand that you will be reusing the pattern
// within your application, consider creating a `Strftime` object
// and reusing it.
func Format(p string, t time.Time) (string, error) {
var dst []byte
// TODO: optimize for 64 byte strings
dst = make([]byte, 0, len(p)+10)
// Compile, but execute as we go
for l := len(p); l > 0; l = len(p) {
i := strings.IndexByte(p, '%')
if i < 0 {
dst = append(dst, p...)
// this is silly, but I don't trust break keywords when there's a
// possibility of this piece of code being rearranged
p = p[l:]
continue
}
if i == l-1 {
return "", errors.New(`stray % at the end of pattern`)
}
// we found a '%'. we need the next byte to decide what to do next
// we already know that i < l - 1
// everything up to the i is verbatim
if i > 0 {
dst = append(dst, p[:i]...)
p = p[i:]
}
directive, ok := directives[p[1]]
if !ok {
return "", errors.Errorf(`unknown time format specification '%c'`, p[1])
}
dst = directive.Append(dst, t)
p = p[2:]
}
return string(dst), nil
}
// Strftime is the object that represents a compiled strftime pattern
type Strftime struct {
pattern string
compiled appenderList
}
// New creates a new Strftime object. If the compilation fails, then
// an error is returned in the second argument.
func New(f string) (*Strftime, error) {
var wl appenderList
if err := compile(&wl, f); err != nil {
return nil, errors.Wrap(err, `failed to compile format`)
}
return &Strftime{
pattern: f,
compiled: wl,
}, nil
}
// Pattern returns the original pattern string
func (f *Strftime) Pattern() string {
return f.pattern
}
// Format takes the destination `dst` and time `t`. It formats the date/time
// using the pre-compiled pattern, and outputs the results to `dst`
func (f *Strftime) Format(dst io.Writer, t time.Time) error {
const bufSize = 64
var b []byte
max := len(f.pattern) + 10
if max < bufSize {
var buf [bufSize]byte
b = buf[:0]
} else {
b = make([]byte, 0, max)
}
if _, err := dst.Write(f.format(b, t)); err != nil {
return err
}
return nil
}
func (f *Strftime) format(b []byte, t time.Time) []byte {
for _, w := range f.compiled {
b = w.Append(b, t)
}
return b
}
// FormatString takes the time `t` and formats it, returning the
// string containing the formated data.
func (f *Strftime) FormatString(t time.Time) string {
const bufSize = 64
var b []byte
max := len(f.pattern) + 10
if max < bufSize {
var buf [bufSize]byte
b = buf[:0]
} else {
b = make([]byte, 0, max)
}
return string(f.format(b, t))
}

168
vendor/github.com/lestrrat-go/strftime/writer.go generated vendored Normal file
View File

@ -0,0 +1,168 @@
package strftime
import (
"strconv"
"strings"
"time"
)
type appender interface {
Append([]byte, time.Time) []byte
}
type appenderList []appender
// does the time.Format thing
type timefmtw struct {
s string
}
func timefmt(s string) *timefmtw {
return &timefmtw{s: s}
}
func (v timefmtw) Append(b []byte, t time.Time) []byte {
return t.AppendFormat(b, v.s)
}
func (v timefmtw) str() string {
return v.s
}
func (v timefmtw) canCombine() bool {
return true
}
func (v timefmtw) combine(w combiner) appender {
return timefmt(v.s + w.str())
}
type verbatimw struct {
s string
}
func verbatim(s string) *verbatimw {
return &verbatimw{s: s}
}
func (v verbatimw) Append(b []byte, _ time.Time) []byte {
return append(b, v.s...)
}
func (v verbatimw) canCombine() bool {
return canCombine(v.s)
}
func (v verbatimw) combine(w combiner) appender {
if _, ok := w.(*timefmtw); ok {
return timefmt(v.s + w.str())
}
return verbatim(v.s + w.str())
}
func (v verbatimw) str() string {
return v.s
}
// These words below, as well as any decimal character
var combineExclusion = []string{
"Mon",
"Monday",
"Jan",
"January",
"MST",
"PM",
}
func canCombine(s string) bool {
if strings.ContainsAny(s, "0123456789") {
return false
}
for _, word := range combineExclusion {
if strings.Contains(s, word) {
return false
}
}
return true
}
type combiner interface {
canCombine() bool
combine(combiner) appender
str() string
}
type century struct{}
func (v century) Append(b []byte, t time.Time) []byte {
n := t.Year() / 100
if n < 10 {
b = append(b, '0')
}
return append(b, strconv.Itoa(n)...)
}
type weekday int
func (v weekday) Append(b []byte, t time.Time) []byte {
n := int(t.Weekday())
if n < int(v) {
n += 7
}
return append(b, byte(n+48))
}
type weeknumberOffset int
func (v weeknumberOffset) Append(b []byte, t time.Time) []byte {
yd := t.YearDay()
offset := int(t.Weekday()) - int(v)
if offset < 0 {
offset += 7
}
if yd < offset {
return append(b, '0', '0')
}
n := ((yd - offset) / 7) + 1
if n < 10 {
b = append(b, '0')
}
return append(b, strconv.Itoa(n)...)
}
type weeknumber struct{}
func (v weeknumber) Append(b []byte, t time.Time) []byte {
_, n := t.ISOWeek()
if n < 10 {
b = append(b, '0')
}
return append(b, strconv.Itoa(n)...)
}
type dayofyear struct{}
func (v dayofyear) Append(b []byte, t time.Time) []byte {
n := t.YearDay()
if n < 10 {
b = append(b, '0', '0')
} else if n < 100 {
b = append(b, '0')
}
return append(b, strconv.Itoa(n)...)
}
type hourwblank bool
func (v hourwblank) Append(b []byte, t time.Time) []byte {
h := t.Hour()
if bool(v) && h > 12 {
h = h - 12
}
if h < 10 {
b = append(b, ' ')
}
return append(b, strconv.Itoa(h)...)
}

24
vendor/github.com/pkg/errors/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# 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

11
vendor/github.com/pkg/errors/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,11 @@
language: go
go_import_path: github.com/pkg/errors
go:
- 1.4.3
- 1.5.4
- 1.6.2
- 1.7.1
- tip
script:
- go test -v ./...

23
vendor/github.com/pkg/errors/LICENSE generated vendored Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

52
vendor/github.com/pkg/errors/README.md generated vendored Normal file
View File

@ -0,0 +1,52 @@
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors)
Package errors provides simple error handling primitives.
`go get github.com/pkg/errors`
The traditional error handling idiom in Go is roughly akin to
```go
if err != nil {
return err
}
```
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
## Adding context to an error
The errors.Wrap function returns a new error that adds context to the original error. For example
```go
_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}
```
## Retrieving the cause of an error
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
```go
type causer interface {
Cause() error
}
```
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
```go
switch err := errors.Cause(err).(type) {
case *MyError:
// handle specifically
default:
// unknown error
}
```
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
Before proposing a change, please discuss your change by raising an issue.
## Licence
BSD-2-Clause

32
vendor/github.com/pkg/errors/appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,32 @@
version: build-{build}.{branch}
clone_folder: C:\gopath\src\github.com\pkg\errors
shallow_clone: true # for startup speed
environment:
GOPATH: C:\gopath
platform:
- x64
# http://www.appveyor.com/docs/installed-software
install:
# some helpful output for debugging builds
- go version
- go env
# pre-installed MinGW at C:\MinGW is 32bit only
# but MSYS2 at C:\msys64 has mingw64
- set PATH=C:\msys64\mingw64\bin;%PATH%
- gcc --version
- g++ --version
build_script:
- go install -v ./...
test_script:
- set PATH=C:\gopath\bin;%PATH%
- go test -v ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off

269
vendor/github.com/pkg/errors/errors.go generated vendored Normal file
View File

@ -0,0 +1,269 @@
// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
// if err != nil {
// return err
// }
//
// which applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error by recording a stack trace at the point Wrap is called,
// and the supplied message. For example
//
// _, err := ioutil.ReadAll(r)
// if err != nil {
// return errors.Wrap(err, "read failed")
// }
//
// If additional control is required the errors.WithStack and errors.WithMessage
// functions destructure errors.Wrap into its component operations of annotating
// an error with a stack trace and an a message, respectively.
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
// type causer interface {
// Cause() error
// }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error which does not implement causer, which is assumed to be
// the original cause. For example:
//
// switch err := errors.Cause(err).(type) {
// case *MyError:
// // handle specifically
// default:
// // unknown error
// }
//
// causer interface is not exported by this package, but is considered a part
// of stable public API.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported
//
// %s print the error. If the error has a Cause it will be
// printed recursively
// %v see %s
// %+v extended format. Each Frame of the error's StackTrace will
// be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface.
//
// type stackTracer interface {
// StackTrace() errors.StackTrace
// }
//
// Where errors.StackTrace is defined as
//
// type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f)
// }
// }
//
// stackTracer interface is not exported by this package, but is considered a part
// of stable public API.
//
// See the documentation for Frame.Format for more details.
package errors
import (
"fmt"
"io"
)
// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
return &fundamental{
msg: message,
stack: callers(),
}
}
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
return &fundamental{
msg: fmt.Sprintf(format, args...),
stack: callers(),
}
}
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
msg string
*stack
}
func (f *fundamental) Error() string { return f.msg }
func (f *fundamental) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, f.msg)
case 'q':
fmt.Fprintf(s, "%q", f.msg)
}
}
// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
func WithStack(err error) error {
if err == nil {
return nil
}
return &withStack{
err,
callers(),
}
}
type withStack struct {
error
*stack
}
func (w *withStack) Cause() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v", w.Cause())
w.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, w.Error())
case 'q':
fmt.Fprintf(s, "%q", w.Error())
}
}
// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: message,
}
return &withStack{
err,
callers(),
}
}
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is call, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
// WithMessage annotates err with a new message.
// If err is nil, WithMessage returns nil.
func WithMessage(err error, message string) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: message,
}
}
type withMessage struct {
cause error
msg string
}
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v\n", w.Cause())
io.WriteString(s, w.msg)
return
}
fallthrough
case 's', 'q':
io.WriteString(s, w.Error())
}
}
// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
// type causer interface {
// Cause() error
// }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
type causer interface {
Cause() error
}
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}

178
vendor/github.com/pkg/errors/stack.go generated vendored Normal file
View File

@ -0,0 +1,178 @@
package errors
import (
"fmt"
"io"
"path"
"runtime"
"strings"
)
// Frame represents a program counter inside a stack frame.
type Frame uintptr
// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f Frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}
// line returns the line number of source code of the
// function for this Frame's pc.
func (f Frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
// %d source line
// %n function name
// %v equivalent to %s:%d
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s path of source file relative to the compile time GOPATH
// %+v equivalent to %+s:%d
func (f Frame) Format(s fmt.State, verb rune) {
switch verb {
case 's':
switch {
case s.Flag('+'):
pc := f.pc()
fn := runtime.FuncForPC(pc)
if fn == nil {
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
fmt.Fprintf(s, "%d", f.line())
case 'n':
name := runtime.FuncForPC(f.pc()).Name()
io.WriteString(s, funcname(name))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
f.Format(s, 'd')
}
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
for _, f := range st {
fmt.Fprintf(s, "\n%+v", f)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
fmt.Fprintf(s, "%v", []Frame(st))
}
case 's':
fmt.Fprintf(s, "%s", []Frame(st))
}
}
// stack represents a stack of program counters.
type stack []uintptr
func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}
func (s *stack) StackTrace() StackTrace {
f := make([]Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = Frame((*s)[i])
}
return f
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
// funcname removes the path prefix component of a function's name reported by func.Name().
func funcname(name string) string {
i := strings.LastIndex(name, "/")
name = name[i+1:]
i = strings.Index(name, ".")
return name[i+1:]
}
func trimGOPATH(name, file string) string {
// Here we want to get the source file path relative to the compile time
// GOPATH. As of Go 1.6.x there is no direct way to know the compiled
// GOPATH at runtime, but we can infer the number of path segments in the
// GOPATH. We note that fn.Name() returns the function name qualified by
// the import path, which does not include the GOPATH. Thus we can trim
// segments from the beginning of the file path until the number of path
// separators remaining is one more than the number of path separators in
// the function name. For example, given:
//
// GOPATH /home/user
// file /home/user/src/pkg/sub/file.go
// fn.Name() pkg/sub.Type.Method
//
// We want to produce:
//
// pkg/sub/file.go
//
// From this we can easily see that fn.Name() has one less path separator
// than our desired output. We count separators from the end of the file
// path until it finds two more than in the function name and then move
// one character forward to preserve the initial path segment without a
// leading separator.
const sep = "/"
goal := strings.Count(name, sep) + 2
i := len(file)
for n := 0; n < goal; n++ {
i = strings.LastIndex(file[:i], sep)
if i == -1 {
// not enough separators found, set i so that the slice expression
// below leaves file unmodified
i = -len(sep)
break
}
}
// get back to 0 or trim the leading separator
file = file[i+len(sep):]
return file
}

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 }

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

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)
}

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

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:])
}

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

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

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

@ -0,0 +1,21 @@
language: go
sudo: false
go:
- "1.9"
- "1.10"
go_import_path: go.uber.org/zap
env:
global:
- 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)

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

@ -0,0 +1,286 @@
# Changelog
## v1.8.0 (13 Apr 2018)
Enhancements:
* [#508][]: Make log level configurable when redirecting the standard
library's logger.
* [#518][]: Add a logger that writes to a `*testing.TB`.
* [#577][]: Add a top-level alias for `zapcore.Field` to clean up GoDoc.
Bugfixes:
* [#574][]: Add a missing import comment to `go.uber.org/zap/buffer`.
Thanks to @DiSiqueira and @djui for their contributions to this release.
## 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
[#504]: https://github.com/uber-go/zap/pull/504
[#508]: https://github.com/uber-go/zap/pull/508
[#518]: https://github.com/uber-go/zap/pull/518
[#577]: https://github.com/uber-go/zap/pull/577
[#574]: https://github.com/uber-go/zap/pull/574

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

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

@ -0,0 +1,154 @@
# 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)
```
## Extensions
We'd love to support every logging need within zap itself, but we're only
familiar with a handful of log ingestion systems, flag-parsing packages, and
the like. Rather than merging code that we can't effectively debug and
support, we'd rather grow an ecosystem of zap extensions.
We're aware of the following extensions, but haven't used them ourselves:
| Package | Integration |
| --- | --- |
| `github.com/tchap/zapext` | Sentry, syslog |
| `github.com/fgrosse/zaptest` | Ginkgo |
[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 internal/ztest
# 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 := 10
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) Field {
return Field{Key: key, Type: zapcore.ArrayMarshalerType, Interface: val}
}
// Bools constructs a field that carries a slice of bools.
func Bools(key string, bs []bool) 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) Field {
return Array(key, byteStringsArray(bss))
}
// Complex128s constructs a field that carries a slice of complex numbers.
func Complex128s(key string, nums []complex128) Field {
return Array(key, complex128s(nums))
}
// Complex64s constructs a field that carries a slice of complex numbers.
func Complex64s(key string, nums []complex64) Field {
return Array(key, complex64s(nums))
}
// Durations constructs a field that carries a slice of time.Durations.
func Durations(key string, ds []time.Duration) Field {
return Array(key, durations(ds))
}
// Float64s constructs a field that carries a slice of floats.
func Float64s(key string, nums []float64) Field {
return Array(key, float64s(nums))
}
// Float32s constructs a field that carries a slice of floats.
func Float32s(key string, nums []float32) Field {
return Array(key, float32s(nums))
}
// Ints constructs a field that carries a slice of integers.
func Ints(key string, nums []int) Field {
return Array(key, ints(nums))
}
// Int64s constructs a field that carries a slice of integers.
func Int64s(key string, nums []int64) Field {
return Array(key, int64s(nums))
}
// Int32s constructs a field that carries a slice of integers.
func Int32s(key string, nums []int32) Field {
return Array(key, int32s(nums))
}
// Int16s constructs a field that carries a slice of integers.
func Int16s(key string, nums []int16) Field {
return Array(key, int16s(nums))
}
// Int8s constructs a field that carries a slice of integers.
func Int8s(key string, nums []int8) Field {
return Array(key, int8s(nums))
}
// Strings constructs a field that carries a slice of strings.
func Strings(key string, ss []string) Field {
return Array(key, stringArray(ss))
}
// Times constructs a field that carries a slice of time.Times.
func Times(key string, ts []time.Time) Field {
return Array(key, times(ts))
}
// Uints constructs a field that carries a slice of unsigned integers.
func Uints(key string, nums []uint) Field {
return Array(key, uints(nums))
}
// Uint64s constructs a field that carries a slice of unsigned integers.
func Uint64s(key string, nums []uint64) Field {
return Array(key, uint64s(nums))
}
// Uint32s constructs a field that carries a slice of unsigned integers.
func Uint32s(key string, nums []uint32) Field {
return Array(key, uint32s(nums))
}
// Uint16s constructs a field that carries a slice of unsigned integers.
func Uint16s(key string, nums []uint16) Field {
return Array(key, uint16s(nums))
}
// Uint8s constructs a field that carries a slice of unsigned integers.
func Uint8s(key string, nums []uint8) Field {
return Array(key, uint8s(nums))
}
// Uintptrs constructs a field that carries a slice of pointer addresses.
func Uintptrs(key string, us []uintptr) Field {
return Array(key, uintptrs(us))
}
// Errors constructs a field that carries a slice of errors.
func Errors(key string, errs []error) 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
}

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 "go.uber.org/zap/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)
}

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)
}

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

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([]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)
}

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)
}

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) 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) Field {
if err == nil {
return Skip()
}
return 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
}

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

@ -0,0 +1,310 @@
// 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"
)
// Field is an alias for Field. Aliasing this type dramatically
// improves the navigability of this package's API documentation.
type Field = zapcore.Field
// Skip constructs a no-op field, which is often useful when handling invalid
// inputs in other Field constructors.
func Skip() Field {
return 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) Field {
return Field{Key: key, Type: zapcore.BinaryType, Interface: val}
}
// Bool constructs a field that carries a bool.
func Bool(key string, val bool) Field {
var ival int64
if val {
ival = 1
}
return 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) Field {
return 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) Field {
return 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) Field {
return 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) Field {
return 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) Field {
return 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) Field {
return Int64(key, int64(val))
}
// Int64 constructs a field with the given key and value.
func Int64(key string, val int64) Field {
return Field{Key: key, Type: zapcore.Int64Type, Integer: val}
}
// Int32 constructs a field with the given key and value.
func Int32(key string, val int32) Field {
return 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) Field {
return 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) Field {
return 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) Field {
return Field{Key: key, Type: zapcore.StringType, String: val}
}
// Uint constructs a field with the given key and value.
func Uint(key string, val uint) Field {
return Uint64(key, uint64(val))
}
// Uint64 constructs a field with the given key and value.
func Uint64(key string, val uint64) Field {
return 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) Field {
return 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) Field {
return 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) Field {
return 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) Field {
return 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{}) Field {
return 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) Field {
return 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) Field {
return Field{Key: key, Type: zapcore.StringerType, Interface: val}
}
// Time constructs a Field with the given key and value. The encoder
// controls how the time is serialized.
func Time(key string, val time.Time) Field {
return 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) 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) Field {
return 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) Field {
return 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 surprises, []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{}) 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)
}
}

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
}

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

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

@ -0,0 +1,169 @@
// 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
_programmerErrorTemplate = "You've found a bug in zap! Please file a bug at " +
"https://github.com/uber-go/zap/issues/new and reference this error: %v"
)
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))
logFunc, err := levelToFunc(logger, level)
if err != nil {
return nil, err
}
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.Stderr.
func RedirectStdLog(l *Logger) func() {
f, err := redirectStdLogAt(l, InfoLevel)
if err != nil {
// Can't get here, since passing InfoLevel to redirectStdLogAt always
// works.
panic(fmt.Sprintf(_programmerErrorTemplate, err))
}
return f
}
// RedirectStdLogAt redirects output from the standard library's package-global
// logger to the supplied logger at the specified level. 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.Stderr.
func RedirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
return redirectStdLogAt(l, level)
}
func redirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
flags := log.Flags()
prefix := log.Prefix()
log.SetFlags(0)
log.SetPrefix("")
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
logFunc, err := levelToFunc(logger, level)
if err != nil {
return nil, err
}
log.SetOutput(&loggerWriter{logFunc})
return func() {
log.SetFlags(flags)
log.SetPrefix(prefix)
log.SetOutput(os.Stderr)
}, nil
}
func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) {
switch lvl {
case DebugLevel:
return logger.Debug, nil
case InfoLevel:
return logger.Info, nil
case WarnLevel:
return logger.Warn, nil
case ErrorLevel:
return logger.Error, nil
case DPanicLevel:
return logger.DPanic, nil
case PanicLevel:
return logger.Panic, nil
case FatalLevel:
return logger.Fatal, nil
}
return nil, fmt.Errorf("unrecognized level: %q", lvl)
}
type loggerWriter struct {
logFunc func(msg string, fields ...Field)
}
func (l *loggerWriter) Write(p []byte) (int, error) {
p = bytes.TrimSpace(p)
l.logFunc(string(p))
return len(p), nil
}

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.",
})
}
}

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)
}

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
}

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 convenience 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()
}

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 ...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 ...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 ...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 ...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 ...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 ...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 ...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 ...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
}

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 ...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
})
}

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
}

304
vendor/go.uber.org/zap/sugar.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 zap
import (
"fmt"
"go.uber.org/zap/zapcore"
"go.uber.org/multierr"
)
const (
_oddNumberErrMsg = "Ignored key without a value."
_nonStringKeyErrMsg = "Ignored key-value pairs with non-string keys."
)
// A SugaredLogger wraps the base Logger functionality in a slower, but less
// verbose, API. Any Logger can be converted to a SugaredLogger with its Sugar
// method.
//
// Unlike the Logger, the SugaredLogger doesn't insist on structured logging.
// For each log level, it exposes three methods: one for loosely-typed
// structured logging, one for println-style formatting, and one for
// printf-style formatting. For example, SugaredLoggers can produce InfoLevel
// output with Infow ("info with" structured context), Info, or Infof.
type SugaredLogger struct {
base *Logger
}
// Desugar unwraps a SugaredLogger, exposing the original Logger. Desugaring
// 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 (s *SugaredLogger) Desugar() *Logger {
base := s.base.clone()
base.callerSkip -= 2
return base
}
// Named adds a sub-scope to the logger's name. See Logger.Named for details.
func (s *SugaredLogger) Named(name string) *SugaredLogger {
return &SugaredLogger{base: s.base.Named(name)}
}
// With adds a variadic number of fields to the logging context. It accepts a
// mix of strongly-typed Field objects and loosely-typed key-value pairs. When
// processing pairs, the first element of the pair is used as the field key
// and the second as the field value.
//
// For example,
// sugaredLogger.With(
// "hello", "world",
// "failure", errors.New("oh no"),
// Stack(),
// "count", 42,
// "user", User{Name: "alice"},
// )
// is the equivalent of
// unsugared.With(
// String("hello", "world"),
// String("failure", "oh no"),
// Stack(),
// Int("count", 42),
// Object("user", User{Name: "alice"}),
// )
//
// Note that the keys in key-value pairs should be strings. In development,
// passing a non-string key panics. In production, the logger is more
// forgiving: a separate error is logged, but the key-value pair is skipped
// and execution continues. Passing an orphaned key triggers similar behavior:
// panics in development and errors in production.
func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger {
return &SugaredLogger{base: s.base.With(s.sweetenFields(args)...)}
}
// Debug uses fmt.Sprint to construct and log a message.
func (s *SugaredLogger) Debug(args ...interface{}) {
s.log(DebugLevel, "", args, nil)
}
// Info uses fmt.Sprint to construct and log a message.
func (s *SugaredLogger) Info(args ...interface{}) {
s.log(InfoLevel, "", args, nil)
}
// Warn uses fmt.Sprint to construct and log a message.
func (s *SugaredLogger) Warn(args ...interface{}) {
s.log(WarnLevel, "", args, nil)
}
// Error uses fmt.Sprint to construct and log a message.
func (s *SugaredLogger) Error(args ...interface{}) {
s.log(ErrorLevel, "", args, nil)
}
// DPanic uses fmt.Sprint to construct and log a message. In development, the
// logger then panics. (See DPanicLevel for details.)
func (s *SugaredLogger) DPanic(args ...interface{}) {
s.log(DPanicLevel, "", args, nil)
}
// Panic uses fmt.Sprint to construct and log a message, then panics.
func (s *SugaredLogger) Panic(args ...interface{}) {
s.log(PanicLevel, "", args, nil)
}
// Fatal uses fmt.Sprint to construct and log a message, then calls os.Exit.
func (s *SugaredLogger) Fatal(args ...interface{}) {
s.log(FatalLevel, "", args, nil)
}
// Debugf uses fmt.Sprintf to log a templated message.
func (s *SugaredLogger) Debugf(template string, args ...interface{}) {
s.log(DebugLevel, template, args, nil)
}
// Infof uses fmt.Sprintf to log a templated message.
func (s *SugaredLogger) Infof(template string, args ...interface{}) {
s.log(InfoLevel, template, args, nil)
}
// Warnf uses fmt.Sprintf to log a templated message.
func (s *SugaredLogger) Warnf(template string, args ...interface{}) {
s.log(WarnLevel, template, args, nil)
}
// Errorf uses fmt.Sprintf to log a templated message.
func (s *SugaredLogger) Errorf(template string, args ...interface{}) {
s.log(ErrorLevel, template, args, nil)
}
// DPanicf uses fmt.Sprintf to log a templated message. In development, the
// logger then panics. (See DPanicLevel for details.)
func (s *SugaredLogger) DPanicf(template string, args ...interface{}) {
s.log(DPanicLevel, template, args, nil)
}
// Panicf uses fmt.Sprintf to log a templated message, then panics.
func (s *SugaredLogger) Panicf(template string, args ...interface{}) {
s.log(PanicLevel, template, args, nil)
}
// Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit.
func (s *SugaredLogger) Fatalf(template string, args ...interface{}) {
s.log(FatalLevel, template, args, nil)
}
// Debugw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
//
// When debug-level logging is disabled, this is much faster than
// s.With(keysAndValues).Debug(msg)
func (s *SugaredLogger) Debugw(msg string, keysAndValues ...interface{}) {
s.log(DebugLevel, msg, nil, keysAndValues)
}
// Infow logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{}) {
s.log(InfoLevel, msg, nil, keysAndValues)
}
// Warnw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func (s *SugaredLogger) Warnw(msg string, keysAndValues ...interface{}) {
s.log(WarnLevel, msg, nil, keysAndValues)
}
// Errorw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func (s *SugaredLogger) Errorw(msg string, keysAndValues ...interface{}) {
s.log(ErrorLevel, msg, nil, keysAndValues)
}
// DPanicw logs a message with some additional context. In development, the
// logger then panics. (See DPanicLevel for details.) The variadic key-value
// pairs are treated as they are in With.
func (s *SugaredLogger) DPanicw(msg string, keysAndValues ...interface{}) {
s.log(DPanicLevel, msg, nil, keysAndValues)
}
// Panicw logs a message with some additional context, then panics. The
// variadic key-value pairs are treated as they are in With.
func (s *SugaredLogger) Panicw(msg string, keysAndValues ...interface{}) {
s.log(PanicLevel, msg, nil, keysAndValues)
}
// Fatalw logs a message with some additional context, then calls os.Exit. The
// variadic key-value pairs are treated as they are in With.
func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{}) {
s.log(FatalLevel, msg, nil, keysAndValues)
}
// Sync flushes any buffered log entries.
func (s *SugaredLogger) Sync() error {
return s.base.Sync()
}
func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interface{}, context []interface{}) {
// If logging at this level is completely disabled, skip the overhead of
// string formatting.
if lvl < DPanicLevel && !s.base.Core().Enabled(lvl) {
return
}
// Format with Sprint, Sprintf, or neither.
msg := template
if msg == "" && len(fmtArgs) > 0 {
msg = fmt.Sprint(fmtArgs...)
} else if msg != "" && len(fmtArgs) > 0 {
msg = fmt.Sprintf(template, fmtArgs...)
}
if ce := s.base.Check(lvl, msg); ce != nil {
ce.Write(s.sweetenFields(context)...)
}
}
func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
if len(args) == 0 {
return nil
}
// Allocate enough space for the worst case; if users pass only structured
// fields, we shouldn't penalize them with extra allocations.
fields := make([]Field, 0, len(args))
var invalid invalidPairs
for i := 0; i < len(args); {
// This is a strongly-typed field. Consume it and move on.
if f, ok := args[i].(Field); ok {
fields = append(fields, f)
i++
continue
}
// Make sure this element isn't a dangling key.
if i == len(args)-1 {
s.base.DPanic(_oddNumberErrMsg, Any("ignored", args[i]))
break
}
// Consume this value and the next, treating them as a key-value pair. If the
// key isn't a string, add this pair to the slice of invalid pairs.
key, val := args[i], args[i+1]
if keyStr, ok := key.(string); !ok {
// Subsequent errors are likely, so allocate once up front.
if cap(invalid) == 0 {
invalid = make(invalidPairs, 0, len(args)/2)
}
invalid = append(invalid, invalidPair{i, key, val})
} else {
fields = append(fields, Any(keyStr, val))
}
i += 2
}
// If we encountered any invalid key-value pairs, log an error.
if len(invalid) > 0 {
s.base.DPanic(_nonStringKeyErrMsg, Array("invalid", invalid))
}
return fields
}
type invalidPair struct {
position int
key, value interface{}
}
func (p invalidPair) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddInt64("position", int64(p.position))
Any("key", p.key).AddTo(enc)
Any("value", p.value).AddTo(enc)
return nil
}
type invalidPairs []invalidPair
func (ps invalidPairs) MarshalLogArray(enc zapcore.ArrayEncoder) error {
var err error
for i := range ps {
err = multierr.Append(err, enc.AppendObject(ps[i]))
}
return err
}

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