commit
9fc66afa51
71
app/services/sales-api/handlers/debug/checkgrp/checkgrp.go
Normal file
71
app/services/sales-api/handlers/debug/checkgrp/checkgrp.go
Normal file
@ -0,0 +1,71 @@
|
||||
package checkgrp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"go.uber.org/zap"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Handlers struct {
|
||||
Build string
|
||||
Log *zap.SugaredLogger
|
||||
}
|
||||
|
||||
func (h Handlers) Readiness(w http.ResponseWriter, r *http.Request) {
|
||||
data := struct {
|
||||
Status string `json:"status"`
|
||||
}{
|
||||
Status: "ok",
|
||||
}
|
||||
statusCode := http.StatusOK
|
||||
if err := response(w, statusCode, data); err != nil {
|
||||
h.Log.Errorw("readiness", "ERROR", err)
|
||||
}
|
||||
h.Log.Infow("readiness", "statusCode", statusCode, "method", r.Method, "path",
|
||||
r.URL.Path, "remoteAddr", r.RemoteAddr)
|
||||
}
|
||||
|
||||
func (h Handlers) Liveliness(w http.ResponseWriter, r *http.Request) {
|
||||
host, err := os.Hostname()
|
||||
if err != nil {
|
||||
host = "unavailable"
|
||||
}
|
||||
data := struct {
|
||||
Status string `json:"status"`
|
||||
Build string `json:"build"`
|
||||
Host string `json:"host"`
|
||||
Pod string `json:"pod"`
|
||||
PodIP string `json:"pod_ip"`
|
||||
Node string `json:"node"`
|
||||
Namespace string `json:"namespace"`
|
||||
}{
|
||||
Status: "up",
|
||||
Build: h.Build,
|
||||
Host: host,
|
||||
Pod: os.Getenv("KUBERNETES_PODNAME"),
|
||||
PodIP: os.Getenv("KUBERNETES_NAMESPACE_POD_IP"),
|
||||
Node: os.Getenv("KUBERNETES_NODENAME"),
|
||||
Namespace: os.Getenv("KUBERNETES_NAMESPACE"),
|
||||
}
|
||||
statusCode := http.StatusOK
|
||||
if err := response(w, statusCode, data); err != nil {
|
||||
h.Log.Errorw("liveness", "ERROR", err)
|
||||
}
|
||||
h.Log.Infow("readiness", "statusCode", statusCode, "method", r.Method, "path",
|
||||
r.URL.Path, "remoteAddr", r.RemoteAddr)
|
||||
}
|
||||
|
||||
func response(w http.ResponseWriter, statusCode int, data interface{}) error {
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Header().Set("Content-type", "application/json")
|
||||
w.WriteHeader(statusCode)
|
||||
|
||||
if _, err := w.Write(jsonData); err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
55
app/services/sales-api/handlers/handlers.go
Normal file
55
app/services/sales-api/handlers/handlers.go
Normal file
@ -0,0 +1,55 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"expvar"
|
||||
"git.hongxiaowei.com/xiaowei/service/app/services/sales-api/handlers/debug/checkgrp"
|
||||
"github.com/dimfeld/httptreemux/v5"
|
||||
"go.uber.org/zap"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"os"
|
||||
)
|
||||
|
||||
func DebugStandardLibaryMux() *http.ServeMux {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
mux.Handle("/debug/vars", expvar.Handler())
|
||||
return mux
|
||||
}
|
||||
|
||||
func DebugMux(build string, log *zap.SugaredLogger) http.Handler {
|
||||
mux := DebugStandardLibaryMux()
|
||||
cgh := checkgrp.Handlers{
|
||||
Build: build,
|
||||
Log: log,
|
||||
}
|
||||
mux.HandleFunc("/debug/readiness", cgh.Readiness)
|
||||
mux.HandleFunc("/debug/liveliness", cgh.Liveliness)
|
||||
return mux
|
||||
}
|
||||
|
||||
type APIMuxConfig struct {
|
||||
Shutdown chan os.Signal
|
||||
Log *zap.SugaredLogger
|
||||
}
|
||||
|
||||
func APIMux(cfg APIMuxConfig) *httptreemux.ContextMux {
|
||||
mux := httptreemux.NewContextMux()
|
||||
|
||||
h := func(w http.ResponseWriter, r *http.Request) {
|
||||
status := struct {
|
||||
Status string
|
||||
}{
|
||||
Status: "ok",
|
||||
}
|
||||
json.NewEncoder(w).Encode(&status)
|
||||
}
|
||||
mux.Handle(http.MethodGet, "/test", h)
|
||||
return mux
|
||||
}
|
@ -1,31 +1,155 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"go.uber.org/automaxprocs/maxprocs"
|
||||
"log"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"git.hongxiaowei.com/xiaowei/service/app/services/sales-api/handlers"
|
||||
|
||||
"github.com/ardanlabs/conf"
|
||||
"go.uber.org/automaxprocs/maxprocs"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var build = "develop"
|
||||
|
||||
func main() {
|
||||
|
||||
// Set the correct number of threads for the service
|
||||
// based on what is available either by the machine or quoras.
|
||||
if _, err := maxprocs.Set(); err != nil {
|
||||
log.Println(err)
|
||||
log, err := initLog("SALES-API")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
g := runtime.GOMAXPROCS(0)
|
||||
log.Printf("starting service build[%s] CPU[%d]", build, g)
|
||||
defer log.Println("service ended")
|
||||
if err := run(log); err != nil {
|
||||
log.Errorw("err", err)
|
||||
}
|
||||
}
|
||||
func run(log *zap.SugaredLogger) error {
|
||||
if _, err := maxprocs.Set(); err != nil {
|
||||
return fmt.Errorf("maxprocs:%w", err)
|
||||
}
|
||||
log.Infow("startup", "GOMAXPROCS", runtime.GOMAXPROCS(0))
|
||||
//configuration
|
||||
cfg := struct {
|
||||
conf.Version
|
||||
Web struct {
|
||||
APIHost string `conf:"default:0.0.0.0:3000"`
|
||||
DebugHost string `conf:"default:0.0.0.0:4000"`
|
||||
ReadTimeout time.Duration `conf:"default:5s"`
|
||||
WriteTimeout time.Duration `conf:"default:10s"`
|
||||
IdleTimeout time.Duration `conf:"default:10s"`
|
||||
ShutDownTimeout time.Duration `conf:"default:10s"`
|
||||
}
|
||||
}{
|
||||
Version: conf.Version{
|
||||
SVN: build,
|
||||
Desc: "copyright information here",
|
||||
},
|
||||
}
|
||||
const prefix = "SALES"
|
||||
help, err := conf.ParseOSArgs(prefix, &cfg)
|
||||
if err != nil {
|
||||
if errors.Is(err, conf.ErrHelpWanted) {
|
||||
fmt.Println(help)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("parsing config:%w", err)
|
||||
}
|
||||
log.Infow("starting service", "version", build)
|
||||
defer log.Infow("shutdown complete")
|
||||
|
||||
out, err := conf.String(&cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infow("startup", "config", out)
|
||||
// =========================================================
|
||||
// Start Debug Service
|
||||
log.Infow("startup", "status", "debug router started", "host", cfg.Web.DebugHost)
|
||||
debugMux := handlers.DebugMux(build, log)
|
||||
go func() {
|
||||
if err := http.ListenAndServe(cfg.Web.DebugHost, debugMux); err != nil {
|
||||
log.Errorw("shutdown", "status",
|
||||
"debug router closed", "host", cfg.Web.DebugHost, "ERROR", err)
|
||||
}
|
||||
}()
|
||||
log.Infow("startup", "status", "initializing API support")
|
||||
|
||||
// Make a channel to listen for an interrupt or terminate signal from ths OS.
|
||||
// Use a buffered channel because the signal package requires it
|
||||
shutdown := make(chan os.Signal, 1)
|
||||
signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-shutdown
|
||||
|
||||
log.Println("stopping service")
|
||||
// Construct the mux for the API calls
|
||||
apiMux := handlers.APIMux(handlers.APIMuxConfig{
|
||||
Shutdown: nil,
|
||||
Log: nil,
|
||||
})
|
||||
|
||||
// Construct a server to service the requests against the mux
|
||||
api := http.Server{
|
||||
Addr: cfg.Web.APIHost,
|
||||
Handler: apiMux,
|
||||
ReadTimeout: cfg.Web.ReadTimeout,
|
||||
WriteTimeout: cfg.Web.WriteTimeout,
|
||||
IdleTimeout: cfg.Web.IdleTimeout,
|
||||
ErrorLog: zap.NewStdLog(log.Desugar()),
|
||||
}
|
||||
|
||||
//Make a channel to listen for errors coming from the listener.Use a
|
||||
// bufferd channel so the goroutine can exit if we don't collect this error
|
||||
serverErrors := make(chan error, 1)
|
||||
|
||||
// Start the service listening for api requests
|
||||
go func() {
|
||||
log.Infow("startup", "status", "api router started", "host", api.Addr)
|
||||
serverErrors <- api.ListenAndServe()
|
||||
}()
|
||||
|
||||
// =====================================================
|
||||
// Shutdown
|
||||
|
||||
// Blocking main and waiting for shutdown
|
||||
select {
|
||||
case err := <-serverErrors:
|
||||
return fmt.Errorf("server err:%w", err)
|
||||
case sig := <-shutdown:
|
||||
log.Infow("shutdown", "status", "shutdown started", "signal", sig)
|
||||
defer log.Infow("shutdown", "status", "shutdown complete", "signal", sig)
|
||||
|
||||
// Give outstanding requests a deadline for completion
|
||||
ctx, cancel := context.WithTimeout(context.Background(), cfg.Web.ShutDownTimeout)
|
||||
defer cancel()
|
||||
|
||||
if err := api.Shutdown(ctx); err != nil {
|
||||
api.Close()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initLog(service string) (*zap.SugaredLogger, error) {
|
||||
config := zap.NewProductionConfig()
|
||||
config.OutputPaths = []string{"stdout"}
|
||||
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
config.DisableStacktrace = true
|
||||
config.InitialFields = map[string]interface{}{
|
||||
"service": service,
|
||||
}
|
||||
|
||||
log, err := config.Build()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return log.Sugar(), err
|
||||
|
||||
}
|
||||
|
1
app/tooling/logfmt/main.go
Normal file
1
app/tooling/logfmt/main.go
Normal file
@ -0,0 +1 @@
|
||||
package logfmt
|
12
go.mod
12
go.mod
@ -2,4 +2,14 @@ module git.hongxiaowei.com/xiaowei/service
|
||||
|
||||
go 1.17
|
||||
|
||||
require go.uber.org/automaxprocs v1.4.0
|
||||
require (
|
||||
github.com/ardanlabs/conf v1.5.0
|
||||
github.com/dimfeld/httptreemux/v5 v5.4.0
|
||||
go.uber.org/automaxprocs v1.4.0
|
||||
go.uber.org/zap v1.20.0
|
||||
)
|
||||
|
||||
require (
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
)
|
||||
|
59
go.sum
59
go.sum
@ -1,16 +1,69 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c=
|
||||
github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dimfeld/httptreemux/v5 v5.4.0 h1:IiHYEjh+A7pYbhWyjmGnj5HZK6gpOOvyBXCJ+BE8/Gs=
|
||||
github.com/dimfeld/httptreemux/v5 v5.4.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
|
||||
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
|
||||
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
go.uber.org/zap v1.20.0 h1:N4oPlghZwYG55MlU6LXk/Zp00FVNE9X9wrYO8CEs4lc=
|
||||
go.uber.org/zap v1.20.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
13
makefile
13
makefile
@ -1,7 +1,7 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
run:
|
||||
go run main.go
|
||||
go run app/services/sales-api/main.go
|
||||
|
||||
build:
|
||||
go build -ldflags "-X main.build=local"
|
||||
@ -9,7 +9,7 @@ build:
|
||||
# =========================================================
|
||||
# Building containers
|
||||
|
||||
VERSION :=1.1
|
||||
VERSION :=1.2
|
||||
|
||||
all: sales-api
|
||||
|
||||
@ -37,9 +37,12 @@ kind-down:
|
||||
kind delete cluster --name $(KIND_CLUSTER)
|
||||
|
||||
kind-status:
|
||||
kubectl get nodes -o wide
|
||||
kubectl get svc -o wide
|
||||
kubectl get pods -o wide
|
||||
kubectl get nodes -o wide -A
|
||||
kubectl get svc -o wide -A
|
||||
kubectl get pods -o wide -A
|
||||
|
||||
kind-status-sales:
|
||||
kubectl get pods -o wide -w
|
||||
|
||||
kind-load:
|
||||
cd zarf/k8s/kind/sales-pod; kustomize edit set image sales-api-image=sales-api-amd64:$(VERSION)
|
||||
|
31
vendor/github.com/ardanlabs/conf/CONTRIBUTORS
generated
vendored
Normal file
31
vendor/github.com/ardanlabs/conf/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
# This is the official list of people who can contribute
|
||||
# (and typically have contributed) code to the gotraining repository.
|
||||
#
|
||||
# Names should be added to this file only after verifying that
|
||||
# the individual or the individual's organization has agreed to
|
||||
# the appropriate Contributor License Agreement, found here:
|
||||
#
|
||||
# http://code.google.com/legal/individual-cla-v1.0.html
|
||||
# http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
#
|
||||
# The agreement for individuals can be filled out on the web.
|
||||
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
#
|
||||
# An entry with two email addresses specifies that the
|
||||
# first address should be used in the submit logs and
|
||||
# that the second address should be recognized as the
|
||||
# same person when interacting with Rietveld.
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Arash Bina <arash@arash.io>
|
||||
Andy Walker
|
||||
Bruno Pereira <brunopereir4@gmail.com>
|
||||
Enrico204 <enrico204@gmail.com>
|
||||
Fábio Correia <fabiodcorreia@gmail.com>
|
||||
Kelsey Hightower
|
||||
Peter Bourgon
|
||||
Steven Edwards <steven@stephenwithav.com>
|
||||
William Kennedy <bill@ardanlabs.com>
|
201
vendor/github.com/ardanlabs/conf/LICENSE
generated
vendored
Normal file
201
vendor/github.com/ardanlabs/conf/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
29
vendor/github.com/ardanlabs/conf/README.md
generated
vendored
Normal file
29
vendor/github.com/ardanlabs/conf/README.md
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
# Conf
|
||||
|
||||
[](https://circleci.com/gh/ardanlabs/conf)
|
||||
|
||||
Copyright 2018, 2019, 2020, 2021, Ardan Labs
|
||||
info@ardanlabs.com
|
||||
|
||||
## Licensing
|
||||
|
||||
```
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
```
|
||||
|
||||
## About The Project
|
||||
|
||||
Package conf provides support for using environmental variables and command
|
||||
line arguments for configuration.
|
||||
|
||||
All of the documentation can be found on the [go.dev](https://pkg.go.dev/github.com/ardanlabs/conf?tab=doc) website.
|
240
vendor/github.com/ardanlabs/conf/conf.go
generated
vendored
Normal file
240
vendor/github.com/ardanlabs/conf/conf.go
generated
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrInvalidStruct indicates that a configuration struct is not the correct type.
|
||||
var ErrInvalidStruct = errors.New("configuration must be a struct pointer")
|
||||
|
||||
// A FieldError occurs when an error occurs updating an individual field
|
||||
// in the provided struct value.
|
||||
type FieldError struct {
|
||||
fieldName string
|
||||
typeName string
|
||||
value string
|
||||
err error
|
||||
}
|
||||
|
||||
func (err *FieldError) Error() string {
|
||||
return fmt.Sprintf("conf: error assigning to field %s: converting '%s' to type %s. details: %s", err.fieldName, err.value, err.typeName, err.err)
|
||||
}
|
||||
|
||||
// Sourcer provides the ability to source data from a configuration source.
|
||||
// Consider the use of lazy-loading for sourcing large datasets or systems.
|
||||
type Sourcer interface {
|
||||
|
||||
// Source takes the field key and attempts to locate that key in its
|
||||
// configuration data. Returns true if found with the value.
|
||||
Source(fld Field) (string, bool)
|
||||
}
|
||||
|
||||
// Version provides the abitily to add version and description to the application.
|
||||
type Version struct {
|
||||
SVN string
|
||||
Desc string
|
||||
}
|
||||
|
||||
// ParseOSArgs parses the configuration allowing command line
|
||||
// arguments to override settings. Function returns ErrHelpWanted
|
||||
// for any information to be provided to the user.
|
||||
func ParseOSArgs(prefix string, cfg interface{}) (string, error) {
|
||||
err := Parse(os.Args[1:], prefix, cfg)
|
||||
if err == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
switch err {
|
||||
case ErrHelpWanted:
|
||||
usage, err := Usage(prefix, cfg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("generating config usage: %w", err)
|
||||
}
|
||||
return usage, ErrHelpWanted
|
||||
|
||||
case ErrVersionWanted:
|
||||
version, err := VersionString(prefix, cfg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("generating config version: %w", err)
|
||||
}
|
||||
return version, ErrHelpWanted
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("parsing config: %w", err)
|
||||
}
|
||||
|
||||
// Parse parses configuration into the provided struct.
|
||||
func Parse(args []string, namespace string, cfgStruct interface{}, sources ...Sourcer) error {
|
||||
|
||||
// Create the flag source.
|
||||
flag, err := newSourceFlag(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Append default sources to any provided list.
|
||||
sources = append(sources, newSourceEnv(namespace))
|
||||
sources = append(sources, flag)
|
||||
|
||||
// Get the list of fields from the configuration struct to process.
|
||||
fields, err := extractFields(nil, cfgStruct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
return errors.New("no fields identified in config struct")
|
||||
}
|
||||
|
||||
// Process all fields found in the config struct provided.
|
||||
for _, field := range fields {
|
||||
|
||||
// If the field is supposed to hold the leftover args then copy them in
|
||||
// from the flags source.
|
||||
if field.Field.Type() == argsT {
|
||||
args := reflect.ValueOf(Args(flag.args))
|
||||
field.Field.Set(args)
|
||||
continue
|
||||
}
|
||||
|
||||
// Set any default value into the struct for this field.
|
||||
if field.Options.DefaultVal != "" {
|
||||
if err := processField(field.Options.DefaultVal, field.Field); err != nil {
|
||||
return &FieldError{
|
||||
fieldName: field.Name,
|
||||
typeName: field.Field.Type().String(),
|
||||
value: field.Options.DefaultVal,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process each field against all sources.
|
||||
var everProvided bool
|
||||
for _, sourcer := range sources {
|
||||
if sourcer == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
value, provided := sourcer.Source(field)
|
||||
if !provided {
|
||||
continue
|
||||
}
|
||||
everProvided = true
|
||||
|
||||
// A value was found so update the struct value with it.
|
||||
if err := processField(value, field.Field); err != nil {
|
||||
return &FieldError{
|
||||
fieldName: field.Name,
|
||||
typeName: field.Field.Type().String(),
|
||||
value: value,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this key is not provided by any source, check if it was
|
||||
// required to be provided.
|
||||
if !everProvided && field.Options.Required {
|
||||
return fmt.Errorf("required field %s is missing value", field.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Usage provides output to display the config usage on the command line.
|
||||
func Usage(namespace string, v interface{}) (string, error) {
|
||||
fields, err := extractFields(nil, v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmtUsage(namespace, fields), nil
|
||||
}
|
||||
|
||||
// VersionString provides output to display the application version and description on the command line.
|
||||
func VersionString(namespace string, v interface{}) (string, error) {
|
||||
fields, err := extractFields(nil, v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var str strings.Builder
|
||||
for i := range fields {
|
||||
if fields[i].Name == versionKey && fields[i].Field.Len() > 0 {
|
||||
str.WriteString("Version: ")
|
||||
str.WriteString(fields[i].Field.String())
|
||||
continue
|
||||
}
|
||||
if fields[i].Name == descKey && fields[i].Field.Len() > 0 {
|
||||
if str.Len() > 0 {
|
||||
str.WriteString("\n")
|
||||
}
|
||||
str.WriteString(fields[i].Field.String())
|
||||
break
|
||||
}
|
||||
}
|
||||
return str.String(), nil
|
||||
}
|
||||
|
||||
// String returns a stringified version of the provided conf-tagged
|
||||
// struct, minus any fields tagged with `noprint`.
|
||||
func String(v interface{}) (string, error) {
|
||||
fields, err := extractFields(nil, v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var s strings.Builder
|
||||
for i, fld := range fields {
|
||||
if fld.Options.Noprint {
|
||||
continue
|
||||
}
|
||||
|
||||
s.WriteString(flagUsage(fld))
|
||||
s.WriteString("=")
|
||||
v := fmt.Sprintf("%v", fld.Field.Interface())
|
||||
|
||||
switch {
|
||||
case fld.Options.Mask:
|
||||
if u, err := url.Parse(v); err == nil {
|
||||
userPass := u.User.String()
|
||||
if userPass != "" {
|
||||
v = strings.Replace(v, userPass, "xxxxxx:xxxxxx", 1)
|
||||
s.WriteString(v)
|
||||
break
|
||||
}
|
||||
}
|
||||
s.WriteString("xxxxxx")
|
||||
|
||||
default:
|
||||
s.WriteString(v)
|
||||
}
|
||||
|
||||
if i < len(fields)-1 {
|
||||
s.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
return s.String(), nil
|
||||
}
|
||||
|
||||
// Args holds command line arguments after flags have been parsed.
|
||||
type Args []string
|
||||
|
||||
// argsT is used by Parse and Usage to detect struct fields of the Args type.
|
||||
var argsT = reflect.TypeOf(Args{})
|
||||
|
||||
// Num returns the i'th argument in the Args slice. It returns an empty string
|
||||
// the request element is not present.
|
||||
func (a Args) Num(i int) string {
|
||||
if i < 0 || i >= len(a) {
|
||||
return ""
|
||||
}
|
||||
return a[i]
|
||||
}
|
128
vendor/github.com/ardanlabs/conf/doc.go
generated
vendored
Normal file
128
vendor/github.com/ardanlabs/conf/doc.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
Package conf provides support for using environmental variables and command
|
||||
line arguments for configuration.
|
||||
|
||||
It is compatible with the GNU extensions to the POSIX recommendations
|
||||
for command-line options. See
|
||||
http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
|
||||
|
||||
There are no hard bindings for this package. This package takes a struct
|
||||
value and parses it for both the environment and flags. It supports several tags
|
||||
to customize the flag options.
|
||||
|
||||
default - Provides the default value for the help
|
||||
env - Allows for overriding the default variable name.
|
||||
flag - Allows for overriding the default flag name.
|
||||
short - Denotes a shorthand option for the flag.
|
||||
noprint - Denotes to not include the field in any display string.
|
||||
mask - Includes the field in any display string but masks out the value.
|
||||
required - Denotes a value must be provided.
|
||||
help - Provides a description for the help.
|
||||
|
||||
The field name and any parent struct name will be used for the long form of
|
||||
the command name unless the name is overridden.
|
||||
|
||||
As an example, this config struct:
|
||||
|
||||
type ip struct {
|
||||
Name string `conf:"default:localhost,env:IP_NAME_VAR"`
|
||||
IP string `conf:"default:127.0.0.0"`
|
||||
}
|
||||
type Embed struct {
|
||||
Name string `conf:"default:bill"`
|
||||
Duration time.Duration `conf:"default:1s,flag:e-dur,short:d"`
|
||||
}
|
||||
type config struct {
|
||||
AnInt int `conf:"default:9"`
|
||||
AString string `conf:"default:B,short:s"`
|
||||
Bool bool
|
||||
Skip string `conf:"-"`
|
||||
IP ip
|
||||
Embed
|
||||
}
|
||||
|
||||
Would produce the following usage output:
|
||||
|
||||
Usage: conf.test [options] [arguments]
|
||||
|
||||
OPTIONS
|
||||
--an-int/$CRUD_AN_INT <int> (default: 9)
|
||||
--a-string/-s/$CRUD_A_STRING <string> (default: B)
|
||||
--bool/$CRUD_BOOL <bool>
|
||||
--ip-name/$CRUD_IP_NAME_VAR <string> (default: localhost)
|
||||
--ip-ip/$CRUD_IP_IP <string> (default: 127.0.0.0)
|
||||
--name/$CRUD_NAME <string> (default: bill)
|
||||
--e-dur/-d/$CRUD_DURATION <duration> (default: 1s)
|
||||
--help/-h
|
||||
display this help message
|
||||
--version/-v
|
||||
display version information
|
||||
|
||||
The API is a single call to Parse
|
||||
|
||||
// Parse(args []string, namespace string, cfgStruct interface{}, sources ...Sourcer) error
|
||||
|
||||
if err := conf.Parse(os.Args, "CRUD", &cfg); err != nil {
|
||||
log.Fatalf("main : Parsing Config : %v", err)
|
||||
}
|
||||
|
||||
Additionally, if the config struct has a field of the slice type conf.Args
|
||||
then it will be populated with any remaining arguments from the command line
|
||||
after flags have been processed.
|
||||
|
||||
For example a program with a config struct like this:
|
||||
|
||||
var cfg struct {
|
||||
Port int
|
||||
Args conf.Args
|
||||
}
|
||||
|
||||
If that program is executed from the command line like this:
|
||||
|
||||
$ my-program --port=9000 serve http
|
||||
|
||||
Then the cfg.Args field will contain the string values ["serve", "http"].
|
||||
The Args type has a method Num for convenient access to these arguments
|
||||
such as this:
|
||||
|
||||
arg0 := cfg.Args.Num(0) // "serve"
|
||||
arg1 := cfg.Args.Num(1) // "http"
|
||||
arg2 := cfg.Args.Num(2) // "" empty string: not enough arguments
|
||||
|
||||
You can add a version with a description by adding the Version type to
|
||||
your config type
|
||||
|
||||
type ConfExplicit struct {
|
||||
Version conf.Version
|
||||
Address string
|
||||
}
|
||||
|
||||
type ConfImplicit struct {
|
||||
conf.Version
|
||||
Address string
|
||||
}
|
||||
|
||||
Then you can set these values at run time for display.
|
||||
|
||||
cfg := struct {
|
||||
Version conf.Version
|
||||
}{
|
||||
Version: conf.Version{
|
||||
SVN: "v1.0.0",
|
||||
Desc: "Service Description",
|
||||
},
|
||||
}
|
||||
|
||||
if err := conf.Parse(os.Args[1:], "APP", &cfg); err != nil {
|
||||
if err == conf.ErrVersionWanted {
|
||||
version, err := conf.VersionString("APP", &cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(version)
|
||||
return nil
|
||||
}
|
||||
fmt.Println("parsing config", err)
|
||||
}
|
||||
*/
|
||||
package conf
|
395
vendor/github.com/ardanlabs/conf/fields.go
generated
vendored
Normal file
395
vendor/github.com/ardanlabs/conf/fields.go
generated
vendored
Normal file
@ -0,0 +1,395 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Field maintains information about a field in the configuration struct.
|
||||
type Field struct {
|
||||
Name string
|
||||
FlagKey []string
|
||||
EnvKey []string
|
||||
Field reflect.Value
|
||||
Options FieldOptions
|
||||
|
||||
// Important for flag parsing or any other source where
|
||||
// booleans might be treated specially.
|
||||
BoolField bool
|
||||
}
|
||||
|
||||
// FieldOptions maintain flag options for a given field.
|
||||
type FieldOptions struct {
|
||||
Help string
|
||||
DefaultVal string
|
||||
EnvName string
|
||||
FlagName string
|
||||
ShortFlagChar rune
|
||||
Noprint bool
|
||||
Required bool
|
||||
Mask bool
|
||||
}
|
||||
|
||||
// extractFields uses reflection to examine the struct and generate the keys.
|
||||
func extractFields(prefix []string, target interface{}) ([]Field, error) {
|
||||
if prefix == nil {
|
||||
prefix = []string{}
|
||||
}
|
||||
s := reflect.ValueOf(target)
|
||||
|
||||
if s.Kind() != reflect.Ptr {
|
||||
return nil, ErrInvalidStruct
|
||||
}
|
||||
s = s.Elem()
|
||||
if s.Kind() != reflect.Struct {
|
||||
return nil, ErrInvalidStruct
|
||||
}
|
||||
targetType := s.Type()
|
||||
|
||||
var fields []Field
|
||||
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
f := s.Field(i)
|
||||
structField := targetType.Field(i)
|
||||
|
||||
// Get the conf tags associated with this item (if any).
|
||||
fieldTags := structField.Tag.Get("conf")
|
||||
|
||||
// If it's ignored or can't be set, move on.
|
||||
if !f.CanSet() || fieldTags == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldName := structField.Name
|
||||
|
||||
// Get and options. TODO: Need more.
|
||||
fieldOpts, err := parseTag(fieldTags)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("conf: error parsing tags for field %s: %s", fieldName, err)
|
||||
}
|
||||
|
||||
// Generate the field key. This could be ignored.
|
||||
fieldKey := append(prefix, camelSplit(fieldName)...)
|
||||
|
||||
// Drill down through pointers until we bottom out at type or nil.
|
||||
for f.Kind() == reflect.Ptr {
|
||||
if f.IsNil() {
|
||||
|
||||
// It's not a struct so leave it alone.
|
||||
if f.Type().Elem().Kind() != reflect.Struct {
|
||||
break
|
||||
}
|
||||
|
||||
// It is a struct so zero it out.
|
||||
f.Set(reflect.New(f.Type().Elem()))
|
||||
}
|
||||
f = f.Elem()
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
// If we've found a struct, drill down, appending fields as we go.
|
||||
case f.Kind() == reflect.Struct:
|
||||
|
||||
// Skip if it can deserialize itself.
|
||||
if setterFrom(f) == nil && textUnmarshaler(f) == nil && binaryUnmarshaler(f) == nil {
|
||||
|
||||
// Prefix for any subkeys is the fieldKey, unless it's
|
||||
// anonymous, then it's just the prefix so far.
|
||||
innerPrefix := fieldKey
|
||||
if structField.Anonymous {
|
||||
innerPrefix = prefix
|
||||
}
|
||||
|
||||
embeddedPtr := f.Addr().Interface()
|
||||
innerFields, err := extractFields(innerPrefix, embeddedPtr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields = append(fields, innerFields...)
|
||||
}
|
||||
default:
|
||||
envKey := fieldKey
|
||||
if fieldOpts.EnvName != "" {
|
||||
envKey = strings.Split(fieldOpts.EnvName, "_")
|
||||
}
|
||||
|
||||
flagKey := fieldKey
|
||||
if fieldOpts.FlagName != "" {
|
||||
flagKey = strings.Split(fieldOpts.FlagName, "-")
|
||||
}
|
||||
|
||||
fld := Field{
|
||||
Name: fieldName,
|
||||
EnvKey: envKey,
|
||||
FlagKey: flagKey,
|
||||
Field: f,
|
||||
Options: fieldOpts,
|
||||
BoolField: f.Kind() == reflect.Bool,
|
||||
}
|
||||
fields = append(fields, fld)
|
||||
}
|
||||
}
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func parseTag(tagStr string) (FieldOptions, error) {
|
||||
var f FieldOptions
|
||||
if tagStr == "" {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
tagParts := strings.Split(tagStr, ",")
|
||||
for _, tagPart := range tagParts {
|
||||
vals := strings.SplitN(tagPart, ":", 2)
|
||||
tagProp := vals[0]
|
||||
|
||||
switch len(vals) {
|
||||
case 1:
|
||||
switch tagProp {
|
||||
case "noprint":
|
||||
f.Noprint = true
|
||||
case "required":
|
||||
f.Required = true
|
||||
case "mask":
|
||||
f.Mask = true
|
||||
}
|
||||
case 2:
|
||||
tagPropVal := strings.TrimSpace(vals[1])
|
||||
if tagPropVal == "" {
|
||||
return f, fmt.Errorf("tag %q missing a value", tagProp)
|
||||
}
|
||||
switch tagProp {
|
||||
case "short":
|
||||
if len([]rune(tagPropVal)) != 1 {
|
||||
return f, fmt.Errorf("short value must be a single rune, got %q", tagPropVal)
|
||||
}
|
||||
f.ShortFlagChar = []rune(tagPropVal)[0]
|
||||
case "default":
|
||||
f.DefaultVal = tagPropVal
|
||||
case "env":
|
||||
f.EnvName = tagPropVal
|
||||
case "flag":
|
||||
f.FlagName = tagPropVal
|
||||
case "help":
|
||||
f.Help = tagPropVal
|
||||
}
|
||||
default:
|
||||
// TODO: Do we check for integrity issues here?
|
||||
}
|
||||
}
|
||||
|
||||
// Perform a sanity check.
|
||||
switch {
|
||||
case f.Required && f.DefaultVal != "":
|
||||
return f, fmt.Errorf("cannot set both `required` and `default`")
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// camelSplit takes a string based on camel case and splits it.
|
||||
func camelSplit(src string) []string {
|
||||
if src == "" {
|
||||
return []string{}
|
||||
}
|
||||
if len(src) < 2 {
|
||||
return []string{src}
|
||||
}
|
||||
|
||||
runes := []rune(src)
|
||||
|
||||
lastClass := charClass(runes[0])
|
||||
lastIdx := 0
|
||||
out := []string{}
|
||||
|
||||
// Split into fields based on class of unicode character.
|
||||
for i, r := range runes {
|
||||
class := charClass(r)
|
||||
|
||||
// If the class has transitioned.
|
||||
if class != lastClass {
|
||||
|
||||
// If going from uppercase to lowercase, we want to retain the last
|
||||
// uppercase letter for names like FOOBar, which should split to
|
||||
// FOO Bar.
|
||||
switch {
|
||||
case lastClass == classUpper && class != classNumber:
|
||||
if i-lastIdx > 1 {
|
||||
out = append(out, string(runes[lastIdx:i-1]))
|
||||
lastIdx = i - 1
|
||||
}
|
||||
default:
|
||||
out = append(out, string(runes[lastIdx:i]))
|
||||
lastIdx = i
|
||||
}
|
||||
}
|
||||
|
||||
if i == len(runes)-1 {
|
||||
out = append(out, string(runes[lastIdx:]))
|
||||
}
|
||||
lastClass = class
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func processField(value string, field reflect.Value) error {
|
||||
typ := field.Type()
|
||||
|
||||
// Look for a Set method.
|
||||
setter := setterFrom(field)
|
||||
if setter != nil {
|
||||
return setter.Set(value)
|
||||
}
|
||||
|
||||
if t := textUnmarshaler(field); t != nil {
|
||||
return t.UnmarshalText([]byte(value))
|
||||
}
|
||||
|
||||
if b := binaryUnmarshaler(field); b != nil {
|
||||
return b.UnmarshalBinary([]byte(value))
|
||||
}
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
if field.IsNil() {
|
||||
field.Set(reflect.New(typ))
|
||||
}
|
||||
field = field.Elem()
|
||||
}
|
||||
|
||||
switch typ.Kind() {
|
||||
case reflect.String:
|
||||
field.SetString(value)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
var (
|
||||
val int64
|
||||
err error
|
||||
)
|
||||
if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" {
|
||||
var d time.Duration
|
||||
d, err = time.ParseDuration(value)
|
||||
val = int64(d)
|
||||
} else {
|
||||
val, err = strconv.ParseInt(value, 0, typ.Bits())
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
field.SetInt(val)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
val, err := strconv.ParseUint(value, 0, typ.Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetUint(val)
|
||||
case reflect.Bool:
|
||||
val, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetBool(val)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
val, err := strconv.ParseFloat(value, typ.Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetFloat(val)
|
||||
case reflect.Slice:
|
||||
vals := strings.Split(value, ";")
|
||||
sl := reflect.MakeSlice(typ, len(vals), len(vals))
|
||||
for i, val := range vals {
|
||||
err := processField(val, sl.Index(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
field.Set(sl)
|
||||
case reflect.Map:
|
||||
mp := reflect.MakeMap(typ)
|
||||
if len(strings.TrimSpace(value)) != 0 {
|
||||
pairs := strings.Split(value, ";")
|
||||
for _, pair := range pairs {
|
||||
kvpair := strings.Split(pair, ":")
|
||||
if len(kvpair) != 2 {
|
||||
return fmt.Errorf("invalid map item: %q", pair)
|
||||
}
|
||||
k := reflect.New(typ.Key()).Elem()
|
||||
err := processField(kvpair[0], k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := reflect.New(typ.Elem()).Elem()
|
||||
err = processField(kvpair[1], v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mp.SetMapIndex(k, v)
|
||||
}
|
||||
}
|
||||
field.Set(mp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func interfaceFrom(field reflect.Value, fn func(interface{}, *bool)) {
|
||||
|
||||
// It may be impossible for a struct field to fail this check.
|
||||
if !field.CanInterface() {
|
||||
return
|
||||
}
|
||||
|
||||
var ok bool
|
||||
fn(field.Interface(), &ok)
|
||||
if !ok && field.CanAddr() {
|
||||
fn(field.Addr().Interface(), &ok)
|
||||
}
|
||||
}
|
||||
|
||||
// Setter is implemented by types can self-deserialize values.
|
||||
// Any type that implements flag.Value also implements Setter.
|
||||
type Setter interface {
|
||||
Set(value string) error
|
||||
}
|
||||
|
||||
func setterFrom(field reflect.Value) (s Setter) {
|
||||
interfaceFrom(field, func(v interface{}, ok *bool) { s, *ok = v.(Setter) })
|
||||
return s
|
||||
}
|
||||
|
||||
func textUnmarshaler(field reflect.Value) (t encoding.TextUnmarshaler) {
|
||||
interfaceFrom(field, func(v interface{}, ok *bool) { t, *ok = v.(encoding.TextUnmarshaler) })
|
||||
return t
|
||||
}
|
||||
|
||||
func binaryUnmarshaler(field reflect.Value) (b encoding.BinaryUnmarshaler) {
|
||||
interfaceFrom(field, func(v interface{}, ok *bool) { b, *ok = v.(encoding.BinaryUnmarshaler) })
|
||||
return b
|
||||
}
|
||||
|
||||
const (
|
||||
classLower int = iota
|
||||
classUpper
|
||||
classNumber
|
||||
classOther
|
||||
)
|
||||
|
||||
func charClass(r rune) int {
|
||||
switch {
|
||||
case unicode.IsLower(r):
|
||||
return classLower
|
||||
case unicode.IsUpper(r):
|
||||
return classUpper
|
||||
case unicode.IsDigit(r):
|
||||
return classNumber
|
||||
}
|
||||
return classOther
|
||||
}
|
205
vendor/github.com/ardanlabs/conf/sources.go
generated
vendored
Normal file
205
vendor/github.com/ardanlabs/conf/sources.go
generated
vendored
Normal file
@ -0,0 +1,205 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// env is a source for environmental variables.
|
||||
type env struct {
|
||||
m map[string]string
|
||||
}
|
||||
|
||||
// newSourceEnv accepts a namespace and parses the environment into a Env for
|
||||
// use by the configuration package.
|
||||
func newSourceEnv(namespace string) *env {
|
||||
m := make(map[string]string)
|
||||
|
||||
// Create the uppercase version to meet the standard {NAMESPACE_} format.
|
||||
// If the namespace is empty, remove the _ from the beginning of the string.
|
||||
uspace := fmt.Sprintf("%s_", strings.ToUpper(namespace))
|
||||
if namespace == "" {
|
||||
uspace = uspace[1:]
|
||||
}
|
||||
|
||||
// Loop and match each variable using the uppercase namespace.
|
||||
for _, val := range os.Environ() {
|
||||
if !strings.HasPrefix(val, uspace) {
|
||||
continue
|
||||
}
|
||||
|
||||
idx := strings.Index(val, "=")
|
||||
m[strings.ToUpper(strings.TrimPrefix(val[0:idx], uspace))] = val[idx+1:]
|
||||
}
|
||||
|
||||
return &env{m: m}
|
||||
}
|
||||
|
||||
// Source implements the confg.Sourcer interface. It returns the stringfied value
|
||||
// stored at the specified key from the environment.
|
||||
func (e *env) Source(fld Field) (string, bool) {
|
||||
k := strings.ToUpper(strings.Join(fld.EnvKey, `_`))
|
||||
v, ok := e.m[k]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// envUsage constructs a usage string for the environment variable.
|
||||
func envUsage(namespace string, fld Field) string {
|
||||
uspace := strings.ToUpper(namespace) + "_" + strings.ToUpper(strings.Join(fld.EnvKey, `_`))
|
||||
if namespace == "" {
|
||||
uspace = uspace[1:]
|
||||
}
|
||||
return "$" + uspace
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// ErrHelpWanted provides an indication help was requested.
|
||||
var ErrHelpWanted = errors.New("help wanted")
|
||||
|
||||
// ErrVersionWanted provides an indication version was requested.
|
||||
var ErrVersionWanted = errors.New("version wanted")
|
||||
|
||||
// flag is a source for command line arguments.
|
||||
type flag struct {
|
||||
m map[string]string
|
||||
args []string
|
||||
}
|
||||
|
||||
// newSourceFlag parsing a string of command line arguments. NewFlag will return
|
||||
// errHelpWanted, if the help flag is identifyed. This code is adapted
|
||||
// from the Go standard library flag package.
|
||||
func newSourceFlag(args []string) (*flag, error) {
|
||||
m := make(map[string]string)
|
||||
|
||||
if len(args) != 0 {
|
||||
for {
|
||||
if len(args) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Look at the next arg.
|
||||
s := args[0]
|
||||
|
||||
// If it's too short or doesn't begin with a `-`, assume we're at
|
||||
// the end of the flags.
|
||||
if len(s) < 2 || s[0] != '-' {
|
||||
break
|
||||
}
|
||||
|
||||
numMinuses := 1
|
||||
if s[1] == '-' {
|
||||
numMinuses++
|
||||
if len(s) == 2 { // "--" terminates the flags
|
||||
args = args[1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
name := s[numMinuses:]
|
||||
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
|
||||
return nil, fmt.Errorf("bad flag syntax: %s", s)
|
||||
}
|
||||
|
||||
// It's a flag. Does it have an argument?
|
||||
args = args[1:]
|
||||
hasValue := false
|
||||
value := ""
|
||||
for i := 1; i < len(name); i++ { // equals cannot be first
|
||||
if name[i] == '=' {
|
||||
value = name[i+1:]
|
||||
hasValue = true
|
||||
name = name[0:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if name == "help" || name == "h" || name == "?" {
|
||||
return nil, ErrHelpWanted
|
||||
}
|
||||
|
||||
if name == "version" || name == "v" {
|
||||
return nil, ErrVersionWanted
|
||||
}
|
||||
|
||||
// If we don't have a value yet, it's possible the flag was not in the
|
||||
// -flag=value format which means it might still have a value which would be
|
||||
// the next argument, provided the next argument isn't a flag.
|
||||
if !hasValue {
|
||||
if len(args) > 0 && len(args[0]) > 0 && args[0][0] != '-' {
|
||||
|
||||
// Doesn't look like a flag. Must be a value.
|
||||
value, args = args[0], args[1:]
|
||||
} else {
|
||||
|
||||
// We assume this is a boolean flag.
|
||||
value = "true"
|
||||
}
|
||||
}
|
||||
|
||||
// Store the flag/value pair.
|
||||
m[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
return &flag{m: m, args: args}, nil
|
||||
}
|
||||
|
||||
// Source implements the confg.Sourcer interface. Returns the stringfied value
|
||||
// stored at the specified key from the flag source.
|
||||
func (f *flag) Source(fld Field) (string, bool) {
|
||||
if fld.Options.ShortFlagChar != 0 {
|
||||
flagKey := fld.Options.ShortFlagChar
|
||||
k := strings.ToLower(string(flagKey))
|
||||
if val, found := f.m[k]; found {
|
||||
return val, found
|
||||
}
|
||||
}
|
||||
|
||||
k := strings.ToLower(strings.Join(fld.FlagKey, `-`))
|
||||
val, found := f.m[k]
|
||||
return val, found
|
||||
}
|
||||
|
||||
// flagUsage constructs a usage string for the flag argument.
|
||||
func flagUsage(fld Field) string {
|
||||
usage := "--" + strings.ToLower(strings.Join(fld.FlagKey, `-`))
|
||||
if fld.Options.ShortFlagChar != 0 {
|
||||
flagKey := []string{string(fld.Options.ShortFlagChar)}
|
||||
usage += "/-" + strings.ToLower(strings.Join(flagKey, `-`))
|
||||
}
|
||||
|
||||
return usage
|
||||
}
|
||||
|
||||
/*
|
||||
Portions Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
184
vendor/github.com/ardanlabs/conf/usage.go
generated
vendored
Normal file
184
vendor/github.com/ardanlabs/conf/usage.go
generated
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
const versionKey = `SVN`
|
||||
const descKey = `Desc`
|
||||
|
||||
func containsField(fields []Field, name string) bool {
|
||||
for i := range fields {
|
||||
if name == fields[i].Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fmtUsage(namespace string, fields []Field) string {
|
||||
var sb strings.Builder
|
||||
|
||||
fields = append(fields, Field{
|
||||
Name: "help",
|
||||
BoolField: true,
|
||||
Field: reflect.ValueOf(true),
|
||||
FlagKey: []string{"help"},
|
||||
Options: FieldOptions{
|
||||
ShortFlagChar: 'h',
|
||||
Help: "display this help message",
|
||||
}})
|
||||
|
||||
if containsField(fields, versionKey) {
|
||||
fields = append(fields, Field{
|
||||
Name: "version",
|
||||
BoolField: true,
|
||||
Field: reflect.ValueOf(true),
|
||||
FlagKey: []string{"version"},
|
||||
Options: FieldOptions{
|
||||
ShortFlagChar: 'v',
|
||||
Help: "display version information",
|
||||
}})
|
||||
}
|
||||
|
||||
_, file := path.Split(os.Args[0])
|
||||
fmt.Fprintf(&sb, "Usage: %s [options] [arguments]\n\n", file)
|
||||
|
||||
fmt.Fprintln(&sb, "OPTIONS")
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(&sb, 0, 4, 2, ' ', tabwriter.TabIndent)
|
||||
|
||||
for _, fld := range fields {
|
||||
|
||||
// Skip printing usage info for fields that just hold arguments.
|
||||
if fld.Field.Type() == argsT {
|
||||
continue
|
||||
}
|
||||
|
||||
// Do not display version fields SVN and Description
|
||||
if fld.Name == versionKey || fld.Name == descKey {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, " %s", flagUsage(fld))
|
||||
|
||||
// Do not display env vars for help since they aren't respected.
|
||||
if fld.Name != "help" && fld.Name != "version" {
|
||||
fmt.Fprintf(w, "/%s", envUsage(namespace, fld))
|
||||
}
|
||||
|
||||
typeName, help := getTypeAndHelp(&fld)
|
||||
|
||||
// Do not display type info for help because it would show <bool> but our
|
||||
// parsing does not really treat --help as a boolean field. Its presence
|
||||
// always indicates true even if they do --help=false.
|
||||
if fld.Name != "help" && fld.Name != "version" {
|
||||
fmt.Fprintf(w, "\t%s", typeName)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "\t%s\n", getOptString(fld))
|
||||
if help != "" {
|
||||
fmt.Fprintf(w, " %s\n", help)
|
||||
}
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// getTypeAndHelp extracts the type and help message for a single field for
|
||||
// printing in the usage message. If the help message contains text in
|
||||
// single quotes ('), this is assumed to be a more specific "type", and will
|
||||
// be returned as such. If there are no back quotes, it attempts to make a
|
||||
// guess as to the type of the field. Boolean flags are not printed with a
|
||||
// type, manually-specified or not, since their presence is equated with a
|
||||
// 'true' value and their absence with a 'false' value. If a type cannot be
|
||||
// determined, it will simply give the name "value". Slices will be annotated
|
||||
// as "<Type>,[Type...]", where "Type" is whatever type name was chosen.
|
||||
// (adapted from package flag).
|
||||
func getTypeAndHelp(fld *Field) (name string, usage string) {
|
||||
|
||||
// Look for a single-quoted name.
|
||||
usage = fld.Options.Help
|
||||
for i := 0; i < len(usage); i++ {
|
||||
if usage[i] == '\'' {
|
||||
for j := i + 1; j < len(usage); j++ {
|
||||
if usage[j] == '\'' {
|
||||
name = usage[i+1 : j]
|
||||
usage = usage[:i] + name + usage[j+1:]
|
||||
}
|
||||
}
|
||||
break // Only one single quote; use type name.
|
||||
}
|
||||
}
|
||||
|
||||
var isSlice bool
|
||||
if fld.Field.IsValid() {
|
||||
t := fld.Field.Type()
|
||||
|
||||
// If it's a pointer, we want to deref.
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
// If it's a slice, we want the type of the slice elements.
|
||||
if t.Kind() == reflect.Slice {
|
||||
t = t.Elem()
|
||||
isSlice = true
|
||||
}
|
||||
|
||||
// If no explicit name was provided, attempt to get the type
|
||||
if name == "" {
|
||||
switch t.Kind() {
|
||||
case reflect.Bool:
|
||||
name = "bool"
|
||||
case reflect.Float32, reflect.Float64:
|
||||
name = "float"
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
typ := fld.Field.Type()
|
||||
if typ.PkgPath() == "time" && typ.Name() == "Duration" {
|
||||
name = "duration"
|
||||
} else {
|
||||
name = "int"
|
||||
}
|
||||
case reflect.String:
|
||||
name = "string"
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
name = "uint"
|
||||
default:
|
||||
name = "value"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case isSlice:
|
||||
name = fmt.Sprintf("<%s>,[%s...]", name, name)
|
||||
case name != "":
|
||||
name = fmt.Sprintf("<%s>", name)
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getOptString(fld Field) string {
|
||||
opts := make([]string, 0, 3)
|
||||
if fld.Options.Required {
|
||||
opts = append(opts, "required")
|
||||
}
|
||||
if fld.Options.Noprint {
|
||||
opts = append(opts, "noprint")
|
||||
}
|
||||
if fld.Options.DefaultVal != "" {
|
||||
opts = append(opts, fmt.Sprintf("default: %s", fld.Options.DefaultVal))
|
||||
}
|
||||
if len(opts) > 0 {
|
||||
return fmt.Sprintf("(%s)", strings.Join(opts, `,`))
|
||||
}
|
||||
return ""
|
||||
}
|
25
vendor/github.com/dimfeld/httptreemux/v5/.gitignore
generated
vendored
Normal file
25
vendor/github.com/dimfeld/httptreemux/v5/.gitignore
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
|
||||
.idea/
|
14
vendor/github.com/dimfeld/httptreemux/v5/.travis.yml
generated
vendored
Normal file
14
vendor/github.com/dimfeld/httptreemux/v5/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
language: go
|
||||
|
||||
gobuild_args: "-v -race"
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
21
vendor/github.com/dimfeld/httptreemux/v5/LICENSE
generated
vendored
Normal file
21
vendor/github.com/dimfeld/httptreemux/v5/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014,2015 Daniel Imfeld
|
||||
|
||||
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.
|
272
vendor/github.com/dimfeld/httptreemux/v5/README.md
generated
vendored
Normal file
272
vendor/github.com/dimfeld/httptreemux/v5/README.md
generated
vendored
Normal file
@ -0,0 +1,272 @@
|
||||
httptreemux [](https://travis-ci.org/dimfeld/httptreemux) [](https://godoc.org/github.com/dimfeld/httptreemux)
|
||||
===========
|
||||
|
||||
High-speed, flexible, tree-based HTTP router for Go.
|
||||
|
||||
This is inspired by [Julien Schmidt's httprouter](https://www.github.com/julienschmidt/httprouter), in that it uses a patricia tree, but the implementation is rather different. Specifically, the routing rules are relaxed so that a single path segment may be a wildcard in one route and a static token in another. This gives a nice combination of high performance with a lot of convenience in designing the routing patterns. In [benchmarks](https://github.com/julienschmidt/go-http-routing-benchmark), httptreemux is close to, but slightly slower than, httprouter.
|
||||
|
||||
Release notes may be found using the [Github releases tab](https://github.com/dimfeld/httptreemux/releases). Version numbers are compatible with the [Semantic Versioning 2.0.0](http://semver.org/) convention, and a new release is made after every change to the code.
|
||||
|
||||
## Installing with Go Modules
|
||||
|
||||
When using Go Modules, import this repository with `import "github.com/dimfeld/httptreemux/v5"` to ensure that you get the right version.
|
||||
|
||||
## Why?
|
||||
There are a lot of good routers out there. But looking at the ones that were really lightweight, I couldn't quite get something that fit with the route patterns I wanted. The code itself is simple enough, so I spent an evening writing this.
|
||||
|
||||
## Handler
|
||||
The handler is a simple function with the prototype `func(w http.ResponseWriter, r *http.Request, params map[string]string)`. The params argument contains the parameters parsed from wildcards and catch-alls in the URL, as described below. This type is aliased as httptreemux.HandlerFunc.
|
||||
|
||||
### Using http.HandlerFunc
|
||||
Due to the inclusion of the [context](https://godoc.org/context) package as of Go 1.7, `httptreemux` now supports handlers of type [http.HandlerFunc](https://godoc.org/net/http#HandlerFunc). There are two ways to enable this support.
|
||||
|
||||
#### Adapting an Existing Router
|
||||
|
||||
The `UsingContext` method will wrap the router or group in a new group at the same path, but adapted for use with `context` and `http.HandlerFunc`.
|
||||
|
||||
```go
|
||||
router := httptreemux.New()
|
||||
|
||||
group := router.NewGroup("/api")
|
||||
group.GET("/v1/:id", func(w http.ResponseWriter, r *http.Request, params map[string]string) {
|
||||
id := params["id"]
|
||||
fmt.Fprintf(w, "GET /api/v1/%s", id)
|
||||
})
|
||||
|
||||
// UsingContext returns a version of the router or group with context support.
|
||||
ctxGroup := group.UsingContext() // sibling to 'group' node in tree
|
||||
ctxGroup.GET("/v2/:id", func(w http.ResponseWriter, r *http.Request) {
|
||||
ctxData := httptreemux.ContextData(r.Context())
|
||||
params := ctxData.Params()
|
||||
id := params["id"]
|
||||
|
||||
// Useful for middleware to see which route was hit without dealing with wildcards
|
||||
routePath := ctxData.Route()
|
||||
|
||||
// Prints GET /api/v2/:id id=...
|
||||
fmt.Fprintf(w, "GET %s id=%s", routePath, id)
|
||||
})
|
||||
|
||||
http.ListenAndServe(":8080", router)
|
||||
```
|
||||
|
||||
#### New Router with Context Support
|
||||
|
||||
The `NewContextMux` function returns a router preconfigured for use with `context` and `http.HandlerFunc`.
|
||||
|
||||
```go
|
||||
router := httptreemux.NewContextMux()
|
||||
|
||||
router.GET("/:page", func(w http.ResponseWriter, r *http.Request) {
|
||||
params := httptreemux.ContextParams(r.Context())
|
||||
fmt.Fprintf(w, "GET /%s", params["page"])
|
||||
})
|
||||
|
||||
group := router.NewGroup("/api")
|
||||
group.GET("/v1/:id", func(w http.ResponseWriter, r *http.Request) {
|
||||
ctxData := httptreemux.ContextData(r.Context())
|
||||
params := ctxData.Params()
|
||||
id := params["id"]
|
||||
|
||||
// Useful for middleware to see which route was hit without dealing with wildcards
|
||||
routePath := ctxData.Route()
|
||||
|
||||
// Prints GET /api/v1/:id id=...
|
||||
fmt.Fprintf(w, "GET %s id=%s", routePath, id)
|
||||
})
|
||||
|
||||
http.ListenAndServe(":8080", router)
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Routing Rules
|
||||
The syntax here is also modeled after httprouter. Each variable in a path may match on one segment only, except for an optional catch-all variable at the end of the URL.
|
||||
|
||||
Some examples of valid URL patterns are:
|
||||
* `/post/all`
|
||||
* `/post/:postid`
|
||||
* `/post/:postid/page/:page`
|
||||
* `/post/:postid/:page`
|
||||
* `/images/*path`
|
||||
* `/favicon.ico`
|
||||
* `/:year/:month/`
|
||||
* `/:year/:month/:post`
|
||||
* `/:page`
|
||||
|
||||
Note that all of the above URL patterns may exist concurrently in the router.
|
||||
|
||||
Path elements starting with `:` indicate a wildcard in the path. A wildcard will only match on a single path segment. That is, the pattern `/post/:postid` will match on `/post/1` or `/post/1/`, but not `/post/1/2`.
|
||||
|
||||
A path element starting with `*` is a catch-all, whose value will be a string containing all text in the URL matched by the wildcards. For example, with a pattern of `/images/*path` and a requested URL `images/abc/def`, path would contain `abc/def`. A catch-all path will not match an empty string, so in this example a separate route would need to be installed if you also want to match `/images/`.
|
||||
|
||||
#### Using : and * in routing patterns
|
||||
|
||||
The characters `:` and `*` can be used at the beginning of a path segment by escaping them with a backslash. A double backslash at the beginning of a segment is interpreted as a single backslash. These escapes are only checked at the very beginning of a path segment; they are not necessary or processed elsewhere in a token.
|
||||
|
||||
```go
|
||||
router.GET("/foo/\\*starToken", handler) // matches /foo/*starToken
|
||||
router.GET("/foo/star*inTheMiddle", handler) // matches /foo/star*inTheMiddle
|
||||
router.GET("/foo/starBackslash\\*", handler) // matches /foo/starBackslash\*
|
||||
router.GET("/foo/\\\\*backslashWithStar") // matches /foo/\*backslashWithStar
|
||||
```
|
||||
|
||||
### Routing Groups
|
||||
Lets you create a new group of routes with a given path prefix. Makes it easier to create clusters of paths like:
|
||||
* `/api/v1/foo`
|
||||
* `/api/v1/bar`
|
||||
|
||||
To use this you do:
|
||||
```go
|
||||
router = httptreemux.New()
|
||||
api := router.NewGroup("/api/v1")
|
||||
api.GET("/foo", fooHandler) // becomes /api/v1/foo
|
||||
api.GET("/bar", barHandler) // becomes /api/v1/bar
|
||||
```
|
||||
|
||||
### Routing Priority
|
||||
The priority rules in the router are simple.
|
||||
|
||||
1. Static path segments take the highest priority. If a segment and its subtree are able to match the URL, that match is returned.
|
||||
2. Wildcards take second priority. For a particular wildcard to match, that wildcard and its subtree must match the URL.
|
||||
3. Finally, a catch-all rule will match when the earlier path segments have matched, and none of the static or wildcard conditions have matched. Catch-all rules must be at the end of a pattern.
|
||||
|
||||
So with the following patterns adapted from [simpleblog](https://www.github.com/dimfeld/simpleblog), we'll see certain matches:
|
||||
```go
|
||||
router = httptreemux.New()
|
||||
router.GET("/:page", pageHandler)
|
||||
router.GET("/:year/:month/:post", postHandler)
|
||||
router.GET("/:year/:month", archiveHandler)
|
||||
router.GET("/images/*path", staticHandler)
|
||||
router.GET("/favicon.ico", staticHandler)
|
||||
```
|
||||
|
||||
#### Example scenarios
|
||||
|
||||
- `/abc` will match `/:page`
|
||||
- `/2014/05` will match `/:year/:month`
|
||||
- `/2014/05/really-great-blog-post` will match `/:year/:month/:post`
|
||||
- `/images/CoolImage.gif` will match `/images/*path`
|
||||
- `/images/2014/05/MayImage.jpg` will also match `/images/*path`, with all the text after `/images` stored in the variable path.
|
||||
- `/favicon.ico` will match `/favicon.ico`
|
||||
|
||||
### Special Method Behavior
|
||||
If TreeMux.HeadCanUseGet is set to true, the router will call the GET handler for a pattern when a HEAD request is processed, if no HEAD handler has been added for that pattern. This behavior is enabled by default.
|
||||
|
||||
Go's http.ServeContent and related functions already handle the HEAD method correctly by sending only the header, so in most cases your handlers will not need any special cases for it.
|
||||
|
||||
By default TreeMux.OptionsHandler is a null handler that doesn't affect your routing. If you set the handler, it will be called on OPTIONS requests to a path already registered by another method. If you set a path specific handler by using `router.OPTIONS`, it will override the global Options Handler for that path.
|
||||
|
||||
### Trailing Slashes
|
||||
The router has special handling for paths with trailing slashes. If a pattern is added to the router with a trailing slash, any matches on that pattern without a trailing slash will be redirected to the version with the slash. If a pattern does not have a trailing slash, matches on that pattern with a trailing slash will be redirected to the version without.
|
||||
|
||||
The trailing slash flag is only stored once for a pattern. That is, if a pattern is added for a method with a trailing slash, all other methods for that pattern will also be considered to have a trailing slash, regardless of whether or not it is specified for those methods too.
|
||||
However this behavior can be turned off by setting TreeMux.RedirectTrailingSlash to false. By default it is set to true.
|
||||
|
||||
One exception to this rule is catch-all patterns. By default, trailing slash redirection is disabled on catch-all patterns, since the structure of the entire URL and the desired patterns can not be predicted. If trailing slash removal is desired on catch-all patterns, set TreeMux.RemoveCatchAllTrailingSlash to true.
|
||||
|
||||
```go
|
||||
router = httptreemux.New()
|
||||
router.GET("/about", pageHandler)
|
||||
router.GET("/posts/", postIndexHandler)
|
||||
router.POST("/posts", postFormHandler)
|
||||
|
||||
GET /about will match normally.
|
||||
GET /about/ will redirect to /about.
|
||||
GET /posts will redirect to /posts/.
|
||||
GET /posts/ will match normally.
|
||||
POST /posts will redirect to /posts/, because the GET method used a trailing slash.
|
||||
```
|
||||
|
||||
### Custom Redirects
|
||||
|
||||
RedirectBehavior sets the behavior when the router redirects the request to the canonical version of the requested URL using RedirectTrailingSlash or RedirectClean. The default behavior is to return a 301 status, redirecting the browser to the version of the URL that matches the given pattern.
|
||||
|
||||
These are the values accepted for RedirectBehavior. You may also add these values to the RedirectMethodBehavior map to define custom per-method redirect behavior.
|
||||
|
||||
* Redirect301 - HTTP 301 Moved Permanently; this is the default.
|
||||
* Redirect307 - HTTP/1.1 Temporary Redirect
|
||||
* Redirect308 - RFC7538 Permanent Redirect
|
||||
* UseHandler - Don't redirect to the canonical path. Just call the handler instead.
|
||||
|
||||
### Case Insensitive Routing
|
||||
|
||||
You can optionally allow case-insensitive routing by setting the _CaseInsensitive_ property on the router to true.
|
||||
This allows you to make all routes case-insensitive. For example:
|
||||
```go
|
||||
router := httptreemux.New()
|
||||
router.CaseInsensitive
|
||||
router.GET("/My-RoUtE", pageHandler)
|
||||
```
|
||||
In this example, performing a GET request to /my-route will match the route and execute the _pageHandler_ functionality.
|
||||
It's important to note that when using case-insensitive routing, the CaseInsensitive property must be set before routes are defined or there may be unexpected side effects.
|
||||
|
||||
#### Rationale/Usage
|
||||
On a POST request, most browsers that receive a 301 will submit a GET request to the redirected URL, meaning that any data will likely be lost. If you want to handle and avoid this behavior, you may use Redirect307, which causes most browsers to resubmit the request using the original method and request body.
|
||||
|
||||
Since 307 is supposed to be a temporary redirect, the new 308 status code has been proposed, which is treated the same, except it indicates correctly that the redirection is permanent. The big caveat here is that the RFC is relatively recent, and older or non-compliant browsers will not handle it. Therefore its use is not recommended unless you really know what you're doing.
|
||||
|
||||
Finally, the UseHandler value will simply call the handler function for the pattern, without redirecting to the canonical version of the URL.
|
||||
|
||||
### RequestURI vs. URL.Path
|
||||
|
||||
#### Escaped Slashes
|
||||
Go automatically processes escaped characters in a URL, converting + to a space and %XX to the corresponding character. This can present issues when the URL contains a %2f, which is unescaped to '/'. This isn't an issue for most applications, but it will prevent the router from correctly matching paths and wildcards.
|
||||
|
||||
For example, the pattern `/post/:post` would not match on `/post/abc%2fdef`, which is unescaped to `/post/abc/def`. The desired behavior is that it matches, and the `post` wildcard is set to `abc/def`.
|
||||
|
||||
Therefore, this router defaults to using the raw URL, stored in the Request.RequestURI variable. Matching wildcards and catch-alls are then unescaped, to give the desired behavior.
|
||||
|
||||
TL;DR: If a requested URL contains a %2f, this router will still do the right thing. Some Go HTTP routers may not due to [Go issue 3659](https://code.google.com/p/go/issues/detail?id=3659).
|
||||
|
||||
#### Escaped Characters
|
||||
|
||||
As mentioned above, characters in the URL are not unescaped when using RequestURI to determine the matched route. If this is a problem for you and you are unable to switch to URL.Path for the above reasons, you may set `router.EscapeAddedRoutes` to `true`. This option will run each added route through the `URL.EscapedPath` function, and add an additional route if the escaped version differs.
|
||||
|
||||
#### http Package Utility Functions
|
||||
|
||||
Although using RequestURI avoids the issue described above, certain utility functions such as `http.StripPrefix` modify URL.Path, and expect that the underlying router is using that field to make its decision. If you are using some of these functions, set the router's `PathSource` member to `URLPath`. This will give up the proper handling of escaped slashes described above, while allowing the router to work properly with these utility functions.
|
||||
|
||||
## Concurrency
|
||||
|
||||
The router contains an `RWMutex` that arbitrates access to the tree. This allows routes to be safely added from multiple goroutines at once.
|
||||
|
||||
No concurrency controls are needed when only reading from the tree, so the default behavior is to not use the `RWMutex` when serving a request. This avoids a theoretical slowdown under high-usage scenarios from competing atomic integer operations inside the `RWMutex`. If your application adds routes to the router after it has begun serving requests, you should avoid potential race conditions by setting `router.SafeAddRoutesWhileRunning` to `true` to use the `RWMutex` when serving requests.
|
||||
|
||||
## Error Handlers
|
||||
|
||||
### NotFoundHandler
|
||||
TreeMux.NotFoundHandler can be set to provide custom 404-error handling. The default implementation is Go's `http.NotFound` function.
|
||||
|
||||
### MethodNotAllowedHandler
|
||||
If a pattern matches, but the pattern does not have an associated handler for the requested method, the router calls the MethodNotAllowedHandler. The default
|
||||
version of this handler just writes the status code `http.StatusMethodNotAllowed` and sets the response header's `Allowed` field appropriately.
|
||||
|
||||
### Panic Handling
|
||||
TreeMux.PanicHandler can be set to provide custom panic handling. The `SimplePanicHandler` just writes the status code `http.StatusInternalServerError`. The function `ShowErrorsPanicHandler`, adapted from [gocraft/web](https://github.com/gocraft/web), will print panic errors to the browser in an easily-readable format.
|
||||
|
||||
## Unexpected Differences from Other Routers
|
||||
|
||||
This router is intentionally light on features in the name of simplicity and
|
||||
performance. When coming from another router that does heavier processing behind
|
||||
the scenes, you may encounter some unexpected behavior. This list is by no means
|
||||
exhaustive, but covers some nonobvious cases that users have encountered.
|
||||
|
||||
### gorilla/pat query string modifications
|
||||
|
||||
When matching on parameters in a route, the `gorilla/pat` router will modify
|
||||
`Request.URL.RawQuery` to make it appear like the parameters were in the
|
||||
query string. `httptreemux` does not do this. See [Issue #26](https://github.com/dimfeld/httptreemux/issues/26) for more details and a
|
||||
code snippet that can perform this transformation for you, should you want it.
|
||||
|
||||
### httprouter and catch-all parameters
|
||||
|
||||
When using `httprouter`, a route with a catch-all parameter (e.g. `/images/*path`) will match on URLs like `/images/` where the catch-all parameter is empty. This router does not match on empty catch-all parameters, but the behavior can be duplicated by adding a route without the catch-all (e.g. `/images/`).
|
||||
|
||||
## Middleware
|
||||
This package provides no middleware. But there are a lot of great options out there and it's pretty easy to write your own. The router provides the `Use` and `UseHandler` functions to ease the creation of middleware chains. (Real documentation of these functions coming soon.)
|
||||
|
||||
# Acknowledgements
|
||||
|
||||
* Inspiration from Julien Schmidt's [httprouter](https://github.com/julienschmidt/httprouter)
|
||||
* Show Errors panic handler from [gocraft/web](https://github.com/gocraft/web)
|
209
vendor/github.com/dimfeld/httptreemux/v5/context.go
generated
vendored
Normal file
209
vendor/github.com/dimfeld/httptreemux/v5/context.go
generated
vendored
Normal file
@ -0,0 +1,209 @@
|
||||
// +build go1.7
|
||||
|
||||
package httptreemux
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ContextGroup is a wrapper around Group, with the purpose of mimicking its API, but with the use of http.HandlerFunc-based handlers.
|
||||
// Instead of passing a parameter map via the handler (i.e. httptreemux.HandlerFunc), the path parameters are accessed via the request
|
||||
// object's context.
|
||||
type ContextGroup struct {
|
||||
group *Group
|
||||
}
|
||||
|
||||
// Use appends a middleware handler to the Group middleware stack.
|
||||
func (cg *ContextGroup) Use(fn MiddlewareFunc) {
|
||||
cg.group.Use(fn)
|
||||
}
|
||||
|
||||
// UseHandler is like Use but accepts http.Handler middleware.
|
||||
func (cg *ContextGroup) UseHandler(middleware func(http.Handler) http.Handler) {
|
||||
cg.group.UseHandler(middleware)
|
||||
}
|
||||
|
||||
// UsingContext wraps the receiver to return a new instance of a ContextGroup.
|
||||
// The returned ContextGroup is a sibling to its wrapped Group, within the parent TreeMux.
|
||||
// The choice of using a *Group as the receiver, as opposed to a function parameter, allows chaining
|
||||
// while method calls between a TreeMux, Group, and ContextGroup. For example:
|
||||
//
|
||||
// tree := httptreemux.New()
|
||||
// group := tree.NewGroup("/api")
|
||||
//
|
||||
// group.GET("/v1", func(w http.ResponseWriter, r *http.Request, params map[string]string) {
|
||||
// w.Write([]byte(`GET /api/v1`))
|
||||
// })
|
||||
//
|
||||
// group.UsingContext().GET("/v2", func(w http.ResponseWriter, r *http.Request) {
|
||||
// w.Write([]byte(`GET /api/v2`))
|
||||
// })
|
||||
//
|
||||
// http.ListenAndServe(":8080", tree)
|
||||
//
|
||||
func (g *Group) UsingContext() *ContextGroup {
|
||||
return &ContextGroup{g}
|
||||
}
|
||||
|
||||
// NewContextGroup adds a child context group to its path.
|
||||
func (cg *ContextGroup) NewContextGroup(path string) *ContextGroup {
|
||||
return &ContextGroup{cg.group.NewGroup(path)}
|
||||
}
|
||||
|
||||
func (cg *ContextGroup) NewGroup(path string) *ContextGroup {
|
||||
return cg.NewContextGroup(path)
|
||||
}
|
||||
|
||||
func (cg *ContextGroup) wrapHandler(path string, handler HandlerFunc) HandlerFunc {
|
||||
if len(cg.group.stack) > 0 {
|
||||
handler = handlerWithMiddlewares(handler, cg.group.stack)
|
||||
}
|
||||
|
||||
//add the context data after adding all middleware
|
||||
fullPath := cg.group.path + path
|
||||
return func(writer http.ResponseWriter, request *http.Request, m map[string]string) {
|
||||
routeData := &contextData{
|
||||
route: fullPath,
|
||||
params: m,
|
||||
}
|
||||
request = request.WithContext(AddRouteDataToContext(request.Context(), routeData))
|
||||
handler(writer, request, m)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle allows handling HTTP requests via an http.HandlerFunc, as opposed to an httptreemux.HandlerFunc.
|
||||
// Any parameters from the request URL are stored in a map[string]string in the request's context.
|
||||
func (cg *ContextGroup) Handle(method, path string, handler http.HandlerFunc) {
|
||||
cg.group.mux.mutex.Lock()
|
||||
defer cg.group.mux.mutex.Unlock()
|
||||
|
||||
wrapped := cg.wrapHandler(path, func(w http.ResponseWriter, r *http.Request, params map[string]string) {
|
||||
handler(w, r)
|
||||
})
|
||||
|
||||
cg.group.addFullStackHandler(method, path, wrapped)
|
||||
}
|
||||
|
||||
// Handler allows handling HTTP requests via an http.Handler interface, as opposed to an httptreemux.HandlerFunc.
|
||||
// Any parameters from the request URL are stored in a map[string]string in the request's context.
|
||||
func (cg *ContextGroup) Handler(method, path string, handler http.Handler) {
|
||||
cg.group.mux.mutex.Lock()
|
||||
defer cg.group.mux.mutex.Unlock()
|
||||
|
||||
wrapped := cg.wrapHandler(path, func(w http.ResponseWriter, r *http.Request, params map[string]string) {
|
||||
handler.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
cg.group.addFullStackHandler(method, path, wrapped)
|
||||
}
|
||||
|
||||
// GET is convenience method for handling GET requests on a context group.
|
||||
func (cg *ContextGroup) GET(path string, handler http.HandlerFunc) {
|
||||
cg.Handle("GET", path, handler)
|
||||
}
|
||||
|
||||
// POST is convenience method for handling POST requests on a context group.
|
||||
func (cg *ContextGroup) POST(path string, handler http.HandlerFunc) {
|
||||
cg.Handle("POST", path, handler)
|
||||
}
|
||||
|
||||
// PUT is convenience method for handling PUT requests on a context group.
|
||||
func (cg *ContextGroup) PUT(path string, handler http.HandlerFunc) {
|
||||
cg.Handle("PUT", path, handler)
|
||||
}
|
||||
|
||||
// DELETE is convenience method for handling DELETE requests on a context group.
|
||||
func (cg *ContextGroup) DELETE(path string, handler http.HandlerFunc) {
|
||||
cg.Handle("DELETE", path, handler)
|
||||
}
|
||||
|
||||
// PATCH is convenience method for handling PATCH requests on a context group.
|
||||
func (cg *ContextGroup) PATCH(path string, handler http.HandlerFunc) {
|
||||
cg.Handle("PATCH", path, handler)
|
||||
}
|
||||
|
||||
// HEAD is convenience method for handling HEAD requests on a context group.
|
||||
func (cg *ContextGroup) HEAD(path string, handler http.HandlerFunc) {
|
||||
cg.Handle("HEAD", path, handler)
|
||||
}
|
||||
|
||||
// OPTIONS is convenience method for handling OPTIONS requests on a context group.
|
||||
func (cg *ContextGroup) OPTIONS(path string, handler http.HandlerFunc) {
|
||||
cg.Handle("OPTIONS", path, handler)
|
||||
}
|
||||
|
||||
type contextData struct {
|
||||
route string
|
||||
params map[string]string
|
||||
}
|
||||
|
||||
func (cd *contextData) Route() string {
|
||||
return cd.route
|
||||
}
|
||||
|
||||
func (cd *contextData) Params() map[string]string {
|
||||
if cd.params != nil {
|
||||
return cd.params
|
||||
}
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
// ContextRouteData is the information associated with the matched path.
|
||||
// Route() returns the matched route, without expanded wildcards.
|
||||
// Params() returns a map of the route's wildcards and their matched values.
|
||||
type ContextRouteData interface {
|
||||
Route() string
|
||||
Params() map[string]string
|
||||
}
|
||||
|
||||
// ContextParams returns a map of the route's wildcards and their matched values.
|
||||
func ContextParams(ctx context.Context) map[string]string {
|
||||
if cd := ContextData(ctx); cd != nil {
|
||||
return cd.Params()
|
||||
}
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
// ContextRoute returns the matched route, without expanded wildcards.
|
||||
func ContextRoute(ctx context.Context) string {
|
||||
if cd := ContextData(ctx); cd != nil {
|
||||
return cd.Route()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ContextData returns the ContextRouteData associated with the matched path
|
||||
func ContextData(ctx context.Context) ContextRouteData {
|
||||
if p, ok := ctx.Value(contextDataKey).(ContextRouteData); ok {
|
||||
return p
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRouteDataToContext can be used for testing handlers, to insert route data into the request's `Context`.
|
||||
func AddRouteDataToContext(ctx context.Context, data ContextRouteData) context.Context {
|
||||
return context.WithValue(ctx, contextDataKey, data)
|
||||
}
|
||||
|
||||
// AddParamsToContext inserts a parameters map into a context using
|
||||
// the package's internal context key.
|
||||
func AddParamsToContext(ctx context.Context, params map[string]string) context.Context {
|
||||
return AddRouteDataToContext(ctx, &contextData{
|
||||
params: params,
|
||||
})
|
||||
}
|
||||
|
||||
// AddRouteToContext inserts a route into a context using
|
||||
// the package's internal context key.
|
||||
func AddRouteToContext(ctx context.Context, route string) context.Context {
|
||||
return AddRouteDataToContext(ctx, &contextData{
|
||||
route: route,
|
||||
})
|
||||
}
|
||||
|
||||
type contextKey int
|
||||
|
||||
// contextDataKey is used to retrieve the path's params map and matched route
|
||||
// from a request's context.
|
||||
const contextDataKey contextKey = 0
|
250
vendor/github.com/dimfeld/httptreemux/v5/group.go
generated
vendored
Normal file
250
vendor/github.com/dimfeld/httptreemux/v5/group.go
generated
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
package httptreemux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MiddlewareFunc func(next HandlerFunc) HandlerFunc
|
||||
|
||||
func handlerWithMiddlewares(handler HandlerFunc, stack []MiddlewareFunc) HandlerFunc {
|
||||
for i := len(stack) - 1; i >= 0; i-- {
|
||||
handler = stack[i](handler)
|
||||
}
|
||||
return handler
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
path string
|
||||
mux *TreeMux
|
||||
stack []MiddlewareFunc
|
||||
}
|
||||
|
||||
// Add a sub-group to this group
|
||||
func (g *Group) NewGroup(path string) *Group {
|
||||
if len(path) < 1 {
|
||||
panic("Group path must not be empty")
|
||||
}
|
||||
|
||||
checkPath(path)
|
||||
path = g.path + path
|
||||
//Don't want trailing slash as all sub-paths start with slash
|
||||
if path[len(path)-1] == '/' {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
return &Group{
|
||||
path: path,
|
||||
mux: g.mux,
|
||||
stack: g.stack[:len(g.stack):len(g.stack)],
|
||||
}
|
||||
}
|
||||
|
||||
// Use appends a middleware handler to the Group middleware stack.
|
||||
func (g *Group) Use(fn MiddlewareFunc) {
|
||||
g.stack = append(g.stack, fn)
|
||||
}
|
||||
|
||||
type handlerWithParams struct {
|
||||
handler HandlerFunc
|
||||
params map[string]string
|
||||
}
|
||||
|
||||
func (h handlerWithParams) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
h.handler(w, r, h.params)
|
||||
}
|
||||
|
||||
// UseHandler is like Use but accepts http.Handler middleware.
|
||||
func (g *Group) UseHandler(middleware func(http.Handler) http.Handler) {
|
||||
g.stack = append(g.stack, func(next HandlerFunc) HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request, params map[string]string) {
|
||||
nextHandler := handlerWithParams{
|
||||
handler: next,
|
||||
params: params,
|
||||
}
|
||||
middleware(nextHandler).ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Path elements starting with : indicate a wildcard in the path. A wildcard will only match on a
|
||||
// single path segment. That is, the pattern `/post/:postid` will match on `/post/1` or `/post/1/`,
|
||||
// but not `/post/1/2`.
|
||||
//
|
||||
// A path element starting with * is a catch-all, whose value will be a string containing all text
|
||||
// in the URL matched by the wildcards. For example, with a pattern of `/images/*path` and a
|
||||
// requested URL `images/abc/def`, path would contain `abc/def`.
|
||||
//
|
||||
// # Routing Rule Priority
|
||||
//
|
||||
// The priority rules in the router are simple.
|
||||
//
|
||||
// 1. Static path segments take the highest priority. If a segment and its subtree are able to match the URL, that match is returned.
|
||||
//
|
||||
// 2. Wildcards take second priority. For a particular wildcard to match, that wildcard and its subtree must match the URL.
|
||||
//
|
||||
// 3. Finally, a catch-all rule will match when the earlier path segments have matched, and none of the static or wildcard conditions have matched. Catch-all rules must be at the end of a pattern.
|
||||
//
|
||||
// So with the following patterns, we'll see certain matches:
|
||||
// router = httptreemux.New()
|
||||
// router.GET("/:page", pageHandler)
|
||||
// router.GET("/:year/:month/:post", postHandler)
|
||||
// router.GET("/:year/:month", archiveHandler)
|
||||
// router.GET("/images/*path", staticHandler)
|
||||
// router.GET("/favicon.ico", staticHandler)
|
||||
//
|
||||
// /abc will match /:page
|
||||
// /2014/05 will match /:year/:month
|
||||
// /2014/05/really-great-blog-post will match /:year/:month/:post
|
||||
// /images/CoolImage.gif will match /images/*path
|
||||
// /images/2014/05/MayImage.jpg will also match /images/*path, with all the text after /images stored in the variable path.
|
||||
// /favicon.ico will match /favicon.ico
|
||||
//
|
||||
// # Trailing Slashes
|
||||
//
|
||||
// The router has special handling for paths with trailing slashes. If a pattern is added to the
|
||||
// router with a trailing slash, any matches on that pattern without a trailing slash will be
|
||||
// redirected to the version with the slash. If a pattern does not have a trailing slash, matches on
|
||||
// that pattern with a trailing slash will be redirected to the version without.
|
||||
//
|
||||
// The trailing slash flag is only stored once for a pattern. That is, if a pattern is added for a
|
||||
// method with a trailing slash, all other methods for that pattern will also be considered to have a
|
||||
// trailing slash, regardless of whether or not it is specified for those methods too.
|
||||
//
|
||||
// This behavior can be turned off by setting TreeMux.RedirectTrailingSlash to false. By
|
||||
// default it is set to true. The specifics of the redirect depend on RedirectBehavior.
|
||||
//
|
||||
// One exception to this rule is catch-all patterns. By default, trailing slash redirection is
|
||||
// disabled on catch-all patterns, since the structure of the entire URL and the desired patterns
|
||||
// can not be predicted. If trailing slash removal is desired on catch-all patterns, set
|
||||
// TreeMux.RemoveCatchAllTrailingSlash to true.
|
||||
//
|
||||
// router = httptreemux.New()
|
||||
// router.GET("/about", pageHandler)
|
||||
// router.GET("/posts/", postIndexHandler)
|
||||
// router.POST("/posts", postFormHandler)
|
||||
//
|
||||
// GET /about will match normally.
|
||||
// GET /about/ will redirect to /about.
|
||||
// GET /posts will redirect to /posts/.
|
||||
// GET /posts/ will match normally.
|
||||
// POST /posts will redirect to /posts/, because the GET method used a trailing slash.
|
||||
func (g *Group) Handle(method string, path string, handler HandlerFunc) {
|
||||
g.mux.mutex.Lock()
|
||||
defer g.mux.mutex.Unlock()
|
||||
|
||||
if len(g.stack) > 0 {
|
||||
handler = handlerWithMiddlewares(handler, g.stack)
|
||||
}
|
||||
|
||||
g.addFullStackHandler(method, path, handler)
|
||||
}
|
||||
|
||||
func (g *Group) addFullStackHandler(method string, path string, handler HandlerFunc) {
|
||||
addSlash := false
|
||||
addOne := func(thePath string) {
|
||||
if g.mux.CaseInsensitive {
|
||||
thePath = strings.ToLower(thePath)
|
||||
}
|
||||
|
||||
node := g.mux.root.addPath(thePath[1:], nil, false)
|
||||
if addSlash {
|
||||
node.addSlash = true
|
||||
}
|
||||
node.setHandler(method, handler, false)
|
||||
|
||||
if g.mux.HeadCanUseGet && method == "GET" && node.leafHandler["HEAD"] == nil {
|
||||
node.setHandler("HEAD", handler, true)
|
||||
}
|
||||
}
|
||||
|
||||
checkPath(path)
|
||||
path = g.path + path
|
||||
if len(path) == 0 {
|
||||
panic("Cannot map an empty path")
|
||||
}
|
||||
|
||||
if len(path) > 1 && path[len(path)-1] == '/' && g.mux.RedirectTrailingSlash {
|
||||
addSlash = true
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
|
||||
if g.mux.EscapeAddedRoutes {
|
||||
u, err := url.ParseRequestURI(path)
|
||||
if err != nil {
|
||||
panic("URL parsing error " + err.Error() + " on url " + path)
|
||||
}
|
||||
escapedPath := unescapeSpecial(u.String())
|
||||
|
||||
if escapedPath != path {
|
||||
addOne(escapedPath)
|
||||
}
|
||||
}
|
||||
|
||||
addOne(path)
|
||||
|
||||
}
|
||||
|
||||
// Syntactic sugar for Handle("GET", path, handler)
|
||||
func (g *Group) GET(path string, handler HandlerFunc) {
|
||||
g.Handle("GET", path, handler)
|
||||
}
|
||||
|
||||
// Syntactic sugar for Handle("POST", path, handler)
|
||||
func (g *Group) POST(path string, handler HandlerFunc) {
|
||||
g.Handle("POST", path, handler)
|
||||
}
|
||||
|
||||
// Syntactic sugar for Handle("PUT", path, handler)
|
||||
func (g *Group) PUT(path string, handler HandlerFunc) {
|
||||
g.Handle("PUT", path, handler)
|
||||
}
|
||||
|
||||
// Syntactic sugar for Handle("DELETE", path, handler)
|
||||
func (g *Group) DELETE(path string, handler HandlerFunc) {
|
||||
g.Handle("DELETE", path, handler)
|
||||
}
|
||||
|
||||
// Syntactic sugar for Handle("PATCH", path, handler)
|
||||
func (g *Group) PATCH(path string, handler HandlerFunc) {
|
||||
g.Handle("PATCH", path, handler)
|
||||
}
|
||||
|
||||
// Syntactic sugar for Handle("HEAD", path, handler)
|
||||
func (g *Group) HEAD(path string, handler HandlerFunc) {
|
||||
g.Handle("HEAD", path, handler)
|
||||
}
|
||||
|
||||
// Syntactic sugar for Handle("OPTIONS", path, handler)
|
||||
func (g *Group) OPTIONS(path string, handler HandlerFunc) {
|
||||
g.Handle("OPTIONS", path, handler)
|
||||
}
|
||||
|
||||
func checkPath(path string) {
|
||||
// All non-empty paths must start with a slash
|
||||
if len(path) > 0 && path[0] != '/' {
|
||||
panic(fmt.Sprintf("Path %s must start with slash", path))
|
||||
}
|
||||
}
|
||||
|
||||
func unescapeSpecial(s string) string {
|
||||
// Look for sequences of \*, *, and \: that were escaped, and undo some of that escaping.
|
||||
|
||||
// Unescape /* since it references a wildcard token.
|
||||
s = strings.Replace(s, "/%2A", "/*", -1)
|
||||
|
||||
// Unescape /\: since it references a literal colon
|
||||
s = strings.Replace(s, "/%5C:", "/\\:", -1)
|
||||
|
||||
// Replace escaped /\\: with /\:
|
||||
s = strings.Replace(s, "/%5C%5C:", "/%5C:", -1)
|
||||
|
||||
// Replace escaped /\* with /*
|
||||
s = strings.Replace(s, "/%5C%2A", "/%2A", -1)
|
||||
|
||||
// Replace escaped /\\* with /\*
|
||||
s = strings.Replace(s, "/%5C%5C%2A", "/%5C%2A", -1)
|
||||
|
||||
return s
|
||||
}
|
211
vendor/github.com/dimfeld/httptreemux/v5/panichandler.go
generated
vendored
Normal file
211
vendor/github.com/dimfeld/httptreemux/v5/panichandler.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
package httptreemux
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SimplePanicHandler just returns error 500.
|
||||
func SimplePanicHandler(w http.ResponseWriter, r *http.Request, err interface{}) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// ShowErrorsPanicHandler prints a nice representation of an error to the browser.
|
||||
// This was taken from github.com/gocraft/web, which adapted it from the Traffic project.
|
||||
func ShowErrorsPanicHandler(w http.ResponseWriter, r *http.Request, err interface{}) {
|
||||
const size = 4096
|
||||
stack := make([]byte, size)
|
||||
stack = stack[:runtime.Stack(stack, false)]
|
||||
renderPrettyError(w, r, err, stack)
|
||||
}
|
||||
|
||||
func makeErrorData(r *http.Request, err interface{}, stack []byte, filePath string, line int) map[string]interface{} {
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Stack": string(stack),
|
||||
"Params": r.URL.Query(),
|
||||
"Method": r.Method,
|
||||
"FilePath": filePath,
|
||||
"Line": line,
|
||||
"Lines": readErrorFileLines(filePath, line),
|
||||
}
|
||||
|
||||
if e, ok := err.(error); ok {
|
||||
data["Error"] = e.Error()
|
||||
} else {
|
||||
data["Error"] = err
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func renderPrettyError(rw http.ResponseWriter, req *http.Request, err interface{}, stack []byte) {
|
||||
_, filePath, line, _ := runtime.Caller(5)
|
||||
|
||||
data := makeErrorData(req, err, stack, filePath, line)
|
||||
rw.Header().Set("Content-Type", "text/html")
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
tpl := template.Must(template.New("ErrorPage").Parse(panicPageTpl))
|
||||
tpl.Execute(rw, data)
|
||||
}
|
||||
|
||||
func ShowErrorsJsonPanicHandler(w http.ResponseWriter, r *http.Request, err interface{}) {
|
||||
const size = 4096
|
||||
stack := make([]byte, size)
|
||||
stack = stack[:runtime.Stack(stack, false)]
|
||||
|
||||
_, filePath, line, _ := runtime.Caller(4)
|
||||
data := makeErrorData(r, err, stack, filePath, line)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
json.NewEncoder(w).Encode(data)
|
||||
}
|
||||
|
||||
func readErrorFileLines(filePath string, errorLine int) map[int]string {
|
||||
lines := make(map[int]string)
|
||||
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return lines
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
reader := bufio.NewReader(file)
|
||||
currentLine := 0
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil || currentLine > errorLine+5 {
|
||||
break
|
||||
}
|
||||
|
||||
currentLine++
|
||||
|
||||
if currentLine >= errorLine-5 {
|
||||
lines[currentLine] = strings.Replace(line, "\n", "", -1)
|
||||
}
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
const panicPageTpl string = `
|
||||
<html>
|
||||
<head>
|
||||
<title>Panic</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style>
|
||||
html, body{ padding: 0; margin: 0; }
|
||||
header { background: #C52F24; color: white; border-bottom: 2px solid #9C0606; }
|
||||
h1 { padding: 10px 0; margin: 0; }
|
||||
.container { margin: 0 20px; }
|
||||
.error { font-size: 18px; background: #FFCCCC; color: #9C0606; padding: 10px 0; }
|
||||
.file-info .file-name { font-weight: bold; }
|
||||
.stack { height: 300px; overflow-y: scroll; border: 1px solid #e5e5e5; padding: 10px; }
|
||||
|
||||
table.source {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
table.source td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table.source .numbers {
|
||||
font-size: 14px;
|
||||
vertical-align: top;
|
||||
width: 1%;
|
||||
color: rgba(0,0,0,0.3);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
table.source .numbers .number {
|
||||
display: block;
|
||||
padding: 0 5px;
|
||||
border-right: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
table.source .numbers .number.line-{{ .Line }} {
|
||||
border-right: 1px solid #ffcccc;
|
||||
}
|
||||
|
||||
table.source .numbers pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
table.source .code {
|
||||
font-size: 14px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.source .code .line {
|
||||
padding-left: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
table.source .numbers .number,
|
||||
table.source .code .line {
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
table.source .code .line:hover {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
table.source .line-{{ .Line }},
|
||||
table.source line-{{ .Line }},
|
||||
table.source .code .line.line-{{ .Line }}:hover {
|
||||
background: #ffcccc;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="container">
|
||||
<h1>Error</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="error">
|
||||
<p class="container">{{ .Error }}</p>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<p class="file-info">
|
||||
In <span class="file-name">{{ .FilePath }}:{{ .Line }}</span></p>
|
||||
</p>
|
||||
|
||||
<table class="source">
|
||||
<tr>
|
||||
<td class="numbers">
|
||||
<pre>{{ range $lineNumber, $line := .Lines }}<span class="number line-{{ $lineNumber }}">{{ $lineNumber }}</span>{{ end }}</pre>
|
||||
</td>
|
||||
<td class="code">
|
||||
<pre>{{ range $lineNumber, $line := .Lines }}<span class="line line-{{ $lineNumber }}">{{ $line }}<br /></span>{{ end }}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>Stack</h2>
|
||||
<pre class="stack">{{ .Stack }}</pre>
|
||||
<h2>Request</h2>
|
||||
<p><strong>Method:</strong> {{ .Method }}</p>
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
{{ range $key, $value := .Params }}
|
||||
<li><strong>{{ $key }}:</strong> {{ $value }}</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
127
vendor/github.com/dimfeld/httptreemux/v5/path.go
generated
vendored
Normal file
127
vendor/github.com/dimfeld/httptreemux/v5/path.go
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright 2013 Julien Schmidt. All rights reserved.
|
||||
// Based on the path package, Copyright 2009 The Go Authors.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
package httptreemux
|
||||
|
||||
// Clean is the URL version of path.Clean, it returns a canonical URL path
|
||||
// for p, eliminating . and .. elements.
|
||||
//
|
||||
// The following rules are applied iteratively until no further processing can
|
||||
// be done:
|
||||
// 1. Replace multiple slashes with a single slash.
|
||||
// 2. Eliminate each . path name element (the current directory).
|
||||
// 3. Eliminate each inner .. path name element (the parent directory)
|
||||
// along with the non-.. element that precedes it.
|
||||
// 4. Eliminate .. elements that begin a rooted path:
|
||||
// that is, replace "/.." by "/" at the beginning of a path.
|
||||
//
|
||||
// If the result of this process is an empty string, "/" is returned
|
||||
func Clean(p string) string {
|
||||
if p == "" {
|
||||
return "/"
|
||||
}
|
||||
|
||||
n := len(p)
|
||||
var buf []byte
|
||||
|
||||
// Invariants:
|
||||
// reading from path; r is index of next byte to process.
|
||||
// writing to buf; w is index of next byte to write.
|
||||
|
||||
// path must start with '/'
|
||||
r := 1
|
||||
w := 1
|
||||
|
||||
if p[0] != '/' {
|
||||
r = 0
|
||||
buf = make([]byte, n+1)
|
||||
buf[0] = '/'
|
||||
}
|
||||
|
||||
trailing := n > 2 && p[n-1] == '/'
|
||||
|
||||
// A bit more clunky without a 'lazybuf' like the path package, but the loop
|
||||
// gets completely inlined (bufApp). So in contrast to the path package this
|
||||
// loop has no expensive function calls (except 1x make)
|
||||
|
||||
for r < n {
|
||||
switch {
|
||||
case p[r] == '/':
|
||||
// empty path element, trailing slash is added after the end
|
||||
r++
|
||||
|
||||
case p[r] == '.' && r+1 == n:
|
||||
trailing = true
|
||||
r++
|
||||
|
||||
case p[r] == '.' && p[r+1] == '/':
|
||||
// . element
|
||||
r++
|
||||
|
||||
case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'):
|
||||
// .. element: remove to last /
|
||||
r += 2
|
||||
|
||||
if w > 1 {
|
||||
// can backtrack
|
||||
w--
|
||||
|
||||
if buf == nil {
|
||||
for w > 1 && p[w] != '/' {
|
||||
w--
|
||||
}
|
||||
} else {
|
||||
for w > 1 && buf[w] != '/' {
|
||||
w--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// real path element.
|
||||
// add slash if needed
|
||||
if w > 1 {
|
||||
bufApp(&buf, p, w, '/')
|
||||
w++
|
||||
}
|
||||
|
||||
// copy element
|
||||
for r < n && p[r] != '/' {
|
||||
bufApp(&buf, p, w, p[r])
|
||||
w++
|
||||
r++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// re-append trailing slash
|
||||
if trailing && w > 1 {
|
||||
bufApp(&buf, p, w, '/')
|
||||
w++
|
||||
}
|
||||
|
||||
// Turn empty string into "/"
|
||||
if w == 0 {
|
||||
return "/"
|
||||
}
|
||||
|
||||
if buf == nil {
|
||||
return p[:w]
|
||||
}
|
||||
return string(buf[:w])
|
||||
}
|
||||
|
||||
// internal helper to lazily create a buffer if necessary
|
||||
func bufApp(buf *[]byte, s string, w int, c byte) {
|
||||
if *buf == nil {
|
||||
if s[w] == c {
|
||||
return
|
||||
}
|
||||
|
||||
*buf = make([]byte, len(s))
|
||||
copy(*buf, s[:w])
|
||||
}
|
||||
(*buf)[w] = c
|
||||
}
|
305
vendor/github.com/dimfeld/httptreemux/v5/router.go
generated
vendored
Normal file
305
vendor/github.com/dimfeld/httptreemux/v5/router.go
generated
vendored
Normal file
@ -0,0 +1,305 @@
|
||||
// This is inspired by Julien Schmidt's httprouter, in that it uses a patricia tree, but the
|
||||
// implementation is rather different. Specifically, the routing rules are relaxed so that a
|
||||
// single path segment may be a wildcard in one route and a static token in another. This gives a
|
||||
// nice combination of high performance with a lot of convenience in designing the routing patterns.
|
||||
package httptreemux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The params argument contains the parameters parsed from wildcards and catch-alls in the URL.
|
||||
type HandlerFunc func(http.ResponseWriter, *http.Request, map[string]string)
|
||||
type PanicHandler func(http.ResponseWriter, *http.Request, interface{})
|
||||
|
||||
// RedirectBehavior sets the behavior when the router redirects the request to the
|
||||
// canonical version of the requested URL using RedirectTrailingSlash or RedirectClean.
|
||||
// The default behavior is to return a 301 status, redirecting the browser to the version
|
||||
// of the URL that matches the given pattern.
|
||||
//
|
||||
// On a POST request, most browsers that receive a 301 will submit a GET request to
|
||||
// the redirected URL, meaning that any data will likely be lost. If you want to handle
|
||||
// and avoid this behavior, you may use Redirect307, which causes most browsers to
|
||||
// resubmit the request using the original method and request body.
|
||||
//
|
||||
// Since 307 is supposed to be a temporary redirect, the new 308 status code has been
|
||||
// proposed, which is treated the same, except it indicates correctly that the redirection
|
||||
// is permanent. The big caveat here is that the RFC is relatively recent, and older
|
||||
// browsers will not know what to do with it. Therefore its use is not recommended
|
||||
// unless you really know what you're doing.
|
||||
//
|
||||
// Finally, the UseHandler value will simply call the handler function for the pattern.
|
||||
type RedirectBehavior int
|
||||
|
||||
type PathSource int
|
||||
|
||||
const (
|
||||
Redirect301 RedirectBehavior = iota // Return 301 Moved Permanently
|
||||
Redirect307 // Return 307 HTTP/1.1 Temporary Redirect
|
||||
Redirect308 // Return a 308 RFC7538 Permanent Redirect
|
||||
UseHandler // Just call the handler function
|
||||
|
||||
RequestURI PathSource = iota // Use r.RequestURI
|
||||
URLPath // Use r.URL.Path
|
||||
)
|
||||
|
||||
// LookupResult contains information about a route lookup, which is returned from Lookup and
|
||||
// can be passed to ServeLookupResult if the request should be served.
|
||||
type LookupResult struct {
|
||||
// StatusCode informs the caller about the result of the lookup.
|
||||
// This will generally be `http.StatusNotFound` or `http.StatusMethodNotAllowed` for an
|
||||
// error case. On a normal success, the statusCode will be `http.StatusOK`. A redirect code
|
||||
// will also be used in the case
|
||||
StatusCode int
|
||||
handler HandlerFunc
|
||||
params map[string]string
|
||||
leafHandler map[string]HandlerFunc // Only has a value when StatusCode is MethodNotAllowed.
|
||||
}
|
||||
|
||||
// Dump returns a text representation of the routing tree.
|
||||
func (t *TreeMux) Dump() string {
|
||||
return t.root.dumpTree("", "")
|
||||
}
|
||||
|
||||
func (t *TreeMux) serveHTTPPanic(w http.ResponseWriter, r *http.Request) {
|
||||
if err := recover(); err != nil {
|
||||
t.PanicHandler(w, r, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TreeMux) redirectStatusCode(method string) (int, bool) {
|
||||
var behavior RedirectBehavior
|
||||
var ok bool
|
||||
if behavior, ok = t.RedirectMethodBehavior[method]; !ok {
|
||||
behavior = t.RedirectBehavior
|
||||
}
|
||||
switch behavior {
|
||||
case Redirect301:
|
||||
return http.StatusMovedPermanently, true
|
||||
case Redirect307:
|
||||
return http.StatusTemporaryRedirect, true
|
||||
case Redirect308:
|
||||
// Go doesn't have a constant for this yet. Yet another sign
|
||||
// that you probably shouldn't use it.
|
||||
return 308, true
|
||||
case UseHandler:
|
||||
return 0, false
|
||||
default:
|
||||
return http.StatusMovedPermanently, true
|
||||
}
|
||||
}
|
||||
|
||||
func redirectHandler(newPath string, statusCode int) HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request, params map[string]string) {
|
||||
redirect(w, r, newPath, statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func redirect(w http.ResponseWriter, r *http.Request, newPath string, statusCode int) {
|
||||
newURL := url.URL{
|
||||
Path: newPath,
|
||||
RawQuery: r.URL.RawQuery,
|
||||
Fragment: r.URL.Fragment,
|
||||
}
|
||||
http.Redirect(w, r, newURL.String(), statusCode)
|
||||
}
|
||||
|
||||
func (t *TreeMux) lookup(w http.ResponseWriter, r *http.Request) (result LookupResult, found bool) {
|
||||
result.StatusCode = http.StatusNotFound
|
||||
path := r.RequestURI
|
||||
unescapedPath := r.URL.Path
|
||||
pathLen := len(path)
|
||||
if pathLen > 0 && t.PathSource == RequestURI {
|
||||
rawQueryLen := len(r.URL.RawQuery)
|
||||
|
||||
if rawQueryLen != 0 || path[pathLen-1] == '?' {
|
||||
// Remove any query string and the ?.
|
||||
path = path[:pathLen-rawQueryLen-1]
|
||||
pathLen = len(path)
|
||||
}
|
||||
} else {
|
||||
// In testing with http.NewRequest,
|
||||
// RequestURI is not set so just grab URL.Path instead.
|
||||
path = r.URL.Path
|
||||
pathLen = len(path)
|
||||
}
|
||||
if t.CaseInsensitive {
|
||||
path = strings.ToLower(path)
|
||||
unescapedPath = strings.ToLower(unescapedPath)
|
||||
}
|
||||
|
||||
trailingSlash := path[pathLen-1] == '/' && pathLen > 1
|
||||
if trailingSlash && t.RedirectTrailingSlash {
|
||||
path = path[:pathLen-1]
|
||||
unescapedPath = unescapedPath[:len(unescapedPath)-1]
|
||||
}
|
||||
|
||||
n, handler, params := t.root.search(r.Method, path[1:])
|
||||
if n == nil {
|
||||
if t.RedirectCleanPath {
|
||||
// Path was not found. Try cleaning it up and search again.
|
||||
// TODO Test this
|
||||
cleanPath := Clean(unescapedPath)
|
||||
n, handler, params = t.root.search(r.Method, cleanPath[1:])
|
||||
if n == nil {
|
||||
// Still nothing found.
|
||||
return
|
||||
}
|
||||
if statusCode, ok := t.redirectStatusCode(r.Method); ok {
|
||||
// Redirect to the actual path
|
||||
return LookupResult{statusCode, redirectHandler(cleanPath, statusCode), nil, nil}, true
|
||||
}
|
||||
} else {
|
||||
// Not found.
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if handler == nil {
|
||||
if r.Method == "OPTIONS" && t.OptionsHandler != nil {
|
||||
handler = t.OptionsHandler
|
||||
}
|
||||
|
||||
if handler == nil {
|
||||
result.leafHandler = n.leafHandler
|
||||
result.StatusCode = http.StatusMethodNotAllowed
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !n.isCatchAll || t.RemoveCatchAllTrailingSlash {
|
||||
if trailingSlash != n.addSlash && t.RedirectTrailingSlash {
|
||||
if statusCode, ok := t.redirectStatusCode(r.Method); ok {
|
||||
var h HandlerFunc
|
||||
if n.addSlash {
|
||||
// Need to add a slash.
|
||||
h = redirectHandler(unescapedPath+"/", statusCode)
|
||||
} else if path != "/" {
|
||||
// We need to remove the slash. This was already done at the
|
||||
// beginning of the function.
|
||||
h = redirectHandler(unescapedPath, statusCode)
|
||||
}
|
||||
|
||||
if h != nil {
|
||||
return LookupResult{statusCode, h, nil, nil}, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var paramMap map[string]string
|
||||
if len(params) != 0 {
|
||||
if len(params) != len(n.leafWildcardNames) {
|
||||
// Need better behavior here. Should this be a panic?
|
||||
panic(fmt.Sprintf("httptreemux parameter list length mismatch: %v, %v",
|
||||
params, n.leafWildcardNames))
|
||||
}
|
||||
|
||||
paramMap = make(map[string]string)
|
||||
numParams := len(params)
|
||||
for index := 0; index < numParams; index++ {
|
||||
paramMap[n.leafWildcardNames[numParams-index-1]] = params[index]
|
||||
}
|
||||
}
|
||||
|
||||
return LookupResult{http.StatusOK, handler, paramMap, nil}, true
|
||||
}
|
||||
|
||||
// Lookup performs a lookup without actually serving the request or mutating the request or response.
|
||||
// The return values are a LookupResult and a boolean. The boolean will be true when a handler
|
||||
// was found or the lookup resulted in a redirect which will point to a real handler. It is false
|
||||
// for requests which would result in a `StatusNotFound` or `StatusMethodNotAllowed`.
|
||||
//
|
||||
// Regardless of the returned boolean's value, the LookupResult may be passed to ServeLookupResult
|
||||
// to be served appropriately.
|
||||
func (t *TreeMux) Lookup(w http.ResponseWriter, r *http.Request) (LookupResult, bool) {
|
||||
if t.SafeAddRoutesWhileRunning {
|
||||
// In concurrency safe mode, we acquire a read lock on the mutex for any access.
|
||||
// This is optional to avoid potential performance loss in high-usage scenarios.
|
||||
t.mutex.RLock()
|
||||
}
|
||||
|
||||
result, found := t.lookup(w, r)
|
||||
|
||||
if t.SafeAddRoutesWhileRunning {
|
||||
t.mutex.RUnlock()
|
||||
}
|
||||
|
||||
return result, found
|
||||
}
|
||||
|
||||
// ServeLookupResult serves a request, given a lookup result from the Lookup function.
|
||||
func (t *TreeMux) ServeLookupResult(w http.ResponseWriter, r *http.Request, lr LookupResult) {
|
||||
if lr.handler == nil {
|
||||
if lr.StatusCode == http.StatusMethodNotAllowed && lr.leafHandler != nil {
|
||||
if t.SafeAddRoutesWhileRunning {
|
||||
t.mutex.RLock()
|
||||
}
|
||||
|
||||
t.MethodNotAllowedHandler(w, r, lr.leafHandler)
|
||||
|
||||
if t.SafeAddRoutesWhileRunning {
|
||||
t.mutex.RUnlock()
|
||||
}
|
||||
} else {
|
||||
t.NotFoundHandler(w, r)
|
||||
}
|
||||
} else {
|
||||
r = t.setDefaultRequestContext(r)
|
||||
lr.handler(w, r, lr.params)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TreeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if t.PanicHandler != nil {
|
||||
defer t.serveHTTPPanic(w, r)
|
||||
}
|
||||
|
||||
if t.SafeAddRoutesWhileRunning {
|
||||
// In concurrency safe mode, we acquire a read lock on the mutex for any access.
|
||||
// This is optional to avoid potential performance loss in high-usage scenarios.
|
||||
t.mutex.RLock()
|
||||
}
|
||||
|
||||
result, _ := t.lookup(w, r)
|
||||
|
||||
if t.SafeAddRoutesWhileRunning {
|
||||
t.mutex.RUnlock()
|
||||
}
|
||||
|
||||
t.ServeLookupResult(w, r, result)
|
||||
}
|
||||
|
||||
// MethodNotAllowedHandler is the default handler for TreeMux.MethodNotAllowedHandler,
|
||||
// which is called for patterns that match, but do not have a handler installed for the
|
||||
// requested method. It simply writes the status code http.StatusMethodNotAllowed and fills
|
||||
// in the `Allow` header value appropriately.
|
||||
func MethodNotAllowedHandler(w http.ResponseWriter, r *http.Request,
|
||||
methods map[string]HandlerFunc) {
|
||||
|
||||
for m := range methods {
|
||||
w.Header().Add("Allow", m)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
||||
func New() *TreeMux {
|
||||
tm := &TreeMux{
|
||||
root: &node{path: "/"},
|
||||
NotFoundHandler: http.NotFound,
|
||||
MethodNotAllowedHandler: MethodNotAllowedHandler,
|
||||
HeadCanUseGet: true,
|
||||
RedirectTrailingSlash: true,
|
||||
RedirectCleanPath: true,
|
||||
RedirectBehavior: Redirect301,
|
||||
RedirectMethodBehavior: make(map[string]RedirectBehavior),
|
||||
PathSource: RequestURI,
|
||||
EscapeAddedRoutes: false,
|
||||
}
|
||||
tm.Group.mux = tm
|
||||
return tm
|
||||
}
|
340
vendor/github.com/dimfeld/httptreemux/v5/tree.go
generated
vendored
Normal file
340
vendor/github.com/dimfeld/httptreemux/v5/tree.go
generated
vendored
Normal file
@ -0,0 +1,340 @@
|
||||
package httptreemux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
path string
|
||||
|
||||
priority int
|
||||
|
||||
// The list of static children to check.
|
||||
staticIndices []byte
|
||||
staticChild []*node
|
||||
|
||||
// If none of the above match, check the wildcard children
|
||||
wildcardChild *node
|
||||
|
||||
// If none of the above match, then we use the catch-all, if applicable.
|
||||
catchAllChild *node
|
||||
|
||||
// Data for the node is below.
|
||||
|
||||
addSlash bool
|
||||
isCatchAll bool
|
||||
// If true, the head handler was set implicitly, so let it also be set explicitly.
|
||||
implicitHead bool
|
||||
// If this node is the end of the URL, then call the handler, if applicable.
|
||||
leafHandler map[string]HandlerFunc
|
||||
|
||||
// The names of the parameters to apply.
|
||||
leafWildcardNames []string
|
||||
}
|
||||
|
||||
func (n *node) sortStaticChild(i int) {
|
||||
for i > 0 && n.staticChild[i].priority > n.staticChild[i-1].priority {
|
||||
n.staticChild[i], n.staticChild[i-1] = n.staticChild[i-1], n.staticChild[i]
|
||||
n.staticIndices[i], n.staticIndices[i-1] = n.staticIndices[i-1], n.staticIndices[i]
|
||||
i -= 1
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) setHandler(verb string, handler HandlerFunc, implicitHead bool) {
|
||||
if n.leafHandler == nil {
|
||||
n.leafHandler = make(map[string]HandlerFunc)
|
||||
}
|
||||
_, ok := n.leafHandler[verb]
|
||||
if ok && (verb != "HEAD" || !n.implicitHead) {
|
||||
panic(fmt.Sprintf("%s already handles %s", n.path, verb))
|
||||
}
|
||||
n.leafHandler[verb] = handler
|
||||
|
||||
if verb == "HEAD" {
|
||||
n.implicitHead = implicitHead
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) addPath(path string, wildcards []string, inStaticToken bool) *node {
|
||||
leaf := len(path) == 0
|
||||
if leaf {
|
||||
if wildcards != nil {
|
||||
// Make sure the current wildcards are the same as the old ones.
|
||||
// If not then we have an ambiguous path.
|
||||
if n.leafWildcardNames != nil {
|
||||
if len(n.leafWildcardNames) != len(wildcards) {
|
||||
// This should never happen.
|
||||
panic("Reached leaf node with differing wildcard array length. Please report this as a bug.")
|
||||
}
|
||||
|
||||
for i := 0; i < len(wildcards); i++ {
|
||||
if n.leafWildcardNames[i] != wildcards[i] {
|
||||
panic(fmt.Sprintf("Wildcards %v are ambiguous with wildcards %v",
|
||||
n.leafWildcardNames, wildcards))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No wildcards yet, so just add the existing set.
|
||||
n.leafWildcardNames = wildcards
|
||||
}
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
c := path[0]
|
||||
nextSlash := strings.Index(path, "/")
|
||||
var thisToken string
|
||||
var tokenEnd int
|
||||
|
||||
if c == '/' {
|
||||
// Done processing the previous token, so reset inStaticToken to false.
|
||||
thisToken = "/"
|
||||
tokenEnd = 1
|
||||
} else if nextSlash == -1 {
|
||||
thisToken = path
|
||||
tokenEnd = len(path)
|
||||
} else {
|
||||
thisToken = path[0:nextSlash]
|
||||
tokenEnd = nextSlash
|
||||
}
|
||||
remainingPath := path[tokenEnd:]
|
||||
|
||||
if c == '*' && !inStaticToken {
|
||||
// Token starts with a *, so it's a catch-all
|
||||
thisToken = thisToken[1:]
|
||||
if n.catchAllChild == nil {
|
||||
n.catchAllChild = &node{path: thisToken, isCatchAll: true}
|
||||
}
|
||||
|
||||
if path[1:] != n.catchAllChild.path {
|
||||
panic(fmt.Sprintf("Catch-all name in %s doesn't match %s. You probably tried to define overlapping catchalls",
|
||||
path, n.catchAllChild.path))
|
||||
}
|
||||
|
||||
if nextSlash != -1 {
|
||||
panic("/ after catch-all found in " + path)
|
||||
}
|
||||
|
||||
if wildcards == nil {
|
||||
wildcards = []string{thisToken}
|
||||
} else {
|
||||
wildcards = append(wildcards, thisToken)
|
||||
}
|
||||
n.catchAllChild.leafWildcardNames = wildcards
|
||||
|
||||
return n.catchAllChild
|
||||
} else if c == ':' && !inStaticToken {
|
||||
// Token starts with a :
|
||||
thisToken = thisToken[1:]
|
||||
|
||||
if wildcards == nil {
|
||||
wildcards = []string{thisToken}
|
||||
} else {
|
||||
wildcards = append(wildcards, thisToken)
|
||||
}
|
||||
|
||||
if n.wildcardChild == nil {
|
||||
n.wildcardChild = &node{path: "wildcard"}
|
||||
}
|
||||
|
||||
return n.wildcardChild.addPath(remainingPath, wildcards, false)
|
||||
|
||||
} else {
|
||||
// if strings.ContainsAny(thisToken, ":*") {
|
||||
// panic("* or : in middle of path component " + path)
|
||||
// }
|
||||
|
||||
unescaped := false
|
||||
if len(thisToken) >= 2 && !inStaticToken {
|
||||
if thisToken[0] == '\\' && (thisToken[1] == '*' || thisToken[1] == ':' || thisToken[1] == '\\') {
|
||||
// The token starts with a character escaped by a backslash. Drop the backslash.
|
||||
c = thisToken[1]
|
||||
thisToken = thisToken[1:]
|
||||
unescaped = true
|
||||
}
|
||||
}
|
||||
|
||||
// Set inStaticToken to ensure that the rest of this token is not mistaken
|
||||
// for a wildcard if a prefix split occurs at a '*' or ':'.
|
||||
inStaticToken = (c != '/')
|
||||
|
||||
// Do we have an existing node that starts with the same letter?
|
||||
for i, index := range n.staticIndices {
|
||||
if c == index {
|
||||
// Yes. Split it based on the common prefix of the existing
|
||||
// node and the new one.
|
||||
child, prefixSplit := n.splitCommonPrefix(i, thisToken)
|
||||
|
||||
child.priority++
|
||||
n.sortStaticChild(i)
|
||||
if unescaped {
|
||||
// Account for the removed backslash.
|
||||
prefixSplit++
|
||||
}
|
||||
return child.addPath(path[prefixSplit:], wildcards, inStaticToken)
|
||||
}
|
||||
}
|
||||
|
||||
// No existing node starting with this letter, so create it.
|
||||
child := &node{path: thisToken}
|
||||
|
||||
if n.staticIndices == nil {
|
||||
n.staticIndices = []byte{c}
|
||||
n.staticChild = []*node{child}
|
||||
} else {
|
||||
n.staticIndices = append(n.staticIndices, c)
|
||||
n.staticChild = append(n.staticChild, child)
|
||||
}
|
||||
return child.addPath(remainingPath, wildcards, inStaticToken)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) splitCommonPrefix(existingNodeIndex int, path string) (*node, int) {
|
||||
childNode := n.staticChild[existingNodeIndex]
|
||||
|
||||
if strings.HasPrefix(path, childNode.path) {
|
||||
// No split needs to be done. Rather, the new path shares the entire
|
||||
// prefix with the existing node, so the new node is just a child of
|
||||
// the existing one. Or the new path is the same as the existing path,
|
||||
// which means that we just move on to the next token. Either way,
|
||||
// this return accomplishes that
|
||||
return childNode, len(childNode.path)
|
||||
}
|
||||
|
||||
var i int
|
||||
// Find the length of the common prefix of the child node and the new path.
|
||||
for i = range childNode.path {
|
||||
if i == len(path) {
|
||||
break
|
||||
}
|
||||
if path[i] != childNode.path[i] {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
commonPrefix := path[0:i]
|
||||
childNode.path = childNode.path[i:]
|
||||
|
||||
// Create a new intermediary node in the place of the existing node, with
|
||||
// the existing node as a child.
|
||||
newNode := &node{
|
||||
path: commonPrefix,
|
||||
priority: childNode.priority,
|
||||
// Index is the first letter of the non-common part of the path.
|
||||
staticIndices: []byte{childNode.path[0]},
|
||||
staticChild: []*node{childNode},
|
||||
}
|
||||
n.staticChild[existingNodeIndex] = newNode
|
||||
|
||||
return newNode, i
|
||||
}
|
||||
|
||||
func (n *node) search(method, path string) (found *node, handler HandlerFunc, params []string) {
|
||||
// if test != nil {
|
||||
// test.Logf("Searching for %s in %s", path, n.dumpTree("", ""))
|
||||
// }
|
||||
pathLen := len(path)
|
||||
if pathLen == 0 {
|
||||
if len(n.leafHandler) == 0 {
|
||||
return nil, nil, nil
|
||||
} else {
|
||||
return n, n.leafHandler[method], nil
|
||||
}
|
||||
}
|
||||
|
||||
// First see if this matches a static token.
|
||||
firstChar := path[0]
|
||||
for i, staticIndex := range n.staticIndices {
|
||||
if staticIndex == firstChar {
|
||||
child := n.staticChild[i]
|
||||
childPathLen := len(child.path)
|
||||
if pathLen >= childPathLen && child.path == path[:childPathLen] {
|
||||
nextPath := path[childPathLen:]
|
||||
found, handler, params = child.search(method, nextPath)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a node and it had a valid handler, then return here. Otherwise
|
||||
// let's remember that we found this one, but look for a better match.
|
||||
if handler != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n.wildcardChild != nil {
|
||||
// Didn't find a static token, so check for a wildcard.
|
||||
nextSlash := strings.IndexByte(path, '/')
|
||||
if nextSlash < 0 {
|
||||
nextSlash = pathLen
|
||||
}
|
||||
|
||||
thisToken := path[0:nextSlash]
|
||||
nextToken := path[nextSlash:]
|
||||
|
||||
if len(thisToken) > 0 { // Don't match on empty tokens.
|
||||
wcNode, wcHandler, wcParams := n.wildcardChild.search(method, nextToken)
|
||||
if wcHandler != nil || (found == nil && wcNode != nil) {
|
||||
unescaped, err := unescape(thisToken)
|
||||
if err != nil {
|
||||
unescaped = thisToken
|
||||
}
|
||||
|
||||
if wcParams == nil {
|
||||
wcParams = []string{unescaped}
|
||||
} else {
|
||||
wcParams = append(wcParams, unescaped)
|
||||
}
|
||||
|
||||
if wcHandler != nil {
|
||||
return wcNode, wcHandler, wcParams
|
||||
}
|
||||
|
||||
// Didn't actually find a handler here, so remember that we
|
||||
// found a node but also see if we can fall through to the
|
||||
// catchall.
|
||||
found = wcNode
|
||||
handler = wcHandler
|
||||
params = wcParams
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catchAllChild := n.catchAllChild
|
||||
if catchAllChild != nil {
|
||||
// Hit the catchall, so just assign the whole remaining path if it
|
||||
// has a matching handler.
|
||||
handler = catchAllChild.leafHandler[method]
|
||||
// Found a handler, or we found a catchall node without a handler.
|
||||
// Either way, return it since there's nothing left to check after this.
|
||||
if handler != nil || found == nil {
|
||||
unescaped, err := unescape(path)
|
||||
if err != nil {
|
||||
unescaped = path
|
||||
}
|
||||
|
||||
return catchAllChild, handler, []string{unescaped}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return found, handler, params
|
||||
}
|
||||
|
||||
func (n *node) dumpTree(prefix, nodeType string) string {
|
||||
line := fmt.Sprintf("%s %02d %s%s [%d] %v wildcards %v\n", prefix, n.priority, nodeType, n.path,
|
||||
len(n.staticChild), n.leafHandler, n.leafWildcardNames)
|
||||
prefix += " "
|
||||
for _, node := range n.staticChild {
|
||||
line += node.dumpTree(prefix, "")
|
||||
}
|
||||
if n.wildcardChild != nil {
|
||||
line += n.wildcardChild.dumpTree(prefix, ":")
|
||||
}
|
||||
if n.catchAllChild != nil {
|
||||
line += n.catchAllChild.dumpTree(prefix, "*")
|
||||
}
|
||||
return line
|
||||
}
|
86
vendor/github.com/dimfeld/httptreemux/v5/treemux_16.go
generated
vendored
Normal file
86
vendor/github.com/dimfeld/httptreemux/v5/treemux_16.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
// +build !go1.7
|
||||
|
||||
package httptreemux
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type TreeMux struct {
|
||||
root *node
|
||||
mutex sync.RWMutex
|
||||
|
||||
Group
|
||||
|
||||
// The default PanicHandler just returns a 500 code.
|
||||
PanicHandler PanicHandler
|
||||
|
||||
// The default NotFoundHandler is http.NotFound.
|
||||
NotFoundHandler func(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Any OPTIONS request that matches a path without its own OPTIONS handler will use this handler,
|
||||
// if set, instead of calling MethodNotAllowedHandler.
|
||||
OptionsHandler HandlerFunc
|
||||
|
||||
// MethodNotAllowedHandler is called when a pattern matches, but that
|
||||
// pattern does not have a handler for the requested method. The default
|
||||
// handler just writes the status code http.StatusMethodNotAllowed and adds
|
||||
// the required Allowed header.
|
||||
// The methods parameter contains the map of each method to the corresponding
|
||||
// handler function.
|
||||
MethodNotAllowedHandler func(w http.ResponseWriter, r *http.Request,
|
||||
methods map[string]HandlerFunc)
|
||||
|
||||
// HeadCanUseGet allows the router to use the GET handler to respond to
|
||||
// HEAD requests if no explicit HEAD handler has been added for the
|
||||
// matching pattern. This is true by default.
|
||||
HeadCanUseGet bool
|
||||
|
||||
// RedirectCleanPath allows the router to try clean the current request path,
|
||||
// if no handler is registered for it, using CleanPath from github.com/dimfeld/httppath.
|
||||
// This is true by default.
|
||||
RedirectCleanPath bool
|
||||
|
||||
// RedirectTrailingSlash enables automatic redirection in case router doesn't find a matching route
|
||||
// for the current request path but a handler for the path with or without the trailing
|
||||
// slash exists. This is true by default.
|
||||
RedirectTrailingSlash bool
|
||||
|
||||
// RemoveCatchAllTrailingSlash removes the trailing slash when a catch-all pattern
|
||||
// is matched, if set to true. By default, catch-all paths are never redirected.
|
||||
RemoveCatchAllTrailingSlash bool
|
||||
|
||||
// RedirectBehavior sets the default redirect behavior when RedirectTrailingSlash or
|
||||
// RedirectCleanPath are true. The default value is Redirect301.
|
||||
RedirectBehavior RedirectBehavior
|
||||
|
||||
// RedirectMethodBehavior overrides the default behavior for a particular HTTP method.
|
||||
// The key is the method name, and the value is the behavior to use for that method.
|
||||
RedirectMethodBehavior map[string]RedirectBehavior
|
||||
|
||||
// PathSource determines from where the router gets its path to search.
|
||||
// By default it pulls the data from the RequestURI member, but this can
|
||||
// be overridden to use URL.Path instead.
|
||||
//
|
||||
// There is a small tradeoff here. Using RequestURI allows the router to handle
|
||||
// encoded slashes (i.e. %2f) in the URL properly, while URL.Path provides
|
||||
// better compatibility with some utility functions in the http
|
||||
// library that modify the Request before passing it to the router.
|
||||
PathSource PathSource
|
||||
|
||||
// EscapeAddedRoutes controls URI escaping behavior when adding a route to the tree.
|
||||
// If set to true, the router will add both the route as originally passed, and
|
||||
// a version passed through URL.EscapedPath. This behavior is disabled by default.
|
||||
EscapeAddedRoutes bool
|
||||
|
||||
// SafeAddRoutesWhileRunning tells the router to protect all accesses to the tree with an RWMutex. This is only needed
|
||||
// if you are going to add routes after the router has already begun serving requests. There is a potential
|
||||
// performance penalty at high load.
|
||||
SafeAddRoutesWhileRunning bool
|
||||
}
|
||||
|
||||
func (t *TreeMux) setDefaultRequestContext(r *http.Request) *http.Request {
|
||||
// Nothing to do on Go 1.6 and before
|
||||
return r
|
||||
}
|
152
vendor/github.com/dimfeld/httptreemux/v5/treemux_17.go
generated
vendored
Normal file
152
vendor/github.com/dimfeld/httptreemux/v5/treemux_17.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
// +build go1.7
|
||||
|
||||
package httptreemux
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type TreeMux struct {
|
||||
root *node
|
||||
mutex sync.RWMutex
|
||||
|
||||
Group
|
||||
|
||||
// The default PanicHandler just returns a 500 code.
|
||||
PanicHandler PanicHandler
|
||||
|
||||
// The default NotFoundHandler is http.NotFound.
|
||||
NotFoundHandler func(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Any OPTIONS request that matches a path without its own OPTIONS handler will use this handler,
|
||||
// if set, instead of calling MethodNotAllowedHandler.
|
||||
OptionsHandler HandlerFunc
|
||||
|
||||
// MethodNotAllowedHandler is called when a pattern matches, but that
|
||||
// pattern does not have a handler for the requested method. The default
|
||||
// handler just writes the status code http.StatusMethodNotAllowed and adds
|
||||
// the required Allowed header.
|
||||
// The methods parameter contains the map of each method to the corresponding
|
||||
// handler function.
|
||||
MethodNotAllowedHandler func(w http.ResponseWriter, r *http.Request,
|
||||
methods map[string]HandlerFunc)
|
||||
|
||||
// HeadCanUseGet allows the router to use the GET handler to respond to
|
||||
// HEAD requests if no explicit HEAD handler has been added for the
|
||||
// matching pattern. This is true by default.
|
||||
HeadCanUseGet bool
|
||||
|
||||
// RedirectCleanPath allows the router to try clean the current request path,
|
||||
// if no handler is registered for it, using CleanPath from github.com/dimfeld/httppath.
|
||||
// This is true by default.
|
||||
RedirectCleanPath bool
|
||||
|
||||
// RedirectTrailingSlash enables automatic redirection in case router doesn't find a matching route
|
||||
// for the current request path but a handler for the path with or without the trailing
|
||||
// slash exists. This is true by default.
|
||||
RedirectTrailingSlash bool
|
||||
|
||||
// RemoveCatchAllTrailingSlash removes the trailing slash when a catch-all pattern
|
||||
// is matched, if set to true. By default, catch-all paths are never redirected.
|
||||
RemoveCatchAllTrailingSlash bool
|
||||
|
||||
// RedirectBehavior sets the default redirect behavior when RedirectTrailingSlash or
|
||||
// RedirectCleanPath are true. The default value is Redirect301.
|
||||
RedirectBehavior RedirectBehavior
|
||||
|
||||
// RedirectMethodBehavior overrides the default behavior for a particular HTTP method.
|
||||
// The key is the method name, and the value is the behavior to use for that method.
|
||||
RedirectMethodBehavior map[string]RedirectBehavior
|
||||
|
||||
// PathSource determines from where the router gets its path to search.
|
||||
// By default it pulls the data from the RequestURI member, but this can
|
||||
// be overridden to use URL.Path instead.
|
||||
//
|
||||
// There is a small tradeoff here. Using RequestURI allows the router to handle
|
||||
// encoded slashes (i.e. %2f) in the URL properly, while URL.Path provides
|
||||
// better compatibility with some utility functions in the http
|
||||
// library that modify the Request before passing it to the router.
|
||||
PathSource PathSource
|
||||
|
||||
// EscapeAddedRoutes controls URI escaping behavior when adding a route to the tree.
|
||||
// If set to true, the router will add both the route as originally passed, and
|
||||
// a version passed through URL.EscapedPath. This behavior is disabled by default.
|
||||
EscapeAddedRoutes bool
|
||||
|
||||
// If present, override the default context with this one.
|
||||
DefaultContext context.Context
|
||||
|
||||
// SafeAddRoutesWhileRunning tells the router to protect all accesses to the tree with an RWMutex. This is only needed
|
||||
// if you are going to add routes after the router has already begun serving requests. There is a potential
|
||||
// performance penalty at high load.
|
||||
SafeAddRoutesWhileRunning bool
|
||||
|
||||
// CaseInsensitive determines if routes should be treated as case-insensitive.
|
||||
CaseInsensitive bool
|
||||
}
|
||||
|
||||
func (t *TreeMux) setDefaultRequestContext(r *http.Request) *http.Request {
|
||||
if t.DefaultContext != nil {
|
||||
r = r.WithContext(t.DefaultContext)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
type ContextMux struct {
|
||||
*TreeMux
|
||||
*ContextGroup
|
||||
}
|
||||
|
||||
// NewContextMux returns a TreeMux preconfigured to work with standard http
|
||||
// Handler functions and context objects.
|
||||
func NewContextMux() *ContextMux {
|
||||
mux := New()
|
||||
cg := mux.UsingContext()
|
||||
|
||||
return &ContextMux{
|
||||
TreeMux: mux,
|
||||
ContextGroup: cg,
|
||||
}
|
||||
}
|
||||
|
||||
func (cm *ContextMux) NewGroup(path string) *ContextGroup {
|
||||
return cm.ContextGroup.NewGroup(path)
|
||||
}
|
||||
|
||||
// GET is convenience method for handling GET requests on a context group.
|
||||
func (cm *ContextMux) GET(path string, handler http.HandlerFunc) {
|
||||
cm.ContextGroup.Handle("GET", path, handler)
|
||||
}
|
||||
|
||||
// POST is convenience method for handling POST requests on a context group.
|
||||
func (cm *ContextMux) POST(path string, handler http.HandlerFunc) {
|
||||
cm.ContextGroup.Handle("POST", path, handler)
|
||||
}
|
||||
|
||||
// PUT is convenience method for handling PUT requests on a context group.
|
||||
func (cm *ContextMux) PUT(path string, handler http.HandlerFunc) {
|
||||
cm.ContextGroup.Handle("PUT", path, handler)
|
||||
}
|
||||
|
||||
// DELETE is convenience method for handling DELETE requests on a context group.
|
||||
func (cm *ContextMux) DELETE(path string, handler http.HandlerFunc) {
|
||||
cm.ContextGroup.Handle("DELETE", path, handler)
|
||||
}
|
||||
|
||||
// PATCH is convenience method for handling PATCH requests on a context group.
|
||||
func (cm *ContextMux) PATCH(path string, handler http.HandlerFunc) {
|
||||
cm.ContextGroup.Handle("PATCH", path, handler)
|
||||
}
|
||||
|
||||
// HEAD is convenience method for handling HEAD requests on a context group.
|
||||
func (cm *ContextMux) HEAD(path string, handler http.HandlerFunc) {
|
||||
cm.ContextGroup.Handle("HEAD", path, handler)
|
||||
}
|
||||
|
||||
// OPTIONS is convenience method for handling OPTIONS requests on a context group.
|
||||
func (cm *ContextMux) OPTIONS(path string, handler http.HandlerFunc) {
|
||||
cm.ContextGroup.Handle("OPTIONS", path, handler)
|
||||
}
|
9
vendor/github.com/dimfeld/httptreemux/v5/unescape_17.go
generated
vendored
Normal file
9
vendor/github.com/dimfeld/httptreemux/v5/unescape_17.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// +build !go1.8
|
||||
|
||||
package httptreemux
|
||||
|
||||
import "net/url"
|
||||
|
||||
func unescape(path string) (string, error) {
|
||||
return url.QueryUnescape(path)
|
||||
}
|
9
vendor/github.com/dimfeld/httptreemux/v5/unescape_18.go
generated
vendored
Normal file
9
vendor/github.com/dimfeld/httptreemux/v5/unescape_18.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// +build go1.8
|
||||
|
||||
package httptreemux
|
||||
|
||||
import "net/url"
|
||||
|
||||
func unescape(path string) (string, error) {
|
||||
return url.PathUnescape(path)
|
||||
}
|
19
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
Normal file
19
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
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
|
||||
|
||||
# Also update COVER_IGNORE_PKGS in the Makefile.
|
||||
ignore:
|
||||
- /internal/gen-atomicint/
|
||||
- /internal/gen-valuewrapper/
|
15
vendor/go.uber.org/atomic/.gitignore
generated
vendored
Normal file
15
vendor/go.uber.org/atomic/.gitignore
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/bin
|
||||
.DS_Store
|
||||
/vendor
|
||||
cover.html
|
||||
cover.out
|
||||
lint.log
|
||||
|
||||
# Binaries
|
||||
*.test
|
||||
|
||||
# Profiling output
|
||||
*.prof
|
||||
|
||||
# Output of fossa analyzer
|
||||
/fossa
|
100
vendor/go.uber.org/atomic/CHANGELOG.md
generated
vendored
Normal file
100
vendor/go.uber.org/atomic/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.9.0] - 2021-07-15
|
||||
### Added
|
||||
- Add `Float64.Swap` to match int atomic operations.
|
||||
- Add `atomic.Time` type for atomic operations on `time.Time` values.
|
||||
|
||||
[1.9.0]: https://github.com/uber-go/atomic/compare/v1.8.0...v1.9.0
|
||||
|
||||
## [1.8.0] - 2021-06-09
|
||||
### Added
|
||||
- Add `atomic.Uintptr` type for atomic operations on `uintptr` values.
|
||||
- Add `atomic.UnsafePointer` type for atomic operations on `unsafe.Pointer` values.
|
||||
|
||||
[1.8.0]: https://github.com/uber-go/atomic/compare/v1.7.0...v1.8.0
|
||||
|
||||
## [1.7.0] - 2020-09-14
|
||||
### Added
|
||||
- Support JSON serialization and deserialization of primitive atomic types.
|
||||
- Support Text marshalling and unmarshalling for string atomics.
|
||||
|
||||
### Changed
|
||||
- Disallow incorrect comparison of atomic values in a non-atomic way.
|
||||
|
||||
### Removed
|
||||
- Remove dependency on `golang.org/x/{lint, tools}`.
|
||||
|
||||
[1.7.0]: https://github.com/uber-go/atomic/compare/v1.6.0...v1.7.0
|
||||
|
||||
## [1.6.0] - 2020-02-24
|
||||
### Changed
|
||||
- Drop library dependency on `golang.org/x/{lint, tools}`.
|
||||
|
||||
[1.6.0]: https://github.com/uber-go/atomic/compare/v1.5.1...v1.6.0
|
||||
|
||||
## [1.5.1] - 2019-11-19
|
||||
- Fix bug where `Bool.CAS` and `Bool.Toggle` do work correctly together
|
||||
causing `CAS` to fail even though the old value matches.
|
||||
|
||||
[1.5.1]: https://github.com/uber-go/atomic/compare/v1.5.0...v1.5.1
|
||||
|
||||
## [1.5.0] - 2019-10-29
|
||||
### Changed
|
||||
- With Go modules, only the `go.uber.org/atomic` import path is supported now.
|
||||
If you need to use the old import path, please add a `replace` directive to
|
||||
your `go.mod`.
|
||||
|
||||
[1.5.0]: https://github.com/uber-go/atomic/compare/v1.4.0...v1.5.0
|
||||
|
||||
## [1.4.0] - 2019-05-01
|
||||
### Added
|
||||
- Add `atomic.Error` type for atomic operations on `error` values.
|
||||
|
||||
[1.4.0]: https://github.com/uber-go/atomic/compare/v1.3.2...v1.4.0
|
||||
|
||||
## [1.3.2] - 2018-05-02
|
||||
### Added
|
||||
- Add `atomic.Duration` type for atomic operations on `time.Duration` values.
|
||||
|
||||
[1.3.2]: https://github.com/uber-go/atomic/compare/v1.3.1...v1.3.2
|
||||
|
||||
## [1.3.1] - 2017-11-14
|
||||
### Fixed
|
||||
- Revert optimization for `atomic.String.Store("")` which caused data races.
|
||||
|
||||
[1.3.1]: https://github.com/uber-go/atomic/compare/v1.3.0...v1.3.1
|
||||
|
||||
## [1.3.0] - 2017-11-13
|
||||
### Added
|
||||
- Add `atomic.Bool.CAS` for compare-and-swap semantics on bools.
|
||||
|
||||
### Changed
|
||||
- Optimize `atomic.String.Store("")` by avoiding an allocation.
|
||||
|
||||
[1.3.0]: https://github.com/uber-go/atomic/compare/v1.2.0...v1.3.0
|
||||
|
||||
## [1.2.0] - 2017-04-12
|
||||
### Added
|
||||
- Shadow `atomic.Value` from `sync/atomic`.
|
||||
|
||||
[1.2.0]: https://github.com/uber-go/atomic/compare/v1.1.0...v1.2.0
|
||||
|
||||
## [1.1.0] - 2017-03-10
|
||||
### Added
|
||||
- Add atomic `Float64` type.
|
||||
|
||||
### Changed
|
||||
- Support new `go.uber.org/atomic` import path.
|
||||
|
||||
[1.1.0]: https://github.com/uber-go/atomic/compare/v1.0.0...v1.1.0
|
||||
|
||||
## [1.0.0] - 2016-07-18
|
||||
|
||||
- Initial release.
|
||||
|
||||
[1.0.0]: https://github.com/uber-go/atomic/releases/tag/v1.0.0
|
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.
|
79
vendor/go.uber.org/atomic/Makefile
generated
vendored
Normal file
79
vendor/go.uber.org/atomic/Makefile
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
# Directory to place `go install`ed binaries into.
|
||||
export GOBIN ?= $(shell pwd)/bin
|
||||
|
||||
GOLINT = $(GOBIN)/golint
|
||||
GEN_ATOMICINT = $(GOBIN)/gen-atomicint
|
||||
GEN_ATOMICWRAPPER = $(GOBIN)/gen-atomicwrapper
|
||||
STATICCHECK = $(GOBIN)/staticcheck
|
||||
|
||||
GO_FILES ?= $(shell find . '(' -path .git -o -path vendor ')' -prune -o -name '*.go' -print)
|
||||
|
||||
# Also update ignore section in .codecov.yml.
|
||||
COVER_IGNORE_PKGS = \
|
||||
go.uber.org/atomic/internal/gen-atomicint \
|
||||
go.uber.org/atomic/internal/gen-atomicwrapper
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build ./...
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -race ./...
|
||||
|
||||
.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)
|
||||
|
||||
$(GOLINT):
|
||||
cd tools && go install golang.org/x/lint/golint
|
||||
|
||||
$(STATICCHECK):
|
||||
cd tools && go install honnef.co/go/tools/cmd/staticcheck
|
||||
|
||||
$(GEN_ATOMICWRAPPER): $(wildcard ./internal/gen-atomicwrapper/*)
|
||||
go build -o $@ ./internal/gen-atomicwrapper
|
||||
|
||||
$(GEN_ATOMICINT): $(wildcard ./internal/gen-atomicint/*)
|
||||
go build -o $@ ./internal/gen-atomicint
|
||||
|
||||
.PHONY: golint
|
||||
golint: $(GOLINT)
|
||||
$(GOLINT) ./...
|
||||
|
||||
.PHONY: staticcheck
|
||||
staticcheck: $(STATICCHECK)
|
||||
$(STATICCHECK) ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint: gofmt golint staticcheck generatenodirty
|
||||
|
||||
# comma separated list of packages to consider for code coverage.
|
||||
COVER_PKG = $(shell \
|
||||
go list -find ./... | \
|
||||
grep -v $(foreach pkg,$(COVER_IGNORE_PKGS),-e "^$(pkg)$$") | \
|
||||
paste -sd, -)
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
go test -coverprofile=cover.out -coverpkg $(COVER_PKG) -v ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
.PHONY: generate
|
||||
generate: $(GEN_ATOMICINT) $(GEN_ATOMICWRAPPER)
|
||||
go generate ./...
|
||||
|
||||
.PHONY: generatenodirty
|
||||
generatenodirty:
|
||||
@[ -z "$$(git status --porcelain)" ] || ( \
|
||||
echo "Working tree is dirty. Commit your changes first."; \
|
||||
git status; \
|
||||
exit 1 )
|
||||
@make generate
|
||||
@status=$$(git status --porcelain); \
|
||||
[ -z "$$status" ] || ( \
|
||||
echo "Working tree is dirty after `make generate`:"; \
|
||||
echo "$$status"; \
|
||||
echo "Please ensure that the generated code is up-to-date." )
|
63
vendor/go.uber.org/atomic/README.md
generated
vendored
Normal file
63
vendor/go.uber.org/atomic/README.md
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
# 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
|
||||
|
||||
```shell
|
||||
$ go get -u go.uber.org/atomic@v1
|
||||
```
|
||||
|
||||
### Legacy Import Path
|
||||
|
||||
As of v1.5.0, the import path `go.uber.org/atomic` is the only supported way
|
||||
of using this package. If you are using Go modules, this package will fail to
|
||||
compile with the legacy import path path `github.com/uber-go/atomic`.
|
||||
|
||||
We recommend migrating your code to the new import path but if you're unable
|
||||
to do so, or if your dependencies are still using the old import path, you
|
||||
will have to add a `replace` directive to your `go.mod` file downgrading the
|
||||
legacy import path to an older version.
|
||||
|
||||
```
|
||||
replace github.com/uber-go/atomic => github.com/uber-go/atomic v1.4.0
|
||||
```
|
||||
|
||||
You can do so automatically by running the following command.
|
||||
|
||||
```shell
|
||||
$ go mod edit -replace github.com/uber-go/atomic=github.com/uber-go/atomic@v1.4.0
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
---
|
||||
|
||||
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://github.com/uber-go/atomic/actions/workflows/go.yml/badge.svg
|
||||
[ci]: https://github.com/uber-go/atomic/actions/workflows/go.yml
|
||||
[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
|
81
vendor/go.uber.org/atomic/bool.go
generated
vendored
Normal file
81
vendor/go.uber.org/atomic/bool.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Bool is an atomic type-safe wrapper for bool values.
|
||||
type Bool struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Uint32
|
||||
}
|
||||
|
||||
var _zeroBool bool
|
||||
|
||||
// NewBool creates a new Bool.
|
||||
func NewBool(val bool) *Bool {
|
||||
x := &Bool{}
|
||||
if val != _zeroBool {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped bool.
|
||||
func (x *Bool) Load() bool {
|
||||
return truthy(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed bool.
|
||||
func (x *Bool) Store(val bool) {
|
||||
x.v.Store(boolToInt(val))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for bool values.
|
||||
func (x *Bool) CAS(old, new bool) (swapped bool) {
|
||||
return x.v.CAS(boolToInt(old), boolToInt(new))
|
||||
}
|
||||
|
||||
// Swap atomically stores the given bool and returns the old
|
||||
// value.
|
||||
func (x *Bool) Swap(val bool) (old bool) {
|
||||
return truthy(x.v.Swap(boolToInt(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped bool into JSON.
|
||||
func (x *Bool) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(x.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes a bool from JSON.
|
||||
func (x *Bool) UnmarshalJSON(b []byte) error {
|
||||
var v bool
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Store(v)
|
||||
return nil
|
||||
}
|
53
vendor/go.uber.org/atomic/bool_ext.go
generated
vendored
Normal file
53
vendor/go.uber.org/atomic/bool_ext.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Bool -type=bool -wrapped=Uint32 -pack=boolToInt -unpack=truthy -cas -swap -json -file=bool.go
|
||||
|
||||
func truthy(n uint32) bool {
|
||||
return n == 1
|
||||
}
|
||||
|
||||
func boolToInt(b bool) uint32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Toggle atomically negates the Boolean and returns the previous value.
|
||||
func (b *Bool) Toggle() (old bool) {
|
||||
for {
|
||||
old := b.Load()
|
||||
if b.CAS(old, !old) {
|
||||
return old
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (b *Bool) String() string {
|
||||
return strconv.FormatBool(b.Load())
|
||||
}
|
23
vendor/go.uber.org/atomic/doc.go
generated
vendored
Normal file
23
vendor/go.uber.org/atomic/doc.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2020 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
|
82
vendor/go.uber.org/atomic/duration.go
generated
vendored
Normal file
82
vendor/go.uber.org/atomic/duration.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Duration is an atomic type-safe wrapper for time.Duration values.
|
||||
type Duration struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Int64
|
||||
}
|
||||
|
||||
var _zeroDuration time.Duration
|
||||
|
||||
// NewDuration creates a new Duration.
|
||||
func NewDuration(val time.Duration) *Duration {
|
||||
x := &Duration{}
|
||||
if val != _zeroDuration {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped time.Duration.
|
||||
func (x *Duration) Load() time.Duration {
|
||||
return time.Duration(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed time.Duration.
|
||||
func (x *Duration) Store(val time.Duration) {
|
||||
x.v.Store(int64(val))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for time.Duration values.
|
||||
func (x *Duration) CAS(old, new time.Duration) (swapped bool) {
|
||||
return x.v.CAS(int64(old), int64(new))
|
||||
}
|
||||
|
||||
// Swap atomically stores the given time.Duration and returns the old
|
||||
// value.
|
||||
func (x *Duration) Swap(val time.Duration) (old time.Duration) {
|
||||
return time.Duration(x.v.Swap(int64(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped time.Duration into JSON.
|
||||
func (x *Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(x.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes a time.Duration from JSON.
|
||||
func (x *Duration) UnmarshalJSON(b []byte) error {
|
||||
var v time.Duration
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Store(v)
|
||||
return nil
|
||||
}
|
40
vendor/go.uber.org/atomic/duration_ext.go
generated
vendored
Normal file
40
vendor/go.uber.org/atomic/duration_ext.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import "time"
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Duration -type=time.Duration -wrapped=Int64 -pack=int64 -unpack=time.Duration -cas -swap -json -imports time -file=duration.go
|
||||
|
||||
// Add atomically adds to the wrapped time.Duration and returns the new value.
|
||||
func (d *Duration) Add(delta time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Add(int64(delta)))
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped time.Duration and returns the new value.
|
||||
func (d *Duration) Sub(delta time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Sub(int64(delta)))
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (d *Duration) String() string {
|
||||
return d.Load().String()
|
||||
}
|
51
vendor/go.uber.org/atomic/error.go
generated
vendored
Normal file
51
vendor/go.uber.org/atomic/error.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 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
|
||||
|
||||
// Error is an atomic type-safe wrapper for error values.
|
||||
type Error struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Value
|
||||
}
|
||||
|
||||
var _zeroError error
|
||||
|
||||
// NewError creates a new Error.
|
||||
func NewError(val error) *Error {
|
||||
x := &Error{}
|
||||
if val != _zeroError {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped error.
|
||||
func (x *Error) Load() error {
|
||||
return unpackError(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed error.
|
||||
func (x *Error) Store(val error) {
|
||||
x.v.Store(packError(val))
|
||||
}
|
39
vendor/go.uber.org/atomic/error_ext.go
generated
vendored
Normal file
39
vendor/go.uber.org/atomic/error_ext.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2020 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
|
||||
|
||||
// atomic.Value panics on nil inputs, or if the underlying type changes.
|
||||
// Stabilize by always storing a custom struct that we control.
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Error -type=error -wrapped=Value -pack=packError -unpack=unpackError -file=error.go
|
||||
|
||||
type packedError struct{ Value error }
|
||||
|
||||
func packError(v error) interface{} {
|
||||
return packedError{v}
|
||||
}
|
||||
|
||||
func unpackError(v interface{}) error {
|
||||
if err, ok := v.(packedError); ok {
|
||||
return err.Value
|
||||
}
|
||||
return nil
|
||||
}
|
77
vendor/go.uber.org/atomic/float64.go
generated
vendored
Normal file
77
vendor/go.uber.org/atomic/float64.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Float64 is an atomic type-safe wrapper for float64 values.
|
||||
type Float64 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Uint64
|
||||
}
|
||||
|
||||
var _zeroFloat64 float64
|
||||
|
||||
// NewFloat64 creates a new Float64.
|
||||
func NewFloat64(val float64) *Float64 {
|
||||
x := &Float64{}
|
||||
if val != _zeroFloat64 {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped float64.
|
||||
func (x *Float64) Load() float64 {
|
||||
return math.Float64frombits(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed float64.
|
||||
func (x *Float64) Store(val float64) {
|
||||
x.v.Store(math.Float64bits(val))
|
||||
}
|
||||
|
||||
// Swap atomically stores the given float64 and returns the old
|
||||
// value.
|
||||
func (x *Float64) Swap(val float64) (old float64) {
|
||||
return math.Float64frombits(x.v.Swap(math.Float64bits(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped float64 into JSON.
|
||||
func (x *Float64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(x.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes a float64 from JSON.
|
||||
func (x *Float64) UnmarshalJSON(b []byte) error {
|
||||
var v float64
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Store(v)
|
||||
return nil
|
||||
}
|
69
vendor/go.uber.org/atomic/float64_ext.go
generated
vendored
Normal file
69
vendor/go.uber.org/atomic/float64_ext.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -swap -json -imports math -file=float64.go
|
||||
|
||||
// Add atomically adds to the wrapped float64 and returns the new value.
|
||||
func (f *Float64) Add(delta float64) float64 {
|
||||
for {
|
||||
old := f.Load()
|
||||
new := old + delta
|
||||
if f.CAS(old, new) {
|
||||
return new
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped float64 and returns the new value.
|
||||
func (f *Float64) Sub(delta float64) float64 {
|
||||
return f.Add(-delta)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for float64 values.
|
||||
//
|
||||
// Note: CAS handles NaN incorrectly. NaN != NaN using Go's inbuilt operators
|
||||
// but CAS allows a stored NaN to compare equal to a passed in NaN.
|
||||
// This avoids typical CAS loops from blocking forever, e.g.,
|
||||
//
|
||||
// for {
|
||||
// old := atom.Load()
|
||||
// new = f(old)
|
||||
// if atom.CAS(old, new) {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// If CAS did not match NaN to match, then the above would loop forever.
|
||||
func (f *Float64) CAS(old, new float64) (swapped bool) {
|
||||
return f.v.CAS(math.Float64bits(old), math.Float64bits(new))
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (f *Float64) String() string {
|
||||
// 'g' is the behavior for floats with %v.
|
||||
return strconv.FormatFloat(f.Load(), 'g', -1, 64)
|
||||
}
|
27
vendor/go.uber.org/atomic/gen.go
generated
vendored
Normal file
27
vendor/go.uber.org/atomic/gen.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2020 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
|
||||
|
||||
//go:generate bin/gen-atomicint -name=Int32 -wrapped=int32 -file=int32.go
|
||||
//go:generate bin/gen-atomicint -name=Int64 -wrapped=int64 -file=int64.go
|
||||
//go:generate bin/gen-atomicint -name=Uint32 -wrapped=uint32 -unsigned -file=uint32.go
|
||||
//go:generate bin/gen-atomicint -name=Uint64 -wrapped=uint64 -unsigned -file=uint64.go
|
||||
//go:generate bin/gen-atomicint -name=Uintptr -wrapped=uintptr -unsigned -file=uintptr.go
|
102
vendor/go.uber.org/atomic/int32.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/int32.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Int32 is an atomic wrapper around int32.
|
||||
type Int32 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v int32
|
||||
}
|
||||
|
||||
// NewInt32 creates a new Int32.
|
||||
func NewInt32(val int32) *Int32 {
|
||||
return &Int32{v: val}
|
||||
}
|
||||
|
||||
// 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(delta int32) int32 {
|
||||
return atomic.AddInt32(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Sub(delta int32) int32 {
|
||||
return atomic.AddInt32(&i.v, -delta)
|
||||
}
|
||||
|
||||
// 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) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt32(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int32) Store(val int32) {
|
||||
atomic.StoreInt32(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int32 and returns the old value.
|
||||
func (i *Int32) Swap(val int32) (old int32) {
|
||||
return atomic.SwapInt32(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped int32 into JSON.
|
||||
func (i *Int32) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped int32.
|
||||
func (i *Int32) UnmarshalJSON(b []byte) error {
|
||||
var v int32
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Int32) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatInt(int64(v), 10)
|
||||
}
|
102
vendor/go.uber.org/atomic/int64.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/int64.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Int64 is an atomic wrapper around int64.
|
||||
type Int64 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v int64
|
||||
}
|
||||
|
||||
// NewInt64 creates a new Int64.
|
||||
func NewInt64(val int64) *Int64 {
|
||||
return &Int64{v: val}
|
||||
}
|
||||
|
||||
// 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(delta int64) int64 {
|
||||
return atomic.AddInt64(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Sub(delta int64) int64 {
|
||||
return atomic.AddInt64(&i.v, -delta)
|
||||
}
|
||||
|
||||
// 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) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt64(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int64) Store(val int64) {
|
||||
atomic.StoreInt64(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int64 and returns the old value.
|
||||
func (i *Int64) Swap(val int64) (old int64) {
|
||||
return atomic.SwapInt64(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped int64 into JSON.
|
||||
func (i *Int64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped int64.
|
||||
func (i *Int64) UnmarshalJSON(b []byte) error {
|
||||
var v int64
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Int64) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatInt(int64(v), 10)
|
||||
}
|
35
vendor/go.uber.org/atomic/nocmp.go
generated
vendored
Normal file
35
vendor/go.uber.org/atomic/nocmp.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2020 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
|
||||
|
||||
// nocmp is an uncomparable struct. Embed this inside another struct to make
|
||||
// it uncomparable.
|
||||
//
|
||||
// type Foo struct {
|
||||
// nocmp
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// This DOES NOT:
|
||||
//
|
||||
// - Disallow shallow copies of structs
|
||||
// - Disallow comparison of pointers to uncomparable structs
|
||||
type nocmp [0]func()
|
54
vendor/go.uber.org/atomic/string.go
generated
vendored
Normal file
54
vendor/go.uber.org/atomic/string.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 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 for string values.
|
||||
type String struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Value
|
||||
}
|
||||
|
||||
var _zeroString string
|
||||
|
||||
// NewString creates a new String.
|
||||
func NewString(val string) *String {
|
||||
x := &String{}
|
||||
if val != _zeroString {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped string.
|
||||
func (x *String) Load() string {
|
||||
if v := x.v.Load(); v != nil {
|
||||
return v.(string)
|
||||
}
|
||||
return _zeroString
|
||||
}
|
||||
|
||||
// Store atomically stores the passed string.
|
||||
func (x *String) Store(val string) {
|
||||
x.v.Store(val)
|
||||
}
|
45
vendor/go.uber.org/atomic/string_ext.go
generated
vendored
Normal file
45
vendor/go.uber.org/atomic/string_ext.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2020 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
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=String -type=string -wrapped=Value -file=string.go
|
||||
// Note: No Swap as String wraps Value, which wraps the stdlib sync/atomic.Value which
|
||||
// only supports Swap as of go1.17: https://github.com/golang/go/issues/39351
|
||||
|
||||
// String returns the wrapped value.
|
||||
func (s *String) String() string {
|
||||
return s.Load()
|
||||
}
|
||||
|
||||
// MarshalText encodes the wrapped string into a textual form.
|
||||
//
|
||||
// This makes it encodable as JSON, YAML, XML, and more.
|
||||
func (s *String) MarshalText() ([]byte, error) {
|
||||
return []byte(s.Load()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText decodes text and replaces the wrapped string with it.
|
||||
//
|
||||
// This makes it decodable from JSON, YAML, XML, and more.
|
||||
func (s *String) UnmarshalText(b []byte) error {
|
||||
s.Store(string(b))
|
||||
return nil
|
||||
}
|
55
vendor/go.uber.org/atomic/time.go
generated
vendored
Normal file
55
vendor/go.uber.org/atomic/time.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Time is an atomic type-safe wrapper for time.Time values.
|
||||
type Time struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Value
|
||||
}
|
||||
|
||||
var _zeroTime time.Time
|
||||
|
||||
// NewTime creates a new Time.
|
||||
func NewTime(val time.Time) *Time {
|
||||
x := &Time{}
|
||||
if val != _zeroTime {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped time.Time.
|
||||
func (x *Time) Load() time.Time {
|
||||
return unpackTime(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed time.Time.
|
||||
func (x *Time) Store(val time.Time) {
|
||||
x.v.Store(packTime(val))
|
||||
}
|
36
vendor/go.uber.org/atomic/time_ext.go
generated
vendored
Normal file
36
vendor/go.uber.org/atomic/time_ext.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import "time"
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Time -type=time.Time -wrapped=Value -pack=packTime -unpack=unpackTime -imports time -file=time.go
|
||||
|
||||
func packTime(t time.Time) interface{} {
|
||||
return t
|
||||
}
|
||||
|
||||
func unpackTime(v interface{}) time.Time {
|
||||
if t, ok := v.(time.Time); ok {
|
||||
return t
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
102
vendor/go.uber.org/atomic/uint32.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/uint32.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uint32 is an atomic wrapper around uint32.
|
||||
type Uint32 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v uint32
|
||||
}
|
||||
|
||||
// NewUint32 creates a new Uint32.
|
||||
func NewUint32(val uint32) *Uint32 {
|
||||
return &Uint32{v: val}
|
||||
}
|
||||
|
||||
// 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(delta uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Sub(delta uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, ^(delta - 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 uint32 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) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint32(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint32) Store(val uint32) {
|
||||
atomic.StoreUint32(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint32 and returns the old value.
|
||||
func (i *Uint32) Swap(val uint32) (old uint32) {
|
||||
return atomic.SwapUint32(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uint32 into JSON.
|
||||
func (i *Uint32) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped uint32.
|
||||
func (i *Uint32) UnmarshalJSON(b []byte) error {
|
||||
var v uint32
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Uint32) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
}
|
102
vendor/go.uber.org/atomic/uint64.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/uint64.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uint64 is an atomic wrapper around uint64.
|
||||
type Uint64 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v uint64
|
||||
}
|
||||
|
||||
// NewUint64 creates a new Uint64.
|
||||
func NewUint64(val uint64) *Uint64 {
|
||||
return &Uint64{v: val}
|
||||
}
|
||||
|
||||
// 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(delta uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Sub(delta uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, ^(delta - 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) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint64(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint64) Store(val uint64) {
|
||||
atomic.StoreUint64(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint64 and returns the old value.
|
||||
func (i *Uint64) Swap(val uint64) (old uint64) {
|
||||
return atomic.SwapUint64(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uint64 into JSON.
|
||||
func (i *Uint64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped uint64.
|
||||
func (i *Uint64) UnmarshalJSON(b []byte) error {
|
||||
var v uint64
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Uint64) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
}
|
102
vendor/go.uber.org/atomic/uintptr.go
generated
vendored
Normal file
102
vendor/go.uber.org/atomic/uintptr.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uintptr is an atomic wrapper around uintptr.
|
||||
type Uintptr struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v uintptr
|
||||
}
|
||||
|
||||
// NewUintptr creates a new Uintptr.
|
||||
func NewUintptr(val uintptr) *Uintptr {
|
||||
return &Uintptr{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Uintptr) Load() uintptr {
|
||||
return atomic.LoadUintptr(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Add(delta uintptr) uintptr {
|
||||
return atomic.AddUintptr(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Sub(delta uintptr) uintptr {
|
||||
return atomic.AddUintptr(&i.v, ^(delta - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Inc() uintptr {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Dec() uintptr {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uintptr) CAS(old, new uintptr) (swapped bool) {
|
||||
return atomic.CompareAndSwapUintptr(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uintptr) Store(val uintptr) {
|
||||
atomic.StoreUintptr(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uintptr and returns the old value.
|
||||
func (i *Uintptr) Swap(val uintptr) (old uintptr) {
|
||||
return atomic.SwapUintptr(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uintptr into JSON.
|
||||
func (i *Uintptr) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped uintptr.
|
||||
func (i *Uintptr) UnmarshalJSON(b []byte) error {
|
||||
var v uintptr
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Uintptr) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
}
|
58
vendor/go.uber.org/atomic/unsafe_pointer.go
generated
vendored
Normal file
58
vendor/go.uber.org/atomic/unsafe_pointer.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// UnsafePointer is an atomic wrapper around unsafe.Pointer.
|
||||
type UnsafePointer struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v unsafe.Pointer
|
||||
}
|
||||
|
||||
// NewUnsafePointer creates a new UnsafePointer.
|
||||
func NewUnsafePointer(val unsafe.Pointer) *UnsafePointer {
|
||||
return &UnsafePointer{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (p *UnsafePointer) Load() unsafe.Pointer {
|
||||
return atomic.LoadPointer(&p.v)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (p *UnsafePointer) Store(val unsafe.Pointer) {
|
||||
atomic.StorePointer(&p.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped unsafe.Pointer and returns the old value.
|
||||
func (p *UnsafePointer) Swap(val unsafe.Pointer) (old unsafe.Pointer) {
|
||||
return atomic.SwapPointer(&p.v, val)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (p *UnsafePointer) CAS(old, new unsafe.Pointer) (swapped bool) {
|
||||
return atomic.CompareAndSwapPointer(&p.v, old, new)
|
||||
}
|
18
vendor/go.uber.org/automaxprocs/automaxprocs.go → vendor/go.uber.org/atomic/value.go
generated
vendored
18
vendor/go.uber.org/automaxprocs/automaxprocs.go → vendor/go.uber.org/atomic/value.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
// Copyright (c) 2020 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
|
||||
@ -18,16 +18,14 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package automaxprocs automatically sets GOMAXPROCS to match the Linux
|
||||
// container CPU quota, if any.
|
||||
package automaxprocs // import "go.uber.org/automaxprocs"
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"log"
|
||||
import "sync/atomic"
|
||||
|
||||
"go.uber.org/automaxprocs/maxprocs"
|
||||
)
|
||||
// Value shadows the type of the same name from sync/atomic
|
||||
// https://godoc.org/sync/atomic#Value
|
||||
type Value struct {
|
||||
atomic.Value
|
||||
|
||||
func init() {
|
||||
maxprocs.Set(maxprocs.Logger(log.Printf))
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
}
|
24
vendor/go.uber.org/automaxprocs/.travis.yml
generated
vendored
24
vendor/go.uber.org/automaxprocs/.travis.yml
generated
vendored
@ -1,24 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go_import_path: go.uber.org/automaxprocs
|
||||
|
||||
env:
|
||||
global:
|
||||
- GO111MODULE=on
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- go: oldstable
|
||||
- go: stable
|
||||
env: LINT=1
|
||||
|
||||
install:
|
||||
- make install
|
||||
|
||||
script:
|
||||
- test -z "$LINT" || make lint
|
||||
- make test
|
||||
|
||||
after_success:
|
||||
- make cover
|
||||
- bash <(curl -s https://codecov.io/bash)
|
26
vendor/go.uber.org/automaxprocs/CHANGELOG.md
generated
vendored
26
vendor/go.uber.org/automaxprocs/CHANGELOG.md
generated
vendored
@ -1,26 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## v1.4.0 (2021-02-01)
|
||||
|
||||
- Support colons in cgroup names.
|
||||
- Remove linters from runtime dependencies.
|
||||
|
||||
## v1.3.0 (2020-01-23)
|
||||
|
||||
- Migrate to Go modules.
|
||||
|
||||
## v1.2.0 (2018-02-22)
|
||||
|
||||
- Fixed quota clamping to always round down rather than up; Rather than
|
||||
guaranteeing constant throttling at saturation, instead assume that the
|
||||
fractional CPU was added as a hedge for factors outside of Go's scheduler.
|
||||
|
||||
## v1.1.0 (2017-11-10)
|
||||
|
||||
- Log the new value of `GOMAXPROCS` rather than the current value.
|
||||
- Make logs more explicit about whether `GOMAXPROCS` was modified or not.
|
||||
- Allow customization of the minimum `GOMAXPROCS`, and modify default from 2 to 1.
|
||||
|
||||
## v1.0.0 (2017-08-09)
|
||||
|
||||
- Initial release.
|
46
vendor/go.uber.org/automaxprocs/Makefile
generated
vendored
46
vendor/go.uber.org/automaxprocs/Makefile
generated
vendored
@ -1,46 +0,0 @@
|
||||
export GOBIN ?= $(shell pwd)/bin
|
||||
|
||||
GO_FILES := $(shell \
|
||||
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
|
||||
-o -name '*.go' -print | cut -b3-)
|
||||
|
||||
GOLINT = $(GOBIN)/golint
|
||||
STATICCHECK = $(GOBIN)/staticcheck
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build ./...
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
go mod download
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -race ./...
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
go test -coverprofile=cover.out -covermode=atomic -coverpkg=./... ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
$(GOLINT): tools/go.mod
|
||||
cd tools && go install golang.org/x/lint/golint
|
||||
|
||||
$(STATICCHECK): tools/go.mod
|
||||
cd tools && go install honnef.co/go/tools/cmd/staticcheck
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(GOLINT) $(STATICCHECK)
|
||||
@rm -rf lint.log
|
||||
@echo "Checking gofmt"
|
||||
@gofmt -d -s $(GO_FILES) 2>&1 | tee lint.log
|
||||
@echo "Checking go vet"
|
||||
@go vet ./... 2>&1 | tee -a lint.log
|
||||
@echo "Checking golint"
|
||||
@$(GOLINT) ./... | tee -a lint.log
|
||||
@echo "Checking staticcheck"
|
||||
@$(STATICCHECK) ./... 2>&1 | tee -a lint.log
|
||||
@echo "Checking for license headers..."
|
||||
@./.build/check_license.sh | tee -a lint.log
|
||||
@[ ! -s lint.log ]
|
46
vendor/go.uber.org/automaxprocs/README.md
generated
vendored
46
vendor/go.uber.org/automaxprocs/README.md
generated
vendored
@ -1,46 +0,0 @@
|
||||
# automaxprocs [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
|
||||
|
||||
Automatically set `GOMAXPROCS` to match Linux container CPU quota.
|
||||
|
||||
## Installation
|
||||
|
||||
`go get -u go.uber.org/automaxprocs`
|
||||
|
||||
## Quick Start
|
||||
|
||||
```go
|
||||
import _ "go.uber.org/automaxprocs"
|
||||
|
||||
func main() {
|
||||
// Your application logic here.
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
automaxprocs 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 automaxprocs 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 automaxprocs maintainers don't have access, so don't hesitate to hold
|
||||
us to a high standard.
|
||||
|
||||
<hr>
|
||||
|
||||
Released under the [MIT License](LICENSE).
|
||||
|
||||
[doc-img]: https://godoc.org/go.uber.org/automaxprocs?status.svg
|
||||
[doc]: https://godoc.org/go.uber.org/automaxprocs
|
||||
[ci-img]: https://travis-ci.com/uber-go/automaxprocs.svg?branch=master
|
||||
[ci]: https://travis-ci.com/uber-go/automaxprocs
|
||||
[cov-img]: https://codecov.io/gh/uber-go/automaxprocs/branch/master/graph/badge.svg
|
||||
[cov]: https://codecov.io/gh/uber-go/automaxprocs
|
||||
|
||||
|
7
vendor/go.uber.org/automaxprocs/glide.yaml
generated
vendored
7
vendor/go.uber.org/automaxprocs/glide.yaml
generated
vendored
@ -1,7 +0,0 @@
|
||||
package: go.uber.org/automaxprocs
|
||||
import: []
|
||||
testImport:
|
||||
- package: github.com/stretchr/testify
|
||||
version: ^1.1.4
|
||||
subpackages:
|
||||
- assert
|
@ -7,8 +7,9 @@ coverage:
|
||||
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: 90% # specify the target coverage for each commit 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
|
||||
|
4
vendor/go.uber.org/multierr/.gitignore
generated
vendored
Normal file
4
vendor/go.uber.org/multierr/.gitignore
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/vendor
|
||||
cover.html
|
||||
cover.out
|
||||
/bin
|
66
vendor/go.uber.org/multierr/CHANGELOG.md
generated
vendored
Normal file
66
vendor/go.uber.org/multierr/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
Releases
|
||||
========
|
||||
|
||||
v1.7.0 (2021-05-06)
|
||||
===================
|
||||
|
||||
- Add `AppendInvoke` to append into errors from `defer` blocks.
|
||||
|
||||
|
||||
v1.6.0 (2020-09-14)
|
||||
===================
|
||||
|
||||
- Actually drop library dependency on development-time tooling.
|
||||
|
||||
|
||||
v1.5.0 (2020-02-24)
|
||||
===================
|
||||
|
||||
- Drop library dependency on development-time tooling.
|
||||
|
||||
|
||||
v1.4.0 (2019-11-04)
|
||||
===================
|
||||
|
||||
- Add `AppendInto` function to more ergonomically build errors inside a
|
||||
loop.
|
||||
|
||||
|
||||
v1.3.0 (2019-10-29)
|
||||
===================
|
||||
|
||||
- Switch to Go modules.
|
||||
|
||||
|
||||
v1.2.0 (2019-09-26)
|
||||
===================
|
||||
|
||||
- Support extracting and matching against wrapped errors with `errors.As`
|
||||
and `errors.Is`.
|
||||
|
||||
|
||||
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-2021 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.
|
38
vendor/go.uber.org/multierr/Makefile
generated
vendored
Normal file
38
vendor/go.uber.org/multierr/Makefile
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
# Directory to put `go install`ed binaries in.
|
||||
export GOBIN ?= $(shell pwd)/bin
|
||||
|
||||
GO_FILES := $(shell \
|
||||
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
|
||||
-o -name '*.go' -print | cut -b3-)
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build ./...
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -race ./...
|
||||
|
||||
.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: golint
|
||||
golint:
|
||||
@cd tools && go install golang.org/x/lint/golint
|
||||
@$(GOBIN)/golint ./...
|
||||
|
||||
.PHONY: staticcheck
|
||||
staticcheck:
|
||||
@cd tools && go install honnef.co/go/tools/cmd/staticcheck
|
||||
@$(GOBIN)/staticcheck ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint: gofmt golint staticcheck
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
go test -race -coverprofile=cover.out -coverpkg=./... -v ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
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://pkg.go.dev/badge/go.uber.org/multierr
|
||||
[doc]: https://pkg.go.dev/go.uber.org/multierr
|
||||
[ci-img]: https://github.com/uber-go/multierr/actions/workflows/go.yml/badge.svg
|
||||
[cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg
|
||||
[ci]: https://github.com/uber-go/multierr/actions/workflows/go.yml
|
||||
[cov]: https://codecov.io/gh/uber-go/multierr
|
639
vendor/go.uber.org/multierr/error.go
generated
vendored
Normal file
639
vendor/go.uber.org/multierr/error.go
generated
vendored
Normal file
@ -0,0 +1,639 @@
|
||||
// Copyright (c) 2017-2021 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.Append(reader.Close(), writer.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:", errors)
|
||||
// }
|
||||
//
|
||||
// Appending from a loop
|
||||
//
|
||||
// You sometimes need to append into an error from a loop.
|
||||
//
|
||||
// var err error
|
||||
// for _, item := range items {
|
||||
// err = multierr.Append(err, process(item))
|
||||
// }
|
||||
//
|
||||
// Cases like this may require knowledge of whether an individual instance
|
||||
// failed. This usually requires introduction of a new variable.
|
||||
//
|
||||
// var err error
|
||||
// for _, item := range items {
|
||||
// if perr := process(item); perr != nil {
|
||||
// log.Warn("skipping item", item)
|
||||
// err = multierr.Append(err, perr)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// multierr includes AppendInto to simplify cases like this.
|
||||
//
|
||||
// var err error
|
||||
// for _, item := range items {
|
||||
// if multierr.AppendInto(&err, process(item)) {
|
||||
// log.Warn("skipping item", item)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This will append the error into the err variable, and return true if that
|
||||
// individual error was non-nil.
|
||||
//
|
||||
// See AppendInto for more information.
|
||||
//
|
||||
// Deferred Functions
|
||||
//
|
||||
// Go makes it possible to modify the return value of a function in a defer
|
||||
// block if the function was using named returns. This makes it possible to
|
||||
// record resource cleanup failures from deferred blocks.
|
||||
//
|
||||
// func sendRequest(req Request) (err error) {
|
||||
// conn, err := openConnection()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// defer func() {
|
||||
// err = multierr.Append(err, conn.Close())
|
||||
// }()
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// multierr provides the Invoker type and AppendInvoke function to make cases
|
||||
// like the above simpler and obviate the need for a closure. The following is
|
||||
// roughly equivalent to the example above.
|
||||
//
|
||||
// func sendRequest(req Request) (err error) {
|
||||
// conn, err := openConnection()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// defer multierr.AppendInvoke(err, multierr.Close(conn))
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// See AppendInvoke and Invoker for more information.
|
||||
//
|
||||
// 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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
var (
|
||||
// Separator for single-line error messages.
|
||||
_singlelineSeparator = []byte("; ")
|
||||
|
||||
// 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, a nil slice is returned.
|
||||
//
|
||||
// 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
|
||||
}
|
||||
|
||||
// As attempts to find the first error in the error list that matches the type
|
||||
// of the value that target points to.
|
||||
//
|
||||
// This function allows errors.As to traverse the values stored on the
|
||||
// multierr error.
|
||||
func (merr *multiError) As(target interface{}) bool {
|
||||
for _, err := range merr.Errors() {
|
||||
if errors.As(err, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Is attempts to match the provided error against errors in the error list.
|
||||
//
|
||||
// This function allows errors.Is to traverse the values stored on the
|
||||
// multierr error.
|
||||
func (merr *multiError) Is(target error) bool {
|
||||
for _, err := range merr.Errors() {
|
||||
if errors.Is(err, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
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:])
|
||||
}
|
||||
|
||||
// AppendInto appends an error into the destination of an error pointer and
|
||||
// returns whether the error being appended was non-nil.
|
||||
//
|
||||
// var err error
|
||||
// multierr.AppendInto(&err, r.Close())
|
||||
// multierr.AppendInto(&err, w.Close())
|
||||
//
|
||||
// The above is equivalent to,
|
||||
//
|
||||
// err := multierr.Append(r.Close(), w.Close())
|
||||
//
|
||||
// As AppendInto reports whether the provided error was non-nil, it may be
|
||||
// used to build a multierr error in a loop more ergonomically. For example:
|
||||
//
|
||||
// var err error
|
||||
// for line := range lines {
|
||||
// var item Item
|
||||
// if multierr.AppendInto(&err, parse(line, &item)) {
|
||||
// continue
|
||||
// }
|
||||
// items = append(items, item)
|
||||
// }
|
||||
//
|
||||
// Compare this with a version that relies solely on Append:
|
||||
//
|
||||
// var err error
|
||||
// for line := range lines {
|
||||
// var item Item
|
||||
// if parseErr := parse(line, &item); parseErr != nil {
|
||||
// err = multierr.Append(err, parseErr)
|
||||
// continue
|
||||
// }
|
||||
// items = append(items, item)
|
||||
// }
|
||||
func AppendInto(into *error, err error) (errored bool) {
|
||||
if into == nil {
|
||||
// We panic if 'into' is nil. This is not documented above
|
||||
// because suggesting that the pointer must be non-nil may
|
||||
// confuse users into thinking that the error that it points
|
||||
// to must be non-nil.
|
||||
panic("misuse of multierr.AppendInto: into pointer must not be nil")
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
*into = Append(*into, err)
|
||||
return true
|
||||
}
|
||||
|
||||
// Invoker is an operation that may fail with an error. Use it with
|
||||
// AppendInvoke to append the result of calling the function into an error.
|
||||
// This allows you to conveniently defer capture of failing operations.
|
||||
//
|
||||
// See also, Close and Invoke.
|
||||
type Invoker interface {
|
||||
Invoke() error
|
||||
}
|
||||
|
||||
// Invoke wraps a function which may fail with an error to match the Invoker
|
||||
// interface. Use it to supply functions matching this signature to
|
||||
// AppendInvoke.
|
||||
//
|
||||
// For example,
|
||||
//
|
||||
// func processReader(r io.Reader) (err error) {
|
||||
// scanner := bufio.NewScanner(r)
|
||||
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
|
||||
// for scanner.Scan() {
|
||||
// // ...
|
||||
// }
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// In this example, the following line will construct the Invoker right away,
|
||||
// but defer the invocation of scanner.Err() until the function returns.
|
||||
//
|
||||
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
|
||||
type Invoke func() error
|
||||
|
||||
// Invoke calls the supplied function and returns its result.
|
||||
func (i Invoke) Invoke() error { return i() }
|
||||
|
||||
// Close builds an Invoker that closes the provided io.Closer. Use it with
|
||||
// AppendInvoke to close io.Closers and append their results into an error.
|
||||
//
|
||||
// For example,
|
||||
//
|
||||
// func processFile(path string) (err error) {
|
||||
// f, err := os.Open(path)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// defer multierr.AppendInvoke(&err, multierr.Close(f))
|
||||
// return processReader(f)
|
||||
// }
|
||||
//
|
||||
// In this example, multierr.Close will construct the Invoker right away, but
|
||||
// defer the invocation of f.Close until the function returns.
|
||||
//
|
||||
// defer multierr.AppendInvoke(&err, multierr.Close(f))
|
||||
func Close(closer io.Closer) Invoker {
|
||||
return Invoke(closer.Close)
|
||||
}
|
||||
|
||||
// AppendInvoke appends the result of calling the given Invoker into the
|
||||
// provided error pointer. Use it with named returns to safely defer
|
||||
// invocation of fallible operations until a function returns, and capture the
|
||||
// resulting errors.
|
||||
//
|
||||
// func doSomething(...) (err error) {
|
||||
// // ...
|
||||
// f, err := openFile(..)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// // multierr will call f.Close() when this function returns and
|
||||
// // if the operation fails, its append its error into the
|
||||
// // returned error.
|
||||
// defer multierr.AppendInvoke(&err, multierr.Close(f))
|
||||
//
|
||||
// scanner := bufio.NewScanner(f)
|
||||
// // Similarly, this scheduled scanner.Err to be called and
|
||||
// // inspected when the function returns and append its error
|
||||
// // into the returned error.
|
||||
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
|
||||
//
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// Without defer, AppendInvoke behaves exactly like AppendInto.
|
||||
//
|
||||
// err := // ...
|
||||
// multierr.AppendInvoke(&err, mutltierr.Invoke(foo))
|
||||
//
|
||||
// // ...is roughly equivalent to...
|
||||
//
|
||||
// err := // ...
|
||||
// multierr.AppendInto(&err, foo())
|
||||
//
|
||||
// The advantage of the indirection introduced by Invoker is to make it easy
|
||||
// to defer the invocation of a function. Without this indirection, the
|
||||
// invoked function will be evaluated at the time of the defer block rather
|
||||
// than when the function returns.
|
||||
//
|
||||
// // BAD: This is likely not what the caller intended. This will evaluate
|
||||
// // foo() right away and append its result into the error when the
|
||||
// // function returns.
|
||||
// defer multierr.AppendInto(&err, foo())
|
||||
//
|
||||
// // GOOD: This will defer invocation of foo unutil the function returns.
|
||||
// defer multierr.AppendInvoke(&err, multierr.Invoke(foo))
|
||||
//
|
||||
// multierr provides a few Invoker implementations out of the box for
|
||||
// convenience. See Invoker for more information.
|
||||
func AppendInvoke(into *error, invoker Invoker) {
|
||||
AppendInto(into, invoker.Invoke())
|
||||
}
|
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
|
||||
|
1
vendor/go.uber.org/automaxprocs/.gitignore → vendor/go.uber.org/zap/.gitignore
generated
vendored
1
vendor/go.uber.org/automaxprocs/.gitignore → vendor/go.uber.org/zap/.gitignore
generated
vendored
@ -26,7 +26,6 @@ _testmain.go
|
||||
*.pprof
|
||||
*.out
|
||||
*.log
|
||||
coverage.txt
|
||||
|
||||
/bin
|
||||
cover.out
|
109
vendor/go.uber.org/zap/.readme.tmpl
generated
vendored
Normal file
109
vendor/go.uber.org/zap/.readme.tmpl
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
# :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 the [benchmarks/go.mod][] file. [↩](#anchor-versions)
|
||||
|
||||
[doc-img]: https://pkg.go.dev/badge/go.uber.org/zap
|
||||
[doc]: https://pkg.go.dev/go.uber.org/zap
|
||||
[ci-img]: https://github.com/uber-go/zap/actions/workflows/go.yml/badge.svg
|
||||
[ci]: https://github.com/uber-go/zap/actions/workflows/go.yml
|
||||
[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
|
||||
[benchmarks/go.mod]: https://github.com/uber-go/zap/blob/master/benchmarks/go.mod
|
||||
|
543
vendor/go.uber.org/zap/CHANGELOG.md
generated
vendored
Normal file
543
vendor/go.uber.org/zap/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,543 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 1.20.0 (4 Jan 2022)
|
||||
|
||||
Enhancements:
|
||||
* [#989][]: Add `EncoderConfig.SkipLineEnding` flag to disable adding newline
|
||||
characters between log statements.
|
||||
* [#1039][]: Add `EncoderConfig.NewReflectedEncoder` field to customize JSON
|
||||
encoding of reflected log fields.
|
||||
|
||||
Bugfixes:
|
||||
* [#1011][]: Fix inaccurate precision when encoding complex64 as JSON.
|
||||
* [#554][], [#1017][]: Close JSON namespaces opened in `MarshalLogObject`
|
||||
methods when the methods return.
|
||||
* [#1033][]: Avoid panicking in Sampler core if `thereafter` is zero.
|
||||
|
||||
Other changes:
|
||||
* [#1028][]: Drop support for Go < 1.15.
|
||||
|
||||
[#554]: https://github.com/uber-go/zap/pull/554
|
||||
[#989]: https://github.com/uber-go/zap/pull/989
|
||||
[#1011]: https://github.com/uber-go/zap/pull/1011
|
||||
[#1017]: https://github.com/uber-go/zap/pull/1017
|
||||
[#1028]: https://github.com/uber-go/zap/pull/1028
|
||||
[#1033]: https://github.com/uber-go/zap/pull/1033
|
||||
[#1039]: https://github.com/uber-go/zap/pull/1039
|
||||
|
||||
Thanks to @psrajat, @lruggieri, @sammyrnycreal for their contributions to this release.
|
||||
|
||||
## 1.19.1 (8 Sep 2021)
|
||||
|
||||
Bugfixes:
|
||||
* [#1001][]: JSON: Fix complex number encoding with negative imaginary part. Thanks to @hemantjadon.
|
||||
* [#1003][]: JSON: Fix inaccurate precision when encoding float32.
|
||||
|
||||
[#1001]: https://github.com/uber-go/zap/pull/1001
|
||||
[#1003]: https://github.com/uber-go/zap/pull/1003
|
||||
|
||||
## 1.19.0 (9 Aug 2021)
|
||||
|
||||
Enhancements:
|
||||
* [#975][]: Avoid panicking in Sampler core if the level is out of bounds.
|
||||
* [#984][]: Reduce the size of BufferedWriteSyncer by aligning the fields
|
||||
better.
|
||||
|
||||
[#975]: https://github.com/uber-go/zap/pull/975
|
||||
[#984]: https://github.com/uber-go/zap/pull/984
|
||||
|
||||
Thanks to @lancoLiu and @thockin for their contributions to this release.
|
||||
|
||||
## 1.18.1 (28 Jun 2021)
|
||||
|
||||
Bugfixes:
|
||||
* [#974][]: Fix nil dereference in logger constructed by `zap.NewNop`.
|
||||
|
||||
[#974]: https://github.com/uber-go/zap/pull/974
|
||||
|
||||
## 1.18.0 (28 Jun 2021)
|
||||
|
||||
Enhancements:
|
||||
* [#961][]: Add `zapcore.BufferedWriteSyncer`, a new `WriteSyncer` that buffers
|
||||
messages in-memory and flushes them periodically.
|
||||
* [#971][]: Add `zapio.Writer` to use a Zap logger as an `io.Writer`.
|
||||
* [#897][]: Add `zap.WithClock` option to control the source of time via the
|
||||
new `zapcore.Clock` interface.
|
||||
* [#949][]: Avoid panicking in `zap.SugaredLogger` when arguments of `*w`
|
||||
methods don't match expectations.
|
||||
* [#943][]: Add support for filtering by level or arbitrary matcher function to
|
||||
`zaptest/observer`.
|
||||
* [#691][]: Comply with `io.StringWriter` and `io.ByteWriter` in Zap's
|
||||
`buffer.Buffer`.
|
||||
|
||||
Thanks to @atrn0, @ernado, @heyanfu, @hnlq715, @zchee
|
||||
for their contributions to this release.
|
||||
|
||||
[#691]: https://github.com/uber-go/zap/pull/691
|
||||
[#897]: https://github.com/uber-go/zap/pull/897
|
||||
[#943]: https://github.com/uber-go/zap/pull/943
|
||||
[#949]: https://github.com/uber-go/zap/pull/949
|
||||
[#961]: https://github.com/uber-go/zap/pull/961
|
||||
[#971]: https://github.com/uber-go/zap/pull/971
|
||||
|
||||
## 1.17.0 (25 May 2021)
|
||||
|
||||
Bugfixes:
|
||||
* [#867][]: Encode `<nil>` for nil `error` instead of a panic.
|
||||
* [#931][], [#936][]: Update minimum version constraints to address
|
||||
vulnerabilities in dependencies.
|
||||
|
||||
Enhancements:
|
||||
* [#865][]: Improve alignment of fields of the Logger struct, reducing its
|
||||
size from 96 to 80 bytes.
|
||||
* [#881][]: Support `grpclog.LoggerV2` in zapgrpc.
|
||||
* [#903][]: Support URL-encoded POST requests to the AtomicLevel HTTP handler
|
||||
with the `application/x-www-form-urlencoded` content type.
|
||||
* [#912][]: Support multi-field encoding with `zap.Inline`.
|
||||
* [#913][]: Speed up SugaredLogger for calls with a single string.
|
||||
* [#928][]: Add support for filtering by field name to `zaptest/observer`.
|
||||
|
||||
Thanks to @ash2k, @FMLS, @jimmystewpot, @Oncilla, @tsoslow, @tylitianrui, @withshubh, and @wziww for their contributions to this release.
|
||||
|
||||
## 1.16.0 (1 Sep 2020)
|
||||
|
||||
Bugfixes:
|
||||
* [#828][]: Fix missing newline in IncreaseLevel error messages.
|
||||
* [#835][]: Fix panic in JSON encoder when encoding times or durations
|
||||
without specifying a time or duration encoder.
|
||||
* [#843][]: Honor CallerSkip when taking stack traces.
|
||||
* [#862][]: Fix the default file permissions to use `0666` and rely on the umask instead.
|
||||
* [#854][]: Encode `<nil>` for nil `Stringer` instead of a panic error log.
|
||||
|
||||
Enhancements:
|
||||
* [#629][]: Added `zapcore.TimeEncoderOfLayout` to easily create time encoders
|
||||
for custom layouts.
|
||||
* [#697][]: Added support for a configurable delimiter in the console encoder.
|
||||
* [#852][]: Optimize console encoder by pooling the underlying JSON encoder.
|
||||
* [#844][]: Add ability to include the calling function as part of logs.
|
||||
* [#843][]: Add `StackSkip` for including truncated stacks as a field.
|
||||
* [#861][]: Add options to customize Fatal behaviour for better testability.
|
||||
|
||||
Thanks to @SteelPhase, @tmshn, @lixingwang, @wyxloading, @moul, @segevfiner, @andy-retailnext and @jcorbin for their contributions to this release.
|
||||
|
||||
## 1.15.0 (23 Apr 2020)
|
||||
|
||||
Bugfixes:
|
||||
* [#804][]: Fix handling of `Time` values out of `UnixNano` range.
|
||||
* [#812][]: Fix `IncreaseLevel` being reset after a call to `With`.
|
||||
|
||||
Enhancements:
|
||||
* [#806][]: Add `WithCaller` option to supersede the `AddCaller` option. This
|
||||
allows disabling annotation of log entries with caller information if
|
||||
previously enabled with `AddCaller`.
|
||||
* [#813][]: Deprecate `NewSampler` constructor in favor of
|
||||
`NewSamplerWithOptions` which supports a `SamplerHook` option. This option
|
||||
adds support for monitoring sampling decisions through a hook.
|
||||
|
||||
Thanks to @danielbprice for their contributions to this release.
|
||||
|
||||
## 1.14.1 (14 Mar 2020)
|
||||
|
||||
Bugfixes:
|
||||
* [#791][]: Fix panic on attempting to build a logger with an invalid Config.
|
||||
* [#795][]: Vendoring Zap with `go mod vendor` no longer includes Zap's
|
||||
development-time dependencies.
|
||||
* [#799][]: Fix issue introduced in 1.14.0 that caused invalid JSON output to
|
||||
be generated for arrays of `time.Time` objects when using string-based time
|
||||
formats.
|
||||
|
||||
Thanks to @YashishDua for their contributions to this release.
|
||||
|
||||
## 1.14.0 (20 Feb 2020)
|
||||
|
||||
Enhancements:
|
||||
* [#771][]: Optimize calls for disabled log levels.
|
||||
* [#773][]: Add millisecond duration encoder.
|
||||
* [#775][]: Add option to increase the level of a logger.
|
||||
* [#786][]: Optimize time formatters using `Time.AppendFormat` where possible.
|
||||
|
||||
Thanks to @caibirdme for their contributions to this release.
|
||||
|
||||
## 1.13.0 (13 Nov 2019)
|
||||
|
||||
Enhancements:
|
||||
* [#758][]: Add `Intp`, `Stringp`, and other similar `*p` field constructors
|
||||
to log pointers to primitives with support for `nil` values.
|
||||
|
||||
Thanks to @jbizzle for their contributions to this release.
|
||||
|
||||
## 1.12.0 (29 Oct 2019)
|
||||
|
||||
Enhancements:
|
||||
* [#751][]: Migrate to Go modules.
|
||||
|
||||
## 1.11.0 (21 Oct 2019)
|
||||
|
||||
Enhancements:
|
||||
* [#725][]: Add `zapcore.OmitKey` to omit keys in an `EncoderConfig`.
|
||||
* [#736][]: Add `RFC3339` and `RFC3339Nano` time encoders.
|
||||
|
||||
Thanks to @juicemia, @uhthomas for their contributions to this release.
|
||||
|
||||
## 1.10.0 (29 Apr 2019)
|
||||
|
||||
Bugfixes:
|
||||
* [#657][]: Fix `MapObjectEncoder.AppendByteString` not adding value as a
|
||||
string.
|
||||
* [#706][]: Fix incorrect call depth to determine caller in Go 1.12.
|
||||
|
||||
Enhancements:
|
||||
* [#610][]: Add `zaptest.WrapOptions` to wrap `zap.Option` for creating test
|
||||
loggers.
|
||||
* [#675][]: Don't panic when encoding a String field.
|
||||
* [#704][]: Disable HTML escaping for JSON objects encoded using the
|
||||
reflect-based encoder.
|
||||
|
||||
Thanks to @iaroslav-ciupin, @lelenanam, @joa, @NWilson for their contributions
|
||||
to this release.
|
||||
|
||||
## 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
|
||||
[#657]: https://github.com/uber-go/zap/pull/657
|
||||
[#706]: https://github.com/uber-go/zap/pull/706
|
||||
[#610]: https://github.com/uber-go/zap/pull/610
|
||||
[#675]: https://github.com/uber-go/zap/pull/675
|
||||
[#704]: https://github.com/uber-go/zap/pull/704
|
||||
[#725]: https://github.com/uber-go/zap/pull/725
|
||||
[#736]: https://github.com/uber-go/zap/pull/736
|
||||
[#751]: https://github.com/uber-go/zap/pull/751
|
||||
[#758]: https://github.com/uber-go/zap/pull/758
|
||||
[#771]: https://github.com/uber-go/zap/pull/771
|
||||
[#773]: https://github.com/uber-go/zap/pull/773
|
||||
[#775]: https://github.com/uber-go/zap/pull/775
|
||||
[#786]: https://github.com/uber-go/zap/pull/786
|
||||
[#791]: https://github.com/uber-go/zap/pull/791
|
||||
[#795]: https://github.com/uber-go/zap/pull/795
|
||||
[#799]: https://github.com/uber-go/zap/pull/799
|
||||
[#804]: https://github.com/uber-go/zap/pull/804
|
||||
[#812]: https://github.com/uber-go/zap/pull/812
|
||||
[#806]: https://github.com/uber-go/zap/pull/806
|
||||
[#813]: https://github.com/uber-go/zap/pull/813
|
||||
[#629]: https://github.com/uber-go/zap/pull/629
|
||||
[#697]: https://github.com/uber-go/zap/pull/697
|
||||
[#828]: https://github.com/uber-go/zap/pull/828
|
||||
[#835]: https://github.com/uber-go/zap/pull/835
|
||||
[#843]: https://github.com/uber-go/zap/pull/843
|
||||
[#844]: https://github.com/uber-go/zap/pull/844
|
||||
[#852]: https://github.com/uber-go/zap/pull/852
|
||||
[#854]: https://github.com/uber-go/zap/pull/854
|
||||
[#861]: https://github.com/uber-go/zap/pull/861
|
||||
[#862]: https://github.com/uber-go/zap/pull/862
|
||||
[#865]: https://github.com/uber-go/zap/pull/865
|
||||
[#867]: https://github.com/uber-go/zap/pull/867
|
||||
[#881]: https://github.com/uber-go/zap/pull/881
|
||||
[#903]: https://github.com/uber-go/zap/pull/903
|
||||
[#912]: https://github.com/uber-go/zap/pull/912
|
||||
[#913]: https://github.com/uber-go/zap/pull/913
|
||||
[#928]: https://github.com/uber-go/zap/pull/928
|
||||
[#931]: https://github.com/uber-go/zap/pull/931
|
||||
[#936]: https://github.com/uber-go/zap/pull/936
|
22
vendor/go.uber.org/automaxprocs/CONTRIBUTING.md → vendor/go.uber.org/zap/CONTRIBUTING.md
generated
vendored
22
vendor/go.uber.org/automaxprocs/CONTRIBUTING.md → vendor/go.uber.org/zap/CONTRIBUTING.md
generated
vendored
@ -1,6 +1,6 @@
|
||||
# Contributing
|
||||
|
||||
We'd love your help improving this package!
|
||||
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
|
||||
@ -19,18 +19,12 @@ you to accept the CLA when you open your pull request.
|
||||
```
|
||||
mkdir -p $GOPATH/src/go.uber.org
|
||||
cd $GOPATH/src/go.uber.org
|
||||
git clone git@github.com:your_github_username/automaxprocs.git
|
||||
cd automaxprocs
|
||||
git remote add upstream https://github.com/uber-go/automaxprocs.git
|
||||
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 the test dependencies:
|
||||
|
||||
```
|
||||
make dependencies
|
||||
```
|
||||
|
||||
Make sure that the tests and the linters pass:
|
||||
|
||||
```
|
||||
@ -48,7 +42,7 @@ pull request.
|
||||
Start by creating a new branch for your changes:
|
||||
|
||||
```
|
||||
cd $GOPATH/src/go.uber.org/automaxprocs
|
||||
cd $GOPATH/src/go.uber.org/zap
|
||||
git checkout master
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
@ -75,7 +69,7 @@ We're much more likely to approve your changes if you:
|
||||
* Write a [good commit message][commit-message].
|
||||
* Maintain backward compatibility.
|
||||
|
||||
[fork]: https://github.com/uber-go/automaxprocs/fork
|
||||
[open-issue]: https://github.com/uber-go/automaxprocs/issues/new
|
||||
[cla]: https://cla-assistant.io/uber-go/automaxprocs
|
||||
[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
|
164
vendor/go.uber.org/zap/FAQ.md
generated
vendored
Normal file
164
vendor/go.uber.org/zap/FAQ.md
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
# 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 are some of my logs missing?
|
||||
|
||||
Logs are dropped intentionally by zap when sampling is enabled. The production
|
||||
configuration (as returned by `NewProductionConfig()` enables sampling which will
|
||||
cause repeated logs within a second to be sampled. See more details on why sampling
|
||||
is enabled in [Why sample application logs](https://github.com/uber-go/zap/blob/master/FAQ.md#why-sample-application-logs).
|
||||
|
||||
### 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 |
|
||||
| `github.com/moul/zapgorm` | Gorm |
|
||||
| `github.com/moul/zapfilter` | Advanced filtering rules |
|
||||
|
||||
[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.
|
73
vendor/go.uber.org/zap/Makefile
generated
vendored
Normal file
73
vendor/go.uber.org/zap/Makefile
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
export GOBIN ?= $(shell pwd)/bin
|
||||
|
||||
GOLINT = $(GOBIN)/golint
|
||||
STATICCHECK = $(GOBIN)/staticcheck
|
||||
BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem
|
||||
|
||||
# Directories containing independent Go modules.
|
||||
#
|
||||
# We track coverage only for the main module.
|
||||
MODULE_DIRS = . ./benchmarks ./zapgrpc/internal/test
|
||||
|
||||
# Many Go tools take file globs or directories as arguments instead of packages.
|
||||
GO_FILES := $(shell \
|
||||
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
|
||||
-o -name '*.go' -print | cut -b3-)
|
||||
|
||||
.PHONY: all
|
||||
all: lint test
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(GOLINT) $(STATICCHECK)
|
||||
@rm -rf lint.log
|
||||
@echo "Checking formatting..."
|
||||
@gofmt -d -s $(GO_FILES) 2>&1 | tee lint.log
|
||||
@echo "Checking vet..."
|
||||
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go vet ./... 2>&1) &&) true | tee -a lint.log
|
||||
@echo "Checking lint..."
|
||||
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && $(GOLINT) ./... 2>&1) &&) true | tee -a lint.log
|
||||
@echo "Checking staticcheck..."
|
||||
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && $(STATICCHECK) ./... 2>&1) &&) true | tee -a lint.log
|
||||
@echo "Checking for unresolved FIXMEs..."
|
||||
@git grep -i fixme | grep -v -e Makefile | tee -a lint.log
|
||||
@echo "Checking for license headers..."
|
||||
@./checklicense.sh | tee -a lint.log
|
||||
@[ ! -s lint.log ]
|
||||
@echo "Checking 'go mod tidy'..."
|
||||
@make tidy
|
||||
@if ! git diff --quiet; then \
|
||||
echo "'go mod tidy' resulted in changes or working tree is dirty:"; \
|
||||
git --no-pager diff; \
|
||||
fi
|
||||
|
||||
$(GOLINT):
|
||||
cd tools && go install golang.org/x/lint/golint
|
||||
|
||||
$(STATICCHECK):
|
||||
cd tools && go install honnef.co/go/tools/cmd/staticcheck
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go test -race ./...) &&) true
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
go test -race -coverprofile=cover.out -coverpkg=./... ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
.PHONY: bench
|
||||
BENCH ?= .
|
||||
bench:
|
||||
@$(foreach dir,$(MODULE_DIRS), ( \
|
||||
cd $(dir) && \
|
||||
go list ./... | xargs -n1 go test -bench=$(BENCH) -run="^$$" $(BENCH_FLAGS) \
|
||||
) &&) true
|
||||
|
||||
.PHONY: updatereadme
|
||||
updatereadme:
|
||||
rm -f README.md
|
||||
cat .readme.tmpl | go run internal/readme/readme.go > README.md
|
||||
|
||||
.PHONY: tidy
|
||||
tidy:
|
||||
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go mod tidy) &&) true
|
134
vendor/go.uber.org/zap/README.md
generated
vendored
Normal file
134
vendor/go.uber.org/zap/README.md
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
# :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 | Time % to zap | Objects Allocated |
|
||||
| :------ | :--: | :-----------: | :---------------: |
|
||||
| :zap: zap | 2900 ns/op | +0% | 5 allocs/op
|
||||
| :zap: zap (sugared) | 3475 ns/op | +20% | 10 allocs/op
|
||||
| zerolog | 10639 ns/op | +267% | 32 allocs/op
|
||||
| go-kit | 14434 ns/op | +398% | 59 allocs/op
|
||||
| logrus | 17104 ns/op | +490% | 81 allocs/op
|
||||
| apex/log | 32424 ns/op | +1018% | 66 allocs/op
|
||||
| log15 | 33579 ns/op | +1058% | 76 allocs/op
|
||||
|
||||
Log a message with a logger that already has 10 fields of context:
|
||||
|
||||
| Package | Time | Time % to zap | Objects Allocated |
|
||||
| :------ | :--: | :-----------: | :---------------: |
|
||||
| :zap: zap | 373 ns/op | +0% | 0 allocs/op
|
||||
| :zap: zap (sugared) | 452 ns/op | +21% | 1 allocs/op
|
||||
| zerolog | 288 ns/op | -23% | 0 allocs/op
|
||||
| go-kit | 11785 ns/op | +3060% | 58 allocs/op
|
||||
| logrus | 19629 ns/op | +5162% | 70 allocs/op
|
||||
| log15 | 21866 ns/op | +5762% | 72 allocs/op
|
||||
| apex/log | 30890 ns/op | +8182% | 55 allocs/op
|
||||
|
||||
Log a static string, without any context or `printf`-style templating:
|
||||
|
||||
| Package | Time | Time % to zap | Objects Allocated |
|
||||
| :------ | :--: | :-----------: | :---------------: |
|
||||
| :zap: zap | 381 ns/op | +0% | 0 allocs/op
|
||||
| :zap: zap (sugared) | 410 ns/op | +8% | 1 allocs/op
|
||||
| zerolog | 369 ns/op | -3% | 0 allocs/op
|
||||
| standard library | 385 ns/op | +1% | 2 allocs/op
|
||||
| go-kit | 606 ns/op | +59% | 11 allocs/op
|
||||
| logrus | 1730 ns/op | +354% | 25 allocs/op
|
||||
| apex/log | 1998 ns/op | +424% | 7 allocs/op
|
||||
| log15 | 4546 ns/op | +1093% | 22 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 the [benchmarks/go.mod][] file. [↩](#anchor-versions)
|
||||
|
||||
[doc-img]: https://pkg.go.dev/badge/go.uber.org/zap
|
||||
[doc]: https://pkg.go.dev/go.uber.org/zap
|
||||
[ci-img]: https://github.com/uber-go/zap/actions/workflows/go.yml/badge.svg
|
||||
[ci]: https://github.com/uber-go/zap/actions/workflows/go.yml
|
||||
[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
|
||||
[benchmarks/go.mod]: https://github.com/uber-go/zap/blob/master/benchmarks/go.mod
|
||||
|
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
|
||||
}
|
141
vendor/go.uber.org/zap/buffer/buffer.go
generated
vendored
Normal file
141
vendor/go.uber.org/zap/buffer/buffer.go
generated
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
// 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"
|
||||
"time"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// AppendTime appends the time formatted using the specified layout.
|
||||
func (b *Buffer) AppendTime(t time.Time, layout string) {
|
||||
b.bs = t.AppendFormat(b.bs, layout)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte to the Buffer.
|
||||
//
|
||||
// Error returned is always nil, function signature is compatible
|
||||
// with bytes.Buffer and bufio.Writer
|
||||
func (b *Buffer) WriteByte(v byte) error {
|
||||
b.AppendByte(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteString writes a string to the Buffer.
|
||||
//
|
||||
// Error returned is always nil, function signature is compatible
|
||||
// with bytes.Buffer and bufio.Writer
|
||||
func (b *Buffer) WriteString(s string) (int, error) {
|
||||
b.AppendString(s)
|
||||
return len(s), 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/checklicense.sh
generated
vendored
Normal file
17
vendor/go.uber.org/zap/checklicense.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
|
264
vendor/go.uber.org/zap/config.go
generated
vendored
Normal file
264
vendor/go.uber.org/zap/config.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
||||
// 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"
|
||||
"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.
|
||||
//
|
||||
// If specified, the Sampler will invoke the Hook after each decision.
|
||||
//
|
||||
// Values configured here are per-second. See zapcore.NewSamplerWithOptions for
|
||||
// details.
|
||||
type SamplingConfig struct {
|
||||
Initial int `json:"initial" yaml:"initial"`
|
||||
Thereafter int `json:"thereafter" yaml:"thereafter"`
|
||||
Hook func(zapcore.Entry, zapcore.SamplingDecision) `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// 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",
|
||||
FunctionKey: zapcore.OmitKey,
|
||||
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",
|
||||
FunctionKey: zapcore.OmitKey,
|
||||
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
|
||||
}
|
||||
|
||||
if cfg.Level == (AtomicLevel{}) {
|
||||
return nil, fmt.Errorf("missing Level")
|
||||
}
|
||||
|
||||
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 scfg := cfg.Sampling; scfg != nil {
|
||||
opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core {
|
||||
var samplerOpts []zapcore.SamplerOption
|
||||
if scfg.Hook != nil {
|
||||
samplerOpts = append(samplerOpts, zapcore.SamplerHook(scfg.Hook))
|
||||
}
|
||||
return zapcore.NewSamplerWithOptions(
|
||||
core,
|
||||
time.Second,
|
||||
cfg.Sampling.Initial,
|
||||
cfg.Sampling.Thereafter,
|
||||
samplerOpts...,
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
||||
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"
|
79
vendor/go.uber.org/zap/encoder.go
generated
vendored
Normal file
79
vendor/go.uber.org/zap/encoder.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// 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) {
|
||||
if encoderConfig.TimeKey != "" && encoderConfig.EncodeTime == nil {
|
||||
return nil, fmt.Errorf("missing EncodeTime in EncoderConfig")
|
||||
}
|
||||
|
||||
_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
|
||||
}
|
549
vendor/go.uber.org/zap/field.go
generated
vendored
Normal file
549
vendor/go.uber.org/zap/field.go
generated
vendored
Normal file
@ -0,0 +1,549 @@
|
||||
// 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
|
||||
|
||||
var (
|
||||
_minTimeInt64 = time.Unix(0, math.MinInt64)
|
||||
_maxTimeInt64 = time.Unix(0, math.MaxInt64)
|
||||
)
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// nilField returns a field which will marshal explicitly as nil. See motivation
|
||||
// in https://github.com/uber-go/zap/issues/753 . If we ever make breaking
|
||||
// changes and add zapcore.NilType and zapcore.ObjectEncoder.AddNil, the
|
||||
// implementation here should be changed to reflect that.
|
||||
func nilField(key string) Field { return Reflect(key, nil) }
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// Boolp constructs a field that carries a *bool. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Boolp(key string, val *bool) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Bool(key, *val)
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// Complex128p constructs a field that carries a *complex128. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Complex128p(key string, val *complex128) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Complex128(key, *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}
|
||||
}
|
||||
|
||||
// Complex64p constructs a field that carries a *complex64. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Complex64p(key string, val *complex64) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Complex64(key, *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))}
|
||||
}
|
||||
|
||||
// Float64p constructs a field that carries a *float64. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Float64p(key string, val *float64) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Float64(key, *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))}
|
||||
}
|
||||
|
||||
// Float32p constructs a field that carries a *float32. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Float32p(key string, val *float32) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Float32(key, *val)
|
||||
}
|
||||
|
||||
// Int constructs a field with the given key and value.
|
||||
func Int(key string, val int) Field {
|
||||
return Int64(key, int64(val))
|
||||
}
|
||||
|
||||
// Intp constructs a field that carries a *int. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Intp(key string, val *int) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Int(key, *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}
|
||||
}
|
||||
|
||||
// Int64p constructs a field that carries a *int64. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Int64p(key string, val *int64) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Int64(key, *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)}
|
||||
}
|
||||
|
||||
// Int32p constructs a field that carries a *int32. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Int32p(key string, val *int32) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Int32(key, *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)}
|
||||
}
|
||||
|
||||
// Int16p constructs a field that carries a *int16. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Int16p(key string, val *int16) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Int16(key, *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)}
|
||||
}
|
||||
|
||||
// Int8p constructs a field that carries a *int8. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Int8p(key string, val *int8) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Int8(key, *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}
|
||||
}
|
||||
|
||||
// Stringp constructs a field that carries a *string. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Stringp(key string, val *string) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return String(key, *val)
|
||||
}
|
||||
|
||||
// Uint constructs a field with the given key and value.
|
||||
func Uint(key string, val uint) Field {
|
||||
return Uint64(key, uint64(val))
|
||||
}
|
||||
|
||||
// Uintp constructs a field that carries a *uint. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Uintp(key string, val *uint) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Uint(key, *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)}
|
||||
}
|
||||
|
||||
// Uint64p constructs a field that carries a *uint64. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Uint64p(key string, val *uint64) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Uint64(key, *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)}
|
||||
}
|
||||
|
||||
// Uint32p constructs a field that carries a *uint32. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Uint32p(key string, val *uint32) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Uint32(key, *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)}
|
||||
}
|
||||
|
||||
// Uint16p constructs a field that carries a *uint16. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Uint16p(key string, val *uint16) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Uint16(key, *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)}
|
||||
}
|
||||
|
||||
// Uint8p constructs a field that carries a *uint8. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Uint8p(key string, val *uint8) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Uint8(key, *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)}
|
||||
}
|
||||
|
||||
// Uintptrp constructs a field that carries a *uintptr. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Uintptrp(key string, val *uintptr) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Uintptr(key, *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 {
|
||||
if val.Before(_minTimeInt64) || val.After(_maxTimeInt64) {
|
||||
return Field{Key: key, Type: zapcore.TimeFullType, Interface: val}
|
||||
}
|
||||
return Field{Key: key, Type: zapcore.TimeType, Integer: val.UnixNano(), Interface: val.Location()}
|
||||
}
|
||||
|
||||
// Timep constructs a field that carries a *time.Time. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Timep(key string, val *time.Time) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Time(key, *val)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return StackSkip(key, 1) // skip Stack
|
||||
}
|
||||
|
||||
// StackSkip constructs a field similarly to Stack, but also skips the given
|
||||
// number of frames from the top of the stacktrace.
|
||||
func StackSkip(key string, skip int) 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(skip+1)) // skip StackSkip
|
||||
}
|
||||
|
||||
// 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)}
|
||||
}
|
||||
|
||||
// Durationp constructs a field that carries a *time.Duration. The returned Field will safely
|
||||
// and explicitly represent `nil` when appropriate.
|
||||
func Durationp(key string, val *time.Duration) Field {
|
||||
if val == nil {
|
||||
return nilField(key)
|
||||
}
|
||||
return Duration(key, *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}
|
||||
}
|
||||
|
||||
// Inline constructs a Field that is similar to Object, but it
|
||||
// will add the elements of the provided ObjectMarshaler to the
|
||||
// current namespace.
|
||||
func Inline(val zapcore.ObjectMarshaler) Field {
|
||||
return zapcore.Field{
|
||||
Type: zapcore.InlineMarshalerType,
|
||||
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 Boolp(key, val)
|
||||
case []bool:
|
||||
return Bools(key, val)
|
||||
case complex128:
|
||||
return Complex128(key, val)
|
||||
case *complex128:
|
||||
return Complex128p(key, val)
|
||||
case []complex128:
|
||||
return Complex128s(key, val)
|
||||
case complex64:
|
||||
return Complex64(key, val)
|
||||
case *complex64:
|
||||
return Complex64p(key, val)
|
||||
case []complex64:
|
||||
return Complex64s(key, val)
|
||||
case float64:
|
||||
return Float64(key, val)
|
||||
case *float64:
|
||||
return Float64p(key, val)
|
||||
case []float64:
|
||||
return Float64s(key, val)
|
||||
case float32:
|
||||
return Float32(key, val)
|
||||
case *float32:
|
||||
return Float32p(key, val)
|
||||
case []float32:
|
||||
return Float32s(key, val)
|
||||
case int:
|
||||
return Int(key, val)
|
||||
case *int:
|
||||
return Intp(key, val)
|
||||
case []int:
|
||||
return Ints(key, val)
|
||||
case int64:
|
||||
return Int64(key, val)
|
||||
case *int64:
|
||||
return Int64p(key, val)
|
||||
case []int64:
|
||||
return Int64s(key, val)
|
||||
case int32:
|
||||
return Int32(key, val)
|
||||
case *int32:
|
||||
return Int32p(key, val)
|
||||
case []int32:
|
||||
return Int32s(key, val)
|
||||
case int16:
|
||||
return Int16(key, val)
|
||||
case *int16:
|
||||
return Int16p(key, val)
|
||||
case []int16:
|
||||
return Int16s(key, val)
|
||||
case int8:
|
||||
return Int8(key, val)
|
||||
case *int8:
|
||||
return Int8p(key, val)
|
||||
case []int8:
|
||||
return Int8s(key, val)
|
||||
case string:
|
||||
return String(key, val)
|
||||
case *string:
|
||||
return Stringp(key, val)
|
||||
case []string:
|
||||
return Strings(key, val)
|
||||
case uint:
|
||||
return Uint(key, val)
|
||||
case *uint:
|
||||
return Uintp(key, val)
|
||||
case []uint:
|
||||
return Uints(key, val)
|
||||
case uint64:
|
||||
return Uint64(key, val)
|
||||
case *uint64:
|
||||
return Uint64p(key, val)
|
||||
case []uint64:
|
||||
return Uint64s(key, val)
|
||||
case uint32:
|
||||
return Uint32(key, val)
|
||||
case *uint32:
|
||||
return Uint32p(key, val)
|
||||
case []uint32:
|
||||
return Uint32s(key, val)
|
||||
case uint16:
|
||||
return Uint16(key, val)
|
||||
case *uint16:
|
||||
return Uint16p(key, val)
|
||||
case []uint16:
|
||||
return Uint16s(key, val)
|
||||
case uint8:
|
||||
return Uint8(key, val)
|
||||
case *uint8:
|
||||
return Uint8p(key, val)
|
||||
case []byte:
|
||||
return Binary(key, val)
|
||||
case uintptr:
|
||||
return Uintptr(key, val)
|
||||
case *uintptr:
|
||||
return Uintptrp(key, val)
|
||||
case []uintptr:
|
||||
return Uintptrs(key, val)
|
||||
case time.Time:
|
||||
return Time(key, val)
|
||||
case *time.Time:
|
||||
return Timep(key, val)
|
||||
case []time.Time:
|
||||
return Times(key, val)
|
||||
case time.Duration:
|
||||
return Duration(key, val)
|
||||
case *time.Duration:
|
||||
return Durationp(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
|
||||
}
|
34
vendor/go.uber.org/zap/glide.yaml
generated
vendored
Normal file
34
vendor/go.uber.org/zap/glide.yaml
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
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: github.com/rs/zerolog
|
||||
- package: golang.org/x/tools
|
||||
subpackages:
|
||||
- cover
|
||||
- package: golang.org/x/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 = 1
|
||||
_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
|
||||
}
|
132
vendor/go.uber.org/zap/http_handler.go
generated
vendored
Normal file
132
vendor/go.uber.org/zap/http_handler.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 (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// ServeHTTP is a simple JSON endpoint that can report on or change the current
|
||||
// logging level.
|
||||
//
|
||||
// GET
|
||||
//
|
||||
// The GET request returns a JSON description of the current logging level like:
|
||||
// {"level":"info"}
|
||||
//
|
||||
// PUT
|
||||
//
|
||||
// The PUT request changes the logging level. It is perfectly safe to change the
|
||||
// logging level while a program is running. Two content types are supported:
|
||||
//
|
||||
// Content-Type: application/x-www-form-urlencoded
|
||||
//
|
||||
// With this content type, the level can be provided through the request body or
|
||||
// a query parameter. The log level is URL encoded like:
|
||||
//
|
||||
// level=debug
|
||||
//
|
||||
// The request body takes precedence over the query parameter, if both are
|
||||
// specified.
|
||||
//
|
||||
// This content type is the default for a curl PUT request. Following are two
|
||||
// example curl requests that both set the logging level to debug.
|
||||
//
|
||||
// curl -X PUT localhost:8080/log/level?level=debug
|
||||
// curl -X PUT localhost:8080/log/level -d level=debug
|
||||
//
|
||||
// For any other content type, the payload is expected to be JSON encoded and
|
||||
// look like:
|
||||
//
|
||||
// {"level":"info"}
|
||||
//
|
||||
// An example curl request could look like this:
|
||||
//
|
||||
// curl -X PUT localhost:8080/log/level -H "Content-Type: application/json" -d '{"level":"debug"}'
|
||||
//
|
||||
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:
|
||||
enc.Encode(payload{Level: lvl.Level()})
|
||||
case http.MethodPut:
|
||||
requestedLvl, err := decodePutRequest(r.Header.Get("Content-Type"), r)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
enc.Encode(errorResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
lvl.SetLevel(requestedLvl)
|
||||
enc.Encode(payload{Level: lvl.Level()})
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
enc.Encode(errorResponse{
|
||||
Error: "Only GET and PUT are supported.",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Decodes incoming PUT requests and returns the requested logging level.
|
||||
func decodePutRequest(contentType string, r *http.Request) (zapcore.Level, error) {
|
||||
if contentType == "application/x-www-form-urlencoded" {
|
||||
return decodePutURL(r)
|
||||
}
|
||||
return decodePutJSON(r.Body)
|
||||
}
|
||||
|
||||
func decodePutURL(r *http.Request) (zapcore.Level, error) {
|
||||
lvl := r.FormValue("level")
|
||||
if lvl == "" {
|
||||
return 0, fmt.Errorf("must specify logging level")
|
||||
}
|
||||
var l zapcore.Level
|
||||
if err := l.UnmarshalText([]byte(lvl)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func decodePutJSON(body io.Reader) (zapcore.Level, error) {
|
||||
var pld struct {
|
||||
Level *zapcore.Level `json:"level"`
|
||||
}
|
||||
if err := json.NewDecoder(body).Decode(&pld); err != nil {
|
||||
return 0, fmt.Errorf("malformed request body: %v", err)
|
||||
}
|
||||
if pld.Level == nil {
|
||||
return 0, fmt.Errorf("must specify logging level")
|
||||
}
|
||||
return *pld.Level, nil
|
||||
|
||||
}
|
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()
|
||||
}
|
348
vendor/go.uber.org/zap/logger.go
generated
vendored
Normal file
348
vendor/go.uber.org/zap/logger.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 zap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"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
|
||||
addCaller bool
|
||||
onFatal zapcore.CheckWriteAction // default is WriteThenFatal
|
||||
|
||||
name string
|
||||
errorOutput zapcore.WriteSyncer
|
||||
|
||||
addStack zapcore.LevelEnabler
|
||||
|
||||
callerSkip int
|
||||
|
||||
clock zapcore.Clock
|
||||
}
|
||||
|
||||
// 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,
|
||||
clock: zapcore.DefaultClock,
|
||||
}
|
||||
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,
|
||||
clock: zapcore.DefaultClock,
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
// Check the level first to reduce the cost of disabled log calls.
|
||||
// Since Panic and higher may exit, we skip the optimization for those levels.
|
||||
if lvl < zapcore.DPanicLevel && !log.core.Enabled(lvl) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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: log.clock.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:
|
||||
onFatal := log.onFatal
|
||||
// Noop is the default value for CheckWriteAction, and it leads to
|
||||
// continued execution after a Fatal which is unexpected.
|
||||
if onFatal == zapcore.WriteThenNoop {
|
||||
onFatal = zapcore.WriteThenFatal
|
||||
}
|
||||
ce = ce.Should(ent, onFatal)
|
||||
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 {
|
||||
frame, defined := getCallerFrame(log.callerSkip + callerSkipOffset)
|
||||
if !defined {
|
||||
fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", ent.Time.UTC())
|
||||
log.errorOutput.Sync()
|
||||
}
|
||||
|
||||
ce.Entry.Caller = zapcore.EntryCaller{
|
||||
Defined: defined,
|
||||
PC: frame.PC,
|
||||
File: frame.File,
|
||||
Line: frame.Line,
|
||||
Function: frame.Function,
|
||||
}
|
||||
}
|
||||
if log.addStack.Enabled(ce.Entry.Level) {
|
||||
ce.Entry.Stack = StackSkip("", log.callerSkip+callerSkipOffset).String
|
||||
}
|
||||
|
||||
return ce
|
||||
}
|
||||
|
||||
// getCallerFrame gets caller frame. The argument skip is the number of stack
|
||||
// frames to ascend, with 0 identifying the caller of getCallerFrame. The
|
||||
// boolean ok is false if it was not possible to recover the information.
|
||||
//
|
||||
// Note: This implementation is similar to runtime.Caller, but it returns the whole frame.
|
||||
func getCallerFrame(skip int) (frame runtime.Frame, ok bool) {
|
||||
const skipOffset = 2 // skip getCallerFrame and Callers
|
||||
|
||||
pc := make([]uintptr, 1)
|
||||
numFrames := runtime.Callers(skip+skipOffset, pc)
|
||||
if numFrames < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
frame, _ = runtime.CallersFrames(pc).Next()
|
||||
return frame, frame.PC != 0
|
||||
}
|
148
vendor/go.uber.org/zap/options.go
generated
vendored
Normal file
148
vendor/go.uber.org/zap/options.go
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// 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,
|
||||
// line number, and function name of zap's caller. See also WithCaller.
|
||||
func AddCaller() Option {
|
||||
return WithCaller(true)
|
||||
}
|
||||
|
||||
// WithCaller configures the Logger to annotate each message with the filename,
|
||||
// line number, and function name of zap's caller, or not, depending on the
|
||||
// value of enabled. This is a generalized form of AddCaller.
|
||||
func WithCaller(enabled bool) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.addCaller = enabled
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
})
|
||||
}
|
||||
|
||||
// IncreaseLevel increase the level of the logger. It has no effect if
|
||||
// the passed in level tries to decrease the level of the logger.
|
||||
func IncreaseLevel(lvl zapcore.LevelEnabler) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
core, err := zapcore.NewIncreaseLevelCore(log.core, lvl)
|
||||
if err != nil {
|
||||
fmt.Fprintf(log.errorOutput, "failed to IncreaseLevel: %v\n", err)
|
||||
} else {
|
||||
log.core = core
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// OnFatal sets the action to take on fatal logs.
|
||||
func OnFatal(action zapcore.CheckWriteAction) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.onFatal = action
|
||||
})
|
||||
}
|
||||
|
||||
// WithClock specifies the clock used by the logger to determine the current
|
||||
// time for logged entries. Defaults to the system clock with time.Now.
|
||||
func WithClock(clock zapcore.Clock) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.clock = clock
|
||||
})
|
||||
}
|
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, 0666)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user