mirror of
https://github.com/fhmq/hmq.git
synced 2026-05-02 14:28:34 +00:00
add feature
This commit is contained in:
@@ -251,10 +251,7 @@ func (c *client) ProcessPublishMessage(packet *packets.PublishPacket) {
|
|||||||
if s.queue {
|
if s.queue {
|
||||||
qsub = append(qsub, i)
|
qsub = append(qsub, i)
|
||||||
} else {
|
} else {
|
||||||
err := s.client.WriterPacket(packet)
|
publish(s, packet)
|
||||||
if err != nil {
|
|
||||||
log.Error("process message for psub error, ", zap.Error(err), zap.String("ClientID", c.info.clientID))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -264,14 +261,24 @@ func (c *client) ProcessPublishMessage(packet *packets.PublishPacket) {
|
|||||||
if len(qsub) > 0 {
|
if len(qsub) > 0 {
|
||||||
idx := r.Intn(len(qsub))
|
idx := r.Intn(len(qsub))
|
||||||
sub := c.subs[qsub[idx]].(*subscription)
|
sub := c.subs[qsub[idx]].(*subscription)
|
||||||
err := sub.client.WriterPacket(packet)
|
publish(sub, packet)
|
||||||
if err != nil {
|
|
||||||
log.Error("process message for qsub error, ", zap.Error(err), zap.String("ClientID", c.info.clientID))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func publish(sub *subscription, packet *packets.PublishPacket) {
|
||||||
|
var p *packets.PublishPacket
|
||||||
|
if sub.client.info.username != "root" {
|
||||||
|
p = unWrapPublishPacket(p)
|
||||||
|
} else {
|
||||||
|
p = wrapPublishPacket(p)
|
||||||
|
}
|
||||||
|
err := sub.client.WriterPacket(p)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("process message for psub error, ", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *client) ProcessSubscribe(packet *packets.SubscribePacket) {
|
func (c *client) ProcessSubscribe(packet *packets.SubscribePacket) {
|
||||||
if c.status == Disconnected {
|
if c.status == Disconnected {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
package broker
|
package broker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"encoding/json"
|
||||||
"crypto/rand"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/hex"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
|
"github.com/eclipse/paho.mqtt.golang/packets"
|
||||||
|
uuid "github.com/satori/go.uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -92,12 +93,24 @@ func equal(k1, k2 interface{}) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GenUniqueId() string {
|
func GenUniqueId() string {
|
||||||
b := make([]byte, 48)
|
return uuid.NewV4().String()
|
||||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
}
|
||||||
return ""
|
|
||||||
}
|
func wrapPublishPacket(packet *packets.PublishPacket) *packets.PublishPacket {
|
||||||
h := md5.New()
|
p := packet.Copy()
|
||||||
h.Write([]byte(base64.URLEncoding.EncodeToString(b)))
|
wrapPayload := map[string]interface{}{
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
"message_id": GenUniqueId(),
|
||||||
// return GetMd5String()
|
"payload": string(p.Payload),
|
||||||
|
}
|
||||||
|
b, _ := json.Marshal(wrapPayload)
|
||||||
|
p.Payload = b
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func unWrapPublishPacket(packet *packets.PublishPacket) *packets.PublishPacket {
|
||||||
|
p := packet.Copy()
|
||||||
|
if gjson.GetBytes(p.Payload, "paload").Exists() {
|
||||||
|
p.Payload = []byte(gjson.GetBytes(p.Payload, "payload").String())
|
||||||
|
}
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -9,9 +9,11 @@ require (
|
|||||||
github.com/eclipse/paho.mqtt.golang v1.2.0
|
github.com/eclipse/paho.mqtt.golang v1.2.0
|
||||||
github.com/fsnotify/fsnotify v1.4.7 // indirect
|
github.com/fsnotify/fsnotify v1.4.7 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||||
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e
|
github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e
|
||||||
github.com/shirou/gopsutil v2.18.12+incompatible
|
github.com/shirou/gopsutil v2.18.12+incompatible
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.3.0
|
||||||
|
github.com/tidwall/gjson v1.3.0
|
||||||
go.uber.org/atomic v1.3.2 // indirect
|
go.uber.org/atomic v1.3.2 // indirect
|
||||||
go.uber.org/multierr v1.1.0 // indirect
|
go.uber.org/multierr v1.1.0 // indirect
|
||||||
go.uber.org/zap v1.9.1
|
go.uber.org/zap v1.9.1
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -36,6 +36,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||||
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e h1:uO75wNGioszjmIzcY/tvdDYKRLVvzggtAmmJkn9j4GQ=
|
github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e h1:uO75wNGioszjmIzcY/tvdDYKRLVvzggtAmmJkn9j4GQ=
|
||||||
github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e/go.mod h1:tm/wZFQ8e24NYaBGIlnO2WGCAi67re4HHuOm0sftE/M=
|
github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e/go.mod h1:tm/wZFQ8e24NYaBGIlnO2WGCAi67re4HHuOm0sftE/M=
|
||||||
github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM=
|
github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM=
|
||||||
@@ -43,6 +45,12 @@ github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMT
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/tidwall/gjson v1.3.0 h1:kfpsw1W3trbg4Xm6doUtqSl9+LhLB6qJ9PkltVAQZYs=
|
||||||
|
github.com/tidwall/gjson v1.3.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
||||||
|
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
||||||
|
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||||
|
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||||
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||||
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
|
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
|
||||||
|
|||||||
23
vendor/github.com/satori/go.uuid/.travis.yml
generated
vendored
Normal file
23
vendor/github.com/satori/go.uuid/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
language: go
|
||||||
|
sudo: false
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- 1.7
|
||||||
|
- 1.8
|
||||||
|
- 1.9
|
||||||
|
- tip
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
|
fast_finish: true
|
||||||
|
before_install:
|
||||||
|
- go get github.com/mattn/goveralls
|
||||||
|
- go get golang.org/x/tools/cmd/cover
|
||||||
|
script:
|
||||||
|
- $HOME/gopath/bin/goveralls -service=travis-ci
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
20
vendor/github.com/satori/go.uuid/LICENSE
generated
vendored
Normal file
20
vendor/github.com/satori/go.uuid/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
|
||||||
|
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.
|
||||||
65
vendor/github.com/satori/go.uuid/README.md
generated
vendored
Normal file
65
vendor/github.com/satori/go.uuid/README.md
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# UUID package for Go language
|
||||||
|
|
||||||
|
[](https://travis-ci.org/satori/go.uuid)
|
||||||
|
[](https://coveralls.io/github/satori/go.uuid)
|
||||||
|
[](http://godoc.org/github.com/satori/go.uuid)
|
||||||
|
|
||||||
|
This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs.
|
||||||
|
|
||||||
|
With 100% test coverage and benchmarks out of box.
|
||||||
|
|
||||||
|
Supported versions:
|
||||||
|
* Version 1, based on timestamp and MAC address (RFC 4122)
|
||||||
|
* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
|
||||||
|
* Version 3, based on MD5 hashing (RFC 4122)
|
||||||
|
* Version 4, based on random numbers (RFC 4122)
|
||||||
|
* Version 5, based on SHA-1 hashing (RFC 4122)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Use the `go` command:
|
||||||
|
|
||||||
|
$ go get github.com/satori/go.uuid
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
UUID package requires Go >= 1.2.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/satori/go.uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Creating UUID Version 4
|
||||||
|
u1 := uuid.NewV4()
|
||||||
|
fmt.Printf("UUIDv4: %s\n", u1)
|
||||||
|
|
||||||
|
// Parsing UUID from string input
|
||||||
|
u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Something gone wrong: %s", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Successfully parsed: %s", u2)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project.
|
||||||
|
|
||||||
|
## Links
|
||||||
|
* [RFC 4122](http://tools.ietf.org/html/rfc4122)
|
||||||
|
* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>.
|
||||||
|
|
||||||
|
UUID package released under MIT License.
|
||||||
|
See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.
|
||||||
206
vendor/github.com/satori/go.uuid/codec.go
generated
vendored
Normal file
206
vendor/github.com/satori/go.uuid/codec.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
//
|
||||||
|
// 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 uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromBytes returns UUID converted from raw byte slice input.
|
||||||
|
// It will return error if the slice isn't 16 bytes long.
|
||||||
|
func FromBytes(input []byte) (u UUID, err error) {
|
||||||
|
err = u.UnmarshalBinary(input)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBytesOrNil returns UUID converted from raw byte slice input.
|
||||||
|
// Same behavior as FromBytes, but returns a Nil UUID on error.
|
||||||
|
func FromBytesOrNil(input []byte) UUID {
|
||||||
|
uuid, err := FromBytes(input)
|
||||||
|
if err != nil {
|
||||||
|
return Nil
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromString returns UUID parsed from string input.
|
||||||
|
// Input is expected in a form accepted by UnmarshalText.
|
||||||
|
func FromString(input string) (u UUID, err error) {
|
||||||
|
err = u.UnmarshalText([]byte(input))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStringOrNil returns UUID parsed from string input.
|
||||||
|
// Same behavior as FromString, but returns a Nil UUID on error.
|
||||||
|
func FromStringOrNil(input string) UUID {
|
||||||
|
uuid, err := FromString(input)
|
||||||
|
if err != nil {
|
||||||
|
return Nil
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
// The encoding is the same as returned by String.
|
||||||
|
func (u UUID) MarshalText() (text []byte, err error) {
|
||||||
|
text = []byte(u.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
// Following formats are supported:
|
||||||
|
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
||||||
|
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
|
||||||
|
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
|
||||||
|
// "6ba7b8109dad11d180b400c04fd430c8"
|
||||||
|
// ABNF for supported UUID text representation follows:
|
||||||
|
// uuid := canonical | hashlike | braced | urn
|
||||||
|
// plain := canonical | hashlike
|
||||||
|
// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
|
||||||
|
// hashlike := 12hexoct
|
||||||
|
// braced := '{' plain '}'
|
||||||
|
// urn := URN ':' UUID-NID ':' plain
|
||||||
|
// URN := 'urn'
|
||||||
|
// UUID-NID := 'uuid'
|
||||||
|
// 12hexoct := 6hexoct 6hexoct
|
||||||
|
// 6hexoct := 4hexoct 2hexoct
|
||||||
|
// 4hexoct := 2hexoct 2hexoct
|
||||||
|
// 2hexoct := hexoct hexoct
|
||||||
|
// hexoct := hexdig hexdig
|
||||||
|
// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
|
||||||
|
// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
|
||||||
|
// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
|
||||||
|
func (u *UUID) UnmarshalText(text []byte) (err error) {
|
||||||
|
switch len(text) {
|
||||||
|
case 32:
|
||||||
|
return u.decodeHashLike(text)
|
||||||
|
case 36:
|
||||||
|
return u.decodeCanonical(text)
|
||||||
|
case 38:
|
||||||
|
return u.decodeBraced(text)
|
||||||
|
case 41:
|
||||||
|
fallthrough
|
||||||
|
case 45:
|
||||||
|
return u.decodeURN(text)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("uuid: incorrect UUID length: %s", text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeCanonical decodes UUID string in format
|
||||||
|
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
|
||||||
|
func (u *UUID) decodeCanonical(t []byte) (err error) {
|
||||||
|
if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
|
||||||
|
return fmt.Errorf("uuid: incorrect UUID format %s", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
src := t[:]
|
||||||
|
dst := u[:]
|
||||||
|
|
||||||
|
for i, byteGroup := range byteGroups {
|
||||||
|
if i > 0 {
|
||||||
|
src = src[1:] // skip dash
|
||||||
|
}
|
||||||
|
_, err = hex.Decode(dst[:byteGroup/2], src[:byteGroup])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
src = src[byteGroup:]
|
||||||
|
dst = dst[byteGroup/2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeHashLike decodes UUID string in format
|
||||||
|
// "6ba7b8109dad11d180b400c04fd430c8".
|
||||||
|
func (u *UUID) decodeHashLike(t []byte) (err error) {
|
||||||
|
src := t[:]
|
||||||
|
dst := u[:]
|
||||||
|
|
||||||
|
if _, err = hex.Decode(dst, src); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeBraced decodes UUID string in format
|
||||||
|
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" or in format
|
||||||
|
// "{6ba7b8109dad11d180b400c04fd430c8}".
|
||||||
|
func (u *UUID) decodeBraced(t []byte) (err error) {
|
||||||
|
l := len(t)
|
||||||
|
|
||||||
|
if t[0] != '{' || t[l-1] != '}' {
|
||||||
|
return fmt.Errorf("uuid: incorrect UUID format %s", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.decodePlain(t[1 : l-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeURN decodes UUID string in format
|
||||||
|
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in format
|
||||||
|
// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8".
|
||||||
|
func (u *UUID) decodeURN(t []byte) (err error) {
|
||||||
|
total := len(t)
|
||||||
|
|
||||||
|
urn_uuid_prefix := t[:9]
|
||||||
|
|
||||||
|
if !bytes.Equal(urn_uuid_prefix, urnPrefix) {
|
||||||
|
return fmt.Errorf("uuid: incorrect UUID format: %s", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.decodePlain(t[9:total])
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodePlain decodes UUID string in canonical format
|
||||||
|
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format
|
||||||
|
// "6ba7b8109dad11d180b400c04fd430c8".
|
||||||
|
func (u *UUID) decodePlain(t []byte) (err error) {
|
||||||
|
switch len(t) {
|
||||||
|
case 32:
|
||||||
|
return u.decodeHashLike(t)
|
||||||
|
case 36:
|
||||||
|
return u.decodeCanonical(t)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("uuid: incorrrect UUID length: %s", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
||||||
|
func (u UUID) MarshalBinary() (data []byte, err error) {
|
||||||
|
data = u.Bytes()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
||||||
|
// It will return error if the slice isn't 16 bytes long.
|
||||||
|
func (u *UUID) UnmarshalBinary(data []byte) (err error) {
|
||||||
|
if len(data) != Size {
|
||||||
|
err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(u[:], data)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
239
vendor/github.com/satori/go.uuid/generator.go
generated
vendored
Normal file
239
vendor/github.com/satori/go.uuid/generator.go
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
//
|
||||||
|
// 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 uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/binary"
|
||||||
|
"hash"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Difference in 100-nanosecond intervals between
|
||||||
|
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
|
||||||
|
const epochStart = 122192928000000000
|
||||||
|
|
||||||
|
var (
|
||||||
|
global = newDefaultGenerator()
|
||||||
|
|
||||||
|
epochFunc = unixTimeFunc
|
||||||
|
posixUID = uint32(os.Getuid())
|
||||||
|
posixGID = uint32(os.Getgid())
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewV1 returns UUID based on current timestamp and MAC address.
|
||||||
|
func NewV1() UUID {
|
||||||
|
return global.NewV1()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
||||||
|
func NewV2(domain byte) UUID {
|
||||||
|
return global.NewV2(domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
||||||
|
func NewV3(ns UUID, name string) UUID {
|
||||||
|
return global.NewV3(ns, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV4 returns random generated UUID.
|
||||||
|
func NewV4() UUID {
|
||||||
|
return global.NewV4()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
||||||
|
func NewV5(ns UUID, name string) UUID {
|
||||||
|
return global.NewV5(ns, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generator provides interface for generating UUIDs.
|
||||||
|
type Generator interface {
|
||||||
|
NewV1() UUID
|
||||||
|
NewV2(domain byte) UUID
|
||||||
|
NewV3(ns UUID, name string) UUID
|
||||||
|
NewV4() UUID
|
||||||
|
NewV5(ns UUID, name string) UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default generator implementation.
|
||||||
|
type generator struct {
|
||||||
|
storageOnce sync.Once
|
||||||
|
storageMutex sync.Mutex
|
||||||
|
|
||||||
|
lastTime uint64
|
||||||
|
clockSequence uint16
|
||||||
|
hardwareAddr [6]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDefaultGenerator() Generator {
|
||||||
|
return &generator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV1 returns UUID based on current timestamp and MAC address.
|
||||||
|
func (g *generator) NewV1() UUID {
|
||||||
|
u := UUID{}
|
||||||
|
|
||||||
|
timeNow, clockSeq, hardwareAddr := g.getStorage()
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
|
||||||
|
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
|
||||||
|
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
|
||||||
|
binary.BigEndian.PutUint16(u[8:], clockSeq)
|
||||||
|
|
||||||
|
copy(u[10:], hardwareAddr)
|
||||||
|
|
||||||
|
u.SetVersion(V1)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
||||||
|
func (g *generator) NewV2(domain byte) UUID {
|
||||||
|
u := UUID{}
|
||||||
|
|
||||||
|
timeNow, clockSeq, hardwareAddr := g.getStorage()
|
||||||
|
|
||||||
|
switch domain {
|
||||||
|
case DomainPerson:
|
||||||
|
binary.BigEndian.PutUint32(u[0:], posixUID)
|
||||||
|
case DomainGroup:
|
||||||
|
binary.BigEndian.PutUint32(u[0:], posixGID)
|
||||||
|
}
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
|
||||||
|
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
|
||||||
|
binary.BigEndian.PutUint16(u[8:], clockSeq)
|
||||||
|
u[9] = domain
|
||||||
|
|
||||||
|
copy(u[10:], hardwareAddr)
|
||||||
|
|
||||||
|
u.SetVersion(V2)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
||||||
|
func (g *generator) NewV3(ns UUID, name string) UUID {
|
||||||
|
u := newFromHash(md5.New(), ns, name)
|
||||||
|
u.SetVersion(V3)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV4 returns random generated UUID.
|
||||||
|
func (g *generator) NewV4() UUID {
|
||||||
|
u := UUID{}
|
||||||
|
g.safeRandom(u[:])
|
||||||
|
u.SetVersion(V4)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
||||||
|
func (g *generator) NewV5(ns UUID, name string) UUID {
|
||||||
|
u := newFromHash(sha1.New(), ns, name)
|
||||||
|
u.SetVersion(V5)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) initStorage() {
|
||||||
|
g.initClockSequence()
|
||||||
|
g.initHardwareAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) initClockSequence() {
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
g.safeRandom(buf)
|
||||||
|
g.clockSequence = binary.BigEndian.Uint16(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) initHardwareAddr() {
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err == nil {
|
||||||
|
for _, iface := range interfaces {
|
||||||
|
if len(iface.HardwareAddr) >= 6 {
|
||||||
|
copy(g.hardwareAddr[:], iface.HardwareAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize hardwareAddr randomly in case
|
||||||
|
// of real network interfaces absence
|
||||||
|
g.safeRandom(g.hardwareAddr[:])
|
||||||
|
|
||||||
|
// Set multicast bit as recommended in RFC 4122
|
||||||
|
g.hardwareAddr[0] |= 0x01
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) safeRandom(dest []byte) {
|
||||||
|
if _, err := rand.Read(dest); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns UUID v1/v2 storage state.
|
||||||
|
// Returns epoch timestamp, clock sequence, and hardware address.
|
||||||
|
func (g *generator) getStorage() (uint64, uint16, []byte) {
|
||||||
|
g.storageOnce.Do(g.initStorage)
|
||||||
|
|
||||||
|
g.storageMutex.Lock()
|
||||||
|
defer g.storageMutex.Unlock()
|
||||||
|
|
||||||
|
timeNow := epochFunc()
|
||||||
|
// Clock changed backwards since last UUID generation.
|
||||||
|
// Should increase clock sequence.
|
||||||
|
if timeNow <= g.lastTime {
|
||||||
|
g.clockSequence++
|
||||||
|
}
|
||||||
|
g.lastTime = timeNow
|
||||||
|
|
||||||
|
return timeNow, g.clockSequence, g.hardwareAddr[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns difference in 100-nanosecond intervals between
|
||||||
|
// UUID epoch (October 15, 1582) and current time.
|
||||||
|
// This is default epoch calculation function.
|
||||||
|
func unixTimeFunc() uint64 {
|
||||||
|
return epochStart + uint64(time.Now().UnixNano()/100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns UUID based on hashing of namespace UUID and name.
|
||||||
|
func newFromHash(h hash.Hash, ns UUID, name string) UUID {
|
||||||
|
u := UUID{}
|
||||||
|
h.Write(ns[:])
|
||||||
|
h.Write([]byte(name))
|
||||||
|
copy(u[:], h.Sum(nil))
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
78
vendor/github.com/satori/go.uuid/sql.go
generated
vendored
Normal file
78
vendor/github.com/satori/go.uuid/sql.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
//
|
||||||
|
// 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 uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Value implements the driver.Valuer interface.
|
||||||
|
func (u UUID) Value() (driver.Value, error) {
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the sql.Scanner interface.
|
||||||
|
// A 16-byte slice is handled by UnmarshalBinary, while
|
||||||
|
// a longer byte slice or a string is handled by UnmarshalText.
|
||||||
|
func (u *UUID) Scan(src interface{}) error {
|
||||||
|
switch src := src.(type) {
|
||||||
|
case []byte:
|
||||||
|
if len(src) == Size {
|
||||||
|
return u.UnmarshalBinary(src)
|
||||||
|
}
|
||||||
|
return u.UnmarshalText(src)
|
||||||
|
|
||||||
|
case string:
|
||||||
|
return u.UnmarshalText([]byte(src))
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("uuid: cannot convert %T to UUID", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NullUUID can be used with the standard sql package to represent a
|
||||||
|
// UUID value that can be NULL in the database
|
||||||
|
type NullUUID struct {
|
||||||
|
UUID UUID
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver.Valuer interface.
|
||||||
|
func (u NullUUID) Value() (driver.Value, error) {
|
||||||
|
if !u.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// Delegate to UUID Value function
|
||||||
|
return u.UUID.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the sql.Scanner interface.
|
||||||
|
func (u *NullUUID) Scan(src interface{}) error {
|
||||||
|
if src == nil {
|
||||||
|
u.UUID, u.Valid = Nil, false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delegate to UUID Scan function
|
||||||
|
u.Valid = true
|
||||||
|
return u.UUID.Scan(src)
|
||||||
|
}
|
||||||
161
vendor/github.com/satori/go.uuid/uuid.go
generated
vendored
Normal file
161
vendor/github.com/satori/go.uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
//
|
||||||
|
// 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 uuid provides implementation of Universally Unique Identifier (UUID).
|
||||||
|
// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
|
||||||
|
// version 2 (as specified in DCE 1.1).
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Size of a UUID in bytes.
|
||||||
|
const Size = 16
|
||||||
|
|
||||||
|
// UUID representation compliant with specification
|
||||||
|
// described in RFC 4122.
|
||||||
|
type UUID [Size]byte
|
||||||
|
|
||||||
|
// UUID versions
|
||||||
|
const (
|
||||||
|
_ byte = iota
|
||||||
|
V1
|
||||||
|
V2
|
||||||
|
V3
|
||||||
|
V4
|
||||||
|
V5
|
||||||
|
)
|
||||||
|
|
||||||
|
// UUID layout variants.
|
||||||
|
const (
|
||||||
|
VariantNCS byte = iota
|
||||||
|
VariantRFC4122
|
||||||
|
VariantMicrosoft
|
||||||
|
VariantFuture
|
||||||
|
)
|
||||||
|
|
||||||
|
// UUID DCE domains.
|
||||||
|
const (
|
||||||
|
DomainPerson = iota
|
||||||
|
DomainGroup
|
||||||
|
DomainOrg
|
||||||
|
)
|
||||||
|
|
||||||
|
// String parse helpers.
|
||||||
|
var (
|
||||||
|
urnPrefix = []byte("urn:uuid:")
|
||||||
|
byteGroups = []int{8, 4, 4, 4, 12}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Nil is special form of UUID that is specified to have all
|
||||||
|
// 128 bits set to zero.
|
||||||
|
var Nil = UUID{}
|
||||||
|
|
||||||
|
// Predefined namespace UUIDs.
|
||||||
|
var (
|
||||||
|
NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
)
|
||||||
|
|
||||||
|
// Equal returns true if u1 and u2 equals, otherwise returns false.
|
||||||
|
func Equal(u1 UUID, u2 UUID) bool {
|
||||||
|
return bytes.Equal(u1[:], u2[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns algorithm version used to generate UUID.
|
||||||
|
func (u UUID) Version() byte {
|
||||||
|
return u[6] >> 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variant returns UUID layout variant.
|
||||||
|
func (u UUID) Variant() byte {
|
||||||
|
switch {
|
||||||
|
case (u[8] >> 7) == 0x00:
|
||||||
|
return VariantNCS
|
||||||
|
case (u[8] >> 6) == 0x02:
|
||||||
|
return VariantRFC4122
|
||||||
|
case (u[8] >> 5) == 0x06:
|
||||||
|
return VariantMicrosoft
|
||||||
|
case (u[8] >> 5) == 0x07:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
return VariantFuture
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns bytes slice representation of UUID.
|
||||||
|
func (u UUID) Bytes() []byte {
|
||||||
|
return u[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns canonical string representation of UUID:
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
|
||||||
|
func (u UUID) String() string {
|
||||||
|
buf := make([]byte, 36)
|
||||||
|
|
||||||
|
hex.Encode(buf[0:8], u[0:4])
|
||||||
|
buf[8] = '-'
|
||||||
|
hex.Encode(buf[9:13], u[4:6])
|
||||||
|
buf[13] = '-'
|
||||||
|
hex.Encode(buf[14:18], u[6:8])
|
||||||
|
buf[18] = '-'
|
||||||
|
hex.Encode(buf[19:23], u[8:10])
|
||||||
|
buf[23] = '-'
|
||||||
|
hex.Encode(buf[24:], u[10:])
|
||||||
|
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVersion sets version bits.
|
||||||
|
func (u *UUID) SetVersion(v byte) {
|
||||||
|
u[6] = (u[6] & 0x0f) | (v << 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVariant sets variant bits.
|
||||||
|
func (u *UUID) SetVariant(v byte) {
|
||||||
|
switch v {
|
||||||
|
case VariantNCS:
|
||||||
|
u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
|
||||||
|
case VariantRFC4122:
|
||||||
|
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
|
||||||
|
case VariantMicrosoft:
|
||||||
|
u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
|
||||||
|
case VariantFuture:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must is a helper that wraps a call to a function returning (UUID, error)
|
||||||
|
// and panics if the error is non-nil. It is intended for use in variable
|
||||||
|
// initializations such as
|
||||||
|
// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
|
||||||
|
func Must(u UUID, err error) UUID {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
1
vendor/github.com/tidwall/gjson/.travis.yml
generated
vendored
Normal file
1
vendor/github.com/tidwall/gjson/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
language: go
|
||||||
20
vendor/github.com/tidwall/gjson/LICENSE
generated
vendored
Normal file
20
vendor/github.com/tidwall/gjson/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Josh Baker
|
||||||
|
|
||||||
|
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.
|
||||||
483
vendor/github.com/tidwall/gjson/README.md
generated
vendored
Normal file
483
vendor/github.com/tidwall/gjson/README.md
generated
vendored
Normal file
@@ -0,0 +1,483 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img
|
||||||
|
src="logo.png"
|
||||||
|
width="240" height="78" border="0" alt="GJSON">
|
||||||
|
<br>
|
||||||
|
<a href="https://travis-ci.org/tidwall/gjson"><img src="https://img.shields.io/travis/tidwall/gjson.svg?style=flat-square" alt="Build Status"></a>
|
||||||
|
<a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
|
||||||
|
<a href="http://tidwall.com/gjson-play"><img src="https://img.shields.io/badge/%F0%9F%8F%90-playground-9900cc.svg?style=flat-square" alt="GJSON Playground"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<p align="center">get json values quickly</a></p>
|
||||||
|
|
||||||
|
GJSON is a Go package that provides a [fast](#performance) and [simple](#get-a-value) way to get values from a json document.
|
||||||
|
It has features such as [one line retrieval](#get-a-value), [dot notation paths](#path-syntax), [iteration](#iterate-through-an-object-or-array), and [parsing json lines](#json-lines).
|
||||||
|
|
||||||
|
Also check out [SJSON](https://github.com/tidwall/sjson) for modifying json, and the [JJ](https://github.com/tidwall/jj) command line tool.
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
|
||||||
|
## Installing
|
||||||
|
|
||||||
|
To start using GJSON, install Go and run `go get`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ go get -u github.com/tidwall/gjson
|
||||||
|
```
|
||||||
|
|
||||||
|
This will retrieve the library.
|
||||||
|
|
||||||
|
## Get a value
|
||||||
|
Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". When the value is found it's returned immediately.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/tidwall/gjson"
|
||||||
|
|
||||||
|
const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
value := gjson.Get(json, "name.last")
|
||||||
|
println(value.String())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will print:
|
||||||
|
|
||||||
|
```
|
||||||
|
Prichard
|
||||||
|
```
|
||||||
|
*There's also the [GetMany](#get-multiple-values-at-once) function to get multiple values at once, and [GetBytes](#working-with-bytes) for working with JSON byte slices.*
|
||||||
|
|
||||||
|
## Path Syntax
|
||||||
|
|
||||||
|
Below is a quick overview of the path syntax, for more complete information please
|
||||||
|
check out [GJSON Syntax](SYNTAX.md).
|
||||||
|
|
||||||
|
A path is a series of keys separated by a dot.
|
||||||
|
A key may contain special wildcard characters '\*' and '?'.
|
||||||
|
To access an array value use the index as the key.
|
||||||
|
To get the number of elements in an array or to access a child path, use the '#' character.
|
||||||
|
The dot and wildcard characters can be escaped with '\\'.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": {"first": "Tom", "last": "Anderson"},
|
||||||
|
"age":37,
|
||||||
|
"children": ["Sara","Alex","Jack"],
|
||||||
|
"fav.movie": "Deer Hunter",
|
||||||
|
"friends": [
|
||||||
|
{"first": "Dale", "last": "Murphy", "age": 44},
|
||||||
|
{"first": "Roger", "last": "Craig", "age": 68},
|
||||||
|
{"first": "Jane", "last": "Murphy", "age": 47}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
"name.last" >> "Anderson"
|
||||||
|
"age" >> 37
|
||||||
|
"children" >> ["Sara","Alex","Jack"]
|
||||||
|
"children.#" >> 3
|
||||||
|
"children.1" >> "Alex"
|
||||||
|
"child*.2" >> "Jack"
|
||||||
|
"c?ildren.0" >> "Sara"
|
||||||
|
"fav\.movie" >> "Deer Hunter"
|
||||||
|
"friends.#.first" >> ["Dale","Roger","Jane"]
|
||||||
|
"friends.1.last" >> "Craig"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also query an array for the first match by using `#[...]`, or find all matches with `#[...]#`.
|
||||||
|
Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators and the simple pattern matching `%` (like) and `!%` (not like) operators.
|
||||||
|
|
||||||
|
```
|
||||||
|
friends.#[last=="Murphy"].first >> "Dale"
|
||||||
|
friends.#[last=="Murphy"]#.first >> ["Dale","Jane"]
|
||||||
|
friends.#[age>45]#.last >> ["Craig","Murphy"]
|
||||||
|
friends.#[first%"D*"].last >> "Murphy"
|
||||||
|
friends.#[first!%"D*"].last >> "Craig"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Result Type
|
||||||
|
|
||||||
|
GJSON supports the json types `string`, `number`, `bool`, and `null`.
|
||||||
|
Arrays and Objects are returned as their raw json types.
|
||||||
|
|
||||||
|
The `Result` type holds one of these:
|
||||||
|
|
||||||
|
```
|
||||||
|
bool, for JSON booleans
|
||||||
|
float64, for JSON numbers
|
||||||
|
string, for JSON string literals
|
||||||
|
nil, for JSON null
|
||||||
|
```
|
||||||
|
|
||||||
|
To directly access the value:
|
||||||
|
|
||||||
|
```go
|
||||||
|
result.Type // can be String, Number, True, False, Null, or JSON
|
||||||
|
result.Str // holds the string
|
||||||
|
result.Num // holds the float64 number
|
||||||
|
result.Raw // holds the raw json
|
||||||
|
result.Index // index of raw value in original json, zero means index unknown
|
||||||
|
```
|
||||||
|
|
||||||
|
There are a variety of handy functions that work on a result:
|
||||||
|
|
||||||
|
```go
|
||||||
|
result.Exists() bool
|
||||||
|
result.Value() interface{}
|
||||||
|
result.Int() int64
|
||||||
|
result.Uint() uint64
|
||||||
|
result.Float() float64
|
||||||
|
result.String() string
|
||||||
|
result.Bool() bool
|
||||||
|
result.Time() time.Time
|
||||||
|
result.Array() []gjson.Result
|
||||||
|
result.Map() map[string]gjson.Result
|
||||||
|
result.Get(path string) Result
|
||||||
|
result.ForEach(iterator func(key, value Result) bool)
|
||||||
|
result.Less(token Result, caseSensitive bool) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
The `result.Value()` function returns an `interface{}` which requires type assertion and is one of the following Go types:
|
||||||
|
|
||||||
|
The `result.Array()` function returns back an array of values.
|
||||||
|
If the result represents a non-existent value, then an empty array will be returned.
|
||||||
|
If the result is not a JSON array, the return value will be an array containing one result.
|
||||||
|
|
||||||
|
```go
|
||||||
|
boolean >> bool
|
||||||
|
number >> float64
|
||||||
|
string >> string
|
||||||
|
null >> nil
|
||||||
|
array >> []interface{}
|
||||||
|
object >> map[string]interface{}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 64-bit integers
|
||||||
|
|
||||||
|
The `result.Int()` and `result.Uint()` calls are capable of reading all 64 bits, allowing for large JSON integers.
|
||||||
|
|
||||||
|
```go
|
||||||
|
result.Int() int64 // -9223372036854775808 to 9223372036854775807
|
||||||
|
result.Uint() int64 // 0 to 18446744073709551615
|
||||||
|
```
|
||||||
|
|
||||||
|
## Modifiers and path chaining
|
||||||
|
|
||||||
|
New in version 1.2 is support for modifier functions and path chaining.
|
||||||
|
|
||||||
|
A modifier is a path component that performs custom processing on the
|
||||||
|
json.
|
||||||
|
|
||||||
|
Multiple paths can be "chained" together using the pipe character.
|
||||||
|
This is useful for getting results from a modified query.
|
||||||
|
|
||||||
|
For example, using the built-in `@reverse` modifier on the above json document,
|
||||||
|
we'll get `children` array and reverse the order:
|
||||||
|
|
||||||
|
```
|
||||||
|
"children|@reverse" >> ["Jack","Alex","Sara"]
|
||||||
|
"children|@reverse|0" >> "Jack"
|
||||||
|
```
|
||||||
|
|
||||||
|
There are currently three built-in modifiers:
|
||||||
|
|
||||||
|
- `@reverse`: Reverse an array or the members of an object.
|
||||||
|
- `@ugly`: Remove all whitespace from a json document.
|
||||||
|
- `@pretty`: Make the json document more human readable.
|
||||||
|
|
||||||
|
### Modifier arguments
|
||||||
|
|
||||||
|
A modifier may accept an optional argument. The argument can be a valid JSON
|
||||||
|
document or just characters.
|
||||||
|
|
||||||
|
For example, the `@pretty` modifier takes a json object as its argument.
|
||||||
|
|
||||||
|
```
|
||||||
|
@pretty:{"sortKeys":true}
|
||||||
|
```
|
||||||
|
|
||||||
|
Which makes the json pretty and orders all of its keys.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"age":37,
|
||||||
|
"children": ["Sara","Alex","Jack"],
|
||||||
|
"fav.movie": "Deer Hunter",
|
||||||
|
"friends": [
|
||||||
|
{"age": 44, "first": "Dale", "last": "Murphy"},
|
||||||
|
{"age": 68, "first": "Roger", "last": "Craig"},
|
||||||
|
{"age": 47, "first": "Jane", "last": "Murphy"}
|
||||||
|
],
|
||||||
|
"name": {"first": "Tom", "last": "Anderson"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
|
||||||
|
Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
|
||||||
|
|
||||||
|
### Custom modifiers
|
||||||
|
|
||||||
|
You can also add custom modifiers.
|
||||||
|
|
||||||
|
For example, here we create a modifier that makes the entire json document upper
|
||||||
|
or lower case.
|
||||||
|
|
||||||
|
```go
|
||||||
|
gjson.AddModifier("case", func(json, arg string) string {
|
||||||
|
if arg == "upper" {
|
||||||
|
return strings.ToUpper(json)
|
||||||
|
}
|
||||||
|
if arg == "lower" {
|
||||||
|
return strings.ToLower(json)
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
"children|@case:upper" >> ["SARA","ALEX","JACK"]
|
||||||
|
"children|@case:lower|@reverse" >> ["jack","alex","sara"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## JSON Lines
|
||||||
|
|
||||||
|
There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"name": "Gilbert", "age": 61}
|
||||||
|
{"name": "Alexa", "age": 34}
|
||||||
|
{"name": "May", "age": 57}
|
||||||
|
{"name": "Deloise", "age": 44}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
..# >> 4
|
||||||
|
..1 >> {"name": "Alexa", "age": 34}
|
||||||
|
..3 >> {"name": "Deloise", "age": 44}
|
||||||
|
..#.name >> ["Gilbert","Alexa","May","Deloise"]
|
||||||
|
..#[name="May"].age >> 57
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ForEachLines` function will iterate through JSON lines.
|
||||||
|
|
||||||
|
```go
|
||||||
|
gjson.ForEachLine(json, func(line gjson.Result) bool{
|
||||||
|
println(line.String())
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get nested array values
|
||||||
|
|
||||||
|
Suppose you want all the last names from the following json:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"programmers": [
|
||||||
|
{
|
||||||
|
"firstName": "Janet",
|
||||||
|
"lastName": "McLaughlin",
|
||||||
|
}, {
|
||||||
|
"firstName": "Elliotte",
|
||||||
|
"lastName": "Hunter",
|
||||||
|
}, {
|
||||||
|
"firstName": "Jason",
|
||||||
|
"lastName": "Harold",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You would use the path "programmers.#.lastName" like such:
|
||||||
|
|
||||||
|
```go
|
||||||
|
result := gjson.Get(json, "programmers.#.lastName")
|
||||||
|
for _, name := range result.Array() {
|
||||||
|
println(name.String())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also query an object inside an array:
|
||||||
|
|
||||||
|
```go
|
||||||
|
name := gjson.Get(json, `programmers.#[lastName="Hunter"].firstName`)
|
||||||
|
println(name.String()) // prints "Elliotte"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Iterate through an object or array
|
||||||
|
|
||||||
|
The `ForEach` function allows for quickly iterating through an object or array.
|
||||||
|
The key and value are passed to the iterator function for objects.
|
||||||
|
Only the value is passed for arrays.
|
||||||
|
Returning `false` from an iterator will stop iteration.
|
||||||
|
|
||||||
|
```go
|
||||||
|
result := gjson.Get(json, "programmers")
|
||||||
|
result.ForEach(func(key, value gjson.Result) bool {
|
||||||
|
println(value.String())
|
||||||
|
return true // keep iterating
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Simple Parse and Get
|
||||||
|
|
||||||
|
There's a `Parse(json)` function that will do a simple parse, and `result.Get(path)` that will search a result.
|
||||||
|
|
||||||
|
For example, all of these will return the same result:
|
||||||
|
|
||||||
|
```go
|
||||||
|
gjson.Parse(json).Get("name").Get("last")
|
||||||
|
gjson.Get(json, "name").Get("last")
|
||||||
|
gjson.Get(json, "name.last")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Check for the existence of a value
|
||||||
|
|
||||||
|
Sometimes you just want to know if a value exists.
|
||||||
|
|
||||||
|
```go
|
||||||
|
value := gjson.Get(json, "name.last")
|
||||||
|
if !value.Exists() {
|
||||||
|
println("no last name")
|
||||||
|
} else {
|
||||||
|
println(value.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or as one step
|
||||||
|
if gjson.Get(json, "name.last").Exists() {
|
||||||
|
println("has a last name")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validate JSON
|
||||||
|
|
||||||
|
The `Get*` and `Parse*` functions expects that the json is well-formed. Bad json will not panic, but it may return back unexpected results.
|
||||||
|
|
||||||
|
If you are consuming JSON from an unpredictable source then you may want to validate prior to using GJSON.
|
||||||
|
|
||||||
|
```go
|
||||||
|
if !gjson.Valid(json) {
|
||||||
|
return errors.New("invalid json")
|
||||||
|
}
|
||||||
|
value := gjson.Get(json, "name.last")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unmarshal to a map
|
||||||
|
|
||||||
|
To unmarshal to a `map[string]interface{}`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
m, ok := gjson.Parse(json).Value().(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
// not a map
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Working with Bytes
|
||||||
|
|
||||||
|
If your JSON is contained in a `[]byte` slice, there's the [GetBytes](https://godoc.org/github.com/tidwall/gjson#GetBytes) function. This is preferred over `Get(string(data), path)`.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var json []byte = ...
|
||||||
|
result := gjson.GetBytes(json, path)
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using the `gjson.GetBytes(json, path)` function and you want to avoid converting `result.Raw` to a `[]byte`, then you can use this pattern:
|
||||||
|
|
||||||
|
```go
|
||||||
|
var json []byte = ...
|
||||||
|
result := gjson.GetBytes(json, path)
|
||||||
|
var raw []byte
|
||||||
|
if result.Index > 0 {
|
||||||
|
raw = json[result.Index:result.Index+len(result.Raw)]
|
||||||
|
} else {
|
||||||
|
raw = []byte(result.Raw)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a best-effort no allocation sub slice of the original json. This method utilizes the `result.Index` field, which is the position of the raw data in the original json. It's possible that the value of `result.Index` equals zero, in which case the `result.Raw` is converted to a `[]byte`.
|
||||||
|
|
||||||
|
## Get multiple values at once
|
||||||
|
|
||||||
|
The `GetMany` function can be used to get multiple values at the same time.
|
||||||
|
|
||||||
|
```go
|
||||||
|
results := gjson.GetMany(json, "name.first", "name.last", "age")
|
||||||
|
```
|
||||||
|
|
||||||
|
The return value is a `[]Result`, which will always contain exactly the same number of items as the input paths.
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
|
||||||
|
[ffjson](https://github.com/pquerna/ffjson),
|
||||||
|
[EasyJSON](https://github.com/mailru/easyjson),
|
||||||
|
[jsonparser](https://github.com/buger/jsonparser),
|
||||||
|
and [json-iterator](https://github.com/json-iterator/go)
|
||||||
|
|
||||||
|
```
|
||||||
|
BenchmarkGJSONGet-8 3000000 372 ns/op 0 B/op 0 allocs/op
|
||||||
|
BenchmarkGJSONUnmarshalMap-8 900000 4154 ns/op 1920 B/op 26 allocs/op
|
||||||
|
BenchmarkJSONUnmarshalMap-8 600000 9019 ns/op 3048 B/op 69 allocs/op
|
||||||
|
BenchmarkJSONDecoder-8 300000 14120 ns/op 4224 B/op 184 allocs/op
|
||||||
|
BenchmarkFFJSONLexer-8 1500000 3111 ns/op 896 B/op 8 allocs/op
|
||||||
|
BenchmarkEasyJSONLexer-8 3000000 887 ns/op 613 B/op 6 allocs/op
|
||||||
|
BenchmarkJSONParserGet-8 3000000 499 ns/op 21 B/op 0 allocs/op
|
||||||
|
BenchmarkJSONIterator-8 3000000 812 ns/op 544 B/op 9 allocs/op
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON document used:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"debug": "on",
|
||||||
|
"window": {
|
||||||
|
"title": "Sample Konfabulator Widget",
|
||||||
|
"name": "main_window",
|
||||||
|
"width": 500,
|
||||||
|
"height": 500
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"src": "Images/Sun.png",
|
||||||
|
"hOffset": 250,
|
||||||
|
"vOffset": 250,
|
||||||
|
"alignment": "center"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"data": "Click Here",
|
||||||
|
"size": 36,
|
||||||
|
"style": "bold",
|
||||||
|
"vOffset": 100,
|
||||||
|
"alignment": "center",
|
||||||
|
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each operation was rotated though one of the following search paths:
|
||||||
|
|
||||||
|
```
|
||||||
|
widget.window.name
|
||||||
|
widget.image.hOffset
|
||||||
|
widget.text.onMouseUp
|
||||||
|
```
|
||||||
|
|
||||||
|
*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.8 and can be be found [here](https://github.com/tidwall/gjson-benchmarks).*
|
||||||
|
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
Josh Baker [@tidwall](http://twitter.com/tidwall)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
GJSON source code is available under the MIT [License](/LICENSE).
|
||||||
227
vendor/github.com/tidwall/gjson/SYNTAX.md
generated
vendored
Normal file
227
vendor/github.com/tidwall/gjson/SYNTAX.md
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
# GJSON Path Syntax
|
||||||
|
|
||||||
|
A GJSON Path is a text string syntax that describes a search pattern for quickly retreiving values from a JSON payload.
|
||||||
|
|
||||||
|
This document is designed to explain the structure of a GJSON Path through examples.
|
||||||
|
|
||||||
|
- [Path structure](#path-structure)
|
||||||
|
- [Basic](#basic)
|
||||||
|
- [Wildcards](#wildcards)
|
||||||
|
- [Escape Character](#escape-character)
|
||||||
|
- [Arrays](#arrays)
|
||||||
|
- [Queries](#queries)
|
||||||
|
- [Dot vs Pipe](#dot-vs-pipe)
|
||||||
|
- [Modifiers](#modifiers)
|
||||||
|
|
||||||
|
The definitive implemenation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson).
|
||||||
|
|
||||||
|
|
||||||
|
## Path structure
|
||||||
|
|
||||||
|
A GJSON Path is intended to be easily expressed as a series of components seperated by a `.` character.
|
||||||
|
|
||||||
|
Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, and `?`.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Given this JSON
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": {"first": "Tom", "last": "Anderson"},
|
||||||
|
"age":37,
|
||||||
|
"children": ["Sara","Alex","Jack"],
|
||||||
|
"fav.movie": "Deer Hunter",
|
||||||
|
"friends": [
|
||||||
|
{"first": "Dale", "last": "Murphy", "age": 44},
|
||||||
|
{"first": "Roger", "last": "Craig", "age": 68},
|
||||||
|
{"first": "Jane", "last": "Murphy", "age": 47}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The following GJSON Paths evaluate to the accompanying values.
|
||||||
|
|
||||||
|
### Basic
|
||||||
|
|
||||||
|
In many cases you'll just want to retreive values by object name or array index.
|
||||||
|
|
||||||
|
```go
|
||||||
|
name.last "Anderson"
|
||||||
|
name.first "Tom"
|
||||||
|
age 37
|
||||||
|
children ["Sara","Alex","Jack"]
|
||||||
|
children.0 "Sara"
|
||||||
|
children.1 "Alex"
|
||||||
|
friends.1 {"first": "Roger", "last": "Craig", "age": 68}
|
||||||
|
friends.1.first "Roger"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wildcards
|
||||||
|
|
||||||
|
A key may contain the special wildcard characters `*` and `?`.
|
||||||
|
The `*` will match on any zero+ characters, and `?` matches on any one character.
|
||||||
|
|
||||||
|
```go
|
||||||
|
child*.2 "Jack"
|
||||||
|
c?ildren.0 "Sara"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Escape character
|
||||||
|
|
||||||
|
Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`.
|
||||||
|
|
||||||
|
```go
|
||||||
|
fav\.movie "Deer Hunter"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Arrays
|
||||||
|
|
||||||
|
The `#` character allows for digging into JSON Arrays.
|
||||||
|
|
||||||
|
To get the length of an array you'll just use the `#` all by itself.
|
||||||
|
|
||||||
|
```go
|
||||||
|
friends.# 3
|
||||||
|
friends.#.age [44,68,47]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Queries
|
||||||
|
|
||||||
|
You can also query an array for the first match by using `#[...]`, or find all matches with `#[...]#`.
|
||||||
|
Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators,
|
||||||
|
and the simple pattern matching `%` (like) and `!%` (not like) operators.
|
||||||
|
|
||||||
|
```go
|
||||||
|
friends.#[last=="Murphy"].first "Dale"
|
||||||
|
friends.#[last=="Murphy"]#.first ["Dale","Jane"]
|
||||||
|
friends.#[age>45]#.last ["Craig","Murphy"]
|
||||||
|
friends.#[first%"D*"].last "Murphy"
|
||||||
|
friends.#[first!%"D*"].last "Craig"
|
||||||
|
```
|
||||||
|
|
||||||
|
To query for a non-object value in an array, you can forgo the string to the right of the operator.
|
||||||
|
```go
|
||||||
|
children.#[!%"*a*"] "Alex"
|
||||||
|
children.#[%"*a*"]# ["Sara","Jack"]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Dot vs Pipe
|
||||||
|
|
||||||
|
The `.` is standard separator, but it's also possible to use a `|`.
|
||||||
|
In most cases they both end up returning the same results.
|
||||||
|
The cases where`|` differs from `.` is when it's used after the `#` for [Arrays](#arrays) and [Queries](#queries).
|
||||||
|
|
||||||
|
Here are some examples
|
||||||
|
|
||||||
|
```go
|
||||||
|
friends.0.first "Dale"
|
||||||
|
friends|0.first "Dale"
|
||||||
|
friends.0|first "Dale"
|
||||||
|
friends|0|first "Dale"
|
||||||
|
friends|# 3
|
||||||
|
friends.# 3
|
||||||
|
friends.#[last="Murphy"]# [{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
|
||||||
|
friends.#[last="Murphy"]#.first ["Dale","Jane"]
|
||||||
|
friends.#[last="Murphy"]#|first <non-existent>
|
||||||
|
friends.#[last="Murphy"]#.0 []
|
||||||
|
friends.#[last="Murphy"]#|0 {"first": "Dale", "last": "Murphy", "age": 44}
|
||||||
|
friends.#[last="Murphy"]#.# []
|
||||||
|
friends.#[last="Murphy"]#|# 2
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's break down a few of these.
|
||||||
|
|
||||||
|
The path `friends.#[last="Murphy"]#` all by itself results in
|
||||||
|
|
||||||
|
```json
|
||||||
|
[{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
|
||||||
|
```
|
||||||
|
|
||||||
|
The `.first` suffix will process the `first` path on each array element *before* returning the results. Which becomes
|
||||||
|
|
||||||
|
```json
|
||||||
|
["Dale","Jane"]
|
||||||
|
```
|
||||||
|
|
||||||
|
But the `|first` suffix actually processes the `first` path *after* the previous result.
|
||||||
|
Since the previous result is an array, not an object, it's not possible to process
|
||||||
|
because `first` does not exist.
|
||||||
|
|
||||||
|
Yet, `|0` suffix returns
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"first": "Dale", "last": "Murphy", "age": 44}
|
||||||
|
```
|
||||||
|
|
||||||
|
Because `0` is the first index of the previous result.
|
||||||
|
|
||||||
|
### Modifiers
|
||||||
|
|
||||||
|
A modifier is a path component that performs custom processing on the JSON.
|
||||||
|
|
||||||
|
For example, using the built-in `@reverse` modifier on the above JSON payload will reverse the `children` array:
|
||||||
|
|
||||||
|
```go
|
||||||
|
children.@reverse ["Jack","Alex","Sara"]
|
||||||
|
children.@reverse.0 "Jack"
|
||||||
|
```
|
||||||
|
|
||||||
|
There are currently three built-in modifiers:
|
||||||
|
|
||||||
|
- `@reverse`: Reverse an array or the members of an object.
|
||||||
|
- `@ugly`: Remove all whitespace from JSON.
|
||||||
|
- `@pretty`: Make the JSON more human readable.
|
||||||
|
|
||||||
|
#### Modifier arguments
|
||||||
|
|
||||||
|
A modifier may accept an optional argument. The argument can be a valid JSON payload or just characters.
|
||||||
|
|
||||||
|
For example, the `@pretty` modifier takes a json object as its argument.
|
||||||
|
|
||||||
|
```
|
||||||
|
@pretty:{"sortKeys":true}
|
||||||
|
```
|
||||||
|
|
||||||
|
Which makes the json pretty and orders all of its keys.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"age":37,
|
||||||
|
"children": ["Sara","Alex","Jack"],
|
||||||
|
"fav.movie": "Deer Hunter",
|
||||||
|
"friends": [
|
||||||
|
{"age": 44, "first": "Dale", "last": "Murphy"},
|
||||||
|
{"age": 68, "first": "Roger", "last": "Craig"},
|
||||||
|
{"age": 47, "first": "Jane", "last": "Murphy"}
|
||||||
|
],
|
||||||
|
"name": {"first": "Tom", "last": "Anderson"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
|
||||||
|
Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
|
||||||
|
|
||||||
|
#### Custom modifiers
|
||||||
|
|
||||||
|
You can also add custom modifiers.
|
||||||
|
|
||||||
|
For example, here we create a modifier which makes the entire JSON payload upper or lower case.
|
||||||
|
|
||||||
|
```go
|
||||||
|
gjson.AddModifier("case", func(json, arg string) string {
|
||||||
|
if arg == "upper" {
|
||||||
|
return strings.ToUpper(json)
|
||||||
|
}
|
||||||
|
if arg == "lower" {
|
||||||
|
return strings.ToLower(json)
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
})
|
||||||
|
"children.@case:upper" ["SARA","ALEX","JACK"]
|
||||||
|
"children.@case:lower.@reverse" ["jack","alex","sara"]
|
||||||
|
```
|
||||||
|
|
||||||
2663
vendor/github.com/tidwall/gjson/gjson.go
generated
vendored
Normal file
2663
vendor/github.com/tidwall/gjson/gjson.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
vendor/github.com/tidwall/gjson/gjson_gae.go
generated
vendored
Normal file
18
vendor/github.com/tidwall/gjson/gjson_gae.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//+build appengine js
|
||||||
|
|
||||||
|
package gjson
|
||||||
|
|
||||||
|
func getBytes(json []byte, path string) Result {
|
||||||
|
return Get(string(json), path)
|
||||||
|
}
|
||||||
|
func fillIndex(json string, c *parseContext) {
|
||||||
|
// noop. Use zero for the Index value.
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringBytes(s string) []byte {
|
||||||
|
return []byte(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bytesString(b []byte) string {
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
81
vendor/github.com/tidwall/gjson/gjson_ngae.go
generated
vendored
Normal file
81
vendor/github.com/tidwall/gjson/gjson_ngae.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
//+build !appengine
|
||||||
|
//+build !js
|
||||||
|
|
||||||
|
package gjson
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getBytes casts the input json bytes to a string and safely returns the
|
||||||
|
// results as uniquely allocated data. This operation is intended to minimize
|
||||||
|
// copies and allocations for the large json string->[]byte.
|
||||||
|
func getBytes(json []byte, path string) Result {
|
||||||
|
var result Result
|
||||||
|
if json != nil {
|
||||||
|
// unsafe cast to string
|
||||||
|
result = Get(*(*string)(unsafe.Pointer(&json)), path)
|
||||||
|
// safely get the string headers
|
||||||
|
rawhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Raw))
|
||||||
|
strhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Str))
|
||||||
|
// create byte slice headers
|
||||||
|
rawh := reflect.SliceHeader{Data: rawhi.Data, Len: rawhi.Len}
|
||||||
|
strh := reflect.SliceHeader{Data: strhi.Data, Len: strhi.Len}
|
||||||
|
if strh.Data == 0 {
|
||||||
|
// str is nil
|
||||||
|
if rawh.Data == 0 {
|
||||||
|
// raw is nil
|
||||||
|
result.Raw = ""
|
||||||
|
} else {
|
||||||
|
// raw has data, safely copy the slice header to a string
|
||||||
|
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
||||||
|
}
|
||||||
|
result.Str = ""
|
||||||
|
} else if rawh.Data == 0 {
|
||||||
|
// raw is nil
|
||||||
|
result.Raw = ""
|
||||||
|
// str has data, safely copy the slice header to a string
|
||||||
|
result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
|
||||||
|
} else if strh.Data >= rawh.Data &&
|
||||||
|
int(strh.Data)+strh.Len <= int(rawh.Data)+rawh.Len {
|
||||||
|
// Str is a substring of Raw.
|
||||||
|
start := int(strh.Data - rawh.Data)
|
||||||
|
// safely copy the raw slice header
|
||||||
|
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
||||||
|
// substring the raw
|
||||||
|
result.Str = result.Raw[start : start+strh.Len]
|
||||||
|
} else {
|
||||||
|
// safely copy both the raw and str slice headers to strings
|
||||||
|
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
||||||
|
result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// fillIndex finds the position of Raw data and assigns it to the Index field
|
||||||
|
// of the resulting value. If the position cannot be found then Index zero is
|
||||||
|
// used instead.
|
||||||
|
func fillIndex(json string, c *parseContext) {
|
||||||
|
if len(c.value.Raw) > 0 && !c.calcd {
|
||||||
|
jhdr := *(*reflect.StringHeader)(unsafe.Pointer(&json))
|
||||||
|
rhdr := *(*reflect.StringHeader)(unsafe.Pointer(&(c.value.Raw)))
|
||||||
|
c.value.Index = int(rhdr.Data - jhdr.Data)
|
||||||
|
if c.value.Index < 0 || c.value.Index >= len(json) {
|
||||||
|
c.value.Index = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringBytes(s string) []byte {
|
||||||
|
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
||||||
|
Data: (*reflect.StringHeader)(unsafe.Pointer(&s)).Data,
|
||||||
|
Len: len(s),
|
||||||
|
Cap: len(s),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func bytesString(b []byte) string {
|
||||||
|
return *(*string)(unsafe.Pointer(&b))
|
||||||
|
}
|
||||||
8
vendor/github.com/tidwall/gjson/go.mod
generated
vendored
Normal file
8
vendor/github.com/tidwall/gjson/go.mod
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module github.com/tidwall/gjson
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/tidwall/match v1.0.1
|
||||||
|
github.com/tidwall/pretty v1.0.0
|
||||||
|
)
|
||||||
4
vendor/github.com/tidwall/gjson/go.sum
generated
vendored
Normal file
4
vendor/github.com/tidwall/gjson/go.sum
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
||||||
|
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||||
|
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||||
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
BIN
vendor/github.com/tidwall/gjson/logo.png
generated
vendored
Normal file
BIN
vendor/github.com/tidwall/gjson/logo.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
1
vendor/github.com/tidwall/match/.travis.yml
generated
vendored
Normal file
1
vendor/github.com/tidwall/match/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
language: go
|
||||||
20
vendor/github.com/tidwall/match/LICENSE
generated
vendored
Normal file
20
vendor/github.com/tidwall/match/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Josh Baker
|
||||||
|
|
||||||
|
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.
|
||||||
32
vendor/github.com/tidwall/match/README.md
generated
vendored
Normal file
32
vendor/github.com/tidwall/match/README.md
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Match
|
||||||
|
=====
|
||||||
|
<a href="https://travis-ci.org/tidwall/match"><img src="https://img.shields.io/travis/tidwall/match.svg?style=flat-square" alt="Build Status"></a>
|
||||||
|
<a href="https://godoc.org/github.com/tidwall/match"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
|
||||||
|
|
||||||
|
Match is a very simple pattern matcher where '*' matches on any
|
||||||
|
number characters and '?' matches on any one character.
|
||||||
|
|
||||||
|
Installing
|
||||||
|
----------
|
||||||
|
|
||||||
|
```
|
||||||
|
go get -u github.com/tidwall/match
|
||||||
|
```
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
```go
|
||||||
|
match.Match("hello", "*llo")
|
||||||
|
match.Match("jello", "?ello")
|
||||||
|
match.Match("hello", "h*o")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Contact
|
||||||
|
-------
|
||||||
|
Josh Baker [@tidwall](http://twitter.com/tidwall)
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
Redcon source code is available under the MIT [License](/LICENSE).
|
||||||
181
vendor/github.com/tidwall/match/match.go
generated
vendored
Normal file
181
vendor/github.com/tidwall/match/match.go
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// Match provides a simple pattern matcher with unicode support.
|
||||||
|
package match
|
||||||
|
|
||||||
|
import "unicode/utf8"
|
||||||
|
|
||||||
|
// Match returns true if str matches pattern. This is a very
|
||||||
|
// simple wildcard match where '*' matches on any number characters
|
||||||
|
// and '?' matches on any one character.
|
||||||
|
|
||||||
|
// pattern:
|
||||||
|
// { term }
|
||||||
|
// term:
|
||||||
|
// '*' matches any sequence of non-Separator characters
|
||||||
|
// '?' matches any single non-Separator character
|
||||||
|
// c matches character c (c != '*', '?', '\\')
|
||||||
|
// '\\' c matches character c
|
||||||
|
//
|
||||||
|
func Match(str, pattern string) bool {
|
||||||
|
if pattern == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return deepMatch(str, pattern)
|
||||||
|
}
|
||||||
|
func deepMatch(str, pattern string) bool {
|
||||||
|
for len(pattern) > 0 {
|
||||||
|
if pattern[0] > 0x7f {
|
||||||
|
return deepMatchRune(str, pattern)
|
||||||
|
}
|
||||||
|
switch pattern[0] {
|
||||||
|
default:
|
||||||
|
if len(str) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if str[0] > 0x7f {
|
||||||
|
return deepMatchRune(str, pattern)
|
||||||
|
}
|
||||||
|
if str[0] != pattern[0] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case '?':
|
||||||
|
if len(str) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case '*':
|
||||||
|
return deepMatch(str, pattern[1:]) ||
|
||||||
|
(len(str) > 0 && deepMatch(str[1:], pattern))
|
||||||
|
}
|
||||||
|
str = str[1:]
|
||||||
|
pattern = pattern[1:]
|
||||||
|
}
|
||||||
|
return len(str) == 0 && len(pattern) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepMatchRune(str, pattern string) bool {
|
||||||
|
var sr, pr rune
|
||||||
|
var srsz, prsz int
|
||||||
|
|
||||||
|
// read the first rune ahead of time
|
||||||
|
if len(str) > 0 {
|
||||||
|
if str[0] > 0x7f {
|
||||||
|
sr, srsz = utf8.DecodeRuneInString(str)
|
||||||
|
} else {
|
||||||
|
sr, srsz = rune(str[0]), 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sr, srsz = utf8.RuneError, 0
|
||||||
|
}
|
||||||
|
if len(pattern) > 0 {
|
||||||
|
if pattern[0] > 0x7f {
|
||||||
|
pr, prsz = utf8.DecodeRuneInString(pattern)
|
||||||
|
} else {
|
||||||
|
pr, prsz = rune(pattern[0]), 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr, prsz = utf8.RuneError, 0
|
||||||
|
}
|
||||||
|
// done reading
|
||||||
|
for pr != utf8.RuneError {
|
||||||
|
switch pr {
|
||||||
|
default:
|
||||||
|
if srsz == utf8.RuneError {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if sr != pr {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case '?':
|
||||||
|
if srsz == utf8.RuneError {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case '*':
|
||||||
|
return deepMatchRune(str, pattern[prsz:]) ||
|
||||||
|
(srsz > 0 && deepMatchRune(str[srsz:], pattern))
|
||||||
|
}
|
||||||
|
str = str[srsz:]
|
||||||
|
pattern = pattern[prsz:]
|
||||||
|
// read the next runes
|
||||||
|
if len(str) > 0 {
|
||||||
|
if str[0] > 0x7f {
|
||||||
|
sr, srsz = utf8.DecodeRuneInString(str)
|
||||||
|
} else {
|
||||||
|
sr, srsz = rune(str[0]), 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sr, srsz = utf8.RuneError, 0
|
||||||
|
}
|
||||||
|
if len(pattern) > 0 {
|
||||||
|
if pattern[0] > 0x7f {
|
||||||
|
pr, prsz = utf8.DecodeRuneInString(pattern)
|
||||||
|
} else {
|
||||||
|
pr, prsz = rune(pattern[0]), 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr, prsz = utf8.RuneError, 0
|
||||||
|
}
|
||||||
|
// done reading
|
||||||
|
}
|
||||||
|
|
||||||
|
return srsz == 0 && prsz == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxRuneBytes = func() []byte {
|
||||||
|
b := make([]byte, 4)
|
||||||
|
if utf8.EncodeRune(b, '\U0010FFFF') != 4 {
|
||||||
|
panic("invalid rune encoding")
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Allowable parses the pattern and determines the minimum and maximum allowable
|
||||||
|
// values that the pattern can represent.
|
||||||
|
// When the max cannot be determined, 'true' will be returned
|
||||||
|
// for infinite.
|
||||||
|
func Allowable(pattern string) (min, max string) {
|
||||||
|
if pattern == "" || pattern[0] == '*' {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
minb := make([]byte, 0, len(pattern))
|
||||||
|
maxb := make([]byte, 0, len(pattern))
|
||||||
|
var wild bool
|
||||||
|
for i := 0; i < len(pattern); i++ {
|
||||||
|
if pattern[i] == '*' {
|
||||||
|
wild = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if pattern[i] == '?' {
|
||||||
|
minb = append(minb, 0)
|
||||||
|
maxb = append(maxb, maxRuneBytes...)
|
||||||
|
} else {
|
||||||
|
minb = append(minb, pattern[i])
|
||||||
|
maxb = append(maxb, pattern[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if wild {
|
||||||
|
r, n := utf8.DecodeLastRune(maxb)
|
||||||
|
if r != utf8.RuneError {
|
||||||
|
if r < utf8.MaxRune {
|
||||||
|
r++
|
||||||
|
if r > 0x7f {
|
||||||
|
b := make([]byte, 4)
|
||||||
|
nn := utf8.EncodeRune(b, r)
|
||||||
|
maxb = append(maxb[:len(maxb)-n], b[:nn]...)
|
||||||
|
} else {
|
||||||
|
maxb = append(maxb[:len(maxb)-n], byte(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(minb), string(maxb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPattern returns true if the string is a pattern.
|
||||||
|
func IsPattern(str string) bool {
|
||||||
|
for i := 0; i < len(str); i++ {
|
||||||
|
if str[i] == '*' || str[i] == '?' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
1
vendor/github.com/tidwall/pretty/.travis.yml
generated
vendored
Normal file
1
vendor/github.com/tidwall/pretty/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
language: go
|
||||||
20
vendor/github.com/tidwall/pretty/LICENSE
generated
vendored
Normal file
20
vendor/github.com/tidwall/pretty/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 Josh Baker
|
||||||
|
|
||||||
|
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.
|
||||||
124
vendor/github.com/tidwall/pretty/README.md
generated
vendored
Normal file
124
vendor/github.com/tidwall/pretty/README.md
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# Pretty
|
||||||
|
[](https://travis-ci.org/tidwall/prettty)
|
||||||
|
[](http://gocover.io/github.com/tidwall/pretty)
|
||||||
|
[](https://godoc.org/github.com/tidwall/pretty)
|
||||||
|
|
||||||
|
|
||||||
|
Pretty is a Go package that provides [fast](#performance) methods for formatting JSON for human readability, or to compact JSON for smaller payloads.
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
|
||||||
|
## Installing
|
||||||
|
|
||||||
|
To start using Pretty, install Go and run `go get`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ go get -u github.com/tidwall/pretty
|
||||||
|
```
|
||||||
|
|
||||||
|
This will retrieve the library.
|
||||||
|
|
||||||
|
## Pretty
|
||||||
|
|
||||||
|
Using this example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"name": {"first":"Tom","last":"Anderson"}, "age":37,
|
||||||
|
"children": ["Sara","Alex","Jack"],
|
||||||
|
"fav.movie": "Deer Hunter", "friends": [
|
||||||
|
{"first": "Janet", "last": "Murphy", "age": 44}
|
||||||
|
]}
|
||||||
|
```
|
||||||
|
|
||||||
|
The following code:
|
||||||
|
```go
|
||||||
|
result = pretty.Pretty(example)
|
||||||
|
```
|
||||||
|
|
||||||
|
Will format the json to:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"first": "Tom",
|
||||||
|
"last": "Anderson"
|
||||||
|
},
|
||||||
|
"age": 37,
|
||||||
|
"children": ["Sara", "Alex", "Jack"],
|
||||||
|
"fav.movie": "Deer Hunter",
|
||||||
|
"friends": [
|
||||||
|
{
|
||||||
|
"first": "Janet",
|
||||||
|
"last": "Murphy",
|
||||||
|
"age": 44
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Color
|
||||||
|
|
||||||
|
Color will colorize the json for outputing to the screen.
|
||||||
|
|
||||||
|
```json
|
||||||
|
result = pretty.Color(json, nil)
|
||||||
|
```
|
||||||
|
|
||||||
|
Will add color to the result for printing to the terminal.
|
||||||
|
The second param is used for a customizing the style, and passing nil will use the default `pretty.TerminalStyle`.
|
||||||
|
|
||||||
|
## Ugly
|
||||||
|
|
||||||
|
The following code:
|
||||||
|
```go
|
||||||
|
result = pretty.Ugly(example)
|
||||||
|
```
|
||||||
|
|
||||||
|
Will format the json to:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"name":{"first":"Tom","last":"Anderson"},"age":37,"children":["Sara","Alex","Jack"],"fav.movie":"Deer Hunter","friends":[{"first":"Janet","last":"Murphy","age":44}]}```
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Customized output
|
||||||
|
|
||||||
|
There's a `PrettyOptions(json, opts)` function which allows for customizing the output with the following options:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Options struct {
|
||||||
|
// Width is an max column width for single line arrays
|
||||||
|
// Default is 80
|
||||||
|
Width int
|
||||||
|
// Prefix is a prefix for all lines
|
||||||
|
// Default is an empty string
|
||||||
|
Prefix string
|
||||||
|
// Indent is the nested indentation
|
||||||
|
// Default is two spaces
|
||||||
|
Indent string
|
||||||
|
// SortKeys will sort the keys alphabetically
|
||||||
|
// Default is false
|
||||||
|
SortKeys bool
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
Benchmarks of Pretty alongside the builtin `encoding/json` Indent/Compact methods.
|
||||||
|
```
|
||||||
|
BenchmarkPretty-8 1000000 1283 ns/op 720 B/op 2 allocs/op
|
||||||
|
BenchmarkUgly-8 3000000 426 ns/op 240 B/op 1 allocs/op
|
||||||
|
BenchmarkUglyInPlace-8 5000000 340 ns/op 0 B/op 0 allocs/op
|
||||||
|
BenchmarkJSONIndent-8 300000 4628 ns/op 1069 B/op 4 allocs/op
|
||||||
|
BenchmarkJSONCompact-8 1000000 2469 ns/op 758 B/op 4 allocs/op
|
||||||
|
```
|
||||||
|
|
||||||
|
*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7.*
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
Josh Baker [@tidwall](http://twitter.com/tidwall)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Pretty source code is available under the MIT [License](/LICENSE).
|
||||||
|
|
||||||
432
vendor/github.com/tidwall/pretty/pretty.go
generated
vendored
Normal file
432
vendor/github.com/tidwall/pretty/pretty.go
generated
vendored
Normal file
@@ -0,0 +1,432 @@
|
|||||||
|
package pretty
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options is Pretty options
|
||||||
|
type Options struct {
|
||||||
|
// Width is an max column width for single line arrays
|
||||||
|
// Default is 80
|
||||||
|
Width int
|
||||||
|
// Prefix is a prefix for all lines
|
||||||
|
// Default is an empty string
|
||||||
|
Prefix string
|
||||||
|
// Indent is the nested indentation
|
||||||
|
// Default is two spaces
|
||||||
|
Indent string
|
||||||
|
// SortKeys will sort the keys alphabetically
|
||||||
|
// Default is false
|
||||||
|
SortKeys bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultOptions is the default options for pretty formats.
|
||||||
|
var DefaultOptions = &Options{Width: 80, Prefix: "", Indent: " ", SortKeys: false}
|
||||||
|
|
||||||
|
// Pretty converts the input json into a more human readable format where each
|
||||||
|
// element is on it's own line with clear indentation.
|
||||||
|
func Pretty(json []byte) []byte { return PrettyOptions(json, nil) }
|
||||||
|
|
||||||
|
// PrettyOptions is like Pretty but with customized options.
|
||||||
|
func PrettyOptions(json []byte, opts *Options) []byte {
|
||||||
|
if opts == nil {
|
||||||
|
opts = DefaultOptions
|
||||||
|
}
|
||||||
|
buf := make([]byte, 0, len(json))
|
||||||
|
if len(opts.Prefix) != 0 {
|
||||||
|
buf = append(buf, opts.Prefix...)
|
||||||
|
}
|
||||||
|
buf, _, _, _ = appendPrettyAny(buf, json, 0, true,
|
||||||
|
opts.Width, opts.Prefix, opts.Indent, opts.SortKeys,
|
||||||
|
0, 0, -1)
|
||||||
|
if len(buf) > 0 {
|
||||||
|
buf = append(buf, '\n')
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ugly removes insignificant space characters from the input json byte slice
|
||||||
|
// and returns the compacted result.
|
||||||
|
func Ugly(json []byte) []byte {
|
||||||
|
buf := make([]byte, 0, len(json))
|
||||||
|
return ugly(buf, json)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UglyInPlace removes insignificant space characters from the input json
|
||||||
|
// byte slice and returns the compacted result. This method reuses the
|
||||||
|
// input json buffer to avoid allocations. Do not use the original bytes
|
||||||
|
// slice upon return.
|
||||||
|
func UglyInPlace(json []byte) []byte { return ugly(json, json) }
|
||||||
|
|
||||||
|
func ugly(dst, src []byte) []byte {
|
||||||
|
dst = dst[:0]
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] > ' ' {
|
||||||
|
dst = append(dst, src[i])
|
||||||
|
if src[i] == '"' {
|
||||||
|
for i = i + 1; i < len(src); i++ {
|
||||||
|
dst = append(dst, src[i])
|
||||||
|
if src[i] == '"' {
|
||||||
|
j := i - 1
|
||||||
|
for ; ; j-- {
|
||||||
|
if src[j] != '\\' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j-i)%2 != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendPrettyAny(buf, json []byte, i int, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) {
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] <= ' ' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if json[i] == '"' {
|
||||||
|
return appendPrettyString(buf, json, i, nl)
|
||||||
|
}
|
||||||
|
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
|
||||||
|
return appendPrettyNumber(buf, json, i, nl)
|
||||||
|
}
|
||||||
|
if json[i] == '{' {
|
||||||
|
return appendPrettyObject(buf, json, i, '{', '}', pretty, width, prefix, indent, sortkeys, tabs, nl, max)
|
||||||
|
}
|
||||||
|
if json[i] == '[' {
|
||||||
|
return appendPrettyObject(buf, json, i, '[', ']', pretty, width, prefix, indent, sortkeys, tabs, nl, max)
|
||||||
|
}
|
||||||
|
switch json[i] {
|
||||||
|
case 't':
|
||||||
|
return append(buf, 't', 'r', 'u', 'e'), i + 4, nl, true
|
||||||
|
case 'f':
|
||||||
|
return append(buf, 'f', 'a', 'l', 's', 'e'), i + 5, nl, true
|
||||||
|
case 'n':
|
||||||
|
return append(buf, 'n', 'u', 'l', 'l'), i + 4, nl, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf, i, nl, true
|
||||||
|
}
|
||||||
|
|
||||||
|
type pair struct {
|
||||||
|
kstart, kend int
|
||||||
|
vstart, vend int
|
||||||
|
}
|
||||||
|
|
||||||
|
type byKey struct {
|
||||||
|
sorted bool
|
||||||
|
json []byte
|
||||||
|
pairs []pair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arr *byKey) Len() int {
|
||||||
|
return len(arr.pairs)
|
||||||
|
}
|
||||||
|
func (arr *byKey) Less(i, j int) bool {
|
||||||
|
key1 := arr.json[arr.pairs[i].kstart+1 : arr.pairs[i].kend-1]
|
||||||
|
key2 := arr.json[arr.pairs[j].kstart+1 : arr.pairs[j].kend-1]
|
||||||
|
return string(key1) < string(key2)
|
||||||
|
}
|
||||||
|
func (arr *byKey) Swap(i, j int) {
|
||||||
|
arr.pairs[i], arr.pairs[j] = arr.pairs[j], arr.pairs[i]
|
||||||
|
arr.sorted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendPrettyObject(buf, json []byte, i int, open, close byte, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) {
|
||||||
|
var ok bool
|
||||||
|
if width > 0 {
|
||||||
|
if pretty && open == '[' && max == -1 {
|
||||||
|
// here we try to create a single line array
|
||||||
|
max := width - (len(buf) - nl)
|
||||||
|
if max > 3 {
|
||||||
|
s1, s2 := len(buf), i
|
||||||
|
buf, i, _, ok = appendPrettyObject(buf, json, i, '[', ']', false, width, prefix, "", sortkeys, 0, 0, max)
|
||||||
|
if ok && len(buf)-s1 <= max {
|
||||||
|
return buf, i, nl, true
|
||||||
|
}
|
||||||
|
buf = buf[:s1]
|
||||||
|
i = s2
|
||||||
|
}
|
||||||
|
} else if max != -1 && open == '{' {
|
||||||
|
return buf, i, nl, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf = append(buf, open)
|
||||||
|
i++
|
||||||
|
var pairs []pair
|
||||||
|
if open == '{' && sortkeys {
|
||||||
|
pairs = make([]pair, 0, 8)
|
||||||
|
}
|
||||||
|
var n int
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] <= ' ' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if json[i] == close {
|
||||||
|
if pretty {
|
||||||
|
if open == '{' && sortkeys {
|
||||||
|
buf = sortPairs(json, buf, pairs)
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
nl = len(buf)
|
||||||
|
buf = append(buf, '\n')
|
||||||
|
}
|
||||||
|
if buf[len(buf)-1] != open {
|
||||||
|
buf = appendTabs(buf, prefix, indent, tabs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf = append(buf, close)
|
||||||
|
return buf, i + 1, nl, open != '{'
|
||||||
|
}
|
||||||
|
if open == '[' || json[i] == '"' {
|
||||||
|
if n > 0 {
|
||||||
|
buf = append(buf, ',')
|
||||||
|
if width != -1 && open == '[' {
|
||||||
|
buf = append(buf, ' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var p pair
|
||||||
|
if pretty {
|
||||||
|
nl = len(buf)
|
||||||
|
buf = append(buf, '\n')
|
||||||
|
if open == '{' && sortkeys {
|
||||||
|
p.kstart = i
|
||||||
|
p.vstart = len(buf)
|
||||||
|
}
|
||||||
|
buf = appendTabs(buf, prefix, indent, tabs+1)
|
||||||
|
}
|
||||||
|
if open == '{' {
|
||||||
|
buf, i, nl, _ = appendPrettyString(buf, json, i, nl)
|
||||||
|
if sortkeys {
|
||||||
|
p.kend = i
|
||||||
|
}
|
||||||
|
buf = append(buf, ':')
|
||||||
|
if pretty {
|
||||||
|
buf = append(buf, ' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf, i, nl, ok = appendPrettyAny(buf, json, i, pretty, width, prefix, indent, sortkeys, tabs+1, nl, max)
|
||||||
|
if max != -1 && !ok {
|
||||||
|
return buf, i, nl, false
|
||||||
|
}
|
||||||
|
if pretty && open == '{' && sortkeys {
|
||||||
|
p.vend = len(buf)
|
||||||
|
if p.kstart > p.kend || p.vstart > p.vend {
|
||||||
|
// bad data. disable sorting
|
||||||
|
sortkeys = false
|
||||||
|
} else {
|
||||||
|
pairs = append(pairs, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i--
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf, i, nl, open != '{'
|
||||||
|
}
|
||||||
|
func sortPairs(json, buf []byte, pairs []pair) []byte {
|
||||||
|
if len(pairs) == 0 {
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
vstart := pairs[0].vstart
|
||||||
|
vend := pairs[len(pairs)-1].vend
|
||||||
|
arr := byKey{false, json, pairs}
|
||||||
|
sort.Sort(&arr)
|
||||||
|
if !arr.sorted {
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
nbuf := make([]byte, 0, vend-vstart)
|
||||||
|
for i, p := range pairs {
|
||||||
|
nbuf = append(nbuf, buf[p.vstart:p.vend]...)
|
||||||
|
if i < len(pairs)-1 {
|
||||||
|
nbuf = append(nbuf, ',')
|
||||||
|
nbuf = append(nbuf, '\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(buf[:vstart], nbuf...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendPrettyString(buf, json []byte, i, nl int) ([]byte, int, int, bool) {
|
||||||
|
s := i
|
||||||
|
i++
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] == '"' {
|
||||||
|
var sc int
|
||||||
|
for j := i - 1; j > s; j-- {
|
||||||
|
if json[j] == '\\' {
|
||||||
|
sc++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sc%2 == 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(buf, json[s:i]...), i, nl, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendPrettyNumber(buf, json []byte, i, nl int) ([]byte, int, int, bool) {
|
||||||
|
s := i
|
||||||
|
i++
|
||||||
|
for ; i < len(json); i++ {
|
||||||
|
if json[i] <= ' ' || json[i] == ',' || json[i] == ':' || json[i] == ']' || json[i] == '}' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(buf, json[s:i]...), i, nl, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendTabs(buf []byte, prefix, indent string, tabs int) []byte {
|
||||||
|
if len(prefix) != 0 {
|
||||||
|
buf = append(buf, prefix...)
|
||||||
|
}
|
||||||
|
if len(indent) == 2 && indent[0] == ' ' && indent[1] == ' ' {
|
||||||
|
for i := 0; i < tabs; i++ {
|
||||||
|
buf = append(buf, ' ', ' ')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := 0; i < tabs; i++ {
|
||||||
|
buf = append(buf, indent...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style is the color style
|
||||||
|
type Style struct {
|
||||||
|
Key, String, Number [2]string
|
||||||
|
True, False, Null [2]string
|
||||||
|
Append func(dst []byte, c byte) []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexp(p byte) byte {
|
||||||
|
switch {
|
||||||
|
case p < 10:
|
||||||
|
return p + '0'
|
||||||
|
default:
|
||||||
|
return (p - 10) + 'a'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TerminalStyle is for terminals
|
||||||
|
var TerminalStyle = &Style{
|
||||||
|
Key: [2]string{"\x1B[94m", "\x1B[0m"},
|
||||||
|
String: [2]string{"\x1B[92m", "\x1B[0m"},
|
||||||
|
Number: [2]string{"\x1B[93m", "\x1B[0m"},
|
||||||
|
True: [2]string{"\x1B[96m", "\x1B[0m"},
|
||||||
|
False: [2]string{"\x1B[96m", "\x1B[0m"},
|
||||||
|
Null: [2]string{"\x1B[91m", "\x1B[0m"},
|
||||||
|
Append: func(dst []byte, c byte) []byte {
|
||||||
|
if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') {
|
||||||
|
dst = append(dst, "\\u00"...)
|
||||||
|
dst = append(dst, hexp((c>>4)&0xF))
|
||||||
|
return append(dst, hexp((c)&0xF))
|
||||||
|
}
|
||||||
|
return append(dst, c)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Color will colorize the json. The style parma is used for customizing
|
||||||
|
// the colors. Passing nil to the style param will use the default
|
||||||
|
// TerminalStyle.
|
||||||
|
func Color(src []byte, style *Style) []byte {
|
||||||
|
if style == nil {
|
||||||
|
style = TerminalStyle
|
||||||
|
}
|
||||||
|
apnd := style.Append
|
||||||
|
if apnd == nil {
|
||||||
|
apnd = func(dst []byte, c byte) []byte {
|
||||||
|
return append(dst, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type stackt struct {
|
||||||
|
kind byte
|
||||||
|
key bool
|
||||||
|
}
|
||||||
|
var dst []byte
|
||||||
|
var stack []stackt
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] == '"' {
|
||||||
|
key := len(stack) > 0 && stack[len(stack)-1].key
|
||||||
|
if key {
|
||||||
|
dst = append(dst, style.Key[0]...)
|
||||||
|
} else {
|
||||||
|
dst = append(dst, style.String[0]...)
|
||||||
|
}
|
||||||
|
dst = apnd(dst, '"')
|
||||||
|
for i = i + 1; i < len(src); i++ {
|
||||||
|
dst = apnd(dst, src[i])
|
||||||
|
if src[i] == '"' {
|
||||||
|
j := i - 1
|
||||||
|
for ; ; j-- {
|
||||||
|
if src[j] != '\\' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j-i)%2 != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if key {
|
||||||
|
dst = append(dst, style.Key[1]...)
|
||||||
|
} else {
|
||||||
|
dst = append(dst, style.String[1]...)
|
||||||
|
}
|
||||||
|
} else if src[i] == '{' || src[i] == '[' {
|
||||||
|
stack = append(stack, stackt{src[i], src[i] == '{'})
|
||||||
|
dst = apnd(dst, src[i])
|
||||||
|
} else if (src[i] == '}' || src[i] == ']') && len(stack) > 0 {
|
||||||
|
stack = stack[:len(stack)-1]
|
||||||
|
dst = apnd(dst, src[i])
|
||||||
|
} else if (src[i] == ':' || src[i] == ',') && len(stack) > 0 && stack[len(stack)-1].kind == '{' {
|
||||||
|
stack[len(stack)-1].key = !stack[len(stack)-1].key
|
||||||
|
dst = apnd(dst, src[i])
|
||||||
|
} else {
|
||||||
|
var kind byte
|
||||||
|
if (src[i] >= '0' && src[i] <= '9') || src[i] == '-' {
|
||||||
|
kind = '0'
|
||||||
|
dst = append(dst, style.Number[0]...)
|
||||||
|
} else if src[i] == 't' {
|
||||||
|
kind = 't'
|
||||||
|
dst = append(dst, style.True[0]...)
|
||||||
|
} else if src[i] == 'f' {
|
||||||
|
kind = 'f'
|
||||||
|
dst = append(dst, style.False[0]...)
|
||||||
|
} else if src[i] == 'n' {
|
||||||
|
kind = 'n'
|
||||||
|
dst = append(dst, style.Null[0]...)
|
||||||
|
} else {
|
||||||
|
dst = apnd(dst, src[i])
|
||||||
|
}
|
||||||
|
if kind != 0 {
|
||||||
|
for ; i < len(src); i++ {
|
||||||
|
if src[i] <= ' ' || src[i] == ',' || src[i] == ':' || src[i] == ']' || src[i] == '}' {
|
||||||
|
i--
|
||||||
|
break
|
||||||
|
}
|
||||||
|
dst = apnd(dst, src[i])
|
||||||
|
}
|
||||||
|
if kind == '0' {
|
||||||
|
dst = append(dst, style.Number[1]...)
|
||||||
|
} else if kind == 't' {
|
||||||
|
dst = append(dst, style.True[1]...)
|
||||||
|
} else if kind == 'f' {
|
||||||
|
dst = append(dst, style.False[1]...)
|
||||||
|
} else if kind == 'n' {
|
||||||
|
dst = append(dst, style.Null[1]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
15
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
Normal file
15
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
Normal 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
|
||||||
|
|
||||||
11
vendor/go.uber.org/atomic/.gitignore
generated
vendored
Normal file
11
vendor/go.uber.org/atomic/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.DS_Store
|
||||||
|
/vendor
|
||||||
|
/cover
|
||||||
|
cover.out
|
||||||
|
lint.log
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Profiling output
|
||||||
|
*.prof
|
||||||
23
vendor/go.uber.org/atomic/.travis.yml
generated
vendored
Normal file
23
vendor/go.uber.org/atomic/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
go_import_path: go.uber.org/atomic
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.7
|
||||||
|
- 1.8
|
||||||
|
- 1.9
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- vendor
|
||||||
|
|
||||||
|
install:
|
||||||
|
- make install_ci
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make test_ci
|
||||||
|
- scripts/test-ubergo.sh
|
||||||
|
- make lint
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
19
vendor/go.uber.org/atomic/LICENSE.txt
generated
vendored
Normal file
19
vendor/go.uber.org/atomic/LICENSE.txt
generated
vendored
Normal 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
64
vendor/go.uber.org/atomic/Makefile
generated
vendored
Normal 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))
|
||||||
36
vendor/go.uber.org/atomic/README.md
generated
vendored
Normal file
36
vendor/go.uber.org/atomic/README.md
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# atomic [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][reportcard-img]][reportcard]
|
||||||
|
|
||||||
|
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://codecov.io/gh/uber-go/atomic/branch/master/graph/badge.svg
|
||||||
|
[cov]: https://codecov.io/gh/uber-go/atomic
|
||||||
|
[reportcard-img]: https://goreportcard.com/badge/go.uber.org/atomic
|
||||||
|
[reportcard]: https://goreportcard.com/report/go.uber.org/atomic
|
||||||
351
vendor/go.uber.org/atomic/atomic.go
generated
vendored
Normal file
351
vendor/go.uber.org/atomic/atomic.go
generated
vendored
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
// 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"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap.
|
||||||
|
func (b *Bool) CAS(old, new bool) bool {
|
||||||
|
return atomic.CompareAndSwapUint32(&b.v, boolToInt(old), boolToInt(new))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration is an atomic wrapper around time.Duration
|
||||||
|
// https://godoc.org/time#Duration
|
||||||
|
type Duration struct {
|
||||||
|
v Int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDuration creates a Duration.
|
||||||
|
func NewDuration(d time.Duration) *Duration {
|
||||||
|
return &Duration{v: *NewInt64(int64(d))}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load atomically loads the wrapped value.
|
||||||
|
func (d *Duration) Load() time.Duration {
|
||||||
|
return time.Duration(d.v.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store atomically stores the passed value.
|
||||||
|
func (d *Duration) Store(n time.Duration) {
|
||||||
|
d.v.Store(int64(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add atomically adds to the wrapped time.Duration and returns the new value.
|
||||||
|
func (d *Duration) Add(n time.Duration) time.Duration {
|
||||||
|
return time.Duration(d.v.Add(int64(n)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub atomically subtracts from the wrapped time.Duration and returns the new value.
|
||||||
|
func (d *Duration) Sub(n time.Duration) time.Duration {
|
||||||
|
return time.Duration(d.v.Sub(int64(n)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap atomically swaps the wrapped time.Duration and returns the old value.
|
||||||
|
func (d *Duration) Swap(n time.Duration) time.Duration {
|
||||||
|
return time.Duration(d.v.Swap(int64(n)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is an atomic compare-and-swap.
|
||||||
|
func (d *Duration) CAS(old, new time.Duration) bool {
|
||||||
|
return d.v.CAS(int64(old), int64(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
17
vendor/go.uber.org/atomic/glide.lock
generated
vendored
Normal 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
6
vendor/go.uber.org/atomic/glide.yaml
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package: go.uber.org/atomic
|
||||||
|
testImport:
|
||||||
|
- package: github.com/stretchr/testify
|
||||||
|
subpackages:
|
||||||
|
- assert
|
||||||
|
- require
|
||||||
49
vendor/go.uber.org/atomic/string.go
generated
vendored
Normal file
49
vendor/go.uber.org/atomic/string.go
generated
vendored
Normal 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 atomic
|
||||||
|
|
||||||
|
// String is an atomic type-safe wrapper around Value for strings.
|
||||||
|
type String struct{ v 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 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
15
vendor/go.uber.org/multierr/.codecov.yml
generated
vendored
Normal 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
1
vendor/go.uber.org/multierr/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/vendor
|
||||||
33
vendor/go.uber.org/multierr/.travis.yml
generated
vendored
Normal file
33
vendor/go.uber.org/multierr/.travis.yml
generated
vendored
Normal 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
28
vendor/go.uber.org/multierr/CHANGELOG.md
generated
vendored
Normal 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
19
vendor/go.uber.org/multierr/LICENSE.txt
generated
vendored
Normal 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
74
vendor/go.uber.org/multierr/Makefile
generated
vendored
Normal 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
23
vendor/go.uber.org/multierr/README.md
generated
vendored
Normal 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
401
vendor/go.uber.org/multierr/error.go
generated
vendored
Normal 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
19
vendor/go.uber.org/multierr/glide.lock
generated
vendored
Normal 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
8
vendor/go.uber.org/multierr/glide.yaml
generated
vendored
Normal 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
17
vendor/go.uber.org/zap/.codecov.yml
generated
vendored
Normal 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
28
vendor/go.uber.org/zap/.gitignore
generated
vendored
Normal 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
108
vendor/go.uber.org/zap/.readme.tmpl
generated
vendored
Normal 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 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 — 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 — 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 —
|
||||||
|
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
21
vendor/go.uber.org/zap/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
language: go
|
||||||
|
sudo: false
|
||||||
|
go:
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
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)
|
||||||
305
vendor/go.uber.org/zap/CHANGELOG.md
generated
vendored
Normal file
305
vendor/go.uber.org/zap/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## v1.9.1 (06 Aug 2018)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
|
||||||
|
* [#614][]: MapObjectEncoder should not ignore empty slices.
|
||||||
|
|
||||||
|
## v1.9.0 (19 Jul 2018)
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
* [#602][]: Reduce number of allocations when logging with reflection.
|
||||||
|
* [#572][], [#606][]: Expose a registry for third-party logging sinks.
|
||||||
|
|
||||||
|
Thanks to @nfarah86, @AlekSi, @JeanMertz, @philippgille, @etsangsplk, and
|
||||||
|
@dimroc for their contributions to this release.
|
||||||
|
|
||||||
|
## 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"** — 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
|
||||||
|
[#602]: https://github.com/uber-go/zap/pull/602
|
||||||
|
[#572]: https://github.com/uber-go/zap/pull/572
|
||||||
|
[#606]: https://github.com/uber-go/zap/pull/606
|
||||||
|
[#614]: https://github.com/uber-go/zap/pull/614
|
||||||
75
vendor/go.uber.org/zap/CODE_OF_CONDUCT.md
generated
vendored
Normal file
75
vendor/go.uber.org/zap/CODE_OF_CONDUCT.md
generated
vendored
Normal 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
81
vendor/go.uber.org/zap/CONTRIBUTING.md
generated
vendored
Normal 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 — 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
|
||||||
155
vendor/go.uber.org/zap/FAQ.md
generated
vendored
Normal file
155
vendor/go.uber.org/zap/FAQ.md
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
# 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 — *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
|
||||||
|
— especially the reason for the crash — 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 |
|
||||||
|
| `github.com/blendle/zapdriver` | Stackdriver |
|
||||||
|
|
||||||
|
[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
19
vendor/go.uber.org/zap/LICENSE.txt
generated
vendored
Normal 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
76
vendor/go.uber.org/zap/Makefile
generated
vendored
Normal 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
136
vendor/go.uber.org/zap/README.md
generated
vendored
Normal 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 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 — 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 — 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 —
|
||||||
|
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
320
vendor/go.uber.org/zap/array.go
generated
vendored
Normal 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
|
||||||
|
}
|
||||||
115
vendor/go.uber.org/zap/buffer/buffer.go
generated
vendored
Normal file
115
vendor/go.uber.org/zap/buffer/buffer.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrimNewline trims any final "\n" byte from the end of the buffer.
|
||||||
|
func (b *Buffer) TrimNewline() {
|
||||||
|
if i := len(b.bs) - 1; i >= 0 {
|
||||||
|
if b.bs[i] == '\n' {
|
||||||
|
b.bs = b.bs[:i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
49
vendor/go.uber.org/zap/buffer/pool.go
generated
vendored
Normal 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
Normal file
17
vendor/go.uber.org/zap/check_license.sh
generated
vendored
Normal 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
243
vendor/go.uber.org/zap/config.go
generated
vendored
Normal 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 URLs or file paths to write logging output to.
|
||||||
|
// See Open for details.
|
||||||
|
OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
|
||||||
|
// ErrorOutputPaths is a list of URLs 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
113
vendor/go.uber.org/zap/doc.go
generated
vendored
Normal 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.Infof("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
75
vendor/go.uber.org/zap/encoder.go
generated
vendored
Normal 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
80
vendor/go.uber.org/zap/error.go
generated
vendored
Normal 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
310
vendor/go.uber.org/zap/field.go
generated
vendored
Normal 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
39
vendor/go.uber.org/zap/flag.go
generated
vendored
Normal 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
76
vendor/go.uber.org/zap/glide.lock
generated
vendored
Normal 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
35
vendor/go.uber.org/zap/glide.yaml
generated
vendored
Normal 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
169
vendor/go.uber.org/zap/global.go
generated
vendored
Normal 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
81
vendor/go.uber.org/zap/http_handler.go
generated
vendored
Normal 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 http.MethodGet:
|
||||||
|
current := lvl.Level()
|
||||||
|
enc.Encode(payload{Level: ¤t})
|
||||||
|
|
||||||
|
case http.MethodPut:
|
||||||
|
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.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
31
vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go
generated
vendored
Normal file
31
vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go
generated
vendored
Normal 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
44
vendor/go.uber.org/zap/internal/color/color.go
generated
vendored
Normal 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
64
vendor/go.uber.org/zap/internal/exit/exit.go
generated
vendored
Normal 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
132
vendor/go.uber.org/zap/level.go
generated
vendored
Normal 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
305
vendor/go.uber.org/zap/logger.go
generated
vendored
Normal 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 ©
|
||||||
|
}
|
||||||
|
|
||||||
|
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
109
vendor/go.uber.org/zap/options.go
generated
vendored
Normal 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
|
||||||
|
})
|
||||||
|
}
|
||||||
161
vendor/go.uber.org/zap/sink.go
generated
vendored
Normal file
161
vendor/go.uber.org/zap/sink.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
// 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"
|
||||||
|
"io"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
)
|
||||||
|
|
||||||
|
const schemeFile = "file"
|
||||||
|
|
||||||
|
var (
|
||||||
|
_sinkMutex sync.RWMutex
|
||||||
|
_sinkFactories map[string]func(*url.URL) (Sink, error) // keyed by scheme
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
resetSinkRegistry()
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetSinkRegistry() {
|
||||||
|
_sinkMutex.Lock()
|
||||||
|
defer _sinkMutex.Unlock()
|
||||||
|
|
||||||
|
_sinkFactories = map[string]func(*url.URL) (Sink, error){
|
||||||
|
schemeFile: newFileSink,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sink defines the interface to write to and close logger destinations.
|
||||||
|
type Sink interface {
|
||||||
|
zapcore.WriteSyncer
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
type nopCloserSink struct{ zapcore.WriteSyncer }
|
||||||
|
|
||||||
|
func (nopCloserSink) Close() error { return nil }
|
||||||
|
|
||||||
|
type errSinkNotFound struct {
|
||||||
|
scheme string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *errSinkNotFound) Error() string {
|
||||||
|
return fmt.Sprintf("no sink found for scheme %q", e.scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterSink registers a user-supplied factory for all sinks with a
|
||||||
|
// particular scheme.
|
||||||
|
//
|
||||||
|
// All schemes must be ASCII, valid under section 3.1 of RFC 3986
|
||||||
|
// (https://tools.ietf.org/html/rfc3986#section-3.1), and must not already
|
||||||
|
// have a factory registered. Zap automatically registers a factory for the
|
||||||
|
// "file" scheme.
|
||||||
|
func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error {
|
||||||
|
_sinkMutex.Lock()
|
||||||
|
defer _sinkMutex.Unlock()
|
||||||
|
|
||||||
|
if scheme == "" {
|
||||||
|
return errors.New("can't register a sink factory for empty string")
|
||||||
|
}
|
||||||
|
normalized, err := normalizeScheme(scheme)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%q is not a valid scheme: %v", scheme, err)
|
||||||
|
}
|
||||||
|
if _, ok := _sinkFactories[normalized]; ok {
|
||||||
|
return fmt.Errorf("sink factory already registered for scheme %q", normalized)
|
||||||
|
}
|
||||||
|
_sinkFactories[normalized] = factory
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSink(rawURL string) (Sink, error) {
|
||||||
|
u, err := url.Parse(rawURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("can't parse %q as a URL: %v", rawURL, err)
|
||||||
|
}
|
||||||
|
if u.Scheme == "" {
|
||||||
|
u.Scheme = schemeFile
|
||||||
|
}
|
||||||
|
|
||||||
|
_sinkMutex.RLock()
|
||||||
|
factory, ok := _sinkFactories[u.Scheme]
|
||||||
|
_sinkMutex.RUnlock()
|
||||||
|
if !ok {
|
||||||
|
return nil, &errSinkNotFound{u.Scheme}
|
||||||
|
}
|
||||||
|
return factory(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFileSink(u *url.URL) (Sink, error) {
|
||||||
|
if u.User != nil {
|
||||||
|
return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u)
|
||||||
|
}
|
||||||
|
if u.Fragment != "" {
|
||||||
|
return nil, fmt.Errorf("fragments not allowed with file URLs: got %v", u)
|
||||||
|
}
|
||||||
|
if u.RawQuery != "" {
|
||||||
|
return nil, fmt.Errorf("query parameters not allowed with file URLs: got %v", u)
|
||||||
|
}
|
||||||
|
// Error messages are better if we check hostname and port separately.
|
||||||
|
if u.Port() != "" {
|
||||||
|
return nil, fmt.Errorf("ports not allowed with file URLs: got %v", u)
|
||||||
|
}
|
||||||
|
if hn := u.Hostname(); hn != "" && hn != "localhost" {
|
||||||
|
return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u)
|
||||||
|
}
|
||||||
|
switch u.Path {
|
||||||
|
case "stdout":
|
||||||
|
return nopCloserSink{os.Stdout}, nil
|
||||||
|
case "stderr":
|
||||||
|
return nopCloserSink{os.Stderr}, nil
|
||||||
|
}
|
||||||
|
return os.OpenFile(u.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeScheme(s string) (string, error) {
|
||||||
|
// https://tools.ietf.org/html/rfc3986#section-3.1
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
if first := s[0]; 'a' > first || 'z' < first {
|
||||||
|
return "", errors.New("must start with a letter")
|
||||||
|
}
|
||||||
|
for i := 1; i < len(s); i++ { // iterate over bytes, not runes
|
||||||
|
c := s[i]
|
||||||
|
switch {
|
||||||
|
case 'a' <= c && c <= 'z':
|
||||||
|
continue
|
||||||
|
case '0' <= c && c <= '9':
|
||||||
|
continue
|
||||||
|
case c == '.' || c == '+' || c == '-':
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("may not contain %q", c)
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
126
vendor/go.uber.org/zap/stacktrace.go
generated
vendored
Normal file
126
vendor/go.uber.org/zap/stacktrace.go
generated
vendored
Normal 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
304
vendor/go.uber.org/zap/sugar.go
generated
vendored
Normal 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
|
||||||
|
}
|
||||||
27
vendor/go.uber.org/zap/time.go
generated
vendored
Normal file
27
vendor/go.uber.org/zap/time.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
func timeToMillis(t time.Time) int64 {
|
||||||
|
return t.UnixNano() / int64(time.Millisecond)
|
||||||
|
}
|
||||||
99
vendor/go.uber.org/zap/writer.go
generated
vendored
Normal file
99
vendor/go.uber.org/zap/writer.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// 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"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
|
||||||
|
"go.uber.org/multierr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Open is a high-level wrapper that takes a variadic number of URLs, opens or
|
||||||
|
// creates each of the specified resources, and combines them into a locked
|
||||||
|
// WriteSyncer. It also returns any error encountered and a function to close
|
||||||
|
// any opened files.
|
||||||
|
//
|
||||||
|
// Passing no URLs returns a no-op WriteSyncer. Zap handles URLs without a
|
||||||
|
// scheme and URLs with the "file" scheme. Third-party code may register
|
||||||
|
// factories for other schemes using RegisterSink.
|
||||||
|
//
|
||||||
|
// URLs with the "file" scheme must use absolute paths on the local
|
||||||
|
// filesystem. No user, password, port, fragments, or query parameters are
|
||||||
|
// allowed, and the hostname must be empty or "localhost".
|
||||||
|
//
|
||||||
|
// Since it's common to write logs to the local filesystem, URLs without a
|
||||||
|
// scheme (e.g., "/var/log/foo.log") are treated as local file paths. Without
|
||||||
|
// a scheme, the special paths "stdout" and "stderr" are interpreted as
|
||||||
|
// os.Stdout and os.Stderr. When specified without a scheme, relative file
|
||||||
|
// paths also work.
|
||||||
|
func Open(paths ...string) (zapcore.WriteSyncer, func(), error) {
|
||||||
|
writers, close, err := open(paths)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
writer := CombineWriteSyncers(writers...)
|
||||||
|
return writer, close, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func open(paths []string) ([]zapcore.WriteSyncer, func(), error) {
|
||||||
|
writers := make([]zapcore.WriteSyncer, 0, len(paths))
|
||||||
|
closers := make([]io.Closer, 0, len(paths))
|
||||||
|
close := func() {
|
||||||
|
for _, c := range closers {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var openErr error
|
||||||
|
for _, path := range paths {
|
||||||
|
sink, err := newSink(path)
|
||||||
|
if err != nil {
|
||||||
|
openErr = multierr.Append(openErr, fmt.Errorf("couldn't open sink %q: %v", path, err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
writers = append(writers, sink)
|
||||||
|
closers = append(closers, sink)
|
||||||
|
}
|
||||||
|
if openErr != nil {
|
||||||
|
close()
|
||||||
|
return writers, nil, openErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return writers, close, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CombineWriteSyncers is a utility that combines multiple WriteSyncers into a
|
||||||
|
// single, locked WriteSyncer. If no inputs are supplied, it returns a no-op
|
||||||
|
// WriteSyncer.
|
||||||
|
//
|
||||||
|
// It's provided purely as a convenience; the result is no different from
|
||||||
|
// using zapcore.NewMultiWriteSyncer and zapcore.Lock individually.
|
||||||
|
func CombineWriteSyncers(writers ...zapcore.WriteSyncer) zapcore.WriteSyncer {
|
||||||
|
if len(writers) == 0 {
|
||||||
|
return zapcore.AddSync(ioutil.Discard)
|
||||||
|
}
|
||||||
|
return zapcore.Lock(zapcore.NewMultiWriteSyncer(writers...))
|
||||||
|
}
|
||||||
147
vendor/go.uber.org/zap/zapcore/console_encoder.go
generated
vendored
Normal file
147
vendor/go.uber.org/zap/zapcore/console_encoder.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package zapcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"go.uber.org/zap/buffer"
|
||||||
|
"go.uber.org/zap/internal/bufferpool"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _sliceEncoderPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &sliceArrayEncoder{elems: make([]interface{}, 0, 2)}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSliceEncoder() *sliceArrayEncoder {
|
||||||
|
return _sliceEncoderPool.Get().(*sliceArrayEncoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putSliceEncoder(e *sliceArrayEncoder) {
|
||||||
|
e.elems = e.elems[:0]
|
||||||
|
_sliceEncoderPool.Put(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
type consoleEncoder struct {
|
||||||
|
*jsonEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConsoleEncoder creates an encoder whose output is designed for human -
|
||||||
|
// rather than machine - consumption. It serializes the core log entry data
|
||||||
|
// (message, level, timestamp, etc.) in a plain-text format and leaves the
|
||||||
|
// structured context as JSON.
|
||||||
|
//
|
||||||
|
// Note that although the console encoder doesn't use the keys specified in the
|
||||||
|
// encoder configuration, it will omit any element whose key is set to the empty
|
||||||
|
// string.
|
||||||
|
func NewConsoleEncoder(cfg EncoderConfig) Encoder {
|
||||||
|
return consoleEncoder{newJSONEncoder(cfg, true)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c consoleEncoder) Clone() Encoder {
|
||||||
|
return consoleEncoder{c.jsonEncoder.Clone().(*jsonEncoder)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c consoleEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) {
|
||||||
|
line := bufferpool.Get()
|
||||||
|
|
||||||
|
// We don't want the entry's metadata to be quoted and escaped (if it's
|
||||||
|
// encoded as strings), which means that we can't use the JSON encoder. The
|
||||||
|
// simplest option is to use the memory encoder and fmt.Fprint.
|
||||||
|
//
|
||||||
|
// If this ever becomes a performance bottleneck, we can implement
|
||||||
|
// ArrayEncoder for our plain-text format.
|
||||||
|
arr := getSliceEncoder()
|
||||||
|
if c.TimeKey != "" && c.EncodeTime != nil {
|
||||||
|
c.EncodeTime(ent.Time, arr)
|
||||||
|
}
|
||||||
|
if c.LevelKey != "" && c.EncodeLevel != nil {
|
||||||
|
c.EncodeLevel(ent.Level, arr)
|
||||||
|
}
|
||||||
|
if ent.LoggerName != "" && c.NameKey != "" {
|
||||||
|
nameEncoder := c.EncodeName
|
||||||
|
|
||||||
|
if nameEncoder == nil {
|
||||||
|
// Fall back to FullNameEncoder for backward compatibility.
|
||||||
|
nameEncoder = FullNameEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
nameEncoder(ent.LoggerName, arr)
|
||||||
|
}
|
||||||
|
if ent.Caller.Defined && c.CallerKey != "" && c.EncodeCaller != nil {
|
||||||
|
c.EncodeCaller(ent.Caller, arr)
|
||||||
|
}
|
||||||
|
for i := range arr.elems {
|
||||||
|
if i > 0 {
|
||||||
|
line.AppendByte('\t')
|
||||||
|
}
|
||||||
|
fmt.Fprint(line, arr.elems[i])
|
||||||
|
}
|
||||||
|
putSliceEncoder(arr)
|
||||||
|
|
||||||
|
// Add the message itself.
|
||||||
|
if c.MessageKey != "" {
|
||||||
|
c.addTabIfNecessary(line)
|
||||||
|
line.AppendString(ent.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any structured context.
|
||||||
|
c.writeContext(line, fields)
|
||||||
|
|
||||||
|
// If there's no stacktrace key, honor that; this allows users to force
|
||||||
|
// single-line output.
|
||||||
|
if ent.Stack != "" && c.StacktraceKey != "" {
|
||||||
|
line.AppendByte('\n')
|
||||||
|
line.AppendString(ent.Stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.LineEnding != "" {
|
||||||
|
line.AppendString(c.LineEnding)
|
||||||
|
} else {
|
||||||
|
line.AppendString(DefaultLineEnding)
|
||||||
|
}
|
||||||
|
return line, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c consoleEncoder) writeContext(line *buffer.Buffer, extra []Field) {
|
||||||
|
context := c.jsonEncoder.Clone().(*jsonEncoder)
|
||||||
|
defer context.buf.Free()
|
||||||
|
|
||||||
|
addFields(context, extra)
|
||||||
|
context.closeOpenNamespaces()
|
||||||
|
if context.buf.Len() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.addTabIfNecessary(line)
|
||||||
|
line.AppendByte('{')
|
||||||
|
line.Write(context.buf.Bytes())
|
||||||
|
line.AppendByte('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c consoleEncoder) addTabIfNecessary(line *buffer.Buffer) {
|
||||||
|
if line.Len() > 0 {
|
||||||
|
line.AppendByte('\t')
|
||||||
|
}
|
||||||
|
}
|
||||||
113
vendor/go.uber.org/zap/zapcore/core.go
generated
vendored
Normal file
113
vendor/go.uber.org/zap/zapcore/core.go
generated
vendored
Normal 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 zapcore
|
||||||
|
|
||||||
|
// Core is a minimal, fast logger interface. It's designed for library authors
|
||||||
|
// to wrap in a more user-friendly API.
|
||||||
|
type Core interface {
|
||||||
|
LevelEnabler
|
||||||
|
|
||||||
|
// With adds structured context to the Core.
|
||||||
|
With([]Field) Core
|
||||||
|
// Check determines whether the supplied Entry should be logged (using the
|
||||||
|
// embedded LevelEnabler and possibly some extra logic). If the entry
|
||||||
|
// should be logged, the Core adds itself to the CheckedEntry and returns
|
||||||
|
// the result.
|
||||||
|
//
|
||||||
|
// Callers must use Check before calling Write.
|
||||||
|
Check(Entry, *CheckedEntry) *CheckedEntry
|
||||||
|
// Write serializes the Entry and any Fields supplied at the log site and
|
||||||
|
// writes them to their destination.
|
||||||
|
//
|
||||||
|
// If called, Write should always log the Entry and Fields; it should not
|
||||||
|
// replicate the logic of Check.
|
||||||
|
Write(Entry, []Field) error
|
||||||
|
// Sync flushes buffered logs (if any).
|
||||||
|
Sync() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type nopCore struct{}
|
||||||
|
|
||||||
|
// NewNopCore returns a no-op Core.
|
||||||
|
func NewNopCore() Core { return nopCore{} }
|
||||||
|
func (nopCore) Enabled(Level) bool { return false }
|
||||||
|
func (n nopCore) With([]Field) Core { return n }
|
||||||
|
func (nopCore) Check(_ Entry, ce *CheckedEntry) *CheckedEntry { return ce }
|
||||||
|
func (nopCore) Write(Entry, []Field) error { return nil }
|
||||||
|
func (nopCore) Sync() error { return nil }
|
||||||
|
|
||||||
|
// NewCore creates a Core that writes logs to a WriteSyncer.
|
||||||
|
func NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core {
|
||||||
|
return &ioCore{
|
||||||
|
LevelEnabler: enab,
|
||||||
|
enc: enc,
|
||||||
|
out: ws,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ioCore struct {
|
||||||
|
LevelEnabler
|
||||||
|
enc Encoder
|
||||||
|
out WriteSyncer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ioCore) With(fields []Field) Core {
|
||||||
|
clone := c.clone()
|
||||||
|
addFields(clone.enc, fields)
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ioCore) Check(ent Entry, ce *CheckedEntry) *CheckedEntry {
|
||||||
|
if c.Enabled(ent.Level) {
|
||||||
|
return ce.AddCore(ent, c)
|
||||||
|
}
|
||||||
|
return ce
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ioCore) Write(ent Entry, fields []Field) error {
|
||||||
|
buf, err := c.enc.EncodeEntry(ent, fields)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = c.out.Write(buf.Bytes())
|
||||||
|
buf.Free()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ent.Level > ErrorLevel {
|
||||||
|
// Since we may be crashing the program, sync the output. Ignore Sync
|
||||||
|
// errors, pending a clean solution to issue #370.
|
||||||
|
c.Sync()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ioCore) Sync() error {
|
||||||
|
return c.out.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ioCore) clone() *ioCore {
|
||||||
|
return &ioCore{
|
||||||
|
LevelEnabler: c.LevelEnabler,
|
||||||
|
enc: c.enc.Clone(),
|
||||||
|
out: c.out,
|
||||||
|
}
|
||||||
|
}
|
||||||
24
vendor/go.uber.org/zap/zapcore/doc.go
generated
vendored
Normal file
24
vendor/go.uber.org/zap/zapcore/doc.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// 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 zapcore defines and implements the low-level interfaces upon which
|
||||||
|
// zap is built. By providing alternate implementations of these interfaces,
|
||||||
|
// external packages can extend zap's capabilities.
|
||||||
|
package zapcore // import "go.uber.org/zap/zapcore"
|
||||||
348
vendor/go.uber.org/zap/zapcore/encoder.go
generated
vendored
Normal file
348
vendor/go.uber.org/zap/zapcore/encoder.go
generated
vendored
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap/buffer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultLineEnding defines the default line ending when writing logs.
|
||||||
|
// Alternate line endings specified in EncoderConfig can override this
|
||||||
|
// behavior.
|
||||||
|
const DefaultLineEnding = "\n"
|
||||||
|
|
||||||
|
// A LevelEncoder serializes a Level to a primitive type.
|
||||||
|
type LevelEncoder func(Level, PrimitiveArrayEncoder)
|
||||||
|
|
||||||
|
// LowercaseLevelEncoder serializes a Level to a lowercase string. For example,
|
||||||
|
// InfoLevel is serialized to "info".
|
||||||
|
func LowercaseLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendString(l.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// LowercaseColorLevelEncoder serializes a Level to a lowercase string and adds coloring.
|
||||||
|
// For example, InfoLevel is serialized to "info" and colored blue.
|
||||||
|
func LowercaseColorLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
|
||||||
|
s, ok := _levelToLowercaseColorString[l]
|
||||||
|
if !ok {
|
||||||
|
s = _unknownLevelColor.Add(l.String())
|
||||||
|
}
|
||||||
|
enc.AppendString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapitalLevelEncoder serializes a Level to an all-caps string. For example,
|
||||||
|
// InfoLevel is serialized to "INFO".
|
||||||
|
func CapitalLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendString(l.CapitalString())
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapitalColorLevelEncoder serializes a Level to an all-caps string and adds color.
|
||||||
|
// For example, InfoLevel is serialized to "INFO" and colored blue.
|
||||||
|
func CapitalColorLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
|
||||||
|
s, ok := _levelToCapitalColorString[l]
|
||||||
|
if !ok {
|
||||||
|
s = _unknownLevelColor.Add(l.CapitalString())
|
||||||
|
}
|
||||||
|
enc.AppendString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText unmarshals text to a LevelEncoder. "capital" is unmarshaled to
|
||||||
|
// CapitalLevelEncoder, "coloredCapital" is unmarshaled to CapitalColorLevelEncoder,
|
||||||
|
// "colored" is unmarshaled to LowercaseColorLevelEncoder, and anything else
|
||||||
|
// is unmarshaled to LowercaseLevelEncoder.
|
||||||
|
func (e *LevelEncoder) UnmarshalText(text []byte) error {
|
||||||
|
switch string(text) {
|
||||||
|
case "capital":
|
||||||
|
*e = CapitalLevelEncoder
|
||||||
|
case "capitalColor":
|
||||||
|
*e = CapitalColorLevelEncoder
|
||||||
|
case "color":
|
||||||
|
*e = LowercaseColorLevelEncoder
|
||||||
|
default:
|
||||||
|
*e = LowercaseLevelEncoder
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A TimeEncoder serializes a time.Time to a primitive type.
|
||||||
|
type TimeEncoder func(time.Time, PrimitiveArrayEncoder)
|
||||||
|
|
||||||
|
// EpochTimeEncoder serializes a time.Time to a floating-point number of seconds
|
||||||
|
// since the Unix epoch.
|
||||||
|
func EpochTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||||
|
nanos := t.UnixNano()
|
||||||
|
sec := float64(nanos) / float64(time.Second)
|
||||||
|
enc.AppendFloat64(sec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EpochMillisTimeEncoder serializes a time.Time to a floating-point number of
|
||||||
|
// milliseconds since the Unix epoch.
|
||||||
|
func EpochMillisTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||||
|
nanos := t.UnixNano()
|
||||||
|
millis := float64(nanos) / float64(time.Millisecond)
|
||||||
|
enc.AppendFloat64(millis)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EpochNanosTimeEncoder serializes a time.Time to an integer number of
|
||||||
|
// nanoseconds since the Unix epoch.
|
||||||
|
func EpochNanosTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendInt64(t.UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ISO8601TimeEncoder serializes a time.Time to an ISO8601-formatted string
|
||||||
|
// with millisecond precision.
|
||||||
|
func ISO8601TimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendString(t.Format("2006-01-02T15:04:05.000Z0700"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText unmarshals text to a TimeEncoder. "iso8601" and "ISO8601" are
|
||||||
|
// unmarshaled to ISO8601TimeEncoder, "millis" is unmarshaled to
|
||||||
|
// EpochMillisTimeEncoder, and anything else is unmarshaled to EpochTimeEncoder.
|
||||||
|
func (e *TimeEncoder) UnmarshalText(text []byte) error {
|
||||||
|
switch string(text) {
|
||||||
|
case "iso8601", "ISO8601":
|
||||||
|
*e = ISO8601TimeEncoder
|
||||||
|
case "millis":
|
||||||
|
*e = EpochMillisTimeEncoder
|
||||||
|
case "nanos":
|
||||||
|
*e = EpochNanosTimeEncoder
|
||||||
|
default:
|
||||||
|
*e = EpochTimeEncoder
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A DurationEncoder serializes a time.Duration to a primitive type.
|
||||||
|
type DurationEncoder func(time.Duration, PrimitiveArrayEncoder)
|
||||||
|
|
||||||
|
// SecondsDurationEncoder serializes a time.Duration to a floating-point number of seconds elapsed.
|
||||||
|
func SecondsDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendFloat64(float64(d) / float64(time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NanosDurationEncoder serializes a time.Duration to an integer number of
|
||||||
|
// nanoseconds elapsed.
|
||||||
|
func NanosDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendInt64(int64(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringDurationEncoder serializes a time.Duration using its built-in String
|
||||||
|
// method.
|
||||||
|
func StringDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendString(d.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText unmarshals text to a DurationEncoder. "string" is unmarshaled
|
||||||
|
// to StringDurationEncoder, and anything else is unmarshaled to
|
||||||
|
// NanosDurationEncoder.
|
||||||
|
func (e *DurationEncoder) UnmarshalText(text []byte) error {
|
||||||
|
switch string(text) {
|
||||||
|
case "string":
|
||||||
|
*e = StringDurationEncoder
|
||||||
|
case "nanos":
|
||||||
|
*e = NanosDurationEncoder
|
||||||
|
default:
|
||||||
|
*e = SecondsDurationEncoder
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CallerEncoder serializes an EntryCaller to a primitive type.
|
||||||
|
type CallerEncoder func(EntryCaller, PrimitiveArrayEncoder)
|
||||||
|
|
||||||
|
// FullCallerEncoder serializes a caller in /full/path/to/package/file:line
|
||||||
|
// format.
|
||||||
|
func FullCallerEncoder(caller EntryCaller, enc PrimitiveArrayEncoder) {
|
||||||
|
// TODO: consider using a byte-oriented API to save an allocation.
|
||||||
|
enc.AppendString(caller.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShortCallerEncoder serializes a caller in package/file:line format, trimming
|
||||||
|
// all but the final directory from the full path.
|
||||||
|
func ShortCallerEncoder(caller EntryCaller, enc PrimitiveArrayEncoder) {
|
||||||
|
// TODO: consider using a byte-oriented API to save an allocation.
|
||||||
|
enc.AppendString(caller.TrimmedPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText unmarshals text to a CallerEncoder. "full" is unmarshaled to
|
||||||
|
// FullCallerEncoder and anything else is unmarshaled to ShortCallerEncoder.
|
||||||
|
func (e *CallerEncoder) UnmarshalText(text []byte) error {
|
||||||
|
switch string(text) {
|
||||||
|
case "full":
|
||||||
|
*e = FullCallerEncoder
|
||||||
|
default:
|
||||||
|
*e = ShortCallerEncoder
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A NameEncoder serializes a period-separated logger name to a primitive
|
||||||
|
// type.
|
||||||
|
type NameEncoder func(string, PrimitiveArrayEncoder)
|
||||||
|
|
||||||
|
// FullNameEncoder serializes the logger name as-is.
|
||||||
|
func FullNameEncoder(loggerName string, enc PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendString(loggerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText unmarshals text to a NameEncoder. Currently, everything is
|
||||||
|
// unmarshaled to FullNameEncoder.
|
||||||
|
func (e *NameEncoder) UnmarshalText(text []byte) error {
|
||||||
|
switch string(text) {
|
||||||
|
case "full":
|
||||||
|
*e = FullNameEncoder
|
||||||
|
default:
|
||||||
|
*e = FullNameEncoder
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// An EncoderConfig allows users to configure the concrete encoders supplied by
|
||||||
|
// zapcore.
|
||||||
|
type EncoderConfig struct {
|
||||||
|
// Set the keys used for each log entry. If any key is empty, that portion
|
||||||
|
// of the entry is omitted.
|
||||||
|
MessageKey string `json:"messageKey" yaml:"messageKey"`
|
||||||
|
LevelKey string `json:"levelKey" yaml:"levelKey"`
|
||||||
|
TimeKey string `json:"timeKey" yaml:"timeKey"`
|
||||||
|
NameKey string `json:"nameKey" yaml:"nameKey"`
|
||||||
|
CallerKey string `json:"callerKey" yaml:"callerKey"`
|
||||||
|
StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"`
|
||||||
|
LineEnding string `json:"lineEnding" yaml:"lineEnding"`
|
||||||
|
// Configure the primitive representations of common complex types. For
|
||||||
|
// example, some users may want all time.Times serialized as floating-point
|
||||||
|
// seconds since epoch, while others may prefer ISO8601 strings.
|
||||||
|
EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"`
|
||||||
|
EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"`
|
||||||
|
EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
|
||||||
|
EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"`
|
||||||
|
// Unlike the other primitive type encoders, EncodeName is optional. The
|
||||||
|
// zero value falls back to FullNameEncoder.
|
||||||
|
EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectEncoder is a strongly-typed, encoding-agnostic interface for adding a
|
||||||
|
// map- or struct-like object to the logging context. Like maps, ObjectEncoders
|
||||||
|
// aren't safe for concurrent use (though typical use shouldn't require locks).
|
||||||
|
type ObjectEncoder interface {
|
||||||
|
// Logging-specific marshalers.
|
||||||
|
AddArray(key string, marshaler ArrayMarshaler) error
|
||||||
|
AddObject(key string, marshaler ObjectMarshaler) error
|
||||||
|
|
||||||
|
// Built-in types.
|
||||||
|
AddBinary(key string, value []byte) // for arbitrary bytes
|
||||||
|
AddByteString(key string, value []byte) // for UTF-8 encoded bytes
|
||||||
|
AddBool(key string, value bool)
|
||||||
|
AddComplex128(key string, value complex128)
|
||||||
|
AddComplex64(key string, value complex64)
|
||||||
|
AddDuration(key string, value time.Duration)
|
||||||
|
AddFloat64(key string, value float64)
|
||||||
|
AddFloat32(key string, value float32)
|
||||||
|
AddInt(key string, value int)
|
||||||
|
AddInt64(key string, value int64)
|
||||||
|
AddInt32(key string, value int32)
|
||||||
|
AddInt16(key string, value int16)
|
||||||
|
AddInt8(key string, value int8)
|
||||||
|
AddString(key, value string)
|
||||||
|
AddTime(key string, value time.Time)
|
||||||
|
AddUint(key string, value uint)
|
||||||
|
AddUint64(key string, value uint64)
|
||||||
|
AddUint32(key string, value uint32)
|
||||||
|
AddUint16(key string, value uint16)
|
||||||
|
AddUint8(key string, value uint8)
|
||||||
|
AddUintptr(key string, value uintptr)
|
||||||
|
|
||||||
|
// AddReflected uses reflection to serialize arbitrary objects, so it's slow
|
||||||
|
// and allocation-heavy.
|
||||||
|
AddReflected(key string, value interface{}) error
|
||||||
|
// OpenNamespace opens an isolated namespace where all subsequent fields will
|
||||||
|
// be added. Applications can use namespaces to prevent key collisions when
|
||||||
|
// injecting loggers into sub-components or third-party libraries.
|
||||||
|
OpenNamespace(key string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayEncoder is a strongly-typed, encoding-agnostic interface for adding
|
||||||
|
// array-like objects to the logging context. Of note, it supports mixed-type
|
||||||
|
// arrays even though they aren't typical in Go. Like slices, ArrayEncoders
|
||||||
|
// aren't safe for concurrent use (though typical use shouldn't require locks).
|
||||||
|
type ArrayEncoder interface {
|
||||||
|
// Built-in types.
|
||||||
|
PrimitiveArrayEncoder
|
||||||
|
|
||||||
|
// Time-related types.
|
||||||
|
AppendDuration(time.Duration)
|
||||||
|
AppendTime(time.Time)
|
||||||
|
|
||||||
|
// Logging-specific marshalers.
|
||||||
|
AppendArray(ArrayMarshaler) error
|
||||||
|
AppendObject(ObjectMarshaler) error
|
||||||
|
|
||||||
|
// AppendReflected uses reflection to serialize arbitrary objects, so it's
|
||||||
|
// slow and allocation-heavy.
|
||||||
|
AppendReflected(value interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrimitiveArrayEncoder is the subset of the ArrayEncoder interface that deals
|
||||||
|
// only in Go's built-in types. It's included only so that Duration- and
|
||||||
|
// TimeEncoders cannot trigger infinite recursion.
|
||||||
|
type PrimitiveArrayEncoder interface {
|
||||||
|
// Built-in types.
|
||||||
|
AppendBool(bool)
|
||||||
|
AppendByteString([]byte) // for UTF-8 encoded bytes
|
||||||
|
AppendComplex128(complex128)
|
||||||
|
AppendComplex64(complex64)
|
||||||
|
AppendFloat64(float64)
|
||||||
|
AppendFloat32(float32)
|
||||||
|
AppendInt(int)
|
||||||
|
AppendInt64(int64)
|
||||||
|
AppendInt32(int32)
|
||||||
|
AppendInt16(int16)
|
||||||
|
AppendInt8(int8)
|
||||||
|
AppendString(string)
|
||||||
|
AppendUint(uint)
|
||||||
|
AppendUint64(uint64)
|
||||||
|
AppendUint32(uint32)
|
||||||
|
AppendUint16(uint16)
|
||||||
|
AppendUint8(uint8)
|
||||||
|
AppendUintptr(uintptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoder is a format-agnostic interface for all log entry marshalers. Since
|
||||||
|
// log encoders don't need to support the same wide range of use cases as
|
||||||
|
// general-purpose marshalers, it's possible to make them faster and
|
||||||
|
// lower-allocation.
|
||||||
|
//
|
||||||
|
// Implementations of the ObjectEncoder interface's methods can, of course,
|
||||||
|
// freely modify the receiver. However, the Clone and EncodeEntry methods will
|
||||||
|
// be called concurrently and shouldn't modify the receiver.
|
||||||
|
type Encoder interface {
|
||||||
|
ObjectEncoder
|
||||||
|
|
||||||
|
// Clone copies the encoder, ensuring that adding fields to the copy doesn't
|
||||||
|
// affect the original.
|
||||||
|
Clone() Encoder
|
||||||
|
|
||||||
|
// EncodeEntry encodes an entry and fields, along with any accumulated
|
||||||
|
// context, into a byte buffer and returns it.
|
||||||
|
EncodeEntry(Entry, []Field) (*buffer.Buffer, error)
|
||||||
|
}
|
||||||
257
vendor/go.uber.org/zap/zapcore/entry.go
generated
vendored
Normal file
257
vendor/go.uber.org/zap/zapcore/entry.go
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap/internal/bufferpool"
|
||||||
|
"go.uber.org/zap/internal/exit"
|
||||||
|
|
||||||
|
"go.uber.org/multierr"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_cePool = sync.Pool{New: func() interface{} {
|
||||||
|
// Pre-allocate some space for cores.
|
||||||
|
return &CheckedEntry{
|
||||||
|
cores: make([]Core, 4),
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
)
|
||||||
|
|
||||||
|
func getCheckedEntry() *CheckedEntry {
|
||||||
|
ce := _cePool.Get().(*CheckedEntry)
|
||||||
|
ce.reset()
|
||||||
|
return ce
|
||||||
|
}
|
||||||
|
|
||||||
|
func putCheckedEntry(ce *CheckedEntry) {
|
||||||
|
if ce == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_cePool.Put(ce)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEntryCaller makes an EntryCaller from the return signature of
|
||||||
|
// runtime.Caller.
|
||||||
|
func NewEntryCaller(pc uintptr, file string, line int, ok bool) EntryCaller {
|
||||||
|
if !ok {
|
||||||
|
return EntryCaller{}
|
||||||
|
}
|
||||||
|
return EntryCaller{
|
||||||
|
PC: pc,
|
||||||
|
File: file,
|
||||||
|
Line: line,
|
||||||
|
Defined: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EntryCaller represents the caller of a logging function.
|
||||||
|
type EntryCaller struct {
|
||||||
|
Defined bool
|
||||||
|
PC uintptr
|
||||||
|
File string
|
||||||
|
Line int
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the full path and line number of the caller.
|
||||||
|
func (ec EntryCaller) String() string {
|
||||||
|
return ec.FullPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullPath returns a /full/path/to/package/file:line description of the
|
||||||
|
// caller.
|
||||||
|
func (ec EntryCaller) FullPath() string {
|
||||||
|
if !ec.Defined {
|
||||||
|
return "undefined"
|
||||||
|
}
|
||||||
|
buf := bufferpool.Get()
|
||||||
|
buf.AppendString(ec.File)
|
||||||
|
buf.AppendByte(':')
|
||||||
|
buf.AppendInt(int64(ec.Line))
|
||||||
|
caller := buf.String()
|
||||||
|
buf.Free()
|
||||||
|
return caller
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrimmedPath returns a package/file:line description of the caller,
|
||||||
|
// preserving only the leaf directory name and file name.
|
||||||
|
func (ec EntryCaller) TrimmedPath() string {
|
||||||
|
if !ec.Defined {
|
||||||
|
return "undefined"
|
||||||
|
}
|
||||||
|
// nb. To make sure we trim the path correctly on Windows too, we
|
||||||
|
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
|
||||||
|
// because the path given originates from Go stdlib, specifically
|
||||||
|
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
|
||||||
|
// Windows.
|
||||||
|
//
|
||||||
|
// See https://github.com/golang/go/issues/3335
|
||||||
|
// and https://github.com/golang/go/issues/18151
|
||||||
|
//
|
||||||
|
// for discussion on the issue on Go side.
|
||||||
|
//
|
||||||
|
// Find the last separator.
|
||||||
|
//
|
||||||
|
idx := strings.LastIndexByte(ec.File, '/')
|
||||||
|
if idx == -1 {
|
||||||
|
return ec.FullPath()
|
||||||
|
}
|
||||||
|
// Find the penultimate separator.
|
||||||
|
idx = strings.LastIndexByte(ec.File[:idx], '/')
|
||||||
|
if idx == -1 {
|
||||||
|
return ec.FullPath()
|
||||||
|
}
|
||||||
|
buf := bufferpool.Get()
|
||||||
|
// Keep everything after the penultimate separator.
|
||||||
|
buf.AppendString(ec.File[idx+1:])
|
||||||
|
buf.AppendByte(':')
|
||||||
|
buf.AppendInt(int64(ec.Line))
|
||||||
|
caller := buf.String()
|
||||||
|
buf.Free()
|
||||||
|
return caller
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Entry represents a complete log message. The entry's structured context
|
||||||
|
// is already serialized, but the log level, time, message, and call site
|
||||||
|
// information are available for inspection and modification.
|
||||||
|
//
|
||||||
|
// Entries are pooled, so any functions that accept them MUST be careful not to
|
||||||
|
// retain references to them.
|
||||||
|
type Entry struct {
|
||||||
|
Level Level
|
||||||
|
Time time.Time
|
||||||
|
LoggerName string
|
||||||
|
Message string
|
||||||
|
Caller EntryCaller
|
||||||
|
Stack string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckWriteAction indicates what action to take after a log entry is
|
||||||
|
// processed. Actions are ordered in increasing severity.
|
||||||
|
type CheckWriteAction uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// WriteThenNoop indicates that nothing special needs to be done. It's the
|
||||||
|
// default behavior.
|
||||||
|
WriteThenNoop CheckWriteAction = iota
|
||||||
|
// WriteThenPanic causes a panic after Write.
|
||||||
|
WriteThenPanic
|
||||||
|
// WriteThenFatal causes a fatal os.Exit after Write.
|
||||||
|
WriteThenFatal
|
||||||
|
)
|
||||||
|
|
||||||
|
// CheckedEntry is an Entry together with a collection of Cores that have
|
||||||
|
// already agreed to log it.
|
||||||
|
//
|
||||||
|
// CheckedEntry references should be created by calling AddCore or Should on a
|
||||||
|
// nil *CheckedEntry. References are returned to a pool after Write, and MUST
|
||||||
|
// NOT be retained after calling their Write method.
|
||||||
|
type CheckedEntry struct {
|
||||||
|
Entry
|
||||||
|
ErrorOutput WriteSyncer
|
||||||
|
dirty bool // best-effort detection of pool misuse
|
||||||
|
should CheckWriteAction
|
||||||
|
cores []Core
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ce *CheckedEntry) reset() {
|
||||||
|
ce.Entry = Entry{}
|
||||||
|
ce.ErrorOutput = nil
|
||||||
|
ce.dirty = false
|
||||||
|
ce.should = WriteThenNoop
|
||||||
|
for i := range ce.cores {
|
||||||
|
// don't keep references to cores
|
||||||
|
ce.cores[i] = nil
|
||||||
|
}
|
||||||
|
ce.cores = ce.cores[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes the entry to the stored Cores, returns any errors, and returns
|
||||||
|
// the CheckedEntry reference to a pool for immediate re-use. Finally, it
|
||||||
|
// executes any required CheckWriteAction.
|
||||||
|
func (ce *CheckedEntry) Write(fields ...Field) {
|
||||||
|
if ce == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ce.dirty {
|
||||||
|
if ce.ErrorOutput != nil {
|
||||||
|
// Make a best effort to detect unsafe re-use of this CheckedEntry.
|
||||||
|
// If the entry is dirty, log an internal error; because the
|
||||||
|
// CheckedEntry is being used after it was returned to the pool,
|
||||||
|
// the message may be an amalgamation from multiple call sites.
|
||||||
|
fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", time.Now(), ce.Entry)
|
||||||
|
ce.ErrorOutput.Sync()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ce.dirty = true
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for i := range ce.cores {
|
||||||
|
err = multierr.Append(err, ce.cores[i].Write(ce.Entry, fields))
|
||||||
|
}
|
||||||
|
if ce.ErrorOutput != nil {
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", time.Now(), err)
|
||||||
|
ce.ErrorOutput.Sync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
should, msg := ce.should, ce.Message
|
||||||
|
putCheckedEntry(ce)
|
||||||
|
|
||||||
|
switch should {
|
||||||
|
case WriteThenPanic:
|
||||||
|
panic(msg)
|
||||||
|
case WriteThenFatal:
|
||||||
|
exit.Exit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCore adds a Core that has agreed to log this CheckedEntry. It's intended to be
|
||||||
|
// used by Core.Check implementations, and is safe to call on nil CheckedEntry
|
||||||
|
// references.
|
||||||
|
func (ce *CheckedEntry) AddCore(ent Entry, core Core) *CheckedEntry {
|
||||||
|
if ce == nil {
|
||||||
|
ce = getCheckedEntry()
|
||||||
|
ce.Entry = ent
|
||||||
|
}
|
||||||
|
ce.cores = append(ce.cores, core)
|
||||||
|
return ce
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should sets this CheckedEntry's CheckWriteAction, which controls whether a
|
||||||
|
// Core will panic or fatal after writing this log entry. Like AddCore, it's
|
||||||
|
// safe to call on nil CheckedEntry references.
|
||||||
|
func (ce *CheckedEntry) Should(ent Entry, should CheckWriteAction) *CheckedEntry {
|
||||||
|
if ce == nil {
|
||||||
|
ce = getCheckedEntry()
|
||||||
|
ce.Entry = ent
|
||||||
|
}
|
||||||
|
ce.should = should
|
||||||
|
return ce
|
||||||
|
}
|
||||||
120
vendor/go.uber.org/zap/zapcore/error.go
generated
vendored
Normal file
120
vendor/go.uber.org/zap/zapcore/error.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encodes the given error into fields of an object. A field with the given
|
||||||
|
// name is added for the error message.
|
||||||
|
//
|
||||||
|
// If the error implements fmt.Formatter, a field with the name ${key}Verbose
|
||||||
|
// is also added with the full verbose error message.
|
||||||
|
//
|
||||||
|
// Finally, if the error implements errorGroup (from go.uber.org/multierr) or
|
||||||
|
// causer (from github.com/pkg/errors), a ${key}Causes field is added with an
|
||||||
|
// array of objects containing the errors this error was comprised of.
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "error": err.Error(),
|
||||||
|
// "errorVerbose": fmt.Sprintf("%+v", err),
|
||||||
|
// "errorCauses": [
|
||||||
|
// ...
|
||||||
|
// ],
|
||||||
|
// }
|
||||||
|
func encodeError(key string, err error, enc ObjectEncoder) error {
|
||||||
|
basic := err.Error()
|
||||||
|
enc.AddString(key, basic)
|
||||||
|
|
||||||
|
switch e := err.(type) {
|
||||||
|
case errorGroup:
|
||||||
|
return enc.AddArray(key+"Causes", errArray(e.Errors()))
|
||||||
|
case fmt.Formatter:
|
||||||
|
verbose := fmt.Sprintf("%+v", e)
|
||||||
|
if verbose != basic {
|
||||||
|
// This is a rich error type, like those produced by
|
||||||
|
// github.com/pkg/errors.
|
||||||
|
enc.AddString(key+"Verbose", verbose)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorGroup interface {
|
||||||
|
// Provides read-only access to the underlying list of errors, preferably
|
||||||
|
// without causing any allocs.
|
||||||
|
Errors() []error
|
||||||
|
}
|
||||||
|
|
||||||
|
type causer interface {
|
||||||
|
// Provides access to the error that caused this error.
|
||||||
|
Cause() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that errArry and errArrayElem are very similar to the version
|
||||||
|
// implemented in the top-level error.go file. We can't re-use this because
|
||||||
|
// that would require exporting errArray as part of the zapcore API.
|
||||||
|
|
||||||
|
// Encodes a list of errors using the standard error encoding logic.
|
||||||
|
type errArray []error
|
||||||
|
|
||||||
|
func (errs errArray) MarshalLogArray(arr ArrayEncoder) error {
|
||||||
|
for i := range errs {
|
||||||
|
if errs[i] == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
el := newErrArrayElem(errs[i])
|
||||||
|
arr.AppendObject(el)
|
||||||
|
el.Free()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _errArrayElemPool = sync.Pool{New: func() interface{} {
|
||||||
|
return &errArrayElem{}
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Encodes any error into a {"error": ...} re-using the same errors logic.
|
||||||
|
//
|
||||||
|
// May be passed in place of an array to build a single-element array.
|
||||||
|
type errArrayElem struct{ err error }
|
||||||
|
|
||||||
|
func newErrArrayElem(err error) *errArrayElem {
|
||||||
|
e := _errArrayElemPool.Get().(*errArrayElem)
|
||||||
|
e.err = err
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *errArrayElem) MarshalLogArray(arr ArrayEncoder) error {
|
||||||
|
return arr.AppendObject(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *errArrayElem) MarshalLogObject(enc ObjectEncoder) error {
|
||||||
|
return encodeError("error", e.err, enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *errArrayElem) Free() {
|
||||||
|
e.err = nil
|
||||||
|
_errArrayElemPool.Put(e)
|
||||||
|
}
|
||||||
201
vendor/go.uber.org/zap/zapcore/field.go
generated
vendored
Normal file
201
vendor/go.uber.org/zap/zapcore/field.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A FieldType indicates which member of the Field union struct should be used
|
||||||
|
// and how it should be serialized.
|
||||||
|
type FieldType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UnknownType is the default field type. Attempting to add it to an encoder will panic.
|
||||||
|
UnknownType FieldType = iota
|
||||||
|
// ArrayMarshalerType indicates that the field carries an ArrayMarshaler.
|
||||||
|
ArrayMarshalerType
|
||||||
|
// ObjectMarshalerType indicates that the field carries an ObjectMarshaler.
|
||||||
|
ObjectMarshalerType
|
||||||
|
// BinaryType indicates that the field carries an opaque binary blob.
|
||||||
|
BinaryType
|
||||||
|
// BoolType indicates that the field carries a bool.
|
||||||
|
BoolType
|
||||||
|
// ByteStringType indicates that the field carries UTF-8 encoded bytes.
|
||||||
|
ByteStringType
|
||||||
|
// Complex128Type indicates that the field carries a complex128.
|
||||||
|
Complex128Type
|
||||||
|
// Complex64Type indicates that the field carries a complex128.
|
||||||
|
Complex64Type
|
||||||
|
// DurationType indicates that the field carries a time.Duration.
|
||||||
|
DurationType
|
||||||
|
// Float64Type indicates that the field carries a float64.
|
||||||
|
Float64Type
|
||||||
|
// Float32Type indicates that the field carries a float32.
|
||||||
|
Float32Type
|
||||||
|
// Int64Type indicates that the field carries an int64.
|
||||||
|
Int64Type
|
||||||
|
// Int32Type indicates that the field carries an int32.
|
||||||
|
Int32Type
|
||||||
|
// Int16Type indicates that the field carries an int16.
|
||||||
|
Int16Type
|
||||||
|
// Int8Type indicates that the field carries an int8.
|
||||||
|
Int8Type
|
||||||
|
// StringType indicates that the field carries a string.
|
||||||
|
StringType
|
||||||
|
// TimeType indicates that the field carries a time.Time.
|
||||||
|
TimeType
|
||||||
|
// Uint64Type indicates that the field carries a uint64.
|
||||||
|
Uint64Type
|
||||||
|
// Uint32Type indicates that the field carries a uint32.
|
||||||
|
Uint32Type
|
||||||
|
// Uint16Type indicates that the field carries a uint16.
|
||||||
|
Uint16Type
|
||||||
|
// Uint8Type indicates that the field carries a uint8.
|
||||||
|
Uint8Type
|
||||||
|
// UintptrType indicates that the field carries a uintptr.
|
||||||
|
UintptrType
|
||||||
|
// ReflectType indicates that the field carries an interface{}, which should
|
||||||
|
// be serialized using reflection.
|
||||||
|
ReflectType
|
||||||
|
// NamespaceType signals the beginning of an isolated namespace. All
|
||||||
|
// subsequent fields should be added to the new namespace.
|
||||||
|
NamespaceType
|
||||||
|
// StringerType indicates that the field carries a fmt.Stringer.
|
||||||
|
StringerType
|
||||||
|
// ErrorType indicates that the field carries an error.
|
||||||
|
ErrorType
|
||||||
|
// SkipType indicates that the field is a no-op.
|
||||||
|
SkipType
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Field is a marshaling operation used to add a key-value pair to a logger's
|
||||||
|
// context. Most fields are lazily marshaled, so it's inexpensive to add fields
|
||||||
|
// to disabled debug-level log statements.
|
||||||
|
type Field struct {
|
||||||
|
Key string
|
||||||
|
Type FieldType
|
||||||
|
Integer int64
|
||||||
|
String string
|
||||||
|
Interface interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTo exports a field through the ObjectEncoder interface. It's primarily
|
||||||
|
// useful to library authors, and shouldn't be necessary in most applications.
|
||||||
|
func (f Field) AddTo(enc ObjectEncoder) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch f.Type {
|
||||||
|
case ArrayMarshalerType:
|
||||||
|
err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))
|
||||||
|
case ObjectMarshalerType:
|
||||||
|
err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))
|
||||||
|
case BinaryType:
|
||||||
|
enc.AddBinary(f.Key, f.Interface.([]byte))
|
||||||
|
case BoolType:
|
||||||
|
enc.AddBool(f.Key, f.Integer == 1)
|
||||||
|
case ByteStringType:
|
||||||
|
enc.AddByteString(f.Key, f.Interface.([]byte))
|
||||||
|
case Complex128Type:
|
||||||
|
enc.AddComplex128(f.Key, f.Interface.(complex128))
|
||||||
|
case Complex64Type:
|
||||||
|
enc.AddComplex64(f.Key, f.Interface.(complex64))
|
||||||
|
case DurationType:
|
||||||
|
enc.AddDuration(f.Key, time.Duration(f.Integer))
|
||||||
|
case Float64Type:
|
||||||
|
enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer)))
|
||||||
|
case Float32Type:
|
||||||
|
enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer)))
|
||||||
|
case Int64Type:
|
||||||
|
enc.AddInt64(f.Key, f.Integer)
|
||||||
|
case Int32Type:
|
||||||
|
enc.AddInt32(f.Key, int32(f.Integer))
|
||||||
|
case Int16Type:
|
||||||
|
enc.AddInt16(f.Key, int16(f.Integer))
|
||||||
|
case Int8Type:
|
||||||
|
enc.AddInt8(f.Key, int8(f.Integer))
|
||||||
|
case StringType:
|
||||||
|
enc.AddString(f.Key, f.String)
|
||||||
|
case TimeType:
|
||||||
|
if f.Interface != nil {
|
||||||
|
enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))
|
||||||
|
} else {
|
||||||
|
// Fall back to UTC if location is nil.
|
||||||
|
enc.AddTime(f.Key, time.Unix(0, f.Integer))
|
||||||
|
}
|
||||||
|
case Uint64Type:
|
||||||
|
enc.AddUint64(f.Key, uint64(f.Integer))
|
||||||
|
case Uint32Type:
|
||||||
|
enc.AddUint32(f.Key, uint32(f.Integer))
|
||||||
|
case Uint16Type:
|
||||||
|
enc.AddUint16(f.Key, uint16(f.Integer))
|
||||||
|
case Uint8Type:
|
||||||
|
enc.AddUint8(f.Key, uint8(f.Integer))
|
||||||
|
case UintptrType:
|
||||||
|
enc.AddUintptr(f.Key, uintptr(f.Integer))
|
||||||
|
case ReflectType:
|
||||||
|
err = enc.AddReflected(f.Key, f.Interface)
|
||||||
|
case NamespaceType:
|
||||||
|
enc.OpenNamespace(f.Key)
|
||||||
|
case StringerType:
|
||||||
|
enc.AddString(f.Key, f.Interface.(fmt.Stringer).String())
|
||||||
|
case ErrorType:
|
||||||
|
encodeError(f.Key, f.Interface.(error), enc)
|
||||||
|
case SkipType:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unknown field type: %v", f))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals returns whether two fields are equal. For non-primitive types such as
|
||||||
|
// errors, marshalers, or reflect types, it uses reflect.DeepEqual.
|
||||||
|
func (f Field) Equals(other Field) bool {
|
||||||
|
if f.Type != other.Type {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if f.Key != other.Key {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch f.Type {
|
||||||
|
case BinaryType, ByteStringType:
|
||||||
|
return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte))
|
||||||
|
case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType:
|
||||||
|
return reflect.DeepEqual(f.Interface, other.Interface)
|
||||||
|
default:
|
||||||
|
return f == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFields(enc ObjectEncoder, fields []Field) {
|
||||||
|
for i := range fields {
|
||||||
|
fields[i].AddTo(enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
68
vendor/go.uber.org/zap/zapcore/hook.go
generated
vendored
Normal file
68
vendor/go.uber.org/zap/zapcore/hook.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import "go.uber.org/multierr"
|
||||||
|
|
||||||
|
type hooked struct {
|
||||||
|
Core
|
||||||
|
funcs []func(Entry) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterHooks wraps a Core and runs a collection of user-defined callback
|
||||||
|
// hooks each time a message is logged. Execution of the callbacks is blocking.
|
||||||
|
//
|
||||||
|
// This offers users an easy way to register simple callbacks (e.g., metrics
|
||||||
|
// collection) without implementing the full Core interface.
|
||||||
|
func RegisterHooks(core Core, hooks ...func(Entry) error) Core {
|
||||||
|
funcs := append([]func(Entry) error{}, hooks...)
|
||||||
|
return &hooked{
|
||||||
|
Core: core,
|
||||||
|
funcs: funcs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hooked) Check(ent Entry, ce *CheckedEntry) *CheckedEntry {
|
||||||
|
// Let the wrapped Core decide whether to log this message or not. This
|
||||||
|
// also gives the downstream a chance to register itself directly with the
|
||||||
|
// CheckedEntry.
|
||||||
|
if downstream := h.Core.Check(ent, ce); downstream != nil {
|
||||||
|
return downstream.AddCore(ent, h)
|
||||||
|
}
|
||||||
|
return ce
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hooked) With(fields []Field) Core {
|
||||||
|
return &hooked{
|
||||||
|
Core: h.Core.With(fields),
|
||||||
|
funcs: h.funcs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hooked) Write(ent Entry, _ []Field) error {
|
||||||
|
// Since our downstream had a chance to register itself directly with the
|
||||||
|
// CheckedMessage, we don't need to call it here.
|
||||||
|
var err error
|
||||||
|
for i := range h.funcs {
|
||||||
|
err = multierr.Append(err, h.funcs[i](ent))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
502
vendor/go.uber.org/zap/zapcore/json_encoder.go
generated
vendored
Normal file
502
vendor/go.uber.org/zap/zapcore/json_encoder.go
generated
vendored
Normal file
@@ -0,0 +1,502 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"go.uber.org/zap/buffer"
|
||||||
|
"go.uber.org/zap/internal/bufferpool"
|
||||||
|
)
|
||||||
|
|
||||||
|
// For JSON-escaping; see jsonEncoder.safeAddString below.
|
||||||
|
const _hex = "0123456789abcdef"
|
||||||
|
|
||||||
|
var _jsonPool = sync.Pool{New: func() interface{} {
|
||||||
|
return &jsonEncoder{}
|
||||||
|
}}
|
||||||
|
|
||||||
|
func getJSONEncoder() *jsonEncoder {
|
||||||
|
return _jsonPool.Get().(*jsonEncoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putJSONEncoder(enc *jsonEncoder) {
|
||||||
|
if enc.reflectBuf != nil {
|
||||||
|
enc.reflectBuf.Free()
|
||||||
|
}
|
||||||
|
enc.EncoderConfig = nil
|
||||||
|
enc.buf = nil
|
||||||
|
enc.spaced = false
|
||||||
|
enc.openNamespaces = 0
|
||||||
|
enc.reflectBuf = nil
|
||||||
|
enc.reflectEnc = nil
|
||||||
|
_jsonPool.Put(enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonEncoder struct {
|
||||||
|
*EncoderConfig
|
||||||
|
buf *buffer.Buffer
|
||||||
|
spaced bool // include spaces after colons and commas
|
||||||
|
openNamespaces int
|
||||||
|
|
||||||
|
// for encoding generic values by reflection
|
||||||
|
reflectBuf *buffer.Buffer
|
||||||
|
reflectEnc *json.Encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewJSONEncoder creates a fast, low-allocation JSON encoder. The encoder
|
||||||
|
// appropriately escapes all field keys and values.
|
||||||
|
//
|
||||||
|
// Note that the encoder doesn't deduplicate keys, so it's possible to produce
|
||||||
|
// a message like
|
||||||
|
// {"foo":"bar","foo":"baz"}
|
||||||
|
// This is permitted by the JSON specification, but not encouraged. Many
|
||||||
|
// libraries will ignore duplicate key-value pairs (typically keeping the last
|
||||||
|
// pair) when unmarshaling, but users should attempt to avoid adding duplicate
|
||||||
|
// keys.
|
||||||
|
func NewJSONEncoder(cfg EncoderConfig) Encoder {
|
||||||
|
return newJSONEncoder(cfg, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder {
|
||||||
|
return &jsonEncoder{
|
||||||
|
EncoderConfig: &cfg,
|
||||||
|
buf: bufferpool.Get(),
|
||||||
|
spaced: spaced,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddArray(key string, arr ArrayMarshaler) error {
|
||||||
|
enc.addKey(key)
|
||||||
|
return enc.AppendArray(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddObject(key string, obj ObjectMarshaler) error {
|
||||||
|
enc.addKey(key)
|
||||||
|
return enc.AppendObject(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddBinary(key string, val []byte) {
|
||||||
|
enc.AddString(key, base64.StdEncoding.EncodeToString(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddByteString(key string, val []byte) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendByteString(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddBool(key string, val bool) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendBool(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddComplex128(key string, val complex128) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendComplex128(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddDuration(key string, val time.Duration) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendDuration(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddFloat64(key string, val float64) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendFloat64(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddInt64(key string, val int64) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendInt64(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) resetReflectBuf() {
|
||||||
|
if enc.reflectBuf == nil {
|
||||||
|
enc.reflectBuf = bufferpool.Get()
|
||||||
|
enc.reflectEnc = json.NewEncoder(enc.reflectBuf)
|
||||||
|
} else {
|
||||||
|
enc.reflectBuf.Reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error {
|
||||||
|
enc.resetReflectBuf()
|
||||||
|
err := enc.reflectEnc.Encode(obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
enc.reflectBuf.TrimNewline()
|
||||||
|
enc.addKey(key)
|
||||||
|
_, err = enc.buf.Write(enc.reflectBuf.Bytes())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) OpenNamespace(key string) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.buf.AppendByte('{')
|
||||||
|
enc.openNamespaces++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddString(key, val string) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendString(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddTime(key string, val time.Time) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendTime(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddUint64(key string, val uint64) {
|
||||||
|
enc.addKey(key)
|
||||||
|
enc.AppendUint64(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendArray(arr ArrayMarshaler) error {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
enc.buf.AppendByte('[')
|
||||||
|
err := arr.MarshalLogArray(enc)
|
||||||
|
enc.buf.AppendByte(']')
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendObject(obj ObjectMarshaler) error {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
enc.buf.AppendByte('{')
|
||||||
|
err := obj.MarshalLogObject(enc)
|
||||||
|
enc.buf.AppendByte('}')
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendBool(val bool) {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
enc.buf.AppendBool(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendByteString(val []byte) {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
enc.buf.AppendByte('"')
|
||||||
|
enc.safeAddByteString(val)
|
||||||
|
enc.buf.AppendByte('"')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendComplex128(val complex128) {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
// Cast to a platform-independent, fixed-size type.
|
||||||
|
r, i := float64(real(val)), float64(imag(val))
|
||||||
|
enc.buf.AppendByte('"')
|
||||||
|
// Because we're always in a quoted string, we can use strconv without
|
||||||
|
// special-casing NaN and +/-Inf.
|
||||||
|
enc.buf.AppendFloat(r, 64)
|
||||||
|
enc.buf.AppendByte('+')
|
||||||
|
enc.buf.AppendFloat(i, 64)
|
||||||
|
enc.buf.AppendByte('i')
|
||||||
|
enc.buf.AppendByte('"')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendDuration(val time.Duration) {
|
||||||
|
cur := enc.buf.Len()
|
||||||
|
enc.EncodeDuration(val, enc)
|
||||||
|
if cur == enc.buf.Len() {
|
||||||
|
// User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep
|
||||||
|
// JSON valid.
|
||||||
|
enc.AppendInt64(int64(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendInt64(val int64) {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
enc.buf.AppendInt(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendReflected(val interface{}) error {
|
||||||
|
enc.resetReflectBuf()
|
||||||
|
err := enc.reflectEnc.Encode(val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
enc.reflectBuf.TrimNewline()
|
||||||
|
enc.addElementSeparator()
|
||||||
|
_, err = enc.buf.Write(enc.reflectBuf.Bytes())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendString(val string) {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
enc.buf.AppendByte('"')
|
||||||
|
enc.safeAddString(val)
|
||||||
|
enc.buf.AppendByte('"')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendTime(val time.Time) {
|
||||||
|
cur := enc.buf.Len()
|
||||||
|
enc.EncodeTime(val, enc)
|
||||||
|
if cur == enc.buf.Len() {
|
||||||
|
// User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep
|
||||||
|
// output JSON valid.
|
||||||
|
enc.AppendInt64(val.UnixNano())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AppendUint64(val uint64) {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
enc.buf.AppendUint(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) }
|
||||||
|
func (enc *jsonEncoder) AddFloat32(k string, v float32) { enc.AddFloat64(k, float64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) }
|
||||||
|
func (enc *jsonEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) }
|
||||||
|
func (enc *jsonEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) }
|
||||||
|
func (enc *jsonEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) }
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) Clone() Encoder {
|
||||||
|
clone := enc.clone()
|
||||||
|
clone.buf.Write(enc.buf.Bytes())
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) clone() *jsonEncoder {
|
||||||
|
clone := getJSONEncoder()
|
||||||
|
clone.EncoderConfig = enc.EncoderConfig
|
||||||
|
clone.spaced = enc.spaced
|
||||||
|
clone.openNamespaces = enc.openNamespaces
|
||||||
|
clone.buf = bufferpool.Get()
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) {
|
||||||
|
final := enc.clone()
|
||||||
|
final.buf.AppendByte('{')
|
||||||
|
|
||||||
|
if final.LevelKey != "" {
|
||||||
|
final.addKey(final.LevelKey)
|
||||||
|
cur := final.buf.Len()
|
||||||
|
final.EncodeLevel(ent.Level, final)
|
||||||
|
if cur == final.buf.Len() {
|
||||||
|
// User-supplied EncodeLevel was a no-op. Fall back to strings to keep
|
||||||
|
// output JSON valid.
|
||||||
|
final.AppendString(ent.Level.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if final.TimeKey != "" {
|
||||||
|
final.AddTime(final.TimeKey, ent.Time)
|
||||||
|
}
|
||||||
|
if ent.LoggerName != "" && final.NameKey != "" {
|
||||||
|
final.addKey(final.NameKey)
|
||||||
|
cur := final.buf.Len()
|
||||||
|
nameEncoder := final.EncodeName
|
||||||
|
|
||||||
|
// if no name encoder provided, fall back to FullNameEncoder for backwards
|
||||||
|
// compatibility
|
||||||
|
if nameEncoder == nil {
|
||||||
|
nameEncoder = FullNameEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
nameEncoder(ent.LoggerName, final)
|
||||||
|
if cur == final.buf.Len() {
|
||||||
|
// User-supplied EncodeName was a no-op. Fall back to strings to
|
||||||
|
// keep output JSON valid.
|
||||||
|
final.AppendString(ent.LoggerName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ent.Caller.Defined && final.CallerKey != "" {
|
||||||
|
final.addKey(final.CallerKey)
|
||||||
|
cur := final.buf.Len()
|
||||||
|
final.EncodeCaller(ent.Caller, final)
|
||||||
|
if cur == final.buf.Len() {
|
||||||
|
// User-supplied EncodeCaller was a no-op. Fall back to strings to
|
||||||
|
// keep output JSON valid.
|
||||||
|
final.AppendString(ent.Caller.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if final.MessageKey != "" {
|
||||||
|
final.addKey(enc.MessageKey)
|
||||||
|
final.AppendString(ent.Message)
|
||||||
|
}
|
||||||
|
if enc.buf.Len() > 0 {
|
||||||
|
final.addElementSeparator()
|
||||||
|
final.buf.Write(enc.buf.Bytes())
|
||||||
|
}
|
||||||
|
addFields(final, fields)
|
||||||
|
final.closeOpenNamespaces()
|
||||||
|
if ent.Stack != "" && final.StacktraceKey != "" {
|
||||||
|
final.AddString(final.StacktraceKey, ent.Stack)
|
||||||
|
}
|
||||||
|
final.buf.AppendByte('}')
|
||||||
|
if final.LineEnding != "" {
|
||||||
|
final.buf.AppendString(final.LineEnding)
|
||||||
|
} else {
|
||||||
|
final.buf.AppendString(DefaultLineEnding)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := final.buf
|
||||||
|
putJSONEncoder(final)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) truncate() {
|
||||||
|
enc.buf.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) closeOpenNamespaces() {
|
||||||
|
for i := 0; i < enc.openNamespaces; i++ {
|
||||||
|
enc.buf.AppendByte('}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) addKey(key string) {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
enc.buf.AppendByte('"')
|
||||||
|
enc.safeAddString(key)
|
||||||
|
enc.buf.AppendByte('"')
|
||||||
|
enc.buf.AppendByte(':')
|
||||||
|
if enc.spaced {
|
||||||
|
enc.buf.AppendByte(' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) addElementSeparator() {
|
||||||
|
last := enc.buf.Len() - 1
|
||||||
|
if last < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch enc.buf.Bytes()[last] {
|
||||||
|
case '{', '[', ':', ',', ' ':
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
enc.buf.AppendByte(',')
|
||||||
|
if enc.spaced {
|
||||||
|
enc.buf.AppendByte(' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) appendFloat(val float64, bitSize int) {
|
||||||
|
enc.addElementSeparator()
|
||||||
|
switch {
|
||||||
|
case math.IsNaN(val):
|
||||||
|
enc.buf.AppendString(`"NaN"`)
|
||||||
|
case math.IsInf(val, 1):
|
||||||
|
enc.buf.AppendString(`"+Inf"`)
|
||||||
|
case math.IsInf(val, -1):
|
||||||
|
enc.buf.AppendString(`"-Inf"`)
|
||||||
|
default:
|
||||||
|
enc.buf.AppendFloat(val, bitSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// safeAddString JSON-escapes a string and appends it to the internal buffer.
|
||||||
|
// Unlike the standard library's encoder, it doesn't attempt to protect the
|
||||||
|
// user from browser vulnerabilities or JSONP-related problems.
|
||||||
|
func (enc *jsonEncoder) safeAddString(s string) {
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
if enc.tryAddRuneSelf(s[i]) {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r, size := utf8.DecodeRuneInString(s[i:])
|
||||||
|
if enc.tryAddRuneError(r, size) {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
enc.buf.AppendString(s[i : i+size])
|
||||||
|
i += size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte.
|
||||||
|
func (enc *jsonEncoder) safeAddByteString(s []byte) {
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
if enc.tryAddRuneSelf(s[i]) {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r, size := utf8.DecodeRune(s[i:])
|
||||||
|
if enc.tryAddRuneError(r, size) {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
enc.buf.Write(s[i : i+size])
|
||||||
|
i += size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte.
|
||||||
|
func (enc *jsonEncoder) tryAddRuneSelf(b byte) bool {
|
||||||
|
if b >= utf8.RuneSelf {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if 0x20 <= b && b != '\\' && b != '"' {
|
||||||
|
enc.buf.AppendByte(b)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch b {
|
||||||
|
case '\\', '"':
|
||||||
|
enc.buf.AppendByte('\\')
|
||||||
|
enc.buf.AppendByte(b)
|
||||||
|
case '\n':
|
||||||
|
enc.buf.AppendByte('\\')
|
||||||
|
enc.buf.AppendByte('n')
|
||||||
|
case '\r':
|
||||||
|
enc.buf.AppendByte('\\')
|
||||||
|
enc.buf.AppendByte('r')
|
||||||
|
case '\t':
|
||||||
|
enc.buf.AppendByte('\\')
|
||||||
|
enc.buf.AppendByte('t')
|
||||||
|
default:
|
||||||
|
// Encode bytes < 0x20, except for the escape sequences above.
|
||||||
|
enc.buf.AppendString(`\u00`)
|
||||||
|
enc.buf.AppendByte(_hex[b>>4])
|
||||||
|
enc.buf.AppendByte(_hex[b&0xF])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *jsonEncoder) tryAddRuneError(r rune, size int) bool {
|
||||||
|
if r == utf8.RuneError && size == 1 {
|
||||||
|
enc.buf.AppendString(`\ufffd`)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
175
vendor/go.uber.org/zap/zapcore/level.go
generated
vendored
Normal file
175
vendor/go.uber.org/zap/zapcore/level.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errUnmarshalNilLevel = errors.New("can't unmarshal a nil *Level")
|
||||||
|
|
||||||
|
// A Level is a logging priority. Higher levels are more important.
|
||||||
|
type Level int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DebugLevel logs are typically voluminous, and are usually disabled in
|
||||||
|
// production.
|
||||||
|
DebugLevel Level = iota - 1
|
||||||
|
// InfoLevel is the default logging priority.
|
||||||
|
InfoLevel
|
||||||
|
// WarnLevel logs are more important than Info, but don't need individual
|
||||||
|
// human review.
|
||||||
|
WarnLevel
|
||||||
|
// ErrorLevel logs are high-priority. If an application is running smoothly,
|
||||||
|
// it shouldn't generate any error-level logs.
|
||||||
|
ErrorLevel
|
||||||
|
// DPanicLevel logs are particularly important errors. In development the
|
||||||
|
// logger panics after writing the message.
|
||||||
|
DPanicLevel
|
||||||
|
// PanicLevel logs a message, then panics.
|
||||||
|
PanicLevel
|
||||||
|
// FatalLevel logs a message, then calls os.Exit(1).
|
||||||
|
FatalLevel
|
||||||
|
|
||||||
|
_minLevel = DebugLevel
|
||||||
|
_maxLevel = FatalLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
// String returns a lower-case ASCII representation of the log level.
|
||||||
|
func (l Level) String() string {
|
||||||
|
switch l {
|
||||||
|
case DebugLevel:
|
||||||
|
return "debug"
|
||||||
|
case InfoLevel:
|
||||||
|
return "info"
|
||||||
|
case WarnLevel:
|
||||||
|
return "warn"
|
||||||
|
case ErrorLevel:
|
||||||
|
return "error"
|
||||||
|
case DPanicLevel:
|
||||||
|
return "dpanic"
|
||||||
|
case PanicLevel:
|
||||||
|
return "panic"
|
||||||
|
case FatalLevel:
|
||||||
|
return "fatal"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Level(%d)", l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapitalString returns an all-caps ASCII representation of the log level.
|
||||||
|
func (l Level) CapitalString() string {
|
||||||
|
// Printing levels in all-caps is common enough that we should export this
|
||||||
|
// functionality.
|
||||||
|
switch l {
|
||||||
|
case DebugLevel:
|
||||||
|
return "DEBUG"
|
||||||
|
case InfoLevel:
|
||||||
|
return "INFO"
|
||||||
|
case WarnLevel:
|
||||||
|
return "WARN"
|
||||||
|
case ErrorLevel:
|
||||||
|
return "ERROR"
|
||||||
|
case DPanicLevel:
|
||||||
|
return "DPANIC"
|
||||||
|
case PanicLevel:
|
||||||
|
return "PANIC"
|
||||||
|
case FatalLevel:
|
||||||
|
return "FATAL"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("LEVEL(%d)", l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText marshals the Level to text. Note that the text representation
|
||||||
|
// drops the -Level suffix (see example).
|
||||||
|
func (l Level) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(l.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText unmarshals text to a level. Like MarshalText, UnmarshalText
|
||||||
|
// expects the text representation of a Level to drop the -Level suffix (see
|
||||||
|
// example).
|
||||||
|
//
|
||||||
|
// In particular, this makes it easy to configure logging levels using YAML,
|
||||||
|
// TOML, or JSON files.
|
||||||
|
func (l *Level) UnmarshalText(text []byte) error {
|
||||||
|
if l == nil {
|
||||||
|
return errUnmarshalNilLevel
|
||||||
|
}
|
||||||
|
if !l.unmarshalText(text) && !l.unmarshalText(bytes.ToLower(text)) {
|
||||||
|
return fmt.Errorf("unrecognized level: %q", text)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Level) unmarshalText(text []byte) bool {
|
||||||
|
switch string(text) {
|
||||||
|
case "debug", "DEBUG":
|
||||||
|
*l = DebugLevel
|
||||||
|
case "info", "INFO", "": // make the zero value useful
|
||||||
|
*l = InfoLevel
|
||||||
|
case "warn", "WARN":
|
||||||
|
*l = WarnLevel
|
||||||
|
case "error", "ERROR":
|
||||||
|
*l = ErrorLevel
|
||||||
|
case "dpanic", "DPANIC":
|
||||||
|
*l = DPanicLevel
|
||||||
|
case "panic", "PANIC":
|
||||||
|
*l = PanicLevel
|
||||||
|
case "fatal", "FATAL":
|
||||||
|
*l = FatalLevel
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the level for the flag.Value interface.
|
||||||
|
func (l *Level) Set(s string) error {
|
||||||
|
return l.UnmarshalText([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the level for the flag.Getter interface.
|
||||||
|
func (l *Level) Get() interface{} {
|
||||||
|
return *l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled returns true if the given level is at or above this level.
|
||||||
|
func (l Level) Enabled(lvl Level) bool {
|
||||||
|
return lvl >= l
|
||||||
|
}
|
||||||
|
|
||||||
|
// LevelEnabler decides whether a given logging level is enabled when logging a
|
||||||
|
// message.
|
||||||
|
//
|
||||||
|
// Enablers are intended to be used to implement deterministic filters;
|
||||||
|
// concerns like sampling are better implemented as a Core.
|
||||||
|
//
|
||||||
|
// Each concrete Level value implements a static LevelEnabler which returns
|
||||||
|
// true for itself and all higher logging levels. For example WarnLevel.Enabled()
|
||||||
|
// will return true for WarnLevel, ErrorLevel, DPanicLevel, PanicLevel, and
|
||||||
|
// FatalLevel, but return false for InfoLevel and DebugLevel.
|
||||||
|
type LevelEnabler interface {
|
||||||
|
Enabled(Level) bool
|
||||||
|
}
|
||||||
46
vendor/go.uber.org/zap/zapcore/level_strings.go
generated
vendored
Normal file
46
vendor/go.uber.org/zap/zapcore/level_strings.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import "go.uber.org/zap/internal/color"
|
||||||
|
|
||||||
|
var (
|
||||||
|
_levelToColor = map[Level]color.Color{
|
||||||
|
DebugLevel: color.Magenta,
|
||||||
|
InfoLevel: color.Blue,
|
||||||
|
WarnLevel: color.Yellow,
|
||||||
|
ErrorLevel: color.Red,
|
||||||
|
DPanicLevel: color.Red,
|
||||||
|
PanicLevel: color.Red,
|
||||||
|
FatalLevel: color.Red,
|
||||||
|
}
|
||||||
|
_unknownLevelColor = color.Red
|
||||||
|
|
||||||
|
_levelToLowercaseColorString = make(map[Level]string, len(_levelToColor))
|
||||||
|
_levelToCapitalColorString = make(map[Level]string, len(_levelToColor))
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for level, color := range _levelToColor {
|
||||||
|
_levelToLowercaseColorString[level] = color.Add(level.String())
|
||||||
|
_levelToCapitalColorString[level] = color.Add(level.CapitalString())
|
||||||
|
}
|
||||||
|
}
|
||||||
53
vendor/go.uber.org/zap/zapcore/marshaler.go
generated
vendored
Normal file
53
vendor/go.uber.org/zap/zapcore/marshaler.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
// ObjectMarshaler allows user-defined types to efficiently add themselves to the
|
||||||
|
// logging context, and to selectively omit information which shouldn't be
|
||||||
|
// included in logs (e.g., passwords).
|
||||||
|
type ObjectMarshaler interface {
|
||||||
|
MarshalLogObject(ObjectEncoder) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectMarshalerFunc is a type adapter that turns a function into an
|
||||||
|
// ObjectMarshaler.
|
||||||
|
type ObjectMarshalerFunc func(ObjectEncoder) error
|
||||||
|
|
||||||
|
// MarshalLogObject calls the underlying function.
|
||||||
|
func (f ObjectMarshalerFunc) MarshalLogObject(enc ObjectEncoder) error {
|
||||||
|
return f(enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayMarshaler allows user-defined types to efficiently add themselves to the
|
||||||
|
// logging context, and to selectively omit information which shouldn't be
|
||||||
|
// included in logs (e.g., passwords).
|
||||||
|
type ArrayMarshaler interface {
|
||||||
|
MarshalLogArray(ArrayEncoder) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayMarshalerFunc is a type adapter that turns a function into an
|
||||||
|
// ArrayMarshaler.
|
||||||
|
type ArrayMarshalerFunc func(ArrayEncoder) error
|
||||||
|
|
||||||
|
// MarshalLogArray calls the underlying function.
|
||||||
|
func (f ArrayMarshalerFunc) MarshalLogArray(enc ArrayEncoder) error {
|
||||||
|
return f(enc)
|
||||||
|
}
|
||||||
179
vendor/go.uber.org/zap/zapcore/memory_encoder.go
generated
vendored
Normal file
179
vendor/go.uber.org/zap/zapcore/memory_encoder.go
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// MapObjectEncoder is an ObjectEncoder backed by a simple
|
||||||
|
// map[string]interface{}. It's not fast enough for production use, but it's
|
||||||
|
// helpful in tests.
|
||||||
|
type MapObjectEncoder struct {
|
||||||
|
// Fields contains the entire encoded log context.
|
||||||
|
Fields map[string]interface{}
|
||||||
|
// cur is a pointer to the namespace we're currently writing to.
|
||||||
|
cur map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMapObjectEncoder creates a new map-backed ObjectEncoder.
|
||||||
|
func NewMapObjectEncoder() *MapObjectEncoder {
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
return &MapObjectEncoder{
|
||||||
|
Fields: m,
|
||||||
|
cur: m,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddArray implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddArray(key string, v ArrayMarshaler) error {
|
||||||
|
arr := &sliceArrayEncoder{elems: make([]interface{}, 0)}
|
||||||
|
err := v.MarshalLogArray(arr)
|
||||||
|
m.cur[key] = arr.elems
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddObject implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddObject(k string, v ObjectMarshaler) error {
|
||||||
|
newMap := NewMapObjectEncoder()
|
||||||
|
m.cur[k] = newMap.Fields
|
||||||
|
return v.MarshalLogObject(newMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddBinary implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddBinary(k string, v []byte) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddByteString implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddByteString(k string, v []byte) { m.cur[k] = string(v) }
|
||||||
|
|
||||||
|
// AddBool implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddBool(k string, v bool) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddDuration implements ObjectEncoder.
|
||||||
|
func (m MapObjectEncoder) AddDuration(k string, v time.Duration) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddComplex128 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddComplex128(k string, v complex128) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddComplex64 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddComplex64(k string, v complex64) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddFloat64 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddFloat64(k string, v float64) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddFloat32 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddFloat32(k string, v float32) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddInt implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddInt(k string, v int) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddInt64 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddInt64(k string, v int64) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddInt32 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddInt32(k string, v int32) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddInt16 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddInt16(k string, v int16) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddInt8 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddInt8(k string, v int8) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddString implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddString(k string, v string) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddTime implements ObjectEncoder.
|
||||||
|
func (m MapObjectEncoder) AddTime(k string, v time.Time) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddUint implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddUint(k string, v uint) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddUint64 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddUint64(k string, v uint64) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddUint32 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddUint32(k string, v uint32) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddUint16 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddUint16(k string, v uint16) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddUint8 implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddUint8(k string, v uint8) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddUintptr implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddUintptr(k string, v uintptr) { m.cur[k] = v }
|
||||||
|
|
||||||
|
// AddReflected implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) AddReflected(k string, v interface{}) error {
|
||||||
|
m.cur[k] = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenNamespace implements ObjectEncoder.
|
||||||
|
func (m *MapObjectEncoder) OpenNamespace(k string) {
|
||||||
|
ns := make(map[string]interface{})
|
||||||
|
m.cur[k] = ns
|
||||||
|
m.cur = ns
|
||||||
|
}
|
||||||
|
|
||||||
|
// sliceArrayEncoder is an ArrayEncoder backed by a simple []interface{}. Like
|
||||||
|
// the MapObjectEncoder, it's not designed for production use.
|
||||||
|
type sliceArrayEncoder struct {
|
||||||
|
elems []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sliceArrayEncoder) AppendArray(v ArrayMarshaler) error {
|
||||||
|
enc := &sliceArrayEncoder{}
|
||||||
|
err := v.MarshalLogArray(enc)
|
||||||
|
s.elems = append(s.elems, enc.elems)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sliceArrayEncoder) AppendObject(v ObjectMarshaler) error {
|
||||||
|
m := NewMapObjectEncoder()
|
||||||
|
err := v.MarshalLogObject(m)
|
||||||
|
s.elems = append(s.elems, m.Fields)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sliceArrayEncoder) AppendReflected(v interface{}) error {
|
||||||
|
s.elems = append(s.elems, v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sliceArrayEncoder) AppendBool(v bool) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendByteString(v []byte) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendComplex128(v complex128) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendComplex64(v complex64) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendDuration(v time.Duration) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendFloat64(v float64) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendFloat32(v float32) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendInt(v int) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendInt64(v int64) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendInt32(v int32) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendInt16(v int16) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendInt8(v int8) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendString(v string) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendTime(v time.Time) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendUint(v uint) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendUint64(v uint64) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendUint32(v uint32) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendUint16(v uint16) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendUint8(v uint8) { s.elems = append(s.elems, v) }
|
||||||
|
func (s *sliceArrayEncoder) AppendUintptr(v uintptr) { s.elems = append(s.elems, v) }
|
||||||
134
vendor/go.uber.org/zap/zapcore/sampler.go
generated
vendored
Normal file
134
vendor/go.uber.org/zap/zapcore/sampler.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
// 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 zapcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_numLevels = _maxLevel - _minLevel + 1
|
||||||
|
_countersPerLevel = 4096
|
||||||
|
)
|
||||||
|
|
||||||
|
type counter struct {
|
||||||
|
resetAt atomic.Int64
|
||||||
|
counter atomic.Uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type counters [_numLevels][_countersPerLevel]counter
|
||||||
|
|
||||||
|
func newCounters() *counters {
|
||||||
|
return &counters{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *counters) get(lvl Level, key string) *counter {
|
||||||
|
i := lvl - _minLevel
|
||||||
|
j := fnv32a(key) % _countersPerLevel
|
||||||
|
return &cs[i][j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// fnv32a, adapted from "hash/fnv", but without a []byte(string) alloc
|
||||||
|
func fnv32a(s string) uint32 {
|
||||||
|
const (
|
||||||
|
offset32 = 2166136261
|
||||||
|
prime32 = 16777619
|
||||||
|
)
|
||||||
|
hash := uint32(offset32)
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
hash ^= uint32(s[i])
|
||||||
|
hash *= prime32
|
||||||
|
}
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) IncCheckReset(t time.Time, tick time.Duration) uint64 {
|
||||||
|
tn := t.UnixNano()
|
||||||
|
resetAfter := c.resetAt.Load()
|
||||||
|
if resetAfter > tn {
|
||||||
|
return c.counter.Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.counter.Store(1)
|
||||||
|
|
||||||
|
newResetAfter := tn + tick.Nanoseconds()
|
||||||
|
if !c.resetAt.CAS(resetAfter, newResetAfter) {
|
||||||
|
// We raced with another goroutine trying to reset, and it also reset
|
||||||
|
// the counter to 1, so we need to reincrement the counter.
|
||||||
|
return c.counter.Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
type sampler struct {
|
||||||
|
Core
|
||||||
|
|
||||||
|
counts *counters
|
||||||
|
tick time.Duration
|
||||||
|
first, thereafter uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSampler creates a Core that samples incoming entries, which caps the CPU
|
||||||
|
// and I/O load of logging while attempting to preserve a representative subset
|
||||||
|
// of your logs.
|
||||||
|
//
|
||||||
|
// Zap samples by logging the first N entries with a given level and message
|
||||||
|
// each tick. If more Entries with the same level and message are seen during
|
||||||
|
// the same interval, every Mth message is logged and the rest are dropped.
|
||||||
|
//
|
||||||
|
// Keep in mind that zap's sampling implementation is optimized for speed over
|
||||||
|
// absolute precision; under load, each tick may be slightly over- or
|
||||||
|
// under-sampled.
|
||||||
|
func NewSampler(core Core, tick time.Duration, first, thereafter int) Core {
|
||||||
|
return &sampler{
|
||||||
|
Core: core,
|
||||||
|
tick: tick,
|
||||||
|
counts: newCounters(),
|
||||||
|
first: uint64(first),
|
||||||
|
thereafter: uint64(thereafter),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sampler) With(fields []Field) Core {
|
||||||
|
return &sampler{
|
||||||
|
Core: s.Core.With(fields),
|
||||||
|
tick: s.tick,
|
||||||
|
counts: s.counts,
|
||||||
|
first: s.first,
|
||||||
|
thereafter: s.thereafter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sampler) Check(ent Entry, ce *CheckedEntry) *CheckedEntry {
|
||||||
|
if !s.Enabled(ent.Level) {
|
||||||
|
return ce
|
||||||
|
}
|
||||||
|
|
||||||
|
counter := s.counts.get(ent.Level, ent.Message)
|
||||||
|
n := counter.IncCheckReset(ent.Time, s.tick)
|
||||||
|
if n > s.first && (n-s.first)%s.thereafter != 0 {
|
||||||
|
return ce
|
||||||
|
}
|
||||||
|
return s.Core.Check(ent, ce)
|
||||||
|
}
|
||||||
81
vendor/go.uber.org/zap/zapcore/tee.go
generated
vendored
Normal file
81
vendor/go.uber.org/zap/zapcore/tee.go
generated
vendored
Normal 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 zapcore
|
||||||
|
|
||||||
|
import "go.uber.org/multierr"
|
||||||
|
|
||||||
|
type multiCore []Core
|
||||||
|
|
||||||
|
// NewTee creates a Core that duplicates log entries into two or more
|
||||||
|
// underlying Cores.
|
||||||
|
//
|
||||||
|
// Calling it with a single Core returns the input unchanged, and calling
|
||||||
|
// it with no input returns a no-op Core.
|
||||||
|
func NewTee(cores ...Core) Core {
|
||||||
|
switch len(cores) {
|
||||||
|
case 0:
|
||||||
|
return NewNopCore()
|
||||||
|
case 1:
|
||||||
|
return cores[0]
|
||||||
|
default:
|
||||||
|
return multiCore(cores)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc multiCore) With(fields []Field) Core {
|
||||||
|
clone := make(multiCore, len(mc))
|
||||||
|
for i := range mc {
|
||||||
|
clone[i] = mc[i].With(fields)
|
||||||
|
}
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc multiCore) Enabled(lvl Level) bool {
|
||||||
|
for i := range mc {
|
||||||
|
if mc[i].Enabled(lvl) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc multiCore) Check(ent Entry, ce *CheckedEntry) *CheckedEntry {
|
||||||
|
for i := range mc {
|
||||||
|
ce = mc[i].Check(ent, ce)
|
||||||
|
}
|
||||||
|
return ce
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc multiCore) Write(ent Entry, fields []Field) error {
|
||||||
|
var err error
|
||||||
|
for i := range mc {
|
||||||
|
err = multierr.Append(err, mc[i].Write(ent, fields))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc multiCore) Sync() error {
|
||||||
|
var err error
|
||||||
|
for i := range mc {
|
||||||
|
err = multierr.Append(err, mc[i].Sync())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user