mirror of
https://github.com/mudler/luet.git
synced 2025-07-31 06:50:21 +00:00
Add vendor go.uber.org/zap
This commit is contained in:
parent
20654d5dbb
commit
4433fc72ac
16
go.mod
16
go.mod
@ -9,6 +9,7 @@ require (
|
||||
github.com/asdine/storm v0.0.0-20190418133842-e0f77eada154
|
||||
github.com/briandowns/spinner v1.7.0
|
||||
github.com/cavaliercoder/grab v2.0.0+incompatible
|
||||
github.com/creack/pty v1.1.9 // indirect
|
||||
github.com/crillab/gophersat v1.1.7
|
||||
github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
@ -16,6 +17,7 @@ require (
|
||||
github.com/hashicorp/go-version v1.2.0
|
||||
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
|
||||
github.com/klauspost/pgzip v1.2.1
|
||||
github.com/kr/pretty v0.2.0 // indirect
|
||||
github.com/kyokomi/emoji v2.1.0+incompatible
|
||||
github.com/logrusorgru/aurora v0.0.0-20190417123914-21d75270181e
|
||||
github.com/marcsauter/single v0.0.0-20181104081128-f8bf46f26ec0
|
||||
@ -27,15 +29,23 @@ require (
|
||||
github.com/pelletier/go-toml v1.6.0 // indirect
|
||||
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/rogpeppe/go-internal v1.5.1 // indirect
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.5.0
|
||||
github.com/stevenle/topsort v0.0.0-20130922064739-8130c1d7596b
|
||||
go.etcd.io/bbolt v1.3.3
|
||||
golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152 // indirect
|
||||
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.5
|
||||
go.uber.org/atomic v1.5.1 // indirect
|
||||
go.uber.org/multierr v1.4.0 // indirect
|
||||
go.uber.org/zap v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 // indirect
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
|
||||
golang.org/x/sys v0.0.0-20200102141924-c96a22e43c9c // indirect
|
||||
golang.org/x/tools v0.0.0-20200102200121-6de373a2766c // indirect
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.7
|
||||
mvdan.cc/sh v2.6.4+incompatible // indirect
|
||||
mvdan.cc/sh/v3 v3.0.0-beta1
|
||||
)
|
||||
|
41
go.sum
41
go.sum
@ -59,6 +59,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/crillab/gophersat v1.1.7 h1:f2Phe0W9jGyN1OefygKdcTdNM99q/goSjbWrFRjZGWc=
|
||||
github.com/crillab/gophersat v1.1.7/go.mod h1:S91tHga1PCZzYhCkStwZAhvp1rCc+zqtSi55I+vDWGc=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||
@ -111,6 +112,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
@ -150,6 +152,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
@ -226,7 +229,9 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.5.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rootless-containers/proto v0.1.0 h1:gS1JOMEtk1YDYHCzBAf/url+olMJbac7MTrgSeP6zh4=
|
||||
github.com/rootless-containers/proto v0.1.0/go.mod h1:vgkUFZbQd0gcE/K/ZwtE4MYjZPu0UNHLXIQxhyqAFh8=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
@ -300,19 +305,39 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
|
||||
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
|
||||
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152 h1:ZC1Xn5A1nlpSmQCIva4bZ3ob3lmhYIefc+GU+DLg1Ow=
|
||||
golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc=
|
||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -323,6 +348,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2 h1:4dVFTC832rPn4pomLSz1vA+are2+dU19w1H8OngV7nc=
|
||||
golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -347,6 +374,8 @@ golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9Y
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 h1:Hynbrlo6LbYI3H1IqXpkVDOcX/3HiPdhVEuyj5a59RM=
|
||||
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200102141924-c96a22e43c9c h1:OYFUffxXPezb7BVTx9AaD4Vl0qtxmklBIkwCKH1YwDY=
|
||||
golang.org/x/sys v0.0.0-20200102141924-c96a22e43c9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@ -355,10 +384,18 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/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-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190913181337-0240832f5c3d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200102200121-6de373a2766c h1:PBxLbymhzlh6kZuAXmeh8JK2tAJR0GM5Q/W71G2QJ40=
|
||||
golang.org/x/tools v0.0.0-20200102200121-6de373a2766c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
@ -384,9 +421,13 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v2.1.0+incompatible h1:5USw7CrJBYKqjg9R7QlA6jzqZKEAtvW82aNmsxxGPxw=
|
||||
gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
mvdan.cc/editorconfig v0.1.1-0.20191109213504-890940e3f00e/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8=
|
||||
mvdan.cc/sh v2.6.4+incompatible h1:eD6tDeh0pw+/TOTI1BBEryZ02rD2nMcFsgcvde7jffM=
|
||||
mvdan.cc/sh v2.6.4+incompatible/go.mod h1:IeeQbZq+x2SUGBensq/jge5lLQbS3XT2ktyp3wrt4x8=
|
||||
|
5
vendor/github.com/BurntSushi/toml/.gitignore
generated
vendored
Normal file
5
vendor/github.com/BurntSushi/toml/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
TAGS
|
||||
tags
|
||||
.*.swp
|
||||
tomlcheck/tomlcheck
|
||||
toml.test
|
15
vendor/github.com/BurntSushi/toml/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/BurntSushi/toml/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
install:
|
||||
- go install ./...
|
||||
- go get github.com/BurntSushi/toml-test
|
||||
script:
|
||||
- export PATH="$PATH:$HOME/gopath/bin"
|
||||
- make test
|
3
vendor/github.com/BurntSushi/toml/COMPATIBLE
generated
vendored
Normal file
3
vendor/github.com/BurntSushi/toml/COMPATIBLE
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
Compatible with TOML version
|
||||
[v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md)
|
||||
|
21
vendor/github.com/BurntSushi/toml/COPYING
generated
vendored
Normal file
21
vendor/github.com/BurntSushi/toml/COPYING
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 TOML authors
|
||||
|
||||
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.
|
19
vendor/github.com/BurntSushi/toml/Makefile
generated
vendored
Normal file
19
vendor/github.com/BurntSushi/toml/Makefile
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
install:
|
||||
go install ./...
|
||||
|
||||
test: install
|
||||
go test -v
|
||||
toml-test toml-test-decoder
|
||||
toml-test -encoder toml-test-encoder
|
||||
|
||||
fmt:
|
||||
gofmt -w *.go */*.go
|
||||
colcheck *.go */*.go
|
||||
|
||||
tags:
|
||||
find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS
|
||||
|
||||
push:
|
||||
git push origin master
|
||||
git push github master
|
||||
|
218
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
Normal file
218
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
## TOML parser and encoder for Go with reflection
|
||||
|
||||
TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
|
||||
reflection interface similar to Go's standard library `json` and `xml`
|
||||
packages. This package also supports the `encoding.TextUnmarshaler` and
|
||||
`encoding.TextMarshaler` interfaces so that you can define custom data
|
||||
representations. (There is an example of this below.)
|
||||
|
||||
Spec: https://github.com/toml-lang/toml
|
||||
|
||||
Compatible with TOML version
|
||||
[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
|
||||
|
||||
Documentation: https://godoc.org/github.com/BurntSushi/toml
|
||||
|
||||
Installation:
|
||||
|
||||
```bash
|
||||
go get github.com/BurntSushi/toml
|
||||
```
|
||||
|
||||
Try the toml validator:
|
||||
|
||||
```bash
|
||||
go get github.com/BurntSushi/toml/cmd/tomlv
|
||||
tomlv some-toml-file.toml
|
||||
```
|
||||
|
||||
[](https://travis-ci.org/BurntSushi/toml) [](https://godoc.org/github.com/BurntSushi/toml)
|
||||
|
||||
### Testing
|
||||
|
||||
This package passes all tests in
|
||||
[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder
|
||||
and the encoder.
|
||||
|
||||
### Examples
|
||||
|
||||
This package works similarly to how the Go standard library handles `XML`
|
||||
and `JSON`. Namely, data is loaded into Go values via reflection.
|
||||
|
||||
For the simplest example, consider some TOML file as just a list of keys
|
||||
and values:
|
||||
|
||||
```toml
|
||||
Age = 25
|
||||
Cats = [ "Cauchy", "Plato" ]
|
||||
Pi = 3.14
|
||||
Perfection = [ 6, 28, 496, 8128 ]
|
||||
DOB = 1987-07-05T05:45:00Z
|
||||
```
|
||||
|
||||
Which could be defined in Go as:
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Age int
|
||||
Cats []string
|
||||
Pi float64
|
||||
Perfection []int
|
||||
DOB time.Time // requires `import time`
|
||||
}
|
||||
```
|
||||
|
||||
And then decoded with:
|
||||
|
||||
```go
|
||||
var conf Config
|
||||
if _, err := toml.Decode(tomlData, &conf); err != nil {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
You can also use struct tags if your struct field name doesn't map to a TOML
|
||||
key value directly:
|
||||
|
||||
```toml
|
||||
some_key_NAME = "wat"
|
||||
```
|
||||
|
||||
```go
|
||||
type TOML struct {
|
||||
ObscureKey string `toml:"some_key_NAME"`
|
||||
}
|
||||
```
|
||||
|
||||
### Using the `encoding.TextUnmarshaler` interface
|
||||
|
||||
Here's an example that automatically parses duration strings into
|
||||
`time.Duration` values:
|
||||
|
||||
```toml
|
||||
[[song]]
|
||||
name = "Thunder Road"
|
||||
duration = "4m49s"
|
||||
|
||||
[[song]]
|
||||
name = "Stairway to Heaven"
|
||||
duration = "8m03s"
|
||||
```
|
||||
|
||||
Which can be decoded with:
|
||||
|
||||
```go
|
||||
type song struct {
|
||||
Name string
|
||||
Duration duration
|
||||
}
|
||||
type songs struct {
|
||||
Song []song
|
||||
}
|
||||
var favorites songs
|
||||
if _, err := toml.Decode(blob, &favorites); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, s := range favorites.Song {
|
||||
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
|
||||
}
|
||||
```
|
||||
|
||||
And you'll also need a `duration` type that satisfies the
|
||||
`encoding.TextUnmarshaler` interface:
|
||||
|
||||
```go
|
||||
type duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (d *duration) UnmarshalText(text []byte) error {
|
||||
var err error
|
||||
d.Duration, err = time.ParseDuration(string(text))
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### More complex usage
|
||||
|
||||
Here's an example of how to load the example from the official spec page:
|
||||
|
||||
```toml
|
||||
# This is a TOML document. Boom.
|
||||
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Tom Preston-Werner"
|
||||
organization = "GitHub"
|
||||
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
|
||||
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
||||
|
||||
[database]
|
||||
server = "192.168.1.1"
|
||||
ports = [ 8001, 8001, 8002 ]
|
||||
connection_max = 5000
|
||||
enabled = true
|
||||
|
||||
[servers]
|
||||
|
||||
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
dc = "eqdc10"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
dc = "eqdc10"
|
||||
|
||||
[clients]
|
||||
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
||||
|
||||
# Line breaks are OK when inside arrays
|
||||
hosts = [
|
||||
"alpha",
|
||||
"omega"
|
||||
]
|
||||
```
|
||||
|
||||
And the corresponding Go types are:
|
||||
|
||||
```go
|
||||
type tomlConfig struct {
|
||||
Title string
|
||||
Owner ownerInfo
|
||||
DB database `toml:"database"`
|
||||
Servers map[string]server
|
||||
Clients clients
|
||||
}
|
||||
|
||||
type ownerInfo struct {
|
||||
Name string
|
||||
Org string `toml:"organization"`
|
||||
Bio string
|
||||
DOB time.Time
|
||||
}
|
||||
|
||||
type database struct {
|
||||
Server string
|
||||
Ports []int
|
||||
ConnMax int `toml:"connection_max"`
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
type server struct {
|
||||
IP string
|
||||
DC string
|
||||
}
|
||||
|
||||
type clients struct {
|
||||
Data [][]interface{}
|
||||
Hosts []string
|
||||
}
|
||||
```
|
||||
|
||||
Note that a case insensitive match will be tried if an exact match can't be
|
||||
found.
|
||||
|
||||
A working example of the above can be found in `_examples/example.{go,toml}`.
|
509
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
Normal file
509
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
Normal file
@ -0,0 +1,509 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func e(format string, args ...interface{}) error {
|
||||
return fmt.Errorf("toml: "+format, args...)
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface implemented by objects that can unmarshal a
|
||||
// TOML description of themselves.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalTOML(interface{}) error
|
||||
}
|
||||
|
||||
// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`.
|
||||
func Unmarshal(p []byte, v interface{}) error {
|
||||
_, err := Decode(string(p), v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Primitive is a TOML value that hasn't been decoded into a Go value.
|
||||
// When using the various `Decode*` functions, the type `Primitive` may
|
||||
// be given to any value, and its decoding will be delayed.
|
||||
//
|
||||
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
|
||||
//
|
||||
// The underlying representation of a `Primitive` value is subject to change.
|
||||
// Do not rely on it.
|
||||
//
|
||||
// N.B. Primitive values are still parsed, so using them will only avoid
|
||||
// the overhead of reflection. They can be useful when you don't know the
|
||||
// exact type of TOML data until run time.
|
||||
type Primitive struct {
|
||||
undecoded interface{}
|
||||
context Key
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
//
|
||||
// Use MetaData.PrimitiveDecode instead.
|
||||
func PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||
md := MetaData{decoded: make(map[string]bool)}
|
||||
return md.unify(primValue.undecoded, rvalue(v))
|
||||
}
|
||||
|
||||
// PrimitiveDecode is just like the other `Decode*` functions, except it
|
||||
// decodes a TOML value that has already been parsed. Valid primitive values
|
||||
// can *only* be obtained from values filled by the decoder functions,
|
||||
// including this method. (i.e., `v` may contain more `Primitive`
|
||||
// values.)
|
||||
//
|
||||
// Meta data for primitive values is included in the meta data returned by
|
||||
// the `Decode*` functions with one exception: keys returned by the Undecoded
|
||||
// method will only reflect keys that were decoded. Namely, any keys hidden
|
||||
// behind a Primitive will be considered undecoded. Executing this method will
|
||||
// update the undecoded keys in the meta data. (See the example.)
|
||||
func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||
md.context = primValue.context
|
||||
defer func() { md.context = nil }()
|
||||
return md.unify(primValue.undecoded, rvalue(v))
|
||||
}
|
||||
|
||||
// Decode will decode the contents of `data` in TOML format into a pointer
|
||||
// `v`.
|
||||
//
|
||||
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
|
||||
// used interchangeably.)
|
||||
//
|
||||
// TOML arrays of tables correspond to either a slice of structs or a slice
|
||||
// of maps.
|
||||
//
|
||||
// TOML datetimes correspond to Go `time.Time` values.
|
||||
//
|
||||
// All other TOML types (float, string, int, bool and array) correspond
|
||||
// to the obvious Go types.
|
||||
//
|
||||
// An exception to the above rules is if a type implements the
|
||||
// encoding.TextUnmarshaler interface. In this case, any primitive TOML value
|
||||
// (floats, strings, integers, booleans and datetimes) will be converted to
|
||||
// a byte string and given to the value's UnmarshalText method. See the
|
||||
// Unmarshaler example for a demonstration with time duration strings.
|
||||
//
|
||||
// Key mapping
|
||||
//
|
||||
// TOML keys can map to either keys in a Go map or field names in a Go
|
||||
// struct. The special `toml` struct tag may be used to map TOML keys to
|
||||
// struct fields that don't match the key name exactly. (See the example.)
|
||||
// A case insensitive match to struct names will be tried if an exact match
|
||||
// can't be found.
|
||||
//
|
||||
// The mapping between TOML values and Go values is loose. That is, there
|
||||
// may exist TOML values that cannot be placed into your representation, and
|
||||
// there may be parts of your representation that do not correspond to
|
||||
// TOML values. This loose mapping can be made stricter by using the IsDefined
|
||||
// and/or Undecoded methods on the MetaData returned.
|
||||
//
|
||||
// This decoder will not handle cyclic types. If a cyclic type is passed,
|
||||
// `Decode` will not terminate.
|
||||
func Decode(data string, v interface{}) (MetaData, error) {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr {
|
||||
return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
|
||||
}
|
||||
if rv.IsNil() {
|
||||
return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
|
||||
}
|
||||
p, err := parse(data)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
md := MetaData{
|
||||
p.mapping, p.types, p.ordered,
|
||||
make(map[string]bool, len(p.ordered)), nil,
|
||||
}
|
||||
return md, md.unify(p.mapping, indirect(rv))
|
||||
}
|
||||
|
||||
// DecodeFile is just like Decode, except it will automatically read the
|
||||
// contents of the file at `fpath` and decode it for you.
|
||||
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
|
||||
bs, err := ioutil.ReadFile(fpath)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
return Decode(string(bs), v)
|
||||
}
|
||||
|
||||
// DecodeReader is just like Decode, except it will consume all bytes
|
||||
// from the reader and decode it for you.
|
||||
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
|
||||
bs, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
return Decode(string(bs), v)
|
||||
}
|
||||
|
||||
// unify performs a sort of type unification based on the structure of `rv`,
|
||||
// which is the client representation.
|
||||
//
|
||||
// Any type mismatch produces an error. Finding a type that we don't know
|
||||
// how to handle produces an unsupported type error.
|
||||
func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
|
||||
|
||||
// Special case. Look for a `Primitive` value.
|
||||
if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
|
||||
// Save the undecoded data and the key context into the primitive
|
||||
// value.
|
||||
context := make(Key, len(md.context))
|
||||
copy(context, md.context)
|
||||
rv.Set(reflect.ValueOf(Primitive{
|
||||
undecoded: data,
|
||||
context: context,
|
||||
}))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Special case. Unmarshaler Interface support.
|
||||
if rv.CanAddr() {
|
||||
if v, ok := rv.Addr().Interface().(Unmarshaler); ok {
|
||||
return v.UnmarshalTOML(data)
|
||||
}
|
||||
}
|
||||
|
||||
// Special case. Handle time.Time values specifically.
|
||||
// TODO: Remove this code when we decide to drop support for Go 1.1.
|
||||
// This isn't necessary in Go 1.2 because time.Time satisfies the encoding
|
||||
// interfaces.
|
||||
if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
|
||||
return md.unifyDatetime(data, rv)
|
||||
}
|
||||
|
||||
// Special case. Look for a value satisfying the TextUnmarshaler interface.
|
||||
if v, ok := rv.Interface().(TextUnmarshaler); ok {
|
||||
return md.unifyText(data, v)
|
||||
}
|
||||
// BUG(burntsushi)
|
||||
// The behavior here is incorrect whenever a Go type satisfies the
|
||||
// encoding.TextUnmarshaler interface but also corresponds to a TOML
|
||||
// hash or array. In particular, the unmarshaler should only be applied
|
||||
// to primitive TOML values. But at this point, it will be applied to
|
||||
// all kinds of values and produce an incorrect error whenever those values
|
||||
// are hashes or arrays (including arrays of tables).
|
||||
|
||||
k := rv.Kind()
|
||||
|
||||
// laziness
|
||||
if k >= reflect.Int && k <= reflect.Uint64 {
|
||||
return md.unifyInt(data, rv)
|
||||
}
|
||||
switch k {
|
||||
case reflect.Ptr:
|
||||
elem := reflect.New(rv.Type().Elem())
|
||||
err := md.unify(data, reflect.Indirect(elem))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rv.Set(elem)
|
||||
return nil
|
||||
case reflect.Struct:
|
||||
return md.unifyStruct(data, rv)
|
||||
case reflect.Map:
|
||||
return md.unifyMap(data, rv)
|
||||
case reflect.Array:
|
||||
return md.unifyArray(data, rv)
|
||||
case reflect.Slice:
|
||||
return md.unifySlice(data, rv)
|
||||
case reflect.String:
|
||||
return md.unifyString(data, rv)
|
||||
case reflect.Bool:
|
||||
return md.unifyBool(data, rv)
|
||||
case reflect.Interface:
|
||||
// we only support empty interfaces.
|
||||
if rv.NumMethod() > 0 {
|
||||
return e("unsupported type %s", rv.Type())
|
||||
}
|
||||
return md.unifyAnything(data, rv)
|
||||
case reflect.Float32:
|
||||
fallthrough
|
||||
case reflect.Float64:
|
||||
return md.unifyFloat64(data, rv)
|
||||
}
|
||||
return e("unsupported type %s", rv.Kind())
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
|
||||
tmap, ok := mapping.(map[string]interface{})
|
||||
if !ok {
|
||||
if mapping == nil {
|
||||
return nil
|
||||
}
|
||||
return e("type mismatch for %s: expected table but found %T",
|
||||
rv.Type().String(), mapping)
|
||||
}
|
||||
|
||||
for key, datum := range tmap {
|
||||
var f *field
|
||||
fields := cachedTypeFields(rv.Type())
|
||||
for i := range fields {
|
||||
ff := &fields[i]
|
||||
if ff.name == key {
|
||||
f = ff
|
||||
break
|
||||
}
|
||||
if f == nil && strings.EqualFold(ff.name, key) {
|
||||
f = ff
|
||||
}
|
||||
}
|
||||
if f != nil {
|
||||
subv := rv
|
||||
for _, i := range f.index {
|
||||
subv = indirect(subv.Field(i))
|
||||
}
|
||||
if isUnifiable(subv) {
|
||||
md.decoded[md.context.add(key).String()] = true
|
||||
md.context = append(md.context, key)
|
||||
if err := md.unify(datum, subv); err != nil {
|
||||
return err
|
||||
}
|
||||
md.context = md.context[0 : len(md.context)-1]
|
||||
} else if f.name != "" {
|
||||
// Bad user! No soup for you!
|
||||
return e("cannot write unexported field %s.%s",
|
||||
rv.Type().String(), f.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
|
||||
tmap, ok := mapping.(map[string]interface{})
|
||||
if !ok {
|
||||
if tmap == nil {
|
||||
return nil
|
||||
}
|
||||
return badtype("map", mapping)
|
||||
}
|
||||
if rv.IsNil() {
|
||||
rv.Set(reflect.MakeMap(rv.Type()))
|
||||
}
|
||||
for k, v := range tmap {
|
||||
md.decoded[md.context.add(k).String()] = true
|
||||
md.context = append(md.context, k)
|
||||
|
||||
rvkey := indirect(reflect.New(rv.Type().Key()))
|
||||
rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
|
||||
if err := md.unify(v, rvval); err != nil {
|
||||
return err
|
||||
}
|
||||
md.context = md.context[0 : len(md.context)-1]
|
||||
|
||||
rvkey.SetString(k)
|
||||
rv.SetMapIndex(rvkey, rvval)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
|
||||
datav := reflect.ValueOf(data)
|
||||
if datav.Kind() != reflect.Slice {
|
||||
if !datav.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return badtype("slice", data)
|
||||
}
|
||||
sliceLen := datav.Len()
|
||||
if sliceLen != rv.Len() {
|
||||
return e("expected array length %d; got TOML array of length %d",
|
||||
rv.Len(), sliceLen)
|
||||
}
|
||||
return md.unifySliceArray(datav, rv)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
|
||||
datav := reflect.ValueOf(data)
|
||||
if datav.Kind() != reflect.Slice {
|
||||
if !datav.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return badtype("slice", data)
|
||||
}
|
||||
n := datav.Len()
|
||||
if rv.IsNil() || rv.Cap() < n {
|
||||
rv.Set(reflect.MakeSlice(rv.Type(), n, n))
|
||||
}
|
||||
rv.SetLen(n)
|
||||
return md.unifySliceArray(datav, rv)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
|
||||
sliceLen := data.Len()
|
||||
for i := 0; i < sliceLen; i++ {
|
||||
v := data.Index(i).Interface()
|
||||
sliceval := indirect(rv.Index(i))
|
||||
if err := md.unify(v, sliceval); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error {
|
||||
if _, ok := data.(time.Time); ok {
|
||||
rv.Set(reflect.ValueOf(data))
|
||||
return nil
|
||||
}
|
||||
return badtype("time.Time", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
|
||||
if s, ok := data.(string); ok {
|
||||
rv.SetString(s)
|
||||
return nil
|
||||
}
|
||||
return badtype("string", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
|
||||
if num, ok := data.(float64); ok {
|
||||
switch rv.Kind() {
|
||||
case reflect.Float32:
|
||||
fallthrough
|
||||
case reflect.Float64:
|
||||
rv.SetFloat(num)
|
||||
default:
|
||||
panic("bug")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return badtype("float", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
|
||||
if num, ok := data.(int64); ok {
|
||||
if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int64:
|
||||
// No bounds checking necessary.
|
||||
case reflect.Int8:
|
||||
if num < math.MinInt8 || num > math.MaxInt8 {
|
||||
return e("value %d is out of range for int8", num)
|
||||
}
|
||||
case reflect.Int16:
|
||||
if num < math.MinInt16 || num > math.MaxInt16 {
|
||||
return e("value %d is out of range for int16", num)
|
||||
}
|
||||
case reflect.Int32:
|
||||
if num < math.MinInt32 || num > math.MaxInt32 {
|
||||
return e("value %d is out of range for int32", num)
|
||||
}
|
||||
}
|
||||
rv.SetInt(num)
|
||||
} else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 {
|
||||
unum := uint64(num)
|
||||
switch rv.Kind() {
|
||||
case reflect.Uint, reflect.Uint64:
|
||||
// No bounds checking necessary.
|
||||
case reflect.Uint8:
|
||||
if num < 0 || unum > math.MaxUint8 {
|
||||
return e("value %d is out of range for uint8", num)
|
||||
}
|
||||
case reflect.Uint16:
|
||||
if num < 0 || unum > math.MaxUint16 {
|
||||
return e("value %d is out of range for uint16", num)
|
||||
}
|
||||
case reflect.Uint32:
|
||||
if num < 0 || unum > math.MaxUint32 {
|
||||
return e("value %d is out of range for uint32", num)
|
||||
}
|
||||
}
|
||||
rv.SetUint(unum)
|
||||
} else {
|
||||
panic("unreachable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return badtype("integer", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
|
||||
if b, ok := data.(bool); ok {
|
||||
rv.SetBool(b)
|
||||
return nil
|
||||
}
|
||||
return badtype("boolean", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
|
||||
rv.Set(reflect.ValueOf(data))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
|
||||
var s string
|
||||
switch sdata := data.(type) {
|
||||
case TextMarshaler:
|
||||
text, err := sdata.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s = string(text)
|
||||
case fmt.Stringer:
|
||||
s = sdata.String()
|
||||
case string:
|
||||
s = sdata
|
||||
case bool:
|
||||
s = fmt.Sprintf("%v", sdata)
|
||||
case int64:
|
||||
s = fmt.Sprintf("%d", sdata)
|
||||
case float64:
|
||||
s = fmt.Sprintf("%f", sdata)
|
||||
default:
|
||||
return badtype("primitive (string-like)", data)
|
||||
}
|
||||
if err := v.UnmarshalText([]byte(s)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rvalue returns a reflect.Value of `v`. All pointers are resolved.
|
||||
func rvalue(v interface{}) reflect.Value {
|
||||
return indirect(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// indirect returns the value pointed to by a pointer.
|
||||
// Pointers are followed until the value is not a pointer.
|
||||
// New values are allocated for each nil pointer.
|
||||
//
|
||||
// An exception to this rule is if the value satisfies an interface of
|
||||
// interest to us (like encoding.TextUnmarshaler).
|
||||
func indirect(v reflect.Value) reflect.Value {
|
||||
if v.Kind() != reflect.Ptr {
|
||||
if v.CanSet() {
|
||||
pv := v.Addr()
|
||||
if _, ok := pv.Interface().(TextUnmarshaler); ok {
|
||||
return pv
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
return indirect(reflect.Indirect(v))
|
||||
}
|
||||
|
||||
func isUnifiable(rv reflect.Value) bool {
|
||||
if rv.CanSet() {
|
||||
return true
|
||||
}
|
||||
if _, ok := rv.Interface().(TextUnmarshaler); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func badtype(expected string, data interface{}) error {
|
||||
return e("cannot load TOML value of type %T into a Go %s", data, expected)
|
||||
}
|
121
vendor/github.com/BurntSushi/toml/decode_meta.go
generated
vendored
Normal file
121
vendor/github.com/BurntSushi/toml/decode_meta.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
package toml
|
||||
|
||||
import "strings"
|
||||
|
||||
// MetaData allows access to meta information about TOML data that may not
|
||||
// be inferrable via reflection. In particular, whether a key has been defined
|
||||
// and the TOML type of a key.
|
||||
type MetaData struct {
|
||||
mapping map[string]interface{}
|
||||
types map[string]tomlType
|
||||
keys []Key
|
||||
decoded map[string]bool
|
||||
context Key // Used only during decoding.
|
||||
}
|
||||
|
||||
// IsDefined returns true if the key given exists in the TOML data. The key
|
||||
// should be specified hierarchially. e.g.,
|
||||
//
|
||||
// // access the TOML key 'a.b.c'
|
||||
// IsDefined("a", "b", "c")
|
||||
//
|
||||
// IsDefined will return false if an empty key given. Keys are case sensitive.
|
||||
func (md *MetaData) IsDefined(key ...string) bool {
|
||||
if len(key) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var hash map[string]interface{}
|
||||
var ok bool
|
||||
var hashOrVal interface{} = md.mapping
|
||||
for _, k := range key {
|
||||
if hash, ok = hashOrVal.(map[string]interface{}); !ok {
|
||||
return false
|
||||
}
|
||||
if hashOrVal, ok = hash[k]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Type returns a string representation of the type of the key specified.
|
||||
//
|
||||
// Type will return the empty string if given an empty key or a key that
|
||||
// does not exist. Keys are case sensitive.
|
||||
func (md *MetaData) Type(key ...string) string {
|
||||
fullkey := strings.Join(key, ".")
|
||||
if typ, ok := md.types[fullkey]; ok {
|
||||
return typ.typeString()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
|
||||
// to get values of this type.
|
||||
type Key []string
|
||||
|
||||
func (k Key) String() string {
|
||||
return strings.Join(k, ".")
|
||||
}
|
||||
|
||||
func (k Key) maybeQuotedAll() string {
|
||||
var ss []string
|
||||
for i := range k {
|
||||
ss = append(ss, k.maybeQuoted(i))
|
||||
}
|
||||
return strings.Join(ss, ".")
|
||||
}
|
||||
|
||||
func (k Key) maybeQuoted(i int) string {
|
||||
quote := false
|
||||
for _, c := range k[i] {
|
||||
if !isBareKeyChar(c) {
|
||||
quote = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if quote {
|
||||
return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\""
|
||||
}
|
||||
return k[i]
|
||||
}
|
||||
|
||||
func (k Key) add(piece string) Key {
|
||||
newKey := make(Key, len(k)+1)
|
||||
copy(newKey, k)
|
||||
newKey[len(k)] = piece
|
||||
return newKey
|
||||
}
|
||||
|
||||
// Keys returns a slice of every key in the TOML data, including key groups.
|
||||
// Each key is itself a slice, where the first element is the top of the
|
||||
// hierarchy and the last is the most specific.
|
||||
//
|
||||
// The list will have the same order as the keys appeared in the TOML data.
|
||||
//
|
||||
// All keys returned are non-empty.
|
||||
func (md *MetaData) Keys() []Key {
|
||||
return md.keys
|
||||
}
|
||||
|
||||
// Undecoded returns all keys that have not been decoded in the order in which
|
||||
// they appear in the original TOML document.
|
||||
//
|
||||
// This includes keys that haven't been decoded because of a Primitive value.
|
||||
// Once the Primitive value is decoded, the keys will be considered decoded.
|
||||
//
|
||||
// Also note that decoding into an empty interface will result in no decoding,
|
||||
// and so no keys will be considered decoded.
|
||||
//
|
||||
// In this sense, the Undecoded keys correspond to keys in the TOML document
|
||||
// that do not have a concrete type in your representation.
|
||||
func (md *MetaData) Undecoded() []Key {
|
||||
undecoded := make([]Key, 0, len(md.keys))
|
||||
for _, key := range md.keys {
|
||||
if !md.decoded[key.String()] {
|
||||
undecoded = append(undecoded, key)
|
||||
}
|
||||
}
|
||||
return undecoded
|
||||
}
|
27
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
Normal file
27
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
Package toml provides facilities for decoding and encoding TOML configuration
|
||||
files via reflection. There is also support for delaying decoding with
|
||||
the Primitive type, and querying the set of keys in a TOML document with the
|
||||
MetaData type.
|
||||
|
||||
The specification implemented: https://github.com/toml-lang/toml
|
||||
|
||||
The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
|
||||
whether a file is a valid TOML document. It can also be used to print the
|
||||
type of each key in a TOML document.
|
||||
|
||||
Testing
|
||||
|
||||
There are two important types of tests used for this package. The first is
|
||||
contained inside '*_test.go' files and uses the standard Go unit testing
|
||||
framework. These tests are primarily devoted to holistically testing the
|
||||
decoder and encoder.
|
||||
|
||||
The second type of testing is used to verify the implementation's adherence
|
||||
to the TOML specification. These tests have been factored into their own
|
||||
project: https://github.com/BurntSushi/toml-test
|
||||
|
||||
The reason the tests are in a separate project is so that they can be used by
|
||||
any implementation of TOML. Namely, it is language agnostic.
|
||||
*/
|
||||
package toml
|
568
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
Normal file
568
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
Normal file
@ -0,0 +1,568 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type tomlEncodeError struct{ error }
|
||||
|
||||
var (
|
||||
errArrayMixedElementTypes = errors.New(
|
||||
"toml: cannot encode array with mixed element types")
|
||||
errArrayNilElement = errors.New(
|
||||
"toml: cannot encode array with nil element")
|
||||
errNonString = errors.New(
|
||||
"toml: cannot encode a map with non-string key type")
|
||||
errAnonNonStruct = errors.New(
|
||||
"toml: cannot encode an anonymous field that is not a struct")
|
||||
errArrayNoTable = errors.New(
|
||||
"toml: TOML array element cannot contain a table")
|
||||
errNoKey = errors.New(
|
||||
"toml: top-level values must be Go maps or structs")
|
||||
errAnything = errors.New("") // used in testing
|
||||
)
|
||||
|
||||
var quotedReplacer = strings.NewReplacer(
|
||||
"\t", "\\t",
|
||||
"\n", "\\n",
|
||||
"\r", "\\r",
|
||||
"\"", "\\\"",
|
||||
"\\", "\\\\",
|
||||
)
|
||||
|
||||
// Encoder controls the encoding of Go values to a TOML document to some
|
||||
// io.Writer.
|
||||
//
|
||||
// The indentation level can be controlled with the Indent field.
|
||||
type Encoder struct {
|
||||
// A single indentation level. By default it is two spaces.
|
||||
Indent string
|
||||
|
||||
// hasWritten is whether we have written any output to w yet.
|
||||
hasWritten bool
|
||||
w *bufio.Writer
|
||||
}
|
||||
|
||||
// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer
|
||||
// given. By default, a single indentation level is 2 spaces.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{
|
||||
w: bufio.NewWriter(w),
|
||||
Indent: " ",
|
||||
}
|
||||
}
|
||||
|
||||
// Encode writes a TOML representation of the Go value to the underlying
|
||||
// io.Writer. If the value given cannot be encoded to a valid TOML document,
|
||||
// then an error is returned.
|
||||
//
|
||||
// The mapping between Go values and TOML values should be precisely the same
|
||||
// as for the Decode* functions. Similarly, the TextMarshaler interface is
|
||||
// supported by encoding the resulting bytes as strings. (If you want to write
|
||||
// arbitrary binary data then you will need to use something like base64 since
|
||||
// TOML does not have any binary types.)
|
||||
//
|
||||
// When encoding TOML hashes (i.e., Go maps or structs), keys without any
|
||||
// sub-hashes are encoded first.
|
||||
//
|
||||
// If a Go map is encoded, then its keys are sorted alphabetically for
|
||||
// deterministic output. More control over this behavior may be provided if
|
||||
// there is demand for it.
|
||||
//
|
||||
// Encoding Go values without a corresponding TOML representation---like map
|
||||
// types with non-string keys---will cause an error to be returned. Similarly
|
||||
// for mixed arrays/slices, arrays/slices with nil elements, embedded
|
||||
// non-struct types and nested slices containing maps or structs.
|
||||
// (e.g., [][]map[string]string is not allowed but []map[string]string is OK
|
||||
// and so is []map[string][]string.)
|
||||
func (enc *Encoder) Encode(v interface{}) error {
|
||||
rv := eindirect(reflect.ValueOf(v))
|
||||
if err := enc.safeEncode(Key([]string{}), rv); err != nil {
|
||||
return err
|
||||
}
|
||||
return enc.w.Flush()
|
||||
}
|
||||
|
||||
func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if terr, ok := r.(tomlEncodeError); ok {
|
||||
err = terr.error
|
||||
return
|
||||
}
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
enc.encode(key, rv)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) encode(key Key, rv reflect.Value) {
|
||||
// Special case. Time needs to be in ISO8601 format.
|
||||
// Special case. If we can marshal the type to text, then we used that.
|
||||
// Basically, this prevents the encoder for handling these types as
|
||||
// generic structs (or whatever the underlying type of a TextMarshaler is).
|
||||
switch rv.Interface().(type) {
|
||||
case time.Time, TextMarshaler:
|
||||
enc.keyEqElement(key, rv)
|
||||
return
|
||||
}
|
||||
|
||||
k := rv.Kind()
|
||||
switch k {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||
reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
|
||||
enc.keyEqElement(key, rv)
|
||||
case reflect.Array, reflect.Slice:
|
||||
if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
|
||||
enc.eArrayOfTables(key, rv)
|
||||
} else {
|
||||
enc.keyEqElement(key, rv)
|
||||
}
|
||||
case reflect.Interface:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.encode(key, rv.Elem())
|
||||
case reflect.Map:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.eTable(key, rv)
|
||||
case reflect.Ptr:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.encode(key, rv.Elem())
|
||||
case reflect.Struct:
|
||||
enc.eTable(key, rv)
|
||||
default:
|
||||
panic(e("unsupported type for key '%s': %s", key, k))
|
||||
}
|
||||
}
|
||||
|
||||
// eElement encodes any value that can be an array element (primitives and
|
||||
// arrays).
|
||||
func (enc *Encoder) eElement(rv reflect.Value) {
|
||||
switch v := rv.Interface().(type) {
|
||||
case time.Time:
|
||||
// Special case time.Time as a primitive. Has to come before
|
||||
// TextMarshaler below because time.Time implements
|
||||
// encoding.TextMarshaler, but we need to always use UTC.
|
||||
enc.wf(v.UTC().Format("2006-01-02T15:04:05Z"))
|
||||
return
|
||||
case TextMarshaler:
|
||||
// Special case. Use text marshaler if it's available for this value.
|
||||
if s, err := v.MarshalText(); err != nil {
|
||||
encPanic(err)
|
||||
} else {
|
||||
enc.writeQuoted(string(s))
|
||||
}
|
||||
return
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
enc.wf(strconv.FormatBool(rv.Bool()))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64:
|
||||
enc.wf(strconv.FormatInt(rv.Int(), 10))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||
reflect.Uint32, reflect.Uint64:
|
||||
enc.wf(strconv.FormatUint(rv.Uint(), 10))
|
||||
case reflect.Float32:
|
||||
enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32)))
|
||||
case reflect.Float64:
|
||||
enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64)))
|
||||
case reflect.Array, reflect.Slice:
|
||||
enc.eArrayOrSliceElement(rv)
|
||||
case reflect.Interface:
|
||||
enc.eElement(rv.Elem())
|
||||
case reflect.String:
|
||||
enc.writeQuoted(rv.String())
|
||||
default:
|
||||
panic(e("unexpected primitive type: %s", rv.Kind()))
|
||||
}
|
||||
}
|
||||
|
||||
// By the TOML spec, all floats must have a decimal with at least one
|
||||
// number on either side.
|
||||
func floatAddDecimal(fstr string) string {
|
||||
if !strings.Contains(fstr, ".") {
|
||||
return fstr + ".0"
|
||||
}
|
||||
return fstr
|
||||
}
|
||||
|
||||
func (enc *Encoder) writeQuoted(s string) {
|
||||
enc.wf("\"%s\"", quotedReplacer.Replace(s))
|
||||
}
|
||||
|
||||
func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
|
||||
length := rv.Len()
|
||||
enc.wf("[")
|
||||
for i := 0; i < length; i++ {
|
||||
elem := rv.Index(i)
|
||||
enc.eElement(elem)
|
||||
if i != length-1 {
|
||||
enc.wf(", ")
|
||||
}
|
||||
}
|
||||
enc.wf("]")
|
||||
}
|
||||
|
||||
func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
|
||||
if len(key) == 0 {
|
||||
encPanic(errNoKey)
|
||||
}
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
trv := rv.Index(i)
|
||||
if isNil(trv) {
|
||||
continue
|
||||
}
|
||||
panicIfInvalidKey(key)
|
||||
enc.newline()
|
||||
enc.wf("%s[[%s]]", enc.indentStr(key), key.maybeQuotedAll())
|
||||
enc.newline()
|
||||
enc.eMapOrStruct(key, trv)
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) eTable(key Key, rv reflect.Value) {
|
||||
panicIfInvalidKey(key)
|
||||
if len(key) == 1 {
|
||||
// Output an extra newline between top-level tables.
|
||||
// (The newline isn't written if nothing else has been written though.)
|
||||
enc.newline()
|
||||
}
|
||||
if len(key) > 0 {
|
||||
enc.wf("%s[%s]", enc.indentStr(key), key.maybeQuotedAll())
|
||||
enc.newline()
|
||||
}
|
||||
enc.eMapOrStruct(key, rv)
|
||||
}
|
||||
|
||||
func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) {
|
||||
switch rv := eindirect(rv); rv.Kind() {
|
||||
case reflect.Map:
|
||||
enc.eMap(key, rv)
|
||||
case reflect.Struct:
|
||||
enc.eStruct(key, rv)
|
||||
default:
|
||||
panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) eMap(key Key, rv reflect.Value) {
|
||||
rt := rv.Type()
|
||||
if rt.Key().Kind() != reflect.String {
|
||||
encPanic(errNonString)
|
||||
}
|
||||
|
||||
// Sort keys so that we have deterministic output. And write keys directly
|
||||
// underneath this key first, before writing sub-structs or sub-maps.
|
||||
var mapKeysDirect, mapKeysSub []string
|
||||
for _, mapKey := range rv.MapKeys() {
|
||||
k := mapKey.String()
|
||||
if typeIsHash(tomlTypeOfGo(rv.MapIndex(mapKey))) {
|
||||
mapKeysSub = append(mapKeysSub, k)
|
||||
} else {
|
||||
mapKeysDirect = append(mapKeysDirect, k)
|
||||
}
|
||||
}
|
||||
|
||||
var writeMapKeys = func(mapKeys []string) {
|
||||
sort.Strings(mapKeys)
|
||||
for _, mapKey := range mapKeys {
|
||||
mrv := rv.MapIndex(reflect.ValueOf(mapKey))
|
||||
if isNil(mrv) {
|
||||
// Don't write anything for nil fields.
|
||||
continue
|
||||
}
|
||||
enc.encode(key.add(mapKey), mrv)
|
||||
}
|
||||
}
|
||||
writeMapKeys(mapKeysDirect)
|
||||
writeMapKeys(mapKeysSub)
|
||||
}
|
||||
|
||||
func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
|
||||
// Write keys for fields directly under this key first, because if we write
|
||||
// a field that creates a new table, then all keys under it will be in that
|
||||
// table (not the one we're writing here).
|
||||
rt := rv.Type()
|
||||
var fieldsDirect, fieldsSub [][]int
|
||||
var addFields func(rt reflect.Type, rv reflect.Value, start []int)
|
||||
addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
|
||||
for i := 0; i < rt.NumField(); i++ {
|
||||
f := rt.Field(i)
|
||||
// skip unexported fields
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
continue
|
||||
}
|
||||
frv := rv.Field(i)
|
||||
if f.Anonymous {
|
||||
t := f.Type
|
||||
switch t.Kind() {
|
||||
case reflect.Struct:
|
||||
// Treat anonymous struct fields with
|
||||
// tag names as though they are not
|
||||
// anonymous, like encoding/json does.
|
||||
if getOptions(f.Tag).name == "" {
|
||||
addFields(t, frv, f.Index)
|
||||
continue
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if t.Elem().Kind() == reflect.Struct &&
|
||||
getOptions(f.Tag).name == "" {
|
||||
if !frv.IsNil() {
|
||||
addFields(t.Elem(), frv.Elem(), f.Index)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Fall through to the normal field encoding logic below
|
||||
// for non-struct anonymous fields.
|
||||
}
|
||||
}
|
||||
|
||||
if typeIsHash(tomlTypeOfGo(frv)) {
|
||||
fieldsSub = append(fieldsSub, append(start, f.Index...))
|
||||
} else {
|
||||
fieldsDirect = append(fieldsDirect, append(start, f.Index...))
|
||||
}
|
||||
}
|
||||
}
|
||||
addFields(rt, rv, nil)
|
||||
|
||||
var writeFields = func(fields [][]int) {
|
||||
for _, fieldIndex := range fields {
|
||||
sft := rt.FieldByIndex(fieldIndex)
|
||||
sf := rv.FieldByIndex(fieldIndex)
|
||||
if isNil(sf) {
|
||||
// Don't write anything for nil fields.
|
||||
continue
|
||||
}
|
||||
|
||||
opts := getOptions(sft.Tag)
|
||||
if opts.skip {
|
||||
continue
|
||||
}
|
||||
keyName := sft.Name
|
||||
if opts.name != "" {
|
||||
keyName = opts.name
|
||||
}
|
||||
if opts.omitempty && isEmpty(sf) {
|
||||
continue
|
||||
}
|
||||
if opts.omitzero && isZero(sf) {
|
||||
continue
|
||||
}
|
||||
|
||||
enc.encode(key.add(keyName), sf)
|
||||
}
|
||||
}
|
||||
writeFields(fieldsDirect)
|
||||
writeFields(fieldsSub)
|
||||
}
|
||||
|
||||
// tomlTypeName returns the TOML type name of the Go value's type. It is
|
||||
// used to determine whether the types of array elements are mixed (which is
|
||||
// forbidden). If the Go value is nil, then it is illegal for it to be an array
|
||||
// element, and valueIsNil is returned as true.
|
||||
|
||||
// Returns the TOML type of a Go value. The type may be `nil`, which means
|
||||
// no concrete TOML type could be found.
|
||||
func tomlTypeOfGo(rv reflect.Value) tomlType {
|
||||
if isNil(rv) || !rv.IsValid() {
|
||||
return nil
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
return tomlBool
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||
reflect.Uint64:
|
||||
return tomlInteger
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return tomlFloat
|
||||
case reflect.Array, reflect.Slice:
|
||||
if typeEqual(tomlHash, tomlArrayType(rv)) {
|
||||
return tomlArrayHash
|
||||
}
|
||||
return tomlArray
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return tomlTypeOfGo(rv.Elem())
|
||||
case reflect.String:
|
||||
return tomlString
|
||||
case reflect.Map:
|
||||
return tomlHash
|
||||
case reflect.Struct:
|
||||
switch rv.Interface().(type) {
|
||||
case time.Time:
|
||||
return tomlDatetime
|
||||
case TextMarshaler:
|
||||
return tomlString
|
||||
default:
|
||||
return tomlHash
|
||||
}
|
||||
default:
|
||||
panic("unexpected reflect.Kind: " + rv.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
// tomlArrayType returns the element type of a TOML array. The type returned
|
||||
// may be nil if it cannot be determined (e.g., a nil slice or a zero length
|
||||
// slize). This function may also panic if it finds a type that cannot be
|
||||
// expressed in TOML (such as nil elements, heterogeneous arrays or directly
|
||||
// nested arrays of tables).
|
||||
func tomlArrayType(rv reflect.Value) tomlType {
|
||||
if isNil(rv) || !rv.IsValid() || rv.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
firstType := tomlTypeOfGo(rv.Index(0))
|
||||
if firstType == nil {
|
||||
encPanic(errArrayNilElement)
|
||||
}
|
||||
|
||||
rvlen := rv.Len()
|
||||
for i := 1; i < rvlen; i++ {
|
||||
elem := rv.Index(i)
|
||||
switch elemType := tomlTypeOfGo(elem); {
|
||||
case elemType == nil:
|
||||
encPanic(errArrayNilElement)
|
||||
case !typeEqual(firstType, elemType):
|
||||
encPanic(errArrayMixedElementTypes)
|
||||
}
|
||||
}
|
||||
// If we have a nested array, then we must make sure that the nested
|
||||
// array contains ONLY primitives.
|
||||
// This checks arbitrarily nested arrays.
|
||||
if typeEqual(firstType, tomlArray) || typeEqual(firstType, tomlArrayHash) {
|
||||
nest := tomlArrayType(eindirect(rv.Index(0)))
|
||||
if typeEqual(nest, tomlHash) || typeEqual(nest, tomlArrayHash) {
|
||||
encPanic(errArrayNoTable)
|
||||
}
|
||||
}
|
||||
return firstType
|
||||
}
|
||||
|
||||
type tagOptions struct {
|
||||
skip bool // "-"
|
||||
name string
|
||||
omitempty bool
|
||||
omitzero bool
|
||||
}
|
||||
|
||||
func getOptions(tag reflect.StructTag) tagOptions {
|
||||
t := tag.Get("toml")
|
||||
if t == "-" {
|
||||
return tagOptions{skip: true}
|
||||
}
|
||||
var opts tagOptions
|
||||
parts := strings.Split(t, ",")
|
||||
opts.name = parts[0]
|
||||
for _, s := range parts[1:] {
|
||||
switch s {
|
||||
case "omitempty":
|
||||
opts.omitempty = true
|
||||
case "omitzero":
|
||||
opts.omitzero = true
|
||||
}
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
func isZero(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return rv.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return rv.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return rv.Float() == 0.0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isEmpty(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
|
||||
return rv.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !rv.Bool()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (enc *Encoder) newline() {
|
||||
if enc.hasWritten {
|
||||
enc.wf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) keyEqElement(key Key, val reflect.Value) {
|
||||
if len(key) == 0 {
|
||||
encPanic(errNoKey)
|
||||
}
|
||||
panicIfInvalidKey(key)
|
||||
enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
|
||||
enc.eElement(val)
|
||||
enc.newline()
|
||||
}
|
||||
|
||||
func (enc *Encoder) wf(format string, v ...interface{}) {
|
||||
if _, err := fmt.Fprintf(enc.w, format, v...); err != nil {
|
||||
encPanic(err)
|
||||
}
|
||||
enc.hasWritten = true
|
||||
}
|
||||
|
||||
func (enc *Encoder) indentStr(key Key) string {
|
||||
return strings.Repeat(enc.Indent, len(key)-1)
|
||||
}
|
||||
|
||||
func encPanic(err error) {
|
||||
panic(tomlEncodeError{err})
|
||||
}
|
||||
|
||||
func eindirect(v reflect.Value) reflect.Value {
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return eindirect(v.Elem())
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func isNil(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
return rv.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func panicIfInvalidKey(key Key) {
|
||||
for _, k := range key {
|
||||
if len(k) == 0 {
|
||||
encPanic(e("Key '%s' is not a valid table name. Key names "+
|
||||
"cannot be empty.", key.maybeQuotedAll()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isValidKeyName(s string) bool {
|
||||
return len(s) != 0
|
||||
}
|
19
vendor/github.com/BurntSushi/toml/encoding_types.go
generated
vendored
Normal file
19
vendor/github.com/BurntSushi/toml/encoding_types.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// +build go1.2
|
||||
|
||||
package toml
|
||||
|
||||
// In order to support Go 1.1, we define our own TextMarshaler and
|
||||
// TextUnmarshaler types. For Go 1.2+, we just alias them with the
|
||||
// standard library interfaces.
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
)
|
||||
|
||||
// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
|
||||
// so that Go 1.1 can be supported.
|
||||
type TextMarshaler encoding.TextMarshaler
|
||||
|
||||
// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
|
||||
// here so that Go 1.1 can be supported.
|
||||
type TextUnmarshaler encoding.TextUnmarshaler
|
18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
generated
vendored
Normal file
18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// +build !go1.2
|
||||
|
||||
package toml
|
||||
|
||||
// These interfaces were introduced in Go 1.2, so we add them manually when
|
||||
// compiling for Go 1.1.
|
||||
|
||||
// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
|
||||
// so that Go 1.1 can be supported.
|
||||
type TextMarshaler interface {
|
||||
MarshalText() (text []byte, err error)
|
||||
}
|
||||
|
||||
// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
|
||||
// here so that Go 1.1 can be supported.
|
||||
type TextUnmarshaler interface {
|
||||
UnmarshalText(text []byte) error
|
||||
}
|
953
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
Normal file
953
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
Normal file
@ -0,0 +1,953 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type itemType int
|
||||
|
||||
const (
|
||||
itemError itemType = iota
|
||||
itemNIL // used in the parser to indicate no type
|
||||
itemEOF
|
||||
itemText
|
||||
itemString
|
||||
itemRawString
|
||||
itemMultilineString
|
||||
itemRawMultilineString
|
||||
itemBool
|
||||
itemInteger
|
||||
itemFloat
|
||||
itemDatetime
|
||||
itemArray // the start of an array
|
||||
itemArrayEnd
|
||||
itemTableStart
|
||||
itemTableEnd
|
||||
itemArrayTableStart
|
||||
itemArrayTableEnd
|
||||
itemKeyStart
|
||||
itemCommentStart
|
||||
itemInlineTableStart
|
||||
itemInlineTableEnd
|
||||
)
|
||||
|
||||
const (
|
||||
eof = 0
|
||||
comma = ','
|
||||
tableStart = '['
|
||||
tableEnd = ']'
|
||||
arrayTableStart = '['
|
||||
arrayTableEnd = ']'
|
||||
tableSep = '.'
|
||||
keySep = '='
|
||||
arrayStart = '['
|
||||
arrayEnd = ']'
|
||||
commentStart = '#'
|
||||
stringStart = '"'
|
||||
stringEnd = '"'
|
||||
rawStringStart = '\''
|
||||
rawStringEnd = '\''
|
||||
inlineTableStart = '{'
|
||||
inlineTableEnd = '}'
|
||||
)
|
||||
|
||||
type stateFn func(lx *lexer) stateFn
|
||||
|
||||
type lexer struct {
|
||||
input string
|
||||
start int
|
||||
pos int
|
||||
line int
|
||||
state stateFn
|
||||
items chan item
|
||||
|
||||
// Allow for backing up up to three runes.
|
||||
// This is necessary because TOML contains 3-rune tokens (""" and ''').
|
||||
prevWidths [3]int
|
||||
nprev int // how many of prevWidths are in use
|
||||
// If we emit an eof, we can still back up, but it is not OK to call
|
||||
// next again.
|
||||
atEOF bool
|
||||
|
||||
// A stack of state functions used to maintain context.
|
||||
// The idea is to reuse parts of the state machine in various places.
|
||||
// For example, values can appear at the top level or within arbitrarily
|
||||
// nested arrays. The last state on the stack is used after a value has
|
||||
// been lexed. Similarly for comments.
|
||||
stack []stateFn
|
||||
}
|
||||
|
||||
type item struct {
|
||||
typ itemType
|
||||
val string
|
||||
line int
|
||||
}
|
||||
|
||||
func (lx *lexer) nextItem() item {
|
||||
for {
|
||||
select {
|
||||
case item := <-lx.items:
|
||||
return item
|
||||
default:
|
||||
lx.state = lx.state(lx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func lex(input string) *lexer {
|
||||
lx := &lexer{
|
||||
input: input,
|
||||
state: lexTop,
|
||||
line: 1,
|
||||
items: make(chan item, 10),
|
||||
stack: make([]stateFn, 0, 10),
|
||||
}
|
||||
return lx
|
||||
}
|
||||
|
||||
func (lx *lexer) push(state stateFn) {
|
||||
lx.stack = append(lx.stack, state)
|
||||
}
|
||||
|
||||
func (lx *lexer) pop() stateFn {
|
||||
if len(lx.stack) == 0 {
|
||||
return lx.errorf("BUG in lexer: no states to pop")
|
||||
}
|
||||
last := lx.stack[len(lx.stack)-1]
|
||||
lx.stack = lx.stack[0 : len(lx.stack)-1]
|
||||
return last
|
||||
}
|
||||
|
||||
func (lx *lexer) current() string {
|
||||
return lx.input[lx.start:lx.pos]
|
||||
}
|
||||
|
||||
func (lx *lexer) emit(typ itemType) {
|
||||
lx.items <- item{typ, lx.current(), lx.line}
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
func (lx *lexer) emitTrim(typ itemType) {
|
||||
lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line}
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
func (lx *lexer) next() (r rune) {
|
||||
if lx.atEOF {
|
||||
panic("next called after EOF")
|
||||
}
|
||||
if lx.pos >= len(lx.input) {
|
||||
lx.atEOF = true
|
||||
return eof
|
||||
}
|
||||
|
||||
if lx.input[lx.pos] == '\n' {
|
||||
lx.line++
|
||||
}
|
||||
lx.prevWidths[2] = lx.prevWidths[1]
|
||||
lx.prevWidths[1] = lx.prevWidths[0]
|
||||
if lx.nprev < 3 {
|
||||
lx.nprev++
|
||||
}
|
||||
r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
|
||||
lx.prevWidths[0] = w
|
||||
lx.pos += w
|
||||
return r
|
||||
}
|
||||
|
||||
// ignore skips over the pending input before this point.
|
||||
func (lx *lexer) ignore() {
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
// backup steps back one rune. Can be called only twice between calls to next.
|
||||
func (lx *lexer) backup() {
|
||||
if lx.atEOF {
|
||||
lx.atEOF = false
|
||||
return
|
||||
}
|
||||
if lx.nprev < 1 {
|
||||
panic("backed up too far")
|
||||
}
|
||||
w := lx.prevWidths[0]
|
||||
lx.prevWidths[0] = lx.prevWidths[1]
|
||||
lx.prevWidths[1] = lx.prevWidths[2]
|
||||
lx.nprev--
|
||||
lx.pos -= w
|
||||
if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
|
||||
lx.line--
|
||||
}
|
||||
}
|
||||
|
||||
// accept consumes the next rune if it's equal to `valid`.
|
||||
func (lx *lexer) accept(valid rune) bool {
|
||||
if lx.next() == valid {
|
||||
return true
|
||||
}
|
||||
lx.backup()
|
||||
return false
|
||||
}
|
||||
|
||||
// peek returns but does not consume the next rune in the input.
|
||||
func (lx *lexer) peek() rune {
|
||||
r := lx.next()
|
||||
lx.backup()
|
||||
return r
|
||||
}
|
||||
|
||||
// skip ignores all input that matches the given predicate.
|
||||
func (lx *lexer) skip(pred func(rune) bool) {
|
||||
for {
|
||||
r := lx.next()
|
||||
if pred(r) {
|
||||
continue
|
||||
}
|
||||
lx.backup()
|
||||
lx.ignore()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// errorf stops all lexing by emitting an error and returning `nil`.
|
||||
// Note that any value that is a character is escaped if it's a special
|
||||
// character (newlines, tabs, etc.).
|
||||
func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
|
||||
lx.items <- item{
|
||||
itemError,
|
||||
fmt.Sprintf(format, values...),
|
||||
lx.line,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// lexTop consumes elements at the top level of TOML data.
|
||||
func lexTop(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isWhitespace(r) || isNL(r) {
|
||||
return lexSkip(lx, lexTop)
|
||||
}
|
||||
switch r {
|
||||
case commentStart:
|
||||
lx.push(lexTop)
|
||||
return lexCommentStart
|
||||
case tableStart:
|
||||
return lexTableStart
|
||||
case eof:
|
||||
if lx.pos > lx.start {
|
||||
return lx.errorf("unexpected EOF")
|
||||
}
|
||||
lx.emit(itemEOF)
|
||||
return nil
|
||||
}
|
||||
|
||||
// At this point, the only valid item can be a key, so we back up
|
||||
// and let the key lexer do the rest.
|
||||
lx.backup()
|
||||
lx.push(lexTopEnd)
|
||||
return lexKeyStart
|
||||
}
|
||||
|
||||
// lexTopEnd is entered whenever a top-level item has been consumed. (A value
|
||||
// or a table.) It must see only whitespace, and will turn back to lexTop
|
||||
// upon a newline. If it sees EOF, it will quit the lexer successfully.
|
||||
func lexTopEnd(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == commentStart:
|
||||
// a comment will read to a newline for us.
|
||||
lx.push(lexTop)
|
||||
return lexCommentStart
|
||||
case isWhitespace(r):
|
||||
return lexTopEnd
|
||||
case isNL(r):
|
||||
lx.ignore()
|
||||
return lexTop
|
||||
case r == eof:
|
||||
lx.emit(itemEOF)
|
||||
return nil
|
||||
}
|
||||
return lx.errorf("expected a top-level item to end with a newline, "+
|
||||
"comment, or EOF, but got %q instead", r)
|
||||
}
|
||||
|
||||
// lexTable lexes the beginning of a table. Namely, it makes sure that
|
||||
// it starts with a character other than '.' and ']'.
|
||||
// It assumes that '[' has already been consumed.
|
||||
// It also handles the case that this is an item in an array of tables.
|
||||
// e.g., '[[name]]'.
|
||||
func lexTableStart(lx *lexer) stateFn {
|
||||
if lx.peek() == arrayTableStart {
|
||||
lx.next()
|
||||
lx.emit(itemArrayTableStart)
|
||||
lx.push(lexArrayTableEnd)
|
||||
} else {
|
||||
lx.emit(itemTableStart)
|
||||
lx.push(lexTableEnd)
|
||||
}
|
||||
return lexTableNameStart
|
||||
}
|
||||
|
||||
func lexTableEnd(lx *lexer) stateFn {
|
||||
lx.emit(itemTableEnd)
|
||||
return lexTopEnd
|
||||
}
|
||||
|
||||
func lexArrayTableEnd(lx *lexer) stateFn {
|
||||
if r := lx.next(); r != arrayTableEnd {
|
||||
return lx.errorf("expected end of table array name delimiter %q, "+
|
||||
"but got %q instead", arrayTableEnd, r)
|
||||
}
|
||||
lx.emit(itemArrayTableEnd)
|
||||
return lexTopEnd
|
||||
}
|
||||
|
||||
func lexTableNameStart(lx *lexer) stateFn {
|
||||
lx.skip(isWhitespace)
|
||||
switch r := lx.peek(); {
|
||||
case r == tableEnd || r == eof:
|
||||
return lx.errorf("unexpected end of table name " +
|
||||
"(table names cannot be empty)")
|
||||
case r == tableSep:
|
||||
return lx.errorf("unexpected table separator " +
|
||||
"(table names cannot be empty)")
|
||||
case r == stringStart || r == rawStringStart:
|
||||
lx.ignore()
|
||||
lx.push(lexTableNameEnd)
|
||||
return lexValue // reuse string lexing
|
||||
default:
|
||||
return lexBareTableName
|
||||
}
|
||||
}
|
||||
|
||||
// lexBareTableName lexes the name of a table. It assumes that at least one
|
||||
// valid character for the table has already been read.
|
||||
func lexBareTableName(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isBareKeyChar(r) {
|
||||
return lexBareTableName
|
||||
}
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexTableNameEnd
|
||||
}
|
||||
|
||||
// lexTableNameEnd reads the end of a piece of a table name, optionally
|
||||
// consuming whitespace.
|
||||
func lexTableNameEnd(lx *lexer) stateFn {
|
||||
lx.skip(isWhitespace)
|
||||
switch r := lx.next(); {
|
||||
case isWhitespace(r):
|
||||
return lexTableNameEnd
|
||||
case r == tableSep:
|
||||
lx.ignore()
|
||||
return lexTableNameStart
|
||||
case r == tableEnd:
|
||||
return lx.pop()
|
||||
default:
|
||||
return lx.errorf("expected '.' or ']' to end table name, "+
|
||||
"but got %q instead", r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexKeyStart consumes a key name up until the first non-whitespace character.
|
||||
// lexKeyStart will ignore whitespace.
|
||||
func lexKeyStart(lx *lexer) stateFn {
|
||||
r := lx.peek()
|
||||
switch {
|
||||
case r == keySep:
|
||||
return lx.errorf("unexpected key separator %q", keySep)
|
||||
case isWhitespace(r) || isNL(r):
|
||||
lx.next()
|
||||
return lexSkip(lx, lexKeyStart)
|
||||
case r == stringStart || r == rawStringStart:
|
||||
lx.ignore()
|
||||
lx.emit(itemKeyStart)
|
||||
lx.push(lexKeyEnd)
|
||||
return lexValue // reuse string lexing
|
||||
default:
|
||||
lx.ignore()
|
||||
lx.emit(itemKeyStart)
|
||||
return lexBareKey
|
||||
}
|
||||
}
|
||||
|
||||
// lexBareKey consumes the text of a bare key. Assumes that the first character
|
||||
// (which is not whitespace) has not yet been consumed.
|
||||
func lexBareKey(lx *lexer) stateFn {
|
||||
switch r := lx.next(); {
|
||||
case isBareKeyChar(r):
|
||||
return lexBareKey
|
||||
case isWhitespace(r):
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexKeyEnd
|
||||
case r == keySep:
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexKeyEnd
|
||||
default:
|
||||
return lx.errorf("bare keys cannot contain %q", r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexKeyEnd consumes the end of a key and trims whitespace (up to the key
|
||||
// separator).
|
||||
func lexKeyEnd(lx *lexer) stateFn {
|
||||
switch r := lx.next(); {
|
||||
case r == keySep:
|
||||
return lexSkip(lx, lexValue)
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexKeyEnd)
|
||||
default:
|
||||
return lx.errorf("expected key separator %q, but got %q instead",
|
||||
keySep, r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexValue starts the consumption of a value anywhere a value is expected.
|
||||
// lexValue will ignore whitespace.
|
||||
// After a value is lexed, the last state on the next is popped and returned.
|
||||
func lexValue(lx *lexer) stateFn {
|
||||
// We allow whitespace to precede a value, but NOT newlines.
|
||||
// In array syntax, the array states are responsible for ignoring newlines.
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexValue)
|
||||
case isDigit(r):
|
||||
lx.backup() // avoid an extra state and use the same as above
|
||||
return lexNumberOrDateStart
|
||||
}
|
||||
switch r {
|
||||
case arrayStart:
|
||||
lx.ignore()
|
||||
lx.emit(itemArray)
|
||||
return lexArrayValue
|
||||
case inlineTableStart:
|
||||
lx.ignore()
|
||||
lx.emit(itemInlineTableStart)
|
||||
return lexInlineTableValue
|
||||
case stringStart:
|
||||
if lx.accept(stringStart) {
|
||||
if lx.accept(stringStart) {
|
||||
lx.ignore() // Ignore """
|
||||
return lexMultilineString
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
lx.ignore() // ignore the '"'
|
||||
return lexString
|
||||
case rawStringStart:
|
||||
if lx.accept(rawStringStart) {
|
||||
if lx.accept(rawStringStart) {
|
||||
lx.ignore() // Ignore """
|
||||
return lexMultilineRawString
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
lx.ignore() // ignore the "'"
|
||||
return lexRawString
|
||||
case '+', '-':
|
||||
return lexNumberStart
|
||||
case '.': // special error case, be kind to users
|
||||
return lx.errorf("floats must start with a digit, not '.'")
|
||||
}
|
||||
if unicode.IsLetter(r) {
|
||||
// Be permissive here; lexBool will give a nice error if the
|
||||
// user wrote something like
|
||||
// x = foo
|
||||
// (i.e. not 'true' or 'false' but is something else word-like.)
|
||||
lx.backup()
|
||||
return lexBool
|
||||
}
|
||||
return lx.errorf("expected value but found %q instead", r)
|
||||
}
|
||||
|
||||
// lexArrayValue consumes one value in an array. It assumes that '[' or ','
|
||||
// have already been consumed. All whitespace and newlines are ignored.
|
||||
func lexArrayValue(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r) || isNL(r):
|
||||
return lexSkip(lx, lexArrayValue)
|
||||
case r == commentStart:
|
||||
lx.push(lexArrayValue)
|
||||
return lexCommentStart
|
||||
case r == comma:
|
||||
return lx.errorf("unexpected comma")
|
||||
case r == arrayEnd:
|
||||
// NOTE(caleb): The spec isn't clear about whether you can have
|
||||
// a trailing comma or not, so we'll allow it.
|
||||
return lexArrayEnd
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.push(lexArrayValueEnd)
|
||||
return lexValue
|
||||
}
|
||||
|
||||
// lexArrayValueEnd consumes everything between the end of an array value and
|
||||
// the next value (or the end of the array): it ignores whitespace and newlines
|
||||
// and expects either a ',' or a ']'.
|
||||
func lexArrayValueEnd(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r) || isNL(r):
|
||||
return lexSkip(lx, lexArrayValueEnd)
|
||||
case r == commentStart:
|
||||
lx.push(lexArrayValueEnd)
|
||||
return lexCommentStart
|
||||
case r == comma:
|
||||
lx.ignore()
|
||||
return lexArrayValue // move on to the next value
|
||||
case r == arrayEnd:
|
||||
return lexArrayEnd
|
||||
}
|
||||
return lx.errorf(
|
||||
"expected a comma or array terminator %q, but got %q instead",
|
||||
arrayEnd, r,
|
||||
)
|
||||
}
|
||||
|
||||
// lexArrayEnd finishes the lexing of an array.
|
||||
// It assumes that a ']' has just been consumed.
|
||||
func lexArrayEnd(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
lx.emit(itemArrayEnd)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexInlineTableValue consumes one key/value pair in an inline table.
|
||||
// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
|
||||
func lexInlineTableValue(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexInlineTableValue)
|
||||
case isNL(r):
|
||||
return lx.errorf("newlines not allowed within inline tables")
|
||||
case r == commentStart:
|
||||
lx.push(lexInlineTableValue)
|
||||
return lexCommentStart
|
||||
case r == comma:
|
||||
return lx.errorf("unexpected comma")
|
||||
case r == inlineTableEnd:
|
||||
return lexInlineTableEnd
|
||||
}
|
||||
lx.backup()
|
||||
lx.push(lexInlineTableValueEnd)
|
||||
return lexKeyStart
|
||||
}
|
||||
|
||||
// lexInlineTableValueEnd consumes everything between the end of an inline table
|
||||
// key/value pair and the next pair (or the end of the table):
|
||||
// it ignores whitespace and expects either a ',' or a '}'.
|
||||
func lexInlineTableValueEnd(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexInlineTableValueEnd)
|
||||
case isNL(r):
|
||||
return lx.errorf("newlines not allowed within inline tables")
|
||||
case r == commentStart:
|
||||
lx.push(lexInlineTableValueEnd)
|
||||
return lexCommentStart
|
||||
case r == comma:
|
||||
lx.ignore()
|
||||
return lexInlineTableValue
|
||||
case r == inlineTableEnd:
|
||||
return lexInlineTableEnd
|
||||
}
|
||||
return lx.errorf("expected a comma or an inline table terminator %q, "+
|
||||
"but got %q instead", inlineTableEnd, r)
|
||||
}
|
||||
|
||||
// lexInlineTableEnd finishes the lexing of an inline table.
|
||||
// It assumes that a '}' has just been consumed.
|
||||
func lexInlineTableEnd(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
lx.emit(itemInlineTableEnd)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexString consumes the inner contents of a string. It assumes that the
|
||||
// beginning '"' has already been consumed and ignored.
|
||||
func lexString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == eof:
|
||||
return lx.errorf("unexpected EOF")
|
||||
case isNL(r):
|
||||
return lx.errorf("strings cannot contain newlines")
|
||||
case r == '\\':
|
||||
lx.push(lexString)
|
||||
return lexStringEscape
|
||||
case r == stringEnd:
|
||||
lx.backup()
|
||||
lx.emit(itemString)
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
return lexString
|
||||
}
|
||||
|
||||
// lexMultilineString consumes the inner contents of a string. It assumes that
|
||||
// the beginning '"""' has already been consumed and ignored.
|
||||
func lexMultilineString(lx *lexer) stateFn {
|
||||
switch lx.next() {
|
||||
case eof:
|
||||
return lx.errorf("unexpected EOF")
|
||||
case '\\':
|
||||
return lexMultilineStringEscape
|
||||
case stringEnd:
|
||||
if lx.accept(stringEnd) {
|
||||
if lx.accept(stringEnd) {
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.emit(itemMultilineString)
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
}
|
||||
return lexMultilineString
|
||||
}
|
||||
|
||||
// lexRawString consumes a raw string. Nothing can be escaped in such a string.
|
||||
// It assumes that the beginning "'" has already been consumed and ignored.
|
||||
func lexRawString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == eof:
|
||||
return lx.errorf("unexpected EOF")
|
||||
case isNL(r):
|
||||
return lx.errorf("strings cannot contain newlines")
|
||||
case r == rawStringEnd:
|
||||
lx.backup()
|
||||
lx.emit(itemRawString)
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
return lexRawString
|
||||
}
|
||||
|
||||
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
|
||||
// a string. It assumes that the beginning "'''" has already been consumed and
|
||||
// ignored.
|
||||
func lexMultilineRawString(lx *lexer) stateFn {
|
||||
switch lx.next() {
|
||||
case eof:
|
||||
return lx.errorf("unexpected EOF")
|
||||
case rawStringEnd:
|
||||
if lx.accept(rawStringEnd) {
|
||||
if lx.accept(rawStringEnd) {
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.emit(itemRawMultilineString)
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
}
|
||||
return lexMultilineRawString
|
||||
}
|
||||
|
||||
// lexMultilineStringEscape consumes an escaped character. It assumes that the
|
||||
// preceding '\\' has already been consumed.
|
||||
func lexMultilineStringEscape(lx *lexer) stateFn {
|
||||
// Handle the special case first:
|
||||
if isNL(lx.next()) {
|
||||
return lexMultilineString
|
||||
}
|
||||
lx.backup()
|
||||
lx.push(lexMultilineString)
|
||||
return lexStringEscape(lx)
|
||||
}
|
||||
|
||||
func lexStringEscape(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch r {
|
||||
case 'b':
|
||||
fallthrough
|
||||
case 't':
|
||||
fallthrough
|
||||
case 'n':
|
||||
fallthrough
|
||||
case 'f':
|
||||
fallthrough
|
||||
case 'r':
|
||||
fallthrough
|
||||
case '"':
|
||||
fallthrough
|
||||
case '\\':
|
||||
return lx.pop()
|
||||
case 'u':
|
||||
return lexShortUnicodeEscape
|
||||
case 'U':
|
||||
return lexLongUnicodeEscape
|
||||
}
|
||||
return lx.errorf("invalid escape character %q; only the following "+
|
||||
"escape characters are allowed: "+
|
||||
`\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
|
||||
}
|
||||
|
||||
func lexShortUnicodeEscape(lx *lexer) stateFn {
|
||||
var r rune
|
||||
for i := 0; i < 4; i++ {
|
||||
r = lx.next()
|
||||
if !isHexadecimal(r) {
|
||||
return lx.errorf(`expected four hexadecimal digits after '\u', `+
|
||||
"but got %q instead", lx.current())
|
||||
}
|
||||
}
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
func lexLongUnicodeEscape(lx *lexer) stateFn {
|
||||
var r rune
|
||||
for i := 0; i < 8; i++ {
|
||||
r = lx.next()
|
||||
if !isHexadecimal(r) {
|
||||
return lx.errorf(`expected eight hexadecimal digits after '\U', `+
|
||||
"but got %q instead", lx.current())
|
||||
}
|
||||
}
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexNumberOrDateStart consumes either an integer, a float, or datetime.
|
||||
func lexNumberOrDateStart(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumberOrDate
|
||||
}
|
||||
switch r {
|
||||
case '_':
|
||||
return lexNumber
|
||||
case 'e', 'E':
|
||||
return lexFloat
|
||||
case '.':
|
||||
return lx.errorf("floats must start with a digit, not '.'")
|
||||
}
|
||||
return lx.errorf("expected a digit but got %q", r)
|
||||
}
|
||||
|
||||
// lexNumberOrDate consumes either an integer, float or datetime.
|
||||
func lexNumberOrDate(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumberOrDate
|
||||
}
|
||||
switch r {
|
||||
case '-':
|
||||
return lexDatetime
|
||||
case '_':
|
||||
return lexNumber
|
||||
case '.', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemInteger)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexDatetime consumes a Datetime, to a first approximation.
|
||||
// The parser validates that it matches one of the accepted formats.
|
||||
func lexDatetime(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexDatetime
|
||||
}
|
||||
switch r {
|
||||
case '-', 'T', ':', '.', 'Z', '+':
|
||||
return lexDatetime
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemDatetime)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexNumberStart consumes either an integer or a float. It assumes that a sign
|
||||
// has already been read, but that *no* digits have been consumed.
|
||||
// lexNumberStart will move to the appropriate integer or float states.
|
||||
func lexNumberStart(lx *lexer) stateFn {
|
||||
// We MUST see a digit. Even floats have to start with a digit.
|
||||
r := lx.next()
|
||||
if !isDigit(r) {
|
||||
if r == '.' {
|
||||
return lx.errorf("floats must start with a digit, not '.'")
|
||||
}
|
||||
return lx.errorf("expected a digit but got %q", r)
|
||||
}
|
||||
return lexNumber
|
||||
}
|
||||
|
||||
// lexNumber consumes an integer or a float after seeing the first digit.
|
||||
func lexNumber(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumber
|
||||
}
|
||||
switch r {
|
||||
case '_':
|
||||
return lexNumber
|
||||
case '.', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemInteger)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexFloat consumes the elements of a float. It allows any sequence of
|
||||
// float-like characters, so floats emitted by the lexer are only a first
|
||||
// approximation and must be validated by the parser.
|
||||
func lexFloat(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexFloat
|
||||
}
|
||||
switch r {
|
||||
case '_', '.', '-', '+', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemFloat)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexBool consumes a bool string: 'true' or 'false.
|
||||
func lexBool(lx *lexer) stateFn {
|
||||
var rs []rune
|
||||
for {
|
||||
r := lx.next()
|
||||
if !unicode.IsLetter(r) {
|
||||
lx.backup()
|
||||
break
|
||||
}
|
||||
rs = append(rs, r)
|
||||
}
|
||||
s := string(rs)
|
||||
switch s {
|
||||
case "true", "false":
|
||||
lx.emit(itemBool)
|
||||
return lx.pop()
|
||||
}
|
||||
return lx.errorf("expected value but found %q instead", s)
|
||||
}
|
||||
|
||||
// lexCommentStart begins the lexing of a comment. It will emit
|
||||
// itemCommentStart and consume no characters, passing control to lexComment.
|
||||
func lexCommentStart(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
lx.emit(itemCommentStart)
|
||||
return lexComment
|
||||
}
|
||||
|
||||
// lexComment lexes an entire comment. It assumes that '#' has been consumed.
|
||||
// It will consume *up to* the first newline character, and pass control
|
||||
// back to the last state on the stack.
|
||||
func lexComment(lx *lexer) stateFn {
|
||||
r := lx.peek()
|
||||
if isNL(r) || r == eof {
|
||||
lx.emit(itemText)
|
||||
return lx.pop()
|
||||
}
|
||||
lx.next()
|
||||
return lexComment
|
||||
}
|
||||
|
||||
// lexSkip ignores all slurped input and moves on to the next state.
|
||||
func lexSkip(lx *lexer, nextState stateFn) stateFn {
|
||||
return func(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
return nextState
|
||||
}
|
||||
}
|
||||
|
||||
// isWhitespace returns true if `r` is a whitespace character according
|
||||
// to the spec.
|
||||
func isWhitespace(r rune) bool {
|
||||
return r == '\t' || r == ' '
|
||||
}
|
||||
|
||||
func isNL(r rune) bool {
|
||||
return r == '\n' || r == '\r'
|
||||
}
|
||||
|
||||
func isDigit(r rune) bool {
|
||||
return r >= '0' && r <= '9'
|
||||
}
|
||||
|
||||
func isHexadecimal(r rune) bool {
|
||||
return (r >= '0' && r <= '9') ||
|
||||
(r >= 'a' && r <= 'f') ||
|
||||
(r >= 'A' && r <= 'F')
|
||||
}
|
||||
|
||||
func isBareKeyChar(r rune) bool {
|
||||
return (r >= 'A' && r <= 'Z') ||
|
||||
(r >= 'a' && r <= 'z') ||
|
||||
(r >= '0' && r <= '9') ||
|
||||
r == '_' ||
|
||||
r == '-'
|
||||
}
|
||||
|
||||
func (itype itemType) String() string {
|
||||
switch itype {
|
||||
case itemError:
|
||||
return "Error"
|
||||
case itemNIL:
|
||||
return "NIL"
|
||||
case itemEOF:
|
||||
return "EOF"
|
||||
case itemText:
|
||||
return "Text"
|
||||
case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
|
||||
return "String"
|
||||
case itemBool:
|
||||
return "Bool"
|
||||
case itemInteger:
|
||||
return "Integer"
|
||||
case itemFloat:
|
||||
return "Float"
|
||||
case itemDatetime:
|
||||
return "DateTime"
|
||||
case itemTableStart:
|
||||
return "TableStart"
|
||||
case itemTableEnd:
|
||||
return "TableEnd"
|
||||
case itemKeyStart:
|
||||
return "KeyStart"
|
||||
case itemArray:
|
||||
return "Array"
|
||||
case itemArrayEnd:
|
||||
return "ArrayEnd"
|
||||
case itemCommentStart:
|
||||
return "CommentStart"
|
||||
}
|
||||
panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
|
||||
}
|
||||
|
||||
func (item item) String() string {
|
||||
return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val)
|
||||
}
|
592
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
Normal file
592
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
Normal file
@ -0,0 +1,592 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type parser struct {
|
||||
mapping map[string]interface{}
|
||||
types map[string]tomlType
|
||||
lx *lexer
|
||||
|
||||
// A list of keys in the order that they appear in the TOML data.
|
||||
ordered []Key
|
||||
|
||||
// the full key for the current hash in scope
|
||||
context Key
|
||||
|
||||
// the base key name for everything except hashes
|
||||
currentKey string
|
||||
|
||||
// rough approximation of line number
|
||||
approxLine int
|
||||
|
||||
// A map of 'key.group.names' to whether they were created implicitly.
|
||||
implicits map[string]bool
|
||||
}
|
||||
|
||||
type parseError string
|
||||
|
||||
func (pe parseError) Error() string {
|
||||
return string(pe)
|
||||
}
|
||||
|
||||
func parse(data string) (p *parser, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
var ok bool
|
||||
if err, ok = r.(parseError); ok {
|
||||
return
|
||||
}
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
p = &parser{
|
||||
mapping: make(map[string]interface{}),
|
||||
types: make(map[string]tomlType),
|
||||
lx: lex(data),
|
||||
ordered: make([]Key, 0),
|
||||
implicits: make(map[string]bool),
|
||||
}
|
||||
for {
|
||||
item := p.next()
|
||||
if item.typ == itemEOF {
|
||||
break
|
||||
}
|
||||
p.topLevel(item)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *parser) panicf(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s",
|
||||
p.approxLine, p.current(), fmt.Sprintf(format, v...))
|
||||
panic(parseError(msg))
|
||||
}
|
||||
|
||||
func (p *parser) next() item {
|
||||
it := p.lx.nextItem()
|
||||
if it.typ == itemError {
|
||||
p.panicf("%s", it.val)
|
||||
}
|
||||
return it
|
||||
}
|
||||
|
||||
func (p *parser) bug(format string, v ...interface{}) {
|
||||
panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
|
||||
}
|
||||
|
||||
func (p *parser) expect(typ itemType) item {
|
||||
it := p.next()
|
||||
p.assertEqual(typ, it.typ)
|
||||
return it
|
||||
}
|
||||
|
||||
func (p *parser) assertEqual(expected, got itemType) {
|
||||
if expected != got {
|
||||
p.bug("Expected '%s' but got '%s'.", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) topLevel(item item) {
|
||||
switch item.typ {
|
||||
case itemCommentStart:
|
||||
p.approxLine = item.line
|
||||
p.expect(itemText)
|
||||
case itemTableStart:
|
||||
kg := p.next()
|
||||
p.approxLine = kg.line
|
||||
|
||||
var key Key
|
||||
for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() {
|
||||
key = append(key, p.keyString(kg))
|
||||
}
|
||||
p.assertEqual(itemTableEnd, kg.typ)
|
||||
|
||||
p.establishContext(key, false)
|
||||
p.setType("", tomlHash)
|
||||
p.ordered = append(p.ordered, key)
|
||||
case itemArrayTableStart:
|
||||
kg := p.next()
|
||||
p.approxLine = kg.line
|
||||
|
||||
var key Key
|
||||
for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() {
|
||||
key = append(key, p.keyString(kg))
|
||||
}
|
||||
p.assertEqual(itemArrayTableEnd, kg.typ)
|
||||
|
||||
p.establishContext(key, true)
|
||||
p.setType("", tomlArrayHash)
|
||||
p.ordered = append(p.ordered, key)
|
||||
case itemKeyStart:
|
||||
kname := p.next()
|
||||
p.approxLine = kname.line
|
||||
p.currentKey = p.keyString(kname)
|
||||
|
||||
val, typ := p.value(p.next())
|
||||
p.setValue(p.currentKey, val)
|
||||
p.setType(p.currentKey, typ)
|
||||
p.ordered = append(p.ordered, p.context.add(p.currentKey))
|
||||
p.currentKey = ""
|
||||
default:
|
||||
p.bug("Unexpected type at top level: %s", item.typ)
|
||||
}
|
||||
}
|
||||
|
||||
// Gets a string for a key (or part of a key in a table name).
|
||||
func (p *parser) keyString(it item) string {
|
||||
switch it.typ {
|
||||
case itemText:
|
||||
return it.val
|
||||
case itemString, itemMultilineString,
|
||||
itemRawString, itemRawMultilineString:
|
||||
s, _ := p.value(it)
|
||||
return s.(string)
|
||||
default:
|
||||
p.bug("Unexpected key type: %s", it.typ)
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// value translates an expected value from the lexer into a Go value wrapped
|
||||
// as an empty interface.
|
||||
func (p *parser) value(it item) (interface{}, tomlType) {
|
||||
switch it.typ {
|
||||
case itemString:
|
||||
return p.replaceEscapes(it.val), p.typeOfPrimitive(it)
|
||||
case itemMultilineString:
|
||||
trimmed := stripFirstNewline(stripEscapedWhitespace(it.val))
|
||||
return p.replaceEscapes(trimmed), p.typeOfPrimitive(it)
|
||||
case itemRawString:
|
||||
return it.val, p.typeOfPrimitive(it)
|
||||
case itemRawMultilineString:
|
||||
return stripFirstNewline(it.val), p.typeOfPrimitive(it)
|
||||
case itemBool:
|
||||
switch it.val {
|
||||
case "true":
|
||||
return true, p.typeOfPrimitive(it)
|
||||
case "false":
|
||||
return false, p.typeOfPrimitive(it)
|
||||
}
|
||||
p.bug("Expected boolean value, but got '%s'.", it.val)
|
||||
case itemInteger:
|
||||
if !numUnderscoresOK(it.val) {
|
||||
p.panicf("Invalid integer %q: underscores must be surrounded by digits",
|
||||
it.val)
|
||||
}
|
||||
val := strings.Replace(it.val, "_", "", -1)
|
||||
num, err := strconv.ParseInt(val, 10, 64)
|
||||
if err != nil {
|
||||
// Distinguish integer values. Normally, it'd be a bug if the lexer
|
||||
// provides an invalid integer, but it's possible that the number is
|
||||
// out of range of valid values (which the lexer cannot determine).
|
||||
// So mark the former as a bug but the latter as a legitimate user
|
||||
// error.
|
||||
if e, ok := err.(*strconv.NumError); ok &&
|
||||
e.Err == strconv.ErrRange {
|
||||
|
||||
p.panicf("Integer '%s' is out of the range of 64-bit "+
|
||||
"signed integers.", it.val)
|
||||
} else {
|
||||
p.bug("Expected integer value, but got '%s'.", it.val)
|
||||
}
|
||||
}
|
||||
return num, p.typeOfPrimitive(it)
|
||||
case itemFloat:
|
||||
parts := strings.FieldsFunc(it.val, func(r rune) bool {
|
||||
switch r {
|
||||
case '.', 'e', 'E':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
for _, part := range parts {
|
||||
if !numUnderscoresOK(part) {
|
||||
p.panicf("Invalid float %q: underscores must be "+
|
||||
"surrounded by digits", it.val)
|
||||
}
|
||||
}
|
||||
if !numPeriodsOK(it.val) {
|
||||
// As a special case, numbers like '123.' or '1.e2',
|
||||
// which are valid as far as Go/strconv are concerned,
|
||||
// must be rejected because TOML says that a fractional
|
||||
// part consists of '.' followed by 1+ digits.
|
||||
p.panicf("Invalid float %q: '.' must be followed "+
|
||||
"by one or more digits", it.val)
|
||||
}
|
||||
val := strings.Replace(it.val, "_", "", -1)
|
||||
num, err := strconv.ParseFloat(val, 64)
|
||||
if err != nil {
|
||||
if e, ok := err.(*strconv.NumError); ok &&
|
||||
e.Err == strconv.ErrRange {
|
||||
|
||||
p.panicf("Float '%s' is out of the range of 64-bit "+
|
||||
"IEEE-754 floating-point numbers.", it.val)
|
||||
} else {
|
||||
p.panicf("Invalid float value: %q", it.val)
|
||||
}
|
||||
}
|
||||
return num, p.typeOfPrimitive(it)
|
||||
case itemDatetime:
|
||||
var t time.Time
|
||||
var ok bool
|
||||
var err error
|
||||
for _, format := range []string{
|
||||
"2006-01-02T15:04:05Z07:00",
|
||||
"2006-01-02T15:04:05",
|
||||
"2006-01-02",
|
||||
} {
|
||||
t, err = time.ParseInLocation(format, it.val, time.Local)
|
||||
if err == nil {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
p.panicf("Invalid TOML Datetime: %q.", it.val)
|
||||
}
|
||||
return t, p.typeOfPrimitive(it)
|
||||
case itemArray:
|
||||
array := make([]interface{}, 0)
|
||||
types := make([]tomlType, 0)
|
||||
|
||||
for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
|
||||
if it.typ == itemCommentStart {
|
||||
p.expect(itemText)
|
||||
continue
|
||||
}
|
||||
|
||||
val, typ := p.value(it)
|
||||
array = append(array, val)
|
||||
types = append(types, typ)
|
||||
}
|
||||
return array, p.typeOfArray(types)
|
||||
case itemInlineTableStart:
|
||||
var (
|
||||
hash = make(map[string]interface{})
|
||||
outerContext = p.context
|
||||
outerKey = p.currentKey
|
||||
)
|
||||
|
||||
p.context = append(p.context, p.currentKey)
|
||||
p.currentKey = ""
|
||||
for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
|
||||
if it.typ != itemKeyStart {
|
||||
p.bug("Expected key start but instead found %q, around line %d",
|
||||
it.val, p.approxLine)
|
||||
}
|
||||
if it.typ == itemCommentStart {
|
||||
p.expect(itemText)
|
||||
continue
|
||||
}
|
||||
|
||||
// retrieve key
|
||||
k := p.next()
|
||||
p.approxLine = k.line
|
||||
kname := p.keyString(k)
|
||||
|
||||
// retrieve value
|
||||
p.currentKey = kname
|
||||
val, typ := p.value(p.next())
|
||||
// make sure we keep metadata up to date
|
||||
p.setType(kname, typ)
|
||||
p.ordered = append(p.ordered, p.context.add(p.currentKey))
|
||||
hash[kname] = val
|
||||
}
|
||||
p.context = outerContext
|
||||
p.currentKey = outerKey
|
||||
return hash, tomlHash
|
||||
}
|
||||
p.bug("Unexpected value type: %s", it.typ)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// numUnderscoresOK checks whether each underscore in s is surrounded by
|
||||
// characters that are not underscores.
|
||||
func numUnderscoresOK(s string) bool {
|
||||
accept := false
|
||||
for _, r := range s {
|
||||
if r == '_' {
|
||||
if !accept {
|
||||
return false
|
||||
}
|
||||
accept = false
|
||||
continue
|
||||
}
|
||||
accept = true
|
||||
}
|
||||
return accept
|
||||
}
|
||||
|
||||
// numPeriodsOK checks whether every period in s is followed by a digit.
|
||||
func numPeriodsOK(s string) bool {
|
||||
period := false
|
||||
for _, r := range s {
|
||||
if period && !isDigit(r) {
|
||||
return false
|
||||
}
|
||||
period = r == '.'
|
||||
}
|
||||
return !period
|
||||
}
|
||||
|
||||
// establishContext sets the current context of the parser,
|
||||
// where the context is either a hash or an array of hashes. Which one is
|
||||
// set depends on the value of the `array` parameter.
|
||||
//
|
||||
// Establishing the context also makes sure that the key isn't a duplicate, and
|
||||
// will create implicit hashes automatically.
|
||||
func (p *parser) establishContext(key Key, array bool) {
|
||||
var ok bool
|
||||
|
||||
// Always start at the top level and drill down for our context.
|
||||
hashContext := p.mapping
|
||||
keyContext := make(Key, 0)
|
||||
|
||||
// We only need implicit hashes for key[0:-1]
|
||||
for _, k := range key[0 : len(key)-1] {
|
||||
_, ok = hashContext[k]
|
||||
keyContext = append(keyContext, k)
|
||||
|
||||
// No key? Make an implicit hash and move on.
|
||||
if !ok {
|
||||
p.addImplicit(keyContext)
|
||||
hashContext[k] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// If the hash context is actually an array of tables, then set
|
||||
// the hash context to the last element in that array.
|
||||
//
|
||||
// Otherwise, it better be a table, since this MUST be a key group (by
|
||||
// virtue of it not being the last element in a key).
|
||||
switch t := hashContext[k].(type) {
|
||||
case []map[string]interface{}:
|
||||
hashContext = t[len(t)-1]
|
||||
case map[string]interface{}:
|
||||
hashContext = t
|
||||
default:
|
||||
p.panicf("Key '%s' was already created as a hash.", keyContext)
|
||||
}
|
||||
}
|
||||
|
||||
p.context = keyContext
|
||||
if array {
|
||||
// If this is the first element for this array, then allocate a new
|
||||
// list of tables for it.
|
||||
k := key[len(key)-1]
|
||||
if _, ok := hashContext[k]; !ok {
|
||||
hashContext[k] = make([]map[string]interface{}, 0, 5)
|
||||
}
|
||||
|
||||
// Add a new table. But make sure the key hasn't already been used
|
||||
// for something else.
|
||||
if hash, ok := hashContext[k].([]map[string]interface{}); ok {
|
||||
hashContext[k] = append(hash, make(map[string]interface{}))
|
||||
} else {
|
||||
p.panicf("Key '%s' was already created and cannot be used as "+
|
||||
"an array.", keyContext)
|
||||
}
|
||||
} else {
|
||||
p.setValue(key[len(key)-1], make(map[string]interface{}))
|
||||
}
|
||||
p.context = append(p.context, key[len(key)-1])
|
||||
}
|
||||
|
||||
// setValue sets the given key to the given value in the current context.
|
||||
// It will make sure that the key hasn't already been defined, account for
|
||||
// implicit key groups.
|
||||
func (p *parser) setValue(key string, value interface{}) {
|
||||
var tmpHash interface{}
|
||||
var ok bool
|
||||
|
||||
hash := p.mapping
|
||||
keyContext := make(Key, 0)
|
||||
for _, k := range p.context {
|
||||
keyContext = append(keyContext, k)
|
||||
if tmpHash, ok = hash[k]; !ok {
|
||||
p.bug("Context for key '%s' has not been established.", keyContext)
|
||||
}
|
||||
switch t := tmpHash.(type) {
|
||||
case []map[string]interface{}:
|
||||
// The context is a table of hashes. Pick the most recent table
|
||||
// defined as the current hash.
|
||||
hash = t[len(t)-1]
|
||||
case map[string]interface{}:
|
||||
hash = t
|
||||
default:
|
||||
p.bug("Expected hash to have type 'map[string]interface{}', but "+
|
||||
"it has '%T' instead.", tmpHash)
|
||||
}
|
||||
}
|
||||
keyContext = append(keyContext, key)
|
||||
|
||||
if _, ok := hash[key]; ok {
|
||||
// Typically, if the given key has already been set, then we have
|
||||
// to raise an error since duplicate keys are disallowed. However,
|
||||
// it's possible that a key was previously defined implicitly. In this
|
||||
// case, it is allowed to be redefined concretely. (See the
|
||||
// `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.)
|
||||
//
|
||||
// But we have to make sure to stop marking it as an implicit. (So that
|
||||
// another redefinition provokes an error.)
|
||||
//
|
||||
// Note that since it has already been defined (as a hash), we don't
|
||||
// want to overwrite it. So our business is done.
|
||||
if p.isImplicit(keyContext) {
|
||||
p.removeImplicit(keyContext)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, we have a concrete key trying to override a previous
|
||||
// key, which is *always* wrong.
|
||||
p.panicf("Key '%s' has already been defined.", keyContext)
|
||||
}
|
||||
hash[key] = value
|
||||
}
|
||||
|
||||
// setType sets the type of a particular value at a given key.
|
||||
// It should be called immediately AFTER setValue.
|
||||
//
|
||||
// Note that if `key` is empty, then the type given will be applied to the
|
||||
// current context (which is either a table or an array of tables).
|
||||
func (p *parser) setType(key string, typ tomlType) {
|
||||
keyContext := make(Key, 0, len(p.context)+1)
|
||||
for _, k := range p.context {
|
||||
keyContext = append(keyContext, k)
|
||||
}
|
||||
if len(key) > 0 { // allow type setting for hashes
|
||||
keyContext = append(keyContext, key)
|
||||
}
|
||||
p.types[keyContext.String()] = typ
|
||||
}
|
||||
|
||||
// addImplicit sets the given Key as having been created implicitly.
|
||||
func (p *parser) addImplicit(key Key) {
|
||||
p.implicits[key.String()] = true
|
||||
}
|
||||
|
||||
// removeImplicit stops tagging the given key as having been implicitly
|
||||
// created.
|
||||
func (p *parser) removeImplicit(key Key) {
|
||||
p.implicits[key.String()] = false
|
||||
}
|
||||
|
||||
// isImplicit returns true if the key group pointed to by the key was created
|
||||
// implicitly.
|
||||
func (p *parser) isImplicit(key Key) bool {
|
||||
return p.implicits[key.String()]
|
||||
}
|
||||
|
||||
// current returns the full key name of the current context.
|
||||
func (p *parser) current() string {
|
||||
if len(p.currentKey) == 0 {
|
||||
return p.context.String()
|
||||
}
|
||||
if len(p.context) == 0 {
|
||||
return p.currentKey
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", p.context, p.currentKey)
|
||||
}
|
||||
|
||||
func stripFirstNewline(s string) string {
|
||||
if len(s) == 0 || s[0] != '\n' {
|
||||
return s
|
||||
}
|
||||
return s[1:]
|
||||
}
|
||||
|
||||
func stripEscapedWhitespace(s string) string {
|
||||
esc := strings.Split(s, "\\\n")
|
||||
if len(esc) > 1 {
|
||||
for i := 1; i < len(esc); i++ {
|
||||
esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace)
|
||||
}
|
||||
}
|
||||
return strings.Join(esc, "")
|
||||
}
|
||||
|
||||
func (p *parser) replaceEscapes(str string) string {
|
||||
var replaced []rune
|
||||
s := []byte(str)
|
||||
r := 0
|
||||
for r < len(s) {
|
||||
if s[r] != '\\' {
|
||||
c, size := utf8.DecodeRune(s[r:])
|
||||
r += size
|
||||
replaced = append(replaced, c)
|
||||
continue
|
||||
}
|
||||
r += 1
|
||||
if r >= len(s) {
|
||||
p.bug("Escape sequence at end of string.")
|
||||
return ""
|
||||
}
|
||||
switch s[r] {
|
||||
default:
|
||||
p.bug("Expected valid escape code after \\, but got %q.", s[r])
|
||||
return ""
|
||||
case 'b':
|
||||
replaced = append(replaced, rune(0x0008))
|
||||
r += 1
|
||||
case 't':
|
||||
replaced = append(replaced, rune(0x0009))
|
||||
r += 1
|
||||
case 'n':
|
||||
replaced = append(replaced, rune(0x000A))
|
||||
r += 1
|
||||
case 'f':
|
||||
replaced = append(replaced, rune(0x000C))
|
||||
r += 1
|
||||
case 'r':
|
||||
replaced = append(replaced, rune(0x000D))
|
||||
r += 1
|
||||
case '"':
|
||||
replaced = append(replaced, rune(0x0022))
|
||||
r += 1
|
||||
case '\\':
|
||||
replaced = append(replaced, rune(0x005C))
|
||||
r += 1
|
||||
case 'u':
|
||||
// At this point, we know we have a Unicode escape of the form
|
||||
// `uXXXX` at [r, r+5). (Because the lexer guarantees this
|
||||
// for us.)
|
||||
escaped := p.asciiEscapeToUnicode(s[r+1 : r+5])
|
||||
replaced = append(replaced, escaped)
|
||||
r += 5
|
||||
case 'U':
|
||||
// At this point, we know we have a Unicode escape of the form
|
||||
// `uXXXX` at [r, r+9). (Because the lexer guarantees this
|
||||
// for us.)
|
||||
escaped := p.asciiEscapeToUnicode(s[r+1 : r+9])
|
||||
replaced = append(replaced, escaped)
|
||||
r += 9
|
||||
}
|
||||
}
|
||||
return string(replaced)
|
||||
}
|
||||
|
||||
func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
|
||||
s := string(bs)
|
||||
hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
|
||||
if err != nil {
|
||||
p.bug("Could not parse '%s' as a hexadecimal number, but the "+
|
||||
"lexer claims it's OK: %s", s, err)
|
||||
}
|
||||
if !utf8.ValidRune(rune(hex)) {
|
||||
p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
|
||||
}
|
||||
return rune(hex)
|
||||
}
|
||||
|
||||
func isStringType(ty itemType) bool {
|
||||
return ty == itemString || ty == itemMultilineString ||
|
||||
ty == itemRawString || ty == itemRawMultilineString
|
||||
}
|
1
vendor/github.com/BurntSushi/toml/session.vim
generated
vendored
Normal file
1
vendor/github.com/BurntSushi/toml/session.vim
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
au BufWritePost *.go silent!make tags > /dev/null 2>&1
|
91
vendor/github.com/BurntSushi/toml/type_check.go
generated
vendored
Normal file
91
vendor/github.com/BurntSushi/toml/type_check.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
package toml
|
||||
|
||||
// tomlType represents any Go type that corresponds to a TOML type.
|
||||
// While the first draft of the TOML spec has a simplistic type system that
|
||||
// probably doesn't need this level of sophistication, we seem to be militating
|
||||
// toward adding real composite types.
|
||||
type tomlType interface {
|
||||
typeString() string
|
||||
}
|
||||
|
||||
// typeEqual accepts any two types and returns true if they are equal.
|
||||
func typeEqual(t1, t2 tomlType) bool {
|
||||
if t1 == nil || t2 == nil {
|
||||
return false
|
||||
}
|
||||
return t1.typeString() == t2.typeString()
|
||||
}
|
||||
|
||||
func typeIsHash(t tomlType) bool {
|
||||
return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
|
||||
}
|
||||
|
||||
type tomlBaseType string
|
||||
|
||||
func (btype tomlBaseType) typeString() string {
|
||||
return string(btype)
|
||||
}
|
||||
|
||||
func (btype tomlBaseType) String() string {
|
||||
return btype.typeString()
|
||||
}
|
||||
|
||||
var (
|
||||
tomlInteger tomlBaseType = "Integer"
|
||||
tomlFloat tomlBaseType = "Float"
|
||||
tomlDatetime tomlBaseType = "Datetime"
|
||||
tomlString tomlBaseType = "String"
|
||||
tomlBool tomlBaseType = "Bool"
|
||||
tomlArray tomlBaseType = "Array"
|
||||
tomlHash tomlBaseType = "Hash"
|
||||
tomlArrayHash tomlBaseType = "ArrayHash"
|
||||
)
|
||||
|
||||
// typeOfPrimitive returns a tomlType of any primitive value in TOML.
|
||||
// Primitive values are: Integer, Float, Datetime, String and Bool.
|
||||
//
|
||||
// Passing a lexer item other than the following will cause a BUG message
|
||||
// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
|
||||
func (p *parser) typeOfPrimitive(lexItem item) tomlType {
|
||||
switch lexItem.typ {
|
||||
case itemInteger:
|
||||
return tomlInteger
|
||||
case itemFloat:
|
||||
return tomlFloat
|
||||
case itemDatetime:
|
||||
return tomlDatetime
|
||||
case itemString:
|
||||
return tomlString
|
||||
case itemMultilineString:
|
||||
return tomlString
|
||||
case itemRawString:
|
||||
return tomlString
|
||||
case itemRawMultilineString:
|
||||
return tomlString
|
||||
case itemBool:
|
||||
return tomlBool
|
||||
}
|
||||
p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// typeOfArray returns a tomlType for an array given a list of types of its
|
||||
// values.
|
||||
//
|
||||
// In the current spec, if an array is homogeneous, then its type is always
|
||||
// "Array". If the array is not homogeneous, an error is generated.
|
||||
func (p *parser) typeOfArray(types []tomlType) tomlType {
|
||||
// Empty arrays are cool.
|
||||
if len(types) == 0 {
|
||||
return tomlArray
|
||||
}
|
||||
|
||||
theType := types[0]
|
||||
for _, t := range types[1:] {
|
||||
if !typeEqual(theType, t) {
|
||||
p.panicf("Array contains values of type '%s' and '%s', but "+
|
||||
"arrays must be homogeneous.", theType, t)
|
||||
}
|
||||
}
|
||||
return tomlArray
|
||||
}
|
242
vendor/github.com/BurntSushi/toml/type_fields.go
generated
vendored
Normal file
242
vendor/github.com/BurntSushi/toml/type_fields.go
generated
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
package toml
|
||||
|
||||
// Struct field handling is adapted from code in encoding/json:
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the Go distribution.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A field represents a single field found in a struct.
|
||||
type field struct {
|
||||
name string // the name of the field (`toml` tag included)
|
||||
tag bool // whether field has a `toml` tag
|
||||
index []int // represents the depth of an anonymous field
|
||||
typ reflect.Type // the type of the field
|
||||
}
|
||||
|
||||
// byName sorts field by name, breaking ties with depth,
|
||||
// then breaking ties with "name came from toml tag", then
|
||||
// breaking ties with index sequence.
|
||||
type byName []field
|
||||
|
||||
func (x byName) Len() int { return len(x) }
|
||||
|
||||
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byName) Less(i, j int) bool {
|
||||
if x[i].name != x[j].name {
|
||||
return x[i].name < x[j].name
|
||||
}
|
||||
if len(x[i].index) != len(x[j].index) {
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
if x[i].tag != x[j].tag {
|
||||
return x[i].tag
|
||||
}
|
||||
return byIndex(x).Less(i, j)
|
||||
}
|
||||
|
||||
// byIndex sorts field by index sequence.
|
||||
type byIndex []field
|
||||
|
||||
func (x byIndex) Len() int { return len(x) }
|
||||
|
||||
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byIndex) Less(i, j int) bool {
|
||||
for k, xik := range x[i].index {
|
||||
if k >= len(x[j].index) {
|
||||
return false
|
||||
}
|
||||
if xik != x[j].index[k] {
|
||||
return xik < x[j].index[k]
|
||||
}
|
||||
}
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
|
||||
// typeFields returns a list of fields that TOML should recognize for the given
|
||||
// type. The algorithm is breadth-first search over the set of structs to
|
||||
// include - the top struct and then any reachable anonymous structs.
|
||||
func typeFields(t reflect.Type) []field {
|
||||
// Anonymous fields to explore at the current level and the next.
|
||||
current := []field{}
|
||||
next := []field{{typ: t}}
|
||||
|
||||
// Count of queued names for current level and the next.
|
||||
count := map[reflect.Type]int{}
|
||||
nextCount := map[reflect.Type]int{}
|
||||
|
||||
// Types already visited at an earlier level.
|
||||
visited := map[reflect.Type]bool{}
|
||||
|
||||
// Fields found.
|
||||
var fields []field
|
||||
|
||||
for len(next) > 0 {
|
||||
current, next = next, current[:0]
|
||||
count, nextCount = nextCount, map[reflect.Type]int{}
|
||||
|
||||
for _, f := range current {
|
||||
if visited[f.typ] {
|
||||
continue
|
||||
}
|
||||
visited[f.typ] = true
|
||||
|
||||
// Scan f.typ for fields to include.
|
||||
for i := 0; i < f.typ.NumField(); i++ {
|
||||
sf := f.typ.Field(i)
|
||||
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||
continue
|
||||
}
|
||||
opts := getOptions(sf.Tag)
|
||||
if opts.skip {
|
||||
continue
|
||||
}
|
||||
index := make([]int, len(f.index)+1)
|
||||
copy(index, f.index)
|
||||
index[len(f.index)] = i
|
||||
|
||||
ft := sf.Type
|
||||
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
|
||||
// Follow pointer.
|
||||
ft = ft.Elem()
|
||||
}
|
||||
|
||||
// Record found field and index sequence.
|
||||
if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||
tagged := opts.name != ""
|
||||
name := opts.name
|
||||
if name == "" {
|
||||
name = sf.Name
|
||||
}
|
||||
fields = append(fields, field{name, tagged, index, ft})
|
||||
if count[f.typ] > 1 {
|
||||
// If there were multiple instances, add a second,
|
||||
// so that the annihilation code will see a duplicate.
|
||||
// It only cares about the distinction between 1 or 2,
|
||||
// so don't bother generating any more copies.
|
||||
fields = append(fields, fields[len(fields)-1])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Record new anonymous struct to explore in next round.
|
||||
nextCount[ft]++
|
||||
if nextCount[ft] == 1 {
|
||||
f := field{name: ft.Name(), index: index, typ: ft}
|
||||
next = append(next, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(byName(fields))
|
||||
|
||||
// Delete all fields that are hidden by the Go rules for embedded fields,
|
||||
// except that fields with TOML tags are promoted.
|
||||
|
||||
// The fields are sorted in primary order of name, secondary order
|
||||
// of field index length. Loop over names; for each name, delete
|
||||
// hidden fields by choosing the one dominant field that survives.
|
||||
out := fields[:0]
|
||||
for advance, i := 0, 0; i < len(fields); i += advance {
|
||||
// One iteration per name.
|
||||
// Find the sequence of fields with the name of this first field.
|
||||
fi := fields[i]
|
||||
name := fi.name
|
||||
for advance = 1; i+advance < len(fields); advance++ {
|
||||
fj := fields[i+advance]
|
||||
if fj.name != name {
|
||||
break
|
||||
}
|
||||
}
|
||||
if advance == 1 { // Only one field with this name
|
||||
out = append(out, fi)
|
||||
continue
|
||||
}
|
||||
dominant, ok := dominantField(fields[i : i+advance])
|
||||
if ok {
|
||||
out = append(out, dominant)
|
||||
}
|
||||
}
|
||||
|
||||
fields = out
|
||||
sort.Sort(byIndex(fields))
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// dominantField looks through the fields, all of which are known to
|
||||
// have the same name, to find the single field that dominates the
|
||||
// others using Go's embedding rules, modified by the presence of
|
||||
// TOML tags. If there are multiple top-level fields, the boolean
|
||||
// will be false: This condition is an error in Go and we skip all
|
||||
// the fields.
|
||||
func dominantField(fields []field) (field, bool) {
|
||||
// The fields are sorted in increasing index-length order. The winner
|
||||
// must therefore be one with the shortest index length. Drop all
|
||||
// longer entries, which is easy: just truncate the slice.
|
||||
length := len(fields[0].index)
|
||||
tagged := -1 // Index of first tagged field.
|
||||
for i, f := range fields {
|
||||
if len(f.index) > length {
|
||||
fields = fields[:i]
|
||||
break
|
||||
}
|
||||
if f.tag {
|
||||
if tagged >= 0 {
|
||||
// Multiple tagged fields at the same level: conflict.
|
||||
// Return no field.
|
||||
return field{}, false
|
||||
}
|
||||
tagged = i
|
||||
}
|
||||
}
|
||||
if tagged >= 0 {
|
||||
return fields[tagged], true
|
||||
}
|
||||
// All remaining fields have the same length. If there's more than one,
|
||||
// we have a conflict (two fields named "X" at the same level) and we
|
||||
// return no field.
|
||||
if len(fields) > 1 {
|
||||
return field{}, false
|
||||
}
|
||||
return fields[0], true
|
||||
}
|
||||
|
||||
var fieldCache struct {
|
||||
sync.RWMutex
|
||||
m map[reflect.Type][]field
|
||||
}
|
||||
|
||||
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
|
||||
func cachedTypeFields(t reflect.Type) []field {
|
||||
fieldCache.RLock()
|
||||
f := fieldCache.m[t]
|
||||
fieldCache.RUnlock()
|
||||
if f != nil {
|
||||
return f
|
||||
}
|
||||
|
||||
// Compute fields without lock.
|
||||
// Might duplicate effort but won't hold other computations back.
|
||||
f = typeFields(t)
|
||||
if f == nil {
|
||||
f = []field{}
|
||||
}
|
||||
|
||||
fieldCache.Lock()
|
||||
if fieldCache.m == nil {
|
||||
fieldCache.m = map[reflect.Type][]field{}
|
||||
}
|
||||
fieldCache.m[t] = f
|
||||
fieldCache.Unlock()
|
||||
return f
|
||||
}
|
15
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
Normal file
15
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
coverage:
|
||||
range: 80..100
|
||||
round: down
|
||||
precision: 2
|
||||
|
||||
status:
|
||||
project: # measuring the overall project coverage
|
||||
default: # context, you can create multiple ones with custom titles
|
||||
enabled: yes # must be yes|true to enable this status
|
||||
target: 100 # specify the target coverage for each commit status
|
||||
# option: "auto" (must increase from parent commit or pull request base)
|
||||
# option: "X%" a static target percentage to hit
|
||||
if_not_found: success # if parent is not found report status as success, error, or failure
|
||||
if_ci_failed: error # if ci fails report status as success, error, or failure
|
||||
|
12
vendor/go.uber.org/atomic/.gitignore
generated
vendored
Normal file
12
vendor/go.uber.org/atomic/.gitignore
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/bin
|
||||
.DS_Store
|
||||
/vendor
|
||||
cover.html
|
||||
cover.out
|
||||
lint.log
|
||||
|
||||
# Binaries
|
||||
*.test
|
||||
|
||||
# Profiling output
|
||||
*.prof
|
27
vendor/go.uber.org/atomic/.travis.yml
generated
vendored
Normal file
27
vendor/go.uber.org/atomic/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
sudo: false
|
||||
language: go
|
||||
go_import_path: go.uber.org/atomic
|
||||
|
||||
env:
|
||||
global:
|
||||
- GO111MODULE=on
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.12.x
|
||||
- go: 1.13.x
|
||||
env: LINT=1
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- vendor
|
||||
|
||||
before_install:
|
||||
- go version
|
||||
|
||||
script:
|
||||
- test -z "$LINT" || make lint
|
||||
- make cover
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
59
vendor/go.uber.org/atomic/CHANGELOG.md
generated
vendored
Normal file
59
vendor/go.uber.org/atomic/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
# 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.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.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.4.0] - 2019-05-01
|
||||
### Added
|
||||
- Add `atomic.Error` type for atomic operations on `error` values.
|
||||
|
||||
## [1.3.2] - 2018-05-02
|
||||
### Added
|
||||
- Add `atomic.Duration` type for atomic operations on `time.Duration` values.
|
||||
|
||||
## [1.3.1] - 2017-11-14
|
||||
### Fixed
|
||||
- Revert optimization for `atomic.String.Store("")` which caused data races.
|
||||
|
||||
## [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.2.0] - 2017-04-12
|
||||
### Added
|
||||
- Shadow `atomic.Value` from `sync/atomic`.
|
||||
|
||||
## [1.1.0] - 2017-03-10
|
||||
### Added
|
||||
- Add atomic `Float64` type.
|
||||
|
||||
### Changed
|
||||
- Support new `go.uber.org/atomic` import path.
|
||||
|
||||
## [1.0.0] - 2016-07-18
|
||||
|
||||
- Initial release.
|
||||
|
||||
[1.5.1]: https://github.com/uber-go/atomic/compare/v1.5.0...v1.5.1
|
||||
[1.5.0]: https://github.com/uber-go/atomic/compare/v1.4.0...v1.5.0
|
||||
[1.4.0]: https://github.com/uber-go/atomic/compare/v1.3.2...v1.4.0
|
||||
[1.3.2]: https://github.com/uber-go/atomic/compare/v1.3.1...v1.3.2
|
||||
[1.3.1]: https://github.com/uber-go/atomic/compare/v1.3.0...v1.3.1
|
||||
[1.3.0]: https://github.com/uber-go/atomic/compare/v1.2.0...v1.3.0
|
||||
[1.2.0]: https://github.com/uber-go/atomic/compare/v1.1.0...v1.2.0
|
||||
[1.1.0]: https://github.com/uber-go/atomic/compare/v1.0.0...v1.1.0
|
||||
[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.
|
35
vendor/go.uber.org/atomic/Makefile
generated
vendored
Normal file
35
vendor/go.uber.org/atomic/Makefile
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
# Directory to place `go install`ed binaries into.
|
||||
export GOBIN ?= $(shell pwd)/bin
|
||||
|
||||
GOLINT = $(GOBIN)/golint
|
||||
|
||||
GO_FILES ?= *.go
|
||||
|
||||
.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):
|
||||
go install golang.org/x/lint/golint
|
||||
|
||||
.PHONY: golint
|
||||
golint: $(GOLINT)
|
||||
$(GOLINT) ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint: gofmt golint
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
go test -coverprofile=cover.out -coverpkg ./... -v ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
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://travis-ci.com/uber-go/atomic.svg?branch=master
|
||||
[ci]: https://travis-ci.com/uber-go/atomic
|
||||
[cov-img]: https://codecov.io/gh/uber-go/atomic/branch/master/graph/badge.svg
|
||||
[cov]: https://codecov.io/gh/uber-go/atomic
|
||||
[reportcard-img]: https://goreportcard.com/badge/go.uber.org/atomic
|
||||
[reportcard]: https://goreportcard.com/report/go.uber.org/atomic
|
356
vendor/go.uber.org/atomic/atomic.go
generated
vendored
Normal file
356
vendor/go.uber.org/atomic/atomic.go
generated
vendored
Normal file
@ -0,0 +1,356 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package atomic provides simple wrappers around numerics to enforce atomic
|
||||
// access.
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Int32 is an atomic wrapper around an int32.
|
||||
type Int32 struct{ v int32 }
|
||||
|
||||
// NewInt32 creates an Int32.
|
||||
func NewInt32(i int32) *Int32 {
|
||||
return &Int32{i}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Int32) Load() int32 {
|
||||
return atomic.LoadInt32(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Add(n int32) int32 {
|
||||
return atomic.AddInt32(&i.v, n)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Sub(n int32) int32 {
|
||||
return atomic.AddInt32(&i.v, -n)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Inc() int32 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Dec() int32 {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Int32) CAS(old, new int32) bool {
|
||||
return atomic.CompareAndSwapInt32(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int32) Store(n int32) {
|
||||
atomic.StoreInt32(&i.v, n)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int32 and returns the old value.
|
||||
func (i *Int32) Swap(n int32) int32 {
|
||||
return atomic.SwapInt32(&i.v, n)
|
||||
}
|
||||
|
||||
// Int64 is an atomic wrapper around an int64.
|
||||
type Int64 struct{ v int64 }
|
||||
|
||||
// NewInt64 creates an Int64.
|
||||
func NewInt64(i int64) *Int64 {
|
||||
return &Int64{i}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Int64) Load() int64 {
|
||||
return atomic.LoadInt64(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Add(n int64) int64 {
|
||||
return atomic.AddInt64(&i.v, n)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Sub(n int64) int64 {
|
||||
return atomic.AddInt64(&i.v, -n)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Inc() int64 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Dec() int64 {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Int64) CAS(old, new int64) bool {
|
||||
return atomic.CompareAndSwapInt64(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int64) Store(n int64) {
|
||||
atomic.StoreInt64(&i.v, n)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int64 and returns the old value.
|
||||
func (i *Int64) Swap(n int64) int64 {
|
||||
return atomic.SwapInt64(&i.v, n)
|
||||
}
|
||||
|
||||
// Uint32 is an atomic wrapper around an uint32.
|
||||
type Uint32 struct{ v uint32 }
|
||||
|
||||
// NewUint32 creates a Uint32.
|
||||
func NewUint32(i uint32) *Uint32 {
|
||||
return &Uint32{i}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Uint32) Load() uint32 {
|
||||
return atomic.LoadUint32(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Add(n uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, n)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Sub(n uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, ^(n - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Inc() uint32 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped int32 and returns the new value.
|
||||
func (i *Uint32) Dec() uint32 {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uint32) CAS(old, new uint32) bool {
|
||||
return atomic.CompareAndSwapUint32(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint32) Store(n uint32) {
|
||||
atomic.StoreUint32(&i.v, n)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint32 and returns the old value.
|
||||
func (i *Uint32) Swap(n uint32) uint32 {
|
||||
return atomic.SwapUint32(&i.v, n)
|
||||
}
|
||||
|
||||
// Uint64 is an atomic wrapper around a uint64.
|
||||
type Uint64 struct{ v uint64 }
|
||||
|
||||
// NewUint64 creates a Uint64.
|
||||
func NewUint64(i uint64) *Uint64 {
|
||||
return &Uint64{i}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Uint64) Load() uint64 {
|
||||
return atomic.LoadUint64(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Add(n uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, n)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Sub(n uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, ^(n - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Inc() uint64 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Dec() uint64 {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uint64) CAS(old, new uint64) bool {
|
||||
return atomic.CompareAndSwapUint64(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint64) Store(n uint64) {
|
||||
atomic.StoreUint64(&i.v, n)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint64 and returns the old value.
|
||||
func (i *Uint64) Swap(n uint64) uint64 {
|
||||
return atomic.SwapUint64(&i.v, n)
|
||||
}
|
||||
|
||||
// Bool is an atomic Boolean.
|
||||
type Bool struct{ v uint32 }
|
||||
|
||||
// NewBool creates a Bool.
|
||||
func NewBool(initial bool) *Bool {
|
||||
return &Bool{boolToInt(initial)}
|
||||
}
|
||||
|
||||
// Load atomically loads the Boolean.
|
||||
func (b *Bool) Load() bool {
|
||||
return truthy(atomic.LoadUint32(&b.v))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (b *Bool) CAS(old, new bool) bool {
|
||||
return atomic.CompareAndSwapUint32(&b.v, boolToInt(old), boolToInt(new))
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (b *Bool) Store(new bool) {
|
||||
atomic.StoreUint32(&b.v, boolToInt(new))
|
||||
}
|
||||
|
||||
// Swap sets the given value and returns the previous value.
|
||||
func (b *Bool) Swap(new bool) bool {
|
||||
return truthy(atomic.SwapUint32(&b.v, boolToInt(new)))
|
||||
}
|
||||
|
||||
// Toggle atomically negates the Boolean and returns the previous value.
|
||||
func (b *Bool) Toggle() bool {
|
||||
for {
|
||||
old := b.Load()
|
||||
if b.CAS(old, !old) {
|
||||
return old
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func truthy(n uint32) bool {
|
||||
return n == 1
|
||||
}
|
||||
|
||||
func boolToInt(b bool) uint32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Float64 is an atomic wrapper around float64.
|
||||
type Float64 struct {
|
||||
v uint64
|
||||
}
|
||||
|
||||
// NewFloat64 creates a Float64.
|
||||
func NewFloat64(f float64) *Float64 {
|
||||
return &Float64{math.Float64bits(f)}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (f *Float64) Load() float64 {
|
||||
return math.Float64frombits(atomic.LoadUint64(&f.v))
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (f *Float64) Store(s float64) {
|
||||
atomic.StoreUint64(&f.v, math.Float64bits(s))
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped float64 and returns the new value.
|
||||
func (f *Float64) Add(s float64) float64 {
|
||||
for {
|
||||
old := f.Load()
|
||||
new := old + s
|
||||
if f.CAS(old, new) {
|
||||
return new
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped float64 and returns the new value.
|
||||
func (f *Float64) Sub(s float64) float64 {
|
||||
return f.Add(-s)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (f *Float64) CAS(old, new float64) bool {
|
||||
return atomic.CompareAndSwapUint64(&f.v, math.Float64bits(old), math.Float64bits(new))
|
||||
}
|
||||
|
||||
// Duration is an atomic wrapper around time.Duration
|
||||
// https://godoc.org/time#Duration
|
||||
type Duration struct {
|
||||
v Int64
|
||||
}
|
||||
|
||||
// NewDuration creates a Duration.
|
||||
func NewDuration(d time.Duration) *Duration {
|
||||
return &Duration{v: *NewInt64(int64(d))}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (d *Duration) Load() time.Duration {
|
||||
return time.Duration(d.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (d *Duration) Store(n time.Duration) {
|
||||
d.v.Store(int64(n))
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped time.Duration and returns the new value.
|
||||
func (d *Duration) Add(n time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Add(int64(n)))
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped time.Duration and returns the new value.
|
||||
func (d *Duration) Sub(n time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Sub(int64(n)))
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped time.Duration and returns the old value.
|
||||
func (d *Duration) Swap(n time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Swap(int64(n)))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (d *Duration) CAS(old, new time.Duration) bool {
|
||||
return d.v.CAS(int64(old), int64(new))
|
||||
}
|
||||
|
||||
// Value shadows the type of the same name from sync/atomic
|
||||
// https://godoc.org/sync/atomic#Value
|
||||
type Value struct{ atomic.Value }
|
55
vendor/go.uber.org/atomic/error.go
generated
vendored
Normal file
55
vendor/go.uber.org/atomic/error.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
// Error is an atomic type-safe wrapper around Value for errors
|
||||
type Error struct{ v Value }
|
||||
|
||||
// errorHolder is non-nil holder for error object.
|
||||
// atomic.Value panics on saving nil object, so err object needs to be
|
||||
// wrapped with valid object first.
|
||||
type errorHolder struct{ err error }
|
||||
|
||||
// NewError creates new atomic error object
|
||||
func NewError(err error) *Error {
|
||||
e := &Error{}
|
||||
if err != nil {
|
||||
e.Store(err)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped error
|
||||
func (e *Error) Load() error {
|
||||
v := e.v.Load()
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
eh := v.(errorHolder)
|
||||
return eh.err
|
||||
}
|
||||
|
||||
// Store atomically stores error.
|
||||
// NOTE: a holder object is allocated on each Store call.
|
||||
func (e *Error) Store(err error) {
|
||||
e.v.Store(errorHolder{err: err})
|
||||
}
|
10
vendor/go.uber.org/atomic/go.mod
generated
vendored
Normal file
10
vendor/go.uber.org/atomic/go.mod
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
module go.uber.org/atomic
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
22
vendor/go.uber.org/atomic/go.sum
generated
vendored
Normal file
22
vendor/go.uber.org/atomic/go.sum
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
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/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.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
49
vendor/go.uber.org/atomic/string.go
generated
vendored
Normal file
49
vendor/go.uber.org/atomic/string.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
// String is an atomic type-safe wrapper around Value for strings.
|
||||
type String struct{ v Value }
|
||||
|
||||
// NewString creates a String.
|
||||
func NewString(str string) *String {
|
||||
s := &String{}
|
||||
if str != "" {
|
||||
s.Store(str)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped string.
|
||||
func (s *String) Load() string {
|
||||
v := s.v.Load()
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return v.(string)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed string.
|
||||
// Note: Converting the string to an interface{} to store in the Value
|
||||
// requires an allocation.
|
||||
func (s *String) Store(str string) {
|
||||
s.v.Store(str)
|
||||
}
|
28
vendor/go.uber.org/atomic/tools.go
generated
vendored
Normal file
28
vendor/go.uber.org/atomic/tools.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
// +build tools
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
// Tools used during development.
|
||||
_ "golang.org/x/lint/golint"
|
||||
)
|
15
vendor/go.uber.org/multierr/.codecov.yml
generated
vendored
Normal file
15
vendor/go.uber.org/multierr/.codecov.yml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
coverage:
|
||||
range: 80..100
|
||||
round: down
|
||||
precision: 2
|
||||
|
||||
status:
|
||||
project: # measuring the overall project coverage
|
||||
default: # context, you can create multiple ones with custom titles
|
||||
enabled: yes # must be yes|true to enable this status
|
||||
target: 100 # specify the target coverage for each commit status
|
||||
# option: "auto" (must increase from parent commit or pull request base)
|
||||
# option: "X%" a static target percentage to hit
|
||||
if_not_found: success # if parent is not found report status as success, error, or failure
|
||||
if_ci_failed: error # if ci fails report status as success, error, or failure
|
||||
|
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
|
29
vendor/go.uber.org/multierr/.travis.yml
generated
vendored
Normal file
29
vendor/go.uber.org/multierr/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
sudo: false
|
||||
language: go
|
||||
go_import_path: go.uber.org/multierr
|
||||
|
||||
env:
|
||||
global:
|
||||
- GO15VENDOREXPERIMENT=1
|
||||
- GO111MODULE=on
|
||||
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- vendor
|
||||
|
||||
before_install:
|
||||
- go version
|
||||
|
||||
script:
|
||||
- |
|
||||
set -e
|
||||
make lint
|
||||
make cover
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
48
vendor/go.uber.org/multierr/CHANGELOG.md
generated
vendored
Normal file
48
vendor/go.uber.org/multierr/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
Releases
|
||||
========
|
||||
|
||||
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 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.
|
42
vendor/go.uber.org/multierr/Makefile
generated
vendored
Normal file
42
vendor/go.uber.org/multierr/Makefile
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
# 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:
|
||||
@go install golang.org/x/lint/golint
|
||||
@$(GOBIN)/golint ./...
|
||||
|
||||
.PHONY: staticcheck
|
||||
staticcheck:
|
||||
@go install honnef.co/go/tools/cmd/staticcheck
|
||||
@$(GOBIN)/staticcheck ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint: gofmt golint staticcheck
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
go test -coverprofile=cover.out -coverpkg=./... -v ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
update-license:
|
||||
@go install go.uber.org/tools/update-license
|
||||
@$(GOBIN)/update-license $(GO_FILES)
|
23
vendor/go.uber.org/multierr/README.md
generated
vendored
Normal file
23
vendor/go.uber.org/multierr/README.md
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# multierr [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
|
||||
|
||||
`multierr` allows combining one or more Go `error`s together.
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u go.uber.org/multierr
|
||||
|
||||
## Status
|
||||
|
||||
Stable: No breaking changes will be made before 2.0.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Released under the [MIT License].
|
||||
|
||||
[MIT License]: LICENSE.txt
|
||||
[doc-img]: https://godoc.org/go.uber.org/multierr?status.svg
|
||||
[doc]: https://godoc.org/go.uber.org/multierr
|
||||
[ci-img]: https://travis-ci.com/uber-go/multierr.svg?branch=master
|
||||
[cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg
|
||||
[ci]: https://travis-ci.com/uber-go/multierr
|
||||
[cov]: https://codecov.io/gh/uber-go/multierr
|
449
vendor/go.uber.org/multierr/error.go
generated
vendored
Normal file
449
vendor/go.uber.org/multierr/error.go
generated
vendored
Normal file
@ -0,0 +1,449 @@
|
||||
// Copyright (c) 2019 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())
|
||||
//
|
||||
// This makes it possible to record resource cleanup failures from deferred
|
||||
// blocks with the help of named return values.
|
||||
//
|
||||
// func sendRequest(req Request) (err error) {
|
||||
// conn, err := openConnection()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// defer func() {
|
||||
// err = multierr.Append(err, conn.Close())
|
||||
// }()
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// The underlying list of errors for a returned error object may be retrieved
|
||||
// with the Errors function.
|
||||
//
|
||||
// errors := multierr.Errors(err)
|
||||
// if len(errors) > 0 {
|
||||
// fmt.Println("The following errors occurred:")
|
||||
// }
|
||||
//
|
||||
// Advanced Usage
|
||||
//
|
||||
// Errors returned by Combine and Append MAY implement the following
|
||||
// interface.
|
||||
//
|
||||
// type errorGroup interface {
|
||||
// // Returns a slice containing the underlying list of errors.
|
||||
// //
|
||||
// // This slice MUST NOT be modified by the caller.
|
||||
// Errors() []error
|
||||
// }
|
||||
//
|
||||
// Note that if you need access to list of errors behind a multierr error, you
|
||||
// should prefer using the Errors function. That said, if you need cheap
|
||||
// read-only access to the underlying errors slice, you can attempt to cast
|
||||
// the error to this interface. You MUST handle the failure case gracefully
|
||||
// because errors returned by Combine and Append are not guaranteed to
|
||||
// implement this interface.
|
||||
//
|
||||
// var errors []error
|
||||
// group, ok := err.(errorGroup)
|
||||
// if ok {
|
||||
// errors = group.Errors()
|
||||
// } else {
|
||||
// errors = []error{err}
|
||||
// }
|
||||
package multierr // import "go.uber.org/multierr"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
var (
|
||||
// Separator for single-line error messages.
|
||||
_singlelineSeparator = []byte("; ")
|
||||
|
||||
// Prefix for multi-line messages
|
||||
_multilinePrefix = []byte("the following errors occurred:")
|
||||
|
||||
// Prefix for the first and following lines of an item in a list of
|
||||
// multi-line error messages.
|
||||
//
|
||||
// For example, if a single item is:
|
||||
//
|
||||
// foo
|
||||
// bar
|
||||
//
|
||||
// It will become,
|
||||
//
|
||||
// - foo
|
||||
// bar
|
||||
_multilineSeparator = []byte("\n - ")
|
||||
_multilineIndent = []byte(" ")
|
||||
)
|
||||
|
||||
// _bufferPool is a pool of bytes.Buffers.
|
||||
var _bufferPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &bytes.Buffer{}
|
||||
},
|
||||
}
|
||||
|
||||
type errorGroup interface {
|
||||
Errors() []error
|
||||
}
|
||||
|
||||
// Errors returns a slice containing zero or more errors that the supplied
|
||||
// error is composed of. If the error is nil, the returned slice is empty.
|
||||
//
|
||||
// err := multierr.Append(r.Close(), w.Close())
|
||||
// errors := multierr.Errors(err)
|
||||
//
|
||||
// If the error is not composed of other errors, the returned slice contains
|
||||
// just the error that was passed in.
|
||||
//
|
||||
// Callers of this function are free to modify the returned slice.
|
||||
func Errors(err error) []error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Note that we're casting to multiError, not errorGroup. Our contract is
|
||||
// that returned errors MAY implement errorGroup. Errors, however, only
|
||||
// has special behavior for multierr-specific error objects.
|
||||
//
|
||||
// This behavior can be expanded in the future but I think it's prudent to
|
||||
// start with as little as possible in terms of contract and possibility
|
||||
// of misuse.
|
||||
eg, ok := err.(*multiError)
|
||||
if !ok {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
errors := eg.Errors()
|
||||
result := make([]error, len(errors))
|
||||
copy(result, errors)
|
||||
return result
|
||||
}
|
||||
|
||||
// multiError is an error that holds one or more errors.
|
||||
//
|
||||
// An instance of this is guaranteed to be non-empty and flattened. That is,
|
||||
// none of the errors inside multiError are other multiErrors.
|
||||
//
|
||||
// multiError formats to a semi-colon delimited list of error messages with
|
||||
// %v and with a more readable multi-line format with %+v.
|
||||
type multiError struct {
|
||||
copyNeeded atomic.Bool
|
||||
errors []error
|
||||
}
|
||||
|
||||
var _ errorGroup = (*multiError)(nil)
|
||||
|
||||
// Errors returns the list of underlying errors.
|
||||
//
|
||||
// This slice MUST NOT be modified.
|
||||
func (merr *multiError) Errors() []error {
|
||||
if merr == nil {
|
||||
return nil
|
||||
}
|
||||
return merr.errors
|
||||
}
|
||||
|
||||
func (merr *multiError) Error() string {
|
||||
if merr == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
buff := _bufferPool.Get().(*bytes.Buffer)
|
||||
buff.Reset()
|
||||
|
||||
merr.writeSingleline(buff)
|
||||
|
||||
result := buff.String()
|
||||
_bufferPool.Put(buff)
|
||||
return result
|
||||
}
|
||||
|
||||
func (merr *multiError) Format(f fmt.State, c rune) {
|
||||
if c == 'v' && f.Flag('+') {
|
||||
merr.writeMultiline(f)
|
||||
} else {
|
||||
merr.writeSingleline(f)
|
||||
}
|
||||
}
|
||||
|
||||
func (merr *multiError) writeSingleline(w io.Writer) {
|
||||
first := true
|
||||
for _, item := range merr.errors {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
w.Write(_singlelineSeparator)
|
||||
}
|
||||
io.WriteString(w, item.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (merr *multiError) writeMultiline(w io.Writer) {
|
||||
w.Write(_multilinePrefix)
|
||||
for _, item := range merr.errors {
|
||||
w.Write(_multilineSeparator)
|
||||
writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item))
|
||||
}
|
||||
}
|
||||
|
||||
// Writes s to the writer with the given prefix added before each line after
|
||||
// the first.
|
||||
func writePrefixLine(w io.Writer, prefix []byte, s string) {
|
||||
first := true
|
||||
for len(s) > 0 {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
w.Write(prefix)
|
||||
}
|
||||
|
||||
idx := strings.IndexByte(s, '\n')
|
||||
if idx < 0 {
|
||||
idx = len(s) - 1
|
||||
}
|
||||
|
||||
io.WriteString(w, s[:idx+1])
|
||||
s = s[idx+1:]
|
||||
}
|
||||
}
|
||||
|
||||
type inspectResult struct {
|
||||
// Number of top-level non-nil errors
|
||||
Count int
|
||||
|
||||
// Total number of errors including multiErrors
|
||||
Capacity int
|
||||
|
||||
// Index of the first non-nil error in the list. Value is meaningless if
|
||||
// Count is zero.
|
||||
FirstErrorIdx int
|
||||
|
||||
// Whether the list contains at least one multiError
|
||||
ContainsMultiError bool
|
||||
}
|
||||
|
||||
// Inspects the given slice of errors so that we can efficiently allocate
|
||||
// space for it.
|
||||
func inspect(errors []error) (res inspectResult) {
|
||||
first := true
|
||||
for i, err := range errors {
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
res.Count++
|
||||
if first {
|
||||
first = false
|
||||
res.FirstErrorIdx = i
|
||||
}
|
||||
|
||||
if merr, ok := err.(*multiError); ok {
|
||||
res.Capacity += len(merr.errors)
|
||||
res.ContainsMultiError = true
|
||||
} else {
|
||||
res.Capacity++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// fromSlice converts the given list of errors into a single error.
|
||||
func fromSlice(errors []error) error {
|
||||
res := inspect(errors)
|
||||
switch res.Count {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
// only one non-nil entry
|
||||
return errors[res.FirstErrorIdx]
|
||||
case len(errors):
|
||||
if !res.ContainsMultiError {
|
||||
// already flat
|
||||
return &multiError{errors: errors}
|
||||
}
|
||||
}
|
||||
|
||||
nonNilErrs := make([]error, 0, res.Capacity)
|
||||
for _, err := range errors[res.FirstErrorIdx:] {
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if nested, ok := err.(*multiError); ok {
|
||||
nonNilErrs = append(nonNilErrs, nested.errors...)
|
||||
} else {
|
||||
nonNilErrs = append(nonNilErrs, err)
|
||||
}
|
||||
}
|
||||
|
||||
return &multiError{errors: nonNilErrs}
|
||||
}
|
||||
|
||||
// Combine combines the passed errors into a single error.
|
||||
//
|
||||
// If zero arguments were passed or if all items are nil, a nil error is
|
||||
// returned.
|
||||
//
|
||||
// Combine(nil, nil) // == nil
|
||||
//
|
||||
// If only a single error was passed, it is returned as-is.
|
||||
//
|
||||
// Combine(err) // == err
|
||||
//
|
||||
// Combine skips over nil arguments so this function may be used to combine
|
||||
// together errors from operations that fail independently of each other.
|
||||
//
|
||||
// multierr.Combine(
|
||||
// reader.Close(),
|
||||
// writer.Close(),
|
||||
// pipe.Close(),
|
||||
// )
|
||||
//
|
||||
// If any of the passed errors is a multierr error, it will be flattened along
|
||||
// with the other errors.
|
||||
//
|
||||
// multierr.Combine(multierr.Combine(err1, err2), err3)
|
||||
// // is the same as
|
||||
// multierr.Combine(err1, err2, err3)
|
||||
//
|
||||
// The returned error formats into a readable multi-line error message if
|
||||
// formatted with %+v.
|
||||
//
|
||||
// fmt.Sprintf("%+v", multierr.Combine(err1, err2))
|
||||
func Combine(errors ...error) error {
|
||||
return fromSlice(errors)
|
||||
}
|
||||
|
||||
// Append appends the given errors together. Either value may be nil.
|
||||
//
|
||||
// This function is a specialization of Combine for the common case where
|
||||
// there are only two errors.
|
||||
//
|
||||
// err = multierr.Append(reader.Close(), writer.Close())
|
||||
//
|
||||
// The following pattern may also be used to record failure of deferred
|
||||
// operations without losing information about the original error.
|
||||
//
|
||||
// func doSomething(..) (err error) {
|
||||
// f := acquireResource()
|
||||
// defer func() {
|
||||
// err = multierr.Append(err, f.Close())
|
||||
// }()
|
||||
func Append(left error, right error) error {
|
||||
switch {
|
||||
case left == nil:
|
||||
return right
|
||||
case right == nil:
|
||||
return left
|
||||
}
|
||||
|
||||
if _, ok := right.(*multiError); !ok {
|
||||
if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) {
|
||||
// Common case where the error on the left is constantly being
|
||||
// appended to.
|
||||
errs := append(l.errors, right)
|
||||
return &multiError{errors: errs}
|
||||
} else if !ok {
|
||||
// Both errors are single errors.
|
||||
return &multiError{errors: []error{left, right}}
|
||||
}
|
||||
}
|
||||
|
||||
// Either right or both, left and right, are multiErrors. Rely on usual
|
||||
// expensive logic.
|
||||
errors := [2]error{left, right}
|
||||
return fromSlice(errors[0:])
|
||||
}
|
||||
|
||||
// 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 verison 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
|
||||
}
|
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
|
12
vendor/go.uber.org/multierr/go.mod
generated
vendored
Normal file
12
vendor/go.uber.org/multierr/go.mod
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
module go.uber.org/multierr
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.3.0
|
||||
go.uber.org/atomic v1.5.0
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 // indirect
|
||||
honnef.co/go/tools v0.0.1-2019.2.3
|
||||
)
|
45
vendor/go.uber.org/multierr/go.sum
generated
vendored
Normal file
45
vendor/go.uber.org/multierr/go.sum
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
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/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
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 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
52
vendor/go.uber.org/multierr/go113.go
generated
vendored
Normal file
52
vendor/go.uber.org/multierr/go113.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
// +build go1.13
|
||||
|
||||
package multierr
|
||||
|
||||
import "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
|
||||
}
|
30
vendor/go.uber.org/multierr/tools.go
generated
vendored
Normal file
30
vendor/go.uber.org/multierr/tools.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
// +build tools
|
||||
|
||||
package multierr
|
||||
|
||||
import (
|
||||
// Tools we use during development.
|
||||
_ "go.uber.org/tools/update-license"
|
||||
_ "golang.org/x/lint/golint"
|
||||
_ "honnef.co/go/tools/cmd/staticcheck"
|
||||
)
|
19
vendor/go.uber.org/tools/LICENSE
generated
vendored
Normal file
19
vendor/go.uber.org/tools/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2017 Uber Technologies, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
1
vendor/go.uber.org/tools/update-license/.gitignore
generated
vendored
Normal file
1
vendor/go.uber.org/tools/update-license/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
update-license
|
24
vendor/go.uber.org/tools/update-license/README.md
generated
vendored
Normal file
24
vendor/go.uber.org/tools/update-license/README.md
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# update-license
|
||||
|
||||
This is a small tool that updates the license header for Uber's open source Golang files.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
go get go.uber.org/tools/update-license
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
update-license go_files...
|
||||
```
|
||||
|
||||
## Further Work
|
||||
|
||||
* Support more licenses by name (MIT, Apache 2.0, etc), file path, url (http GET)
|
||||
* Support custom owner (not just "Uber Technologies, Inc.")
|
||||
* Support more languages than go (cover go, java, js, py to start, along with LICENSE, LICENSE.txt)
|
||||
* Talk about removing custom logic for header comments (ie `@generated`, `Code generated by`), it probably makes more sense just to put the license at the top
|
||||
* Better detection support for existing licenses so they can be removed
|
||||
* Verbose, dry run support
|
56
vendor/go.uber.org/tools/update-license/licenses.go
generated
vendored
Normal file
56
vendor/go.uber.org/tools/update-license/licenses.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2019 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
var licenseTemplates = map[string]string{
|
||||
"Apache-2.0": `// Copyright {{.Year}} {{.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.`,
|
||||
"MIT": `// Copyright (c) {{.Year}} {{.Owner}}
|
||||
//
|
||||
// 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.`,
|
||||
}
|
228
vendor/go.uber.org/tools/update-license/main.go
generated
vendored
Normal file
228
vendor/go.uber.org/tools/update-license/main.go
generated
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
// Copyright (c) 2019 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// how many lines to check for an existing copyright
|
||||
// this logic is not great and we should probably do something else
|
||||
// but this was copied from the python script
|
||||
copyrightLineLimit = 5
|
||||
headerPrefix = "// Copyright"
|
||||
)
|
||||
|
||||
var (
|
||||
flagDryRun = flag.Bool("dry", false, "Do not edit files and just print out what files would be edited")
|
||||
flagOwner = flag.String("owner", "Uber Technologies, Inc.", "Copyright owner")
|
||||
flagLicense = flag.String(
|
||||
"license",
|
||||
"MIT",
|
||||
fmt.Sprintf(
|
||||
"Type of license to use [%s]",
|
||||
strings.Join(validLicenses(), ", "),
|
||||
),
|
||||
)
|
||||
|
||||
lineSkipPrefixes = []string{
|
||||
"// Code generated by",
|
||||
"// @generated",
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetPrefix("")
|
||||
if err := do(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func do() error {
|
||||
flag.Parse()
|
||||
|
||||
if len(flag.Args()) < 1 {
|
||||
return fmt.Errorf("usage: %s GO_FILES", os.Args[0])
|
||||
}
|
||||
|
||||
return updateFiles(
|
||||
flag.Args(),
|
||||
time.Now().UTC().Year(),
|
||||
*flagLicense,
|
||||
*flagOwner,
|
||||
*flagDryRun,
|
||||
)
|
||||
}
|
||||
|
||||
func fullLicense(ts string, year int, owner string) string {
|
||||
var buf bytes.Buffer
|
||||
t, err := template.New("").Parse(ts)
|
||||
if err != nil {
|
||||
log.Panic("failed to parse license template", err)
|
||||
}
|
||||
|
||||
data := struct {
|
||||
Year int
|
||||
Owner string
|
||||
}{year, owner}
|
||||
if err := t.Execute(&buf, data); err != nil {
|
||||
log.Panic("failed to execture license template", err)
|
||||
}
|
||||
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
// validLicenses grabs all the license templates from the folder
|
||||
func validLicenses() []string {
|
||||
res := make([]string, 0, len(licenseTemplates))
|
||||
|
||||
for k := range licenseTemplates {
|
||||
res = append(res, k)
|
||||
}
|
||||
|
||||
sort.Strings(res)
|
||||
return res
|
||||
}
|
||||
|
||||
func updateFiles(
|
||||
filePaths []string,
|
||||
year int,
|
||||
license string,
|
||||
owner string,
|
||||
dryRun bool,
|
||||
) error {
|
||||
if err := checkFilePaths(filePaths); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, filePath := range filePaths {
|
||||
if err := updateFile(filePath, year, license, owner, dryRun); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkFilePaths(filePaths []string) error {
|
||||
for _, filePath := range filePaths {
|
||||
if filepath.Ext(filePath) != ".go" {
|
||||
return fmt.Errorf("%s is not a go file", filePath)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateFile(
|
||||
filePath string,
|
||||
year int,
|
||||
license string,
|
||||
owner string,
|
||||
dryRun bool,
|
||||
) error {
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newData := updateData(data, year, license, owner)
|
||||
if !bytes.Equal(data, newData) {
|
||||
if dryRun {
|
||||
log.Print(filePath)
|
||||
return nil
|
||||
}
|
||||
// we could do something more complicated so that we do not
|
||||
// need to pass 0644 as the file mode, but in this case it should
|
||||
// never actually be used to create a file since we know the file
|
||||
// already exists, and it's easier to use the ReadFile/WriteFile
|
||||
// logic as it is right now, and since this is just a generation
|
||||
// program, this should be acceptable
|
||||
return ioutil.WriteFile(filePath, newData, 0644)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateData(
|
||||
data []byte,
|
||||
year int,
|
||||
license string,
|
||||
owner string,
|
||||
) []byte {
|
||||
licenseText := fullLicense(string(licenseTemplates[license]), year, owner)
|
||||
|
||||
return []byte(
|
||||
strings.Join(
|
||||
updateLines(strings.Split(string(data), "\n"), licenseText),
|
||||
"\n",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// a value in the returned slice may contain newlines itself
|
||||
func updateLines(lines []string, license string) []string {
|
||||
for i, line := range lines {
|
||||
if i >= copyrightLineLimit {
|
||||
break
|
||||
}
|
||||
if strings.HasPrefix(line, headerPrefix) {
|
||||
// assume that the new license text always starts with the copyright
|
||||
// string. Pretty safe to assume, right? RIGHT?
|
||||
lines[i] = strings.Split(license, "\n")[0]
|
||||
return lines
|
||||
}
|
||||
}
|
||||
return addToLines(lines, license)
|
||||
}
|
||||
|
||||
// a value in the returned slice may contain newlines itself
|
||||
func addToLines(lines []string, license string) []string {
|
||||
i := 0
|
||||
for len(lines) > i && lineContainsSkipPrefix(lines[i]) {
|
||||
i++
|
||||
// skip comments under the generated line too
|
||||
for strings.HasPrefix(lines[i], "//") {
|
||||
i++
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
return append([]string{license, ""}, lines...)
|
||||
}
|
||||
return append(lines[0:i], append([]string{"", license}, lines[i:]...)...)
|
||||
}
|
||||
|
||||
func lineContainsSkipPrefix(line string) bool {
|
||||
for _, skipPrefix := range lineSkipPrefixes {
|
||||
if strings.HasPrefix(line, skipPrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
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
|
||||
|
32
vendor/go.uber.org/zap/.gitignore
generated
vendored
Normal file
32
vendor/go.uber.org/zap/.gitignore
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
vendor
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
*.pprof
|
||||
*.out
|
||||
*.log
|
||||
|
||||
/bin
|
||||
cover.out
|
||||
cover.html
|
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 zap's [glide.lock][] file. [↩](#anchor-versions)
|
||||
|
||||
[doc-img]: https://godoc.org/go.uber.org/zap?status.svg
|
||||
[doc]: https://godoc.org/go.uber.org/zap
|
||||
[ci-img]: https://travis-ci.com/uber-go/zap.svg?branch=master
|
||||
[ci]: https://travis-ci.com/uber-go/zap
|
||||
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
|
||||
[cov]: https://codecov.io/gh/uber-go/zap
|
||||
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
|
||||
[glide.lock]: https://github.com/uber-go/zap/blob/master/glide.lock
|
||||
|
23
vendor/go.uber.org/zap/.travis.yml
generated
vendored
Normal file
23
vendor/go.uber.org/zap/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
language: go
|
||||
sudo: false
|
||||
|
||||
go_import_path: go.uber.org/zap
|
||||
env:
|
||||
global:
|
||||
- TEST_TIMEOUT_SCALE=10
|
||||
- GO111MODULE=on
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.12.x
|
||||
- go: 1.13.x
|
||||
env: LINT=1
|
||||
|
||||
script:
|
||||
- test -z "$LINT" || make lint
|
||||
- make test
|
||||
- make bench
|
||||
|
||||
after_success:
|
||||
- make cover
|
||||
- bash <(curl -s https://codecov.io/bash)
|
352
vendor/go.uber.org/zap/CHANGELOG.md
generated
vendored
Normal file
352
vendor/go.uber.org/zap/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,352 @@
|
||||
# Changelog
|
||||
|
||||
## 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
|
75
vendor/go.uber.org/zap/CODE_OF_CONDUCT.md
generated
vendored
Normal file
75
vendor/go.uber.org/zap/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age,
|
||||
body size, disability, ethnicity, gender identity and expression, level of
|
||||
experience, nationality, personal appearance, race, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an
|
||||
appointed representative at an online or offline event. Representation of a
|
||||
project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at oss-conduct@uber.com. The project
|
||||
team will review and investigate all complaints, and will respond in a way
|
||||
that it deems appropriate to the circumstances. The project team is obligated
|
||||
to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 1.4, available at
|
||||
[http://contributor-covenant.org/version/1/4][version].
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
81
vendor/go.uber.org/zap/CONTRIBUTING.md
generated
vendored
Normal file
81
vendor/go.uber.org/zap/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
# Contributing
|
||||
|
||||
We'd love your help making zap the very best structured logging library in Go!
|
||||
|
||||
If you'd like to add new exported APIs, please [open an issue][open-issue]
|
||||
describing your proposal — discussing API changes ahead of time makes
|
||||
pull request review much smoother. In your issue, pull request, and any other
|
||||
communications, please remember to treat your fellow contributors with
|
||||
respect! We take our [code of conduct](CODE_OF_CONDUCT.md) seriously.
|
||||
|
||||
Note that you'll need to sign [Uber's Contributor License Agreement][cla]
|
||||
before we can accept any of your contributions. If necessary, a bot will remind
|
||||
you to accept the CLA when you open your pull request.
|
||||
|
||||
## Setup
|
||||
|
||||
[Fork][fork], then clone the repository:
|
||||
|
||||
```
|
||||
mkdir -p $GOPATH/src/go.uber.org
|
||||
cd $GOPATH/src/go.uber.org
|
||||
git clone git@github.com:your_github_username/zap.git
|
||||
cd zap
|
||||
git remote add upstream https://github.com/uber-go/zap.git
|
||||
git fetch upstream
|
||||
```
|
||||
|
||||
Install zap's dependencies:
|
||||
|
||||
```
|
||||
make dependencies
|
||||
```
|
||||
|
||||
Make sure that the tests and the linters pass:
|
||||
|
||||
```
|
||||
make test
|
||||
make lint
|
||||
```
|
||||
|
||||
If you're not using the minor version of Go specified in the Makefile's
|
||||
`LINTABLE_MINOR_VERSIONS` variable, `make lint` doesn't do anything. This is
|
||||
fine, but it means that you'll only discover lint failures after you open your
|
||||
pull request.
|
||||
|
||||
## Making Changes
|
||||
|
||||
Start by creating a new branch for your changes:
|
||||
|
||||
```
|
||||
cd $GOPATH/src/go.uber.org/zap
|
||||
git checkout master
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
git checkout -b cool_new_feature
|
||||
```
|
||||
|
||||
Make your changes, then ensure that `make lint` and `make test` still pass. If
|
||||
you're satisfied with your changes, push them to your fork.
|
||||
|
||||
```
|
||||
git push origin cool_new_feature
|
||||
```
|
||||
|
||||
Then use the GitHub UI to open a pull request.
|
||||
|
||||
At this point, you're waiting on us to review your changes. We *try* to respond
|
||||
to issues and pull requests within a few business days, and we may suggest some
|
||||
improvements or alternatives. Once your changes are approved, one of the
|
||||
project maintainers will merge them.
|
||||
|
||||
We're much more likely to approve your changes if you:
|
||||
|
||||
* Add tests for new functionality.
|
||||
* Write a [good commit message][commit-message].
|
||||
* Maintain backward compatibility.
|
||||
|
||||
[fork]: https://github.com/uber-go/zap/fork
|
||||
[open-issue]: https://github.com/uber-go/zap/issues/new
|
||||
[cla]: https://cla-assistant.io/uber-go/zap
|
||||
[commit-message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
155
vendor/go.uber.org/zap/FAQ.md
generated
vendored
Normal file
155
vendor/go.uber.org/zap/FAQ.md
generated
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
## Design
|
||||
|
||||
### Why spend so much effort on logger performance?
|
||||
|
||||
Of course, most applications won't notice the impact of a slow logger: they
|
||||
already take tens or hundreds of milliseconds for each operation, so an extra
|
||||
millisecond doesn't matter.
|
||||
|
||||
On the other hand, why *not* make structured logging fast? The `SugaredLogger`
|
||||
isn't any harder to use than other logging packages, and the `Logger` makes
|
||||
structured logging possible in performance-sensitive contexts. Across a fleet
|
||||
of Go microservices, making each application even slightly more efficient adds
|
||||
up quickly.
|
||||
|
||||
### Why aren't `Logger` and `SugaredLogger` interfaces?
|
||||
|
||||
Unlike the familiar `io.Writer` and `http.Handler`, `Logger` and
|
||||
`SugaredLogger` interfaces would include *many* methods. As [Rob Pike points
|
||||
out][go-proverbs], "The bigger the interface, the weaker the abstraction."
|
||||
Interfaces are also rigid — *any* change requires releasing a new major
|
||||
version, since it breaks all third-party implementations.
|
||||
|
||||
Making the `Logger` and `SugaredLogger` concrete types doesn't sacrifice much
|
||||
abstraction, and it lets us add methods without introducing breaking changes.
|
||||
Your applications should define and depend upon an interface that includes
|
||||
just the methods you use.
|
||||
|
||||
### Why sample application logs?
|
||||
|
||||
Applications often experience runs of errors, either because of a bug or
|
||||
because of a misbehaving user. Logging errors is usually a good idea, but it
|
||||
can easily make this bad situation worse: not only is your application coping
|
||||
with a flood of errors, it's also spending extra CPU cycles and I/O logging
|
||||
those errors. Since writes are typically serialized, logging limits throughput
|
||||
when you need it most.
|
||||
|
||||
Sampling fixes this problem by dropping repetitive log entries. Under normal
|
||||
conditions, your application writes out every entry. When similar entries are
|
||||
logged hundreds or thousands of times each second, though, zap begins dropping
|
||||
duplicates to preserve throughput.
|
||||
|
||||
### Why do the structured logging APIs take a message in addition to fields?
|
||||
|
||||
Subjectively, we find it helpful to accompany structured context with a brief
|
||||
description. This isn't critical during development, but it makes debugging
|
||||
and operating unfamiliar systems much easier.
|
||||
|
||||
More concretely, zap's sampling algorithm uses the message to identify
|
||||
duplicate entries. In our experience, this is a practical middle ground
|
||||
between random sampling (which often drops the exact entry that you need while
|
||||
debugging) and hashing the complete entry (which is prohibitively expensive).
|
||||
|
||||
### Why include package-global loggers?
|
||||
|
||||
Since so many other logging packages include a global logger, many
|
||||
applications aren't designed to accept loggers as explicit parameters.
|
||||
Changing function signatures is often a breaking change, so zap includes
|
||||
global loggers to simplify migration.
|
||||
|
||||
Avoid them where possible.
|
||||
|
||||
### Why include dedicated Panic and Fatal log levels?
|
||||
|
||||
In general, application code should handle errors gracefully instead of using
|
||||
`panic` or `os.Exit`. However, every rule has exceptions, and it's common to
|
||||
crash when an error is truly unrecoverable. To avoid losing any information
|
||||
— especially the reason for the crash — the logger must flush any
|
||||
buffered entries before the process exits.
|
||||
|
||||
Zap makes this easy by offering `Panic` and `Fatal` logging methods that
|
||||
automatically flush before exiting. Of course, this doesn't guarantee that
|
||||
logs will never be lost, but it eliminates a common error.
|
||||
|
||||
See the discussion in uber-go/zap#207 for more details.
|
||||
|
||||
### What's `DPanic`?
|
||||
|
||||
`DPanic` stands for "panic in development." In development, it logs at
|
||||
`PanicLevel`; otherwise, it logs at `ErrorLevel`. `DPanic` makes it easier to
|
||||
catch errors that are theoretically possible, but shouldn't actually happen,
|
||||
*without* crashing in production.
|
||||
|
||||
If you've ever written code like this, you need `DPanic`:
|
||||
|
||||
```go
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("shouldn't ever get here: %v", err))
|
||||
}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### What does the error `expects import "go.uber.org/zap"` mean?
|
||||
|
||||
Either zap was installed incorrectly or you're referencing the wrong package
|
||||
name in your code.
|
||||
|
||||
Zap's source code happens to be hosted on GitHub, but the [import
|
||||
path][import-path] is `go.uber.org/zap`. This gives us, the project
|
||||
maintainers, the freedom to move the source code if necessary. However, it
|
||||
means that you need to take a little care when installing and using the
|
||||
package.
|
||||
|
||||
If you follow two simple rules, everything should work: install zap with `go
|
||||
get -u go.uber.org/zap`, and always import it in your code with `import
|
||||
"go.uber.org/zap"`. Your code shouldn't contain *any* references to
|
||||
`github.com/uber-go/zap`.
|
||||
|
||||
## Usage
|
||||
|
||||
### Does zap support log rotation?
|
||||
|
||||
Zap doesn't natively support rotating log files, since we prefer to leave this
|
||||
to an external program like `logrotate`.
|
||||
|
||||
However, it's easy to integrate a log rotation package like
|
||||
[`gopkg.in/natefinch/lumberjack.v2`][lumberjack] as a `zapcore.WriteSyncer`.
|
||||
|
||||
```go
|
||||
// lumberjack.Logger is already safe for concurrent use, so we don't need to
|
||||
// lock it.
|
||||
w := zapcore.AddSync(&lumberjack.Logger{
|
||||
Filename: "/var/log/myapp/foo.log",
|
||||
MaxSize: 500, // megabytes
|
||||
MaxBackups: 3,
|
||||
MaxAge: 28, // days
|
||||
})
|
||||
core := zapcore.NewCore(
|
||||
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
|
||||
w,
|
||||
zap.InfoLevel,
|
||||
)
|
||||
logger := zap.New(core)
|
||||
```
|
||||
|
||||
## Extensions
|
||||
|
||||
We'd love to support every logging need within zap itself, but we're only
|
||||
familiar with a handful of log ingestion systems, flag-parsing packages, and
|
||||
the like. Rather than merging code that we can't effectively debug and
|
||||
support, we'd rather grow an ecosystem of zap extensions.
|
||||
|
||||
We're aware of the following extensions, but haven't used them ourselves:
|
||||
|
||||
| Package | Integration |
|
||||
| --- | --- |
|
||||
| `github.com/tchap/zapext` | Sentry, syslog |
|
||||
| `github.com/fgrosse/zaptest` | Ginkgo |
|
||||
| `github.com/blendle/zapdriver` | Stackdriver |
|
||||
|
||||
[go-proverbs]: https://go-proverbs.github.io/
|
||||
[import-path]: https://golang.org/cmd/go/#hdr-Remote_import_paths
|
||||
[lumberjack]: https://godoc.org/gopkg.in/natefinch/lumberjack.v2
|
19
vendor/go.uber.org/zap/LICENSE.txt
generated
vendored
Normal file
19
vendor/go.uber.org/zap/LICENSE.txt
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2016-2017 Uber Technologies, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
57
vendor/go.uber.org/zap/Makefile
generated
vendored
Normal file
57
vendor/go.uber.org/zap/Makefile
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
export GOBIN ?= $(shell pwd)/bin
|
||||
|
||||
GOLINT = $(GOBIN)/golint
|
||||
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
|
||||
|
||||
# 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)
|
||||
@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 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 ]
|
||||
|
||||
$(GOLINT):
|
||||
go install golang.org/x/lint/golint
|
||||
|
||||
.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
|
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 | 862 ns/op | +0% | 5 allocs/op
|
||||
| :zap: zap (sugared) | 1250 ns/op | +45% | 11 allocs/op
|
||||
| zerolog | 4021 ns/op | +366% | 76 allocs/op
|
||||
| go-kit | 4542 ns/op | +427% | 105 allocs/op
|
||||
| apex/log | 26785 ns/op | +3007% | 115 allocs/op
|
||||
| logrus | 29501 ns/op | +3322% | 125 allocs/op
|
||||
| log15 | 29906 ns/op | +3369% | 122 allocs/op
|
||||
|
||||
Log a message with a logger that already has 10 fields of context:
|
||||
|
||||
| Package | Time | Time % to zap | Objects Allocated |
|
||||
| :------ | :--: | :-----------: | :---------------: |
|
||||
| :zap: zap | 126 ns/op | +0% | 0 allocs/op
|
||||
| :zap: zap (sugared) | 187 ns/op | +48% | 2 allocs/op
|
||||
| zerolog | 88 ns/op | -30% | 0 allocs/op
|
||||
| go-kit | 5087 ns/op | +3937% | 103 allocs/op
|
||||
| log15 | 18548 ns/op | +14621% | 73 allocs/op
|
||||
| apex/log | 26012 ns/op | +20544% | 104 allocs/op
|
||||
| logrus | 27236 ns/op | +21516% | 113 allocs/op
|
||||
|
||||
Log a static string, without any context or `printf`-style templating:
|
||||
|
||||
| Package | Time | Time % to zap | Objects Allocated |
|
||||
| :------ | :--: | :-----------: | :---------------: |
|
||||
| :zap: zap | 118 ns/op | +0% | 0 allocs/op
|
||||
| :zap: zap (sugared) | 191 ns/op | +62% | 2 allocs/op
|
||||
| zerolog | 93 ns/op | -21% | 0 allocs/op
|
||||
| go-kit | 280 ns/op | +137% | 11 allocs/op
|
||||
| standard library | 499 ns/op | +323% | 2 allocs/op
|
||||
| apex/log | 1990 ns/op | +1586% | 10 allocs/op
|
||||
| logrus | 3129 ns/op | +2552% | 24 allocs/op
|
||||
| log15 | 3887 ns/op | +3194% | 23 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://godoc.org/go.uber.org/zap?status.svg
|
||||
[doc]: https://godoc.org/go.uber.org/zap
|
||||
[ci-img]: https://travis-ci.com/uber-go/zap.svg?branch=master
|
||||
[ci]: https://travis-ci.com/uber-go/zap
|
||||
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
|
||||
[cov]: https://codecov.io/gh/uber-go/zap
|
||||
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
|
||||
[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
|
||||
}
|
115
vendor/go.uber.org/zap/buffer/buffer.go
generated
vendored
Normal file
115
vendor/go.uber.org/zap/buffer/buffer.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package buffer provides a thin wrapper around a byte slice. Unlike the
|
||||
// standard library's bytes.Buffer, it supports a portion of the strconv
|
||||
// package's zero-allocation formatters.
|
||||
package buffer // import "go.uber.org/zap/buffer"
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _size = 1024 // by default, create 1 KiB buffers
|
||||
|
||||
// Buffer is a thin wrapper around a byte slice. It's intended to be pooled, so
|
||||
// the only way to construct one is via a Pool.
|
||||
type Buffer struct {
|
||||
bs []byte
|
||||
pool Pool
|
||||
}
|
||||
|
||||
// AppendByte writes a single byte to the Buffer.
|
||||
func (b *Buffer) AppendByte(v byte) {
|
||||
b.bs = append(b.bs, v)
|
||||
}
|
||||
|
||||
// AppendString writes a string to the Buffer.
|
||||
func (b *Buffer) AppendString(s string) {
|
||||
b.bs = append(b.bs, s...)
|
||||
}
|
||||
|
||||
// AppendInt appends an integer to the underlying buffer (assuming base 10).
|
||||
func (b *Buffer) AppendInt(i int64) {
|
||||
b.bs = strconv.AppendInt(b.bs, i, 10)
|
||||
}
|
||||
|
||||
// AppendUint appends an unsigned integer to the underlying buffer (assuming
|
||||
// base 10).
|
||||
func (b *Buffer) AppendUint(i uint64) {
|
||||
b.bs = strconv.AppendUint(b.bs, i, 10)
|
||||
}
|
||||
|
||||
// AppendBool appends a bool to the underlying buffer.
|
||||
func (b *Buffer) AppendBool(v bool) {
|
||||
b.bs = strconv.AppendBool(b.bs, v)
|
||||
}
|
||||
|
||||
// AppendFloat appends a float to the underlying buffer. It doesn't quote NaN
|
||||
// or +/- Inf.
|
||||
func (b *Buffer) AppendFloat(f float64, bitSize int) {
|
||||
b.bs = strconv.AppendFloat(b.bs, f, 'f', -1, bitSize)
|
||||
}
|
||||
|
||||
// Len returns the length of the underlying byte slice.
|
||||
func (b *Buffer) Len() int {
|
||||
return len(b.bs)
|
||||
}
|
||||
|
||||
// Cap returns the capacity of the underlying byte slice.
|
||||
func (b *Buffer) Cap() int {
|
||||
return cap(b.bs)
|
||||
}
|
||||
|
||||
// Bytes returns a mutable reference to the underlying byte slice.
|
||||
func (b *Buffer) Bytes() []byte {
|
||||
return b.bs
|
||||
}
|
||||
|
||||
// String returns a string copy of the underlying byte slice.
|
||||
func (b *Buffer) String() string {
|
||||
return string(b.bs)
|
||||
}
|
||||
|
||||
// Reset resets the underlying byte slice. Subsequent writes re-use the slice's
|
||||
// backing array.
|
||||
func (b *Buffer) Reset() {
|
||||
b.bs = b.bs[:0]
|
||||
}
|
||||
|
||||
// Write implements io.Writer.
|
||||
func (b *Buffer) Write(bs []byte) (int, error) {
|
||||
b.bs = append(b.bs, bs...)
|
||||
return len(bs), nil
|
||||
}
|
||||
|
||||
// TrimNewline trims any final "\n" byte from the end of the buffer.
|
||||
func (b *Buffer) TrimNewline() {
|
||||
if i := len(b.bs) - 1; i >= 0 {
|
||||
if b.bs[i] == '\n' {
|
||||
b.bs = b.bs[:i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free returns the Buffer to its Pool.
|
||||
//
|
||||
// Callers must not retain references to the Buffer after calling Free.
|
||||
func (b *Buffer) Free() {
|
||||
b.pool.put(b)
|
||||
}
|
49
vendor/go.uber.org/zap/buffer/pool.go
generated
vendored
Normal file
49
vendor/go.uber.org/zap/buffer/pool.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package buffer
|
||||
|
||||
import "sync"
|
||||
|
||||
// A Pool is a type-safe wrapper around a sync.Pool.
|
||||
type Pool struct {
|
||||
p *sync.Pool
|
||||
}
|
||||
|
||||
// NewPool constructs a new Pool.
|
||||
func NewPool() Pool {
|
||||
return Pool{p: &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &Buffer{bs: make([]byte, 0, _size)}
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
// Get retrieves a Buffer from the pool, creating one if necessary.
|
||||
func (p Pool) Get() *Buffer {
|
||||
buf := p.p.Get().(*Buffer)
|
||||
buf.Reset()
|
||||
buf.pool = p
|
||||
return buf
|
||||
}
|
||||
|
||||
func (p Pool) put(buf *Buffer) {
|
||||
p.p.Put(buf)
|
||||
}
|
17
vendor/go.uber.org/zap/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
|
243
vendor/go.uber.org/zap/config.go
generated
vendored
Normal file
243
vendor/go.uber.org/zap/config.go
generated
vendored
Normal file
@ -0,0 +1,243 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// SamplingConfig sets a sampling strategy for the logger. Sampling caps the
|
||||
// global CPU and I/O load that logging puts on your process while attempting
|
||||
// to preserve a representative subset of your logs.
|
||||
//
|
||||
// Values configured here are per-second. See zapcore.NewSampler for details.
|
||||
type SamplingConfig struct {
|
||||
Initial int `json:"initial" yaml:"initial"`
|
||||
Thereafter int `json:"thereafter" yaml:"thereafter"`
|
||||
}
|
||||
|
||||
// Config offers a declarative way to construct a logger. It doesn't do
|
||||
// anything that can't be done with New, Options, and the various
|
||||
// zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to
|
||||
// toggle common options.
|
||||
//
|
||||
// Note that Config intentionally supports only the most common options. More
|
||||
// unusual logging setups (logging to network connections or message queues,
|
||||
// splitting output between multiple files, etc.) are possible, but require
|
||||
// direct use of the zapcore package. For sample code, see the package-level
|
||||
// BasicConfiguration and AdvancedConfiguration examples.
|
||||
//
|
||||
// For an example showing runtime log level changes, see the documentation for
|
||||
// AtomicLevel.
|
||||
type Config struct {
|
||||
// Level is the minimum enabled logging level. Note that this is a dynamic
|
||||
// level, so calling Config.Level.SetLevel will atomically change the log
|
||||
// level of all loggers descended from this config.
|
||||
Level AtomicLevel `json:"level" yaml:"level"`
|
||||
// Development puts the logger in development mode, which changes the
|
||||
// behavior of DPanicLevel and takes stacktraces more liberally.
|
||||
Development bool `json:"development" yaml:"development"`
|
||||
// DisableCaller stops annotating logs with the calling function's file
|
||||
// name and line number. By default, all logs are annotated.
|
||||
DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
|
||||
// DisableStacktrace completely disables automatic stacktrace capturing. By
|
||||
// default, stacktraces are captured for WarnLevel and above logs in
|
||||
// development and ErrorLevel and above in production.
|
||||
DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
|
||||
// Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
|
||||
Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
|
||||
// Encoding sets the logger's encoding. Valid values are "json" and
|
||||
// "console", as well as any third-party encodings registered via
|
||||
// RegisterEncoder.
|
||||
Encoding string `json:"encoding" yaml:"encoding"`
|
||||
// EncoderConfig sets options for the chosen encoder. See
|
||||
// zapcore.EncoderConfig for details.
|
||||
EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
|
||||
// OutputPaths is a list of URLs or file paths to write logging output to.
|
||||
// See Open for details.
|
||||
OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
|
||||
// ErrorOutputPaths is a list of URLs to write internal logger errors to.
|
||||
// The default is standard error.
|
||||
//
|
||||
// Note that this setting only affects internal errors; for sample code that
|
||||
// sends error-level logs to a different location from info- and debug-level
|
||||
// logs, see the package-level AdvancedConfiguration example.
|
||||
ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
|
||||
// InitialFields is a collection of fields to add to the root logger.
|
||||
InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
|
||||
}
|
||||
|
||||
// NewProductionEncoderConfig returns an opinionated EncoderConfig for
|
||||
// production environments.
|
||||
func NewProductionEncoderConfig() zapcore.EncoderConfig {
|
||||
return zapcore.EncoderConfig{
|
||||
TimeKey: "ts",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger",
|
||||
CallerKey: "caller",
|
||||
MessageKey: "msg",
|
||||
StacktraceKey: "stacktrace",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
||||
EncodeTime: zapcore.EpochTimeEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
}
|
||||
}
|
||||
|
||||
// NewProductionConfig is a reasonable production logging configuration.
|
||||
// Logging is enabled at InfoLevel and above.
|
||||
//
|
||||
// It uses a JSON encoder, writes to standard error, and enables sampling.
|
||||
// Stacktraces are automatically included on logs of ErrorLevel and above.
|
||||
func NewProductionConfig() Config {
|
||||
return Config{
|
||||
Level: NewAtomicLevelAt(InfoLevel),
|
||||
Development: false,
|
||||
Sampling: &SamplingConfig{
|
||||
Initial: 100,
|
||||
Thereafter: 100,
|
||||
},
|
||||
Encoding: "json",
|
||||
EncoderConfig: NewProductionEncoderConfig(),
|
||||
OutputPaths: []string{"stderr"},
|
||||
ErrorOutputPaths: []string{"stderr"},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for
|
||||
// development environments.
|
||||
func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
|
||||
return zapcore.EncoderConfig{
|
||||
// Keys can be anything except the empty string.
|
||||
TimeKey: "T",
|
||||
LevelKey: "L",
|
||||
NameKey: "N",
|
||||
CallerKey: "C",
|
||||
MessageKey: "M",
|
||||
StacktraceKey: "S",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||||
EncodeTime: zapcore.ISO8601TimeEncoder,
|
||||
EncodeDuration: zapcore.StringDurationEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDevelopmentConfig is a reasonable development logging configuration.
|
||||
// Logging is enabled at DebugLevel and above.
|
||||
//
|
||||
// It enables development mode (which makes DPanicLevel logs panic), uses a
|
||||
// console encoder, writes to standard error, and disables sampling.
|
||||
// Stacktraces are automatically included on logs of WarnLevel and above.
|
||||
func NewDevelopmentConfig() Config {
|
||||
return Config{
|
||||
Level: NewAtomicLevelAt(DebugLevel),
|
||||
Development: true,
|
||||
Encoding: "console",
|
||||
EncoderConfig: NewDevelopmentEncoderConfig(),
|
||||
OutputPaths: []string{"stderr"},
|
||||
ErrorOutputPaths: []string{"stderr"},
|
||||
}
|
||||
}
|
||||
|
||||
// Build constructs a logger from the Config and Options.
|
||||
func (cfg Config) Build(opts ...Option) (*Logger, error) {
|
||||
enc, err := cfg.buildEncoder()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sink, errSink, err := cfg.openSinks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log := New(
|
||||
zapcore.NewCore(enc, sink, cfg.Level),
|
||||
cfg.buildOptions(errSink)...,
|
||||
)
|
||||
if len(opts) > 0 {
|
||||
log = log.WithOptions(opts...)
|
||||
}
|
||||
return log, nil
|
||||
}
|
||||
|
||||
func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
|
||||
opts := []Option{ErrorOutput(errSink)}
|
||||
|
||||
if cfg.Development {
|
||||
opts = append(opts, Development())
|
||||
}
|
||||
|
||||
if !cfg.DisableCaller {
|
||||
opts = append(opts, AddCaller())
|
||||
}
|
||||
|
||||
stackLevel := ErrorLevel
|
||||
if cfg.Development {
|
||||
stackLevel = WarnLevel
|
||||
}
|
||||
if !cfg.DisableStacktrace {
|
||||
opts = append(opts, AddStacktrace(stackLevel))
|
||||
}
|
||||
|
||||
if cfg.Sampling != nil {
|
||||
opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core {
|
||||
return zapcore.NewSampler(core, time.Second, int(cfg.Sampling.Initial), int(cfg.Sampling.Thereafter))
|
||||
}))
|
||||
}
|
||||
|
||||
if len(cfg.InitialFields) > 0 {
|
||||
fs := make([]Field, 0, len(cfg.InitialFields))
|
||||
keys := make([]string, 0, len(cfg.InitialFields))
|
||||
for k := range cfg.InitialFields {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
fs = append(fs, Any(k, cfg.InitialFields[k]))
|
||||
}
|
||||
opts = append(opts, Fields(fs...))
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
|
||||
sink, closeOut, err := Open(cfg.OutputPaths...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
errSink, _, err := Open(cfg.ErrorOutputPaths...)
|
||||
if err != nil {
|
||||
closeOut()
|
||||
return nil, nil, err
|
||||
}
|
||||
return sink, errSink, nil
|
||||
}
|
||||
|
||||
func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
|
||||
return newEncoder(cfg.Encoding, cfg.EncoderConfig)
|
||||
}
|
113
vendor/go.uber.org/zap/doc.go
generated
vendored
Normal file
113
vendor/go.uber.org/zap/doc.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package zap provides fast, structured, leveled logging.
|
||||
//
|
||||
// For applications that log in the hot path, reflection-based serialization
|
||||
// and string formatting are prohibitively expensive - they're CPU-intensive
|
||||
// and make many small allocations. Put differently, using json.Marshal and
|
||||
// fmt.Fprintf to log tons of interface{} makes your application slow.
|
||||
//
|
||||
// Zap takes a different approach. It includes a reflection-free,
|
||||
// zero-allocation JSON encoder, and the base Logger strives to avoid
|
||||
// serialization overhead and allocations wherever possible. By building the
|
||||
// high-level SugaredLogger on that foundation, zap lets users choose when
|
||||
// they need to count every allocation and when they'd prefer a more familiar,
|
||||
// loosely typed API.
|
||||
//
|
||||
// Choosing a Logger
|
||||
//
|
||||
// In contexts where performance is nice, but not critical, use the
|
||||
// SugaredLogger. It's 4-10x faster than other structured logging packages and
|
||||
// supports both structured and printf-style logging. Like log15 and go-kit,
|
||||
// the SugaredLogger's structured logging APIs are loosely typed and accept a
|
||||
// variadic number of key-value pairs. (For more advanced use cases, they also
|
||||
// accept strongly typed fields - see the SugaredLogger.With documentation for
|
||||
// details.)
|
||||
// sugar := zap.NewExample().Sugar()
|
||||
// defer sugar.Sync()
|
||||
// sugar.Infow("failed to fetch URL",
|
||||
// "url", "http://example.com",
|
||||
// "attempt", 3,
|
||||
// "backoff", time.Second,
|
||||
// )
|
||||
// sugar.Infof("failed to fetch URL: %s", "http://example.com")
|
||||
//
|
||||
// By default, loggers are unbuffered. However, since zap's low-level APIs
|
||||
// allow buffering, calling Sync before letting your process exit is a good
|
||||
// habit.
|
||||
//
|
||||
// In the rare contexts where every microsecond and every allocation matter,
|
||||
// use the Logger. It's even faster than the SugaredLogger and allocates far
|
||||
// less, but it only supports strongly-typed, structured logging.
|
||||
// logger := zap.NewExample()
|
||||
// defer logger.Sync()
|
||||
// logger.Info("failed to fetch URL",
|
||||
// zap.String("url", "http://example.com"),
|
||||
// zap.Int("attempt", 3),
|
||||
// zap.Duration("backoff", time.Second),
|
||||
// )
|
||||
//
|
||||
// Choosing between the Logger and SugaredLogger doesn't need to be an
|
||||
// application-wide decision: converting between the two is simple and
|
||||
// inexpensive.
|
||||
// logger := zap.NewExample()
|
||||
// defer logger.Sync()
|
||||
// sugar := logger.Sugar()
|
||||
// plain := sugar.Desugar()
|
||||
//
|
||||
// Configuring Zap
|
||||
//
|
||||
// The simplest way to build a Logger is to use zap's opinionated presets:
|
||||
// NewExample, NewProduction, and NewDevelopment. These presets build a logger
|
||||
// with a single function call:
|
||||
// logger, err := zap.NewProduction()
|
||||
// if err != nil {
|
||||
// log.Fatalf("can't initialize zap logger: %v", err)
|
||||
// }
|
||||
// defer logger.Sync()
|
||||
//
|
||||
// Presets are fine for small projects, but larger projects and organizations
|
||||
// naturally require a bit more customization. For most users, zap's Config
|
||||
// struct strikes the right balance between flexibility and convenience. See
|
||||
// the package-level BasicConfiguration example for sample code.
|
||||
//
|
||||
// More unusual configurations (splitting output between files, sending logs
|
||||
// to a message queue, etc.) are possible, but require direct use of
|
||||
// go.uber.org/zap/zapcore. See the package-level AdvancedConfiguration
|
||||
// example for sample code.
|
||||
//
|
||||
// Extending Zap
|
||||
//
|
||||
// The zap package itself is a relatively thin wrapper around the interfaces
|
||||
// in go.uber.org/zap/zapcore. Extending zap to support a new encoding (e.g.,
|
||||
// BSON), a new log sink (e.g., Kafka), or something more exotic (perhaps an
|
||||
// exception aggregation service, like Sentry or Rollbar) typically requires
|
||||
// implementing the zapcore.Encoder, zapcore.WriteSyncer, or zapcore.Core
|
||||
// interfaces. See the zapcore documentation for details.
|
||||
//
|
||||
// Similarly, package authors can use the high-performance Encoder and Core
|
||||
// implementations in the zapcore package to build their own loggers.
|
||||
//
|
||||
// Frequently Asked Questions
|
||||
//
|
||||
// An FAQ covering everything from installation errors to design decisions is
|
||||
// available at https://github.com/uber-go/zap/blob/master/FAQ.md.
|
||||
package zap // import "go.uber.org/zap"
|
75
vendor/go.uber.org/zap/encoder.go
generated
vendored
Normal file
75
vendor/go.uber.org/zap/encoder.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoEncoderNameSpecified = errors.New("no encoder name specified")
|
||||
|
||||
_encoderNameToConstructor = map[string]func(zapcore.EncoderConfig) (zapcore.Encoder, error){
|
||||
"console": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||||
return zapcore.NewConsoleEncoder(encoderConfig), nil
|
||||
},
|
||||
"json": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||||
return zapcore.NewJSONEncoder(encoderConfig), nil
|
||||
},
|
||||
}
|
||||
_encoderMutex sync.RWMutex
|
||||
)
|
||||
|
||||
// RegisterEncoder registers an encoder constructor, which the Config struct
|
||||
// can then reference. By default, the "json" and "console" encoders are
|
||||
// registered.
|
||||
//
|
||||
// Attempting to register an encoder whose name is already taken returns an
|
||||
// error.
|
||||
func RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) error {
|
||||
_encoderMutex.Lock()
|
||||
defer _encoderMutex.Unlock()
|
||||
if name == "" {
|
||||
return errNoEncoderNameSpecified
|
||||
}
|
||||
if _, ok := _encoderNameToConstructor[name]; ok {
|
||||
return fmt.Errorf("encoder already registered for name %q", name)
|
||||
}
|
||||
_encoderNameToConstructor[name] = constructor
|
||||
return nil
|
||||
}
|
||||
|
||||
func newEncoder(name string, encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||||
_encoderMutex.RLock()
|
||||
defer _encoderMutex.RUnlock()
|
||||
if name == "" {
|
||||
return nil, errNoEncoderNameSpecified
|
||||
}
|
||||
constructor, ok := _encoderNameToConstructor[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no encoder registered for name %q", name)
|
||||
}
|
||||
return constructor(encoderConfig)
|
||||
}
|
80
vendor/go.uber.org/zap/error.go
generated
vendored
Normal file
80
vendor/go.uber.org/zap/error.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var _errArrayElemPool = sync.Pool{New: func() interface{} {
|
||||
return &errArrayElem{}
|
||||
}}
|
||||
|
||||
// Error is shorthand for the common idiom NamedError("error", err).
|
||||
func Error(err error) Field {
|
||||
return NamedError("error", err)
|
||||
}
|
||||
|
||||
// NamedError constructs a field that lazily stores err.Error() under the
|
||||
// provided key. Errors which also implement fmt.Formatter (like those produced
|
||||
// by github.com/pkg/errors) will also have their verbose representation stored
|
||||
// under key+"Verbose". If passed a nil error, the field is a no-op.
|
||||
//
|
||||
// For the common case in which the key is simply "error", the Error function
|
||||
// is shorter and less repetitive.
|
||||
func NamedError(key string, err error) Field {
|
||||
if err == nil {
|
||||
return Skip()
|
||||
}
|
||||
return Field{Key: key, Type: zapcore.ErrorType, Interface: err}
|
||||
}
|
||||
|
||||
type errArray []error
|
||||
|
||||
func (errs errArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
|
||||
for i := range errs {
|
||||
if errs[i] == nil {
|
||||
continue
|
||||
}
|
||||
// To represent each error as an object with an "error" attribute and
|
||||
// potentially an "errorVerbose" attribute, we need to wrap it in a
|
||||
// type that implements LogObjectMarshaler. To prevent this from
|
||||
// allocating, pool the wrapper type.
|
||||
elem := _errArrayElemPool.Get().(*errArrayElem)
|
||||
elem.error = errs[i]
|
||||
arr.AppendObject(elem)
|
||||
elem.error = nil
|
||||
_errArrayElemPool.Put(elem)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type errArrayElem struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (e *errArrayElem) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
||||
// Re-use the error field's logic, which supports non-standard error types.
|
||||
Error(e.error).AddTo(enc)
|
||||
return nil
|
||||
}
|
525
vendor/go.uber.org/zap/field.go
generated
vendored
Normal file
525
vendor/go.uber.org/zap/field.go
generated
vendored
Normal file
@ -0,0 +1,525 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// Field is an alias for Field. Aliasing this type dramatically
|
||||
// improves the navigability of this package's API documentation.
|
||||
type Field = zapcore.Field
|
||||
|
||||
// Skip constructs a no-op field, which is often useful when handling invalid
|
||||
// inputs in other Field constructors.
|
||||
func Skip() Field {
|
||||
return Field{Type: zapcore.SkipType}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
// Returning the stacktrace as a string costs an allocation, but saves us
|
||||
// from expanding the zapcore.Field union struct to include a byte slice. Since
|
||||
// taking a stacktrace is already so expensive (~10us), the extra allocation
|
||||
// is okay.
|
||||
return String(key, takeStacktrace())
|
||||
}
|
||||
|
||||
// Duration constructs a field with the given key and value. The encoder
|
||||
// controls how the duration is serialized.
|
||||
func Duration(key string, val time.Duration) Field {
|
||||
return Field{Key: key, Type: zapcore.DurationType, Integer: int64(val)}
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// 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
|
168
vendor/go.uber.org/zap/global.go
generated
vendored
Normal file
168
vendor/go.uber.org/zap/global.go
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
// 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 (
|
||||
_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
|
||||
}
|
26
vendor/go.uber.org/zap/global_go112.go
generated
vendored
Normal file
26
vendor/go.uber.org/zap/global_go112.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
// See #682 for more information.
|
||||
// +build go1.12
|
||||
|
||||
package zap
|
||||
|
||||
const _stdLogDefaultDepth = 1
|
26
vendor/go.uber.org/zap/global_prego112.go
generated
vendored
Normal file
26
vendor/go.uber.org/zap/global_prego112.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
// See #682 for more information.
|
||||
// +build !go1.12
|
||||
|
||||
package zap
|
||||
|
||||
const _stdLogDefaultDepth = 2
|
11
vendor/go.uber.org/zap/go.mod
generated
vendored
Normal file
11
vendor/go.uber.org/zap/go.mod
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
module go.uber.org/zap
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/stretchr/testify v1.4.0
|
||||
go.uber.org/atomic v1.5.0
|
||||
go.uber.org/multierr v1.3.0
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de
|
||||
)
|
56
vendor/go.uber.org/zap/go.sum
generated
vendored
Normal file
56
vendor/go.uber.org/zap/go.sum
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
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/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
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/sync v0.0.0-20190423024810-112230192c58/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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
81
vendor/go.uber.org/zap/http_handler.go
generated
vendored
Normal file
81
vendor/go.uber.org/zap/http_handler.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// ServeHTTP is a simple JSON endpoint that can report on or change the current
|
||||
// logging level.
|
||||
//
|
||||
// GET requests return a JSON description of the current logging level. PUT
|
||||
// requests change the logging level and expect a payload like:
|
||||
// {"level":"info"}
|
||||
//
|
||||
// It's perfectly safe to change the logging level while a program is running.
|
||||
func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
type errorResponse struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
type payload struct {
|
||||
Level *zapcore.Level `json:"level"`
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
|
||||
switch r.Method {
|
||||
|
||||
case http.MethodGet:
|
||||
current := lvl.Level()
|
||||
enc.Encode(payload{Level: ¤t})
|
||||
|
||||
case http.MethodPut:
|
||||
var req payload
|
||||
|
||||
if errmess := func() string {
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return fmt.Sprintf("Request body must be well-formed JSON: %v", err)
|
||||
}
|
||||
if req.Level == nil {
|
||||
return "Must specify a logging level."
|
||||
}
|
||||
return ""
|
||||
}(); errmess != "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
enc.Encode(errorResponse{Error: errmess})
|
||||
return
|
||||
}
|
||||
|
||||
lvl.SetLevel(*req.Level)
|
||||
enc.Encode(req)
|
||||
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
enc.Encode(errorResponse{
|
||||
Error: "Only GET and PUT are supported.",
|
||||
})
|
||||
}
|
||||
}
|
31
vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go
generated
vendored
Normal file
31
vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package bufferpool houses zap's shared internal buffer pool. Third-party
|
||||
// packages can recreate the same functionality with buffers.NewPool.
|
||||
package bufferpool
|
||||
|
||||
import "go.uber.org/zap/buffer"
|
||||
|
||||
var (
|
||||
_pool = buffer.NewPool()
|
||||
// Get retrieves a buffer from the pool, creating one if necessary.
|
||||
Get = _pool.Get
|
||||
)
|
44
vendor/go.uber.org/zap/internal/color/color.go
generated
vendored
Normal file
44
vendor/go.uber.org/zap/internal/color/color.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package color adds coloring functionality for TTY output.
|
||||
package color
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Foreground colors.
|
||||
const (
|
||||
Black Color = iota + 30
|
||||
Red
|
||||
Green
|
||||
Yellow
|
||||
Blue
|
||||
Magenta
|
||||
Cyan
|
||||
White
|
||||
)
|
||||
|
||||
// Color represents a text color.
|
||||
type Color uint8
|
||||
|
||||
// Add adds the coloring to the given string.
|
||||
func (c Color) Add(s string) string {
|
||||
return fmt.Sprintf("\x1b[%dm%s\x1b[0m", uint8(c), s)
|
||||
}
|
64
vendor/go.uber.org/zap/internal/exit/exit.go
generated
vendored
Normal file
64
vendor/go.uber.org/zap/internal/exit/exit.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package exit provides stubs so that unit tests can exercise code that calls
|
||||
// os.Exit(1).
|
||||
package exit
|
||||
|
||||
import "os"
|
||||
|
||||
var real = func() { os.Exit(1) }
|
||||
|
||||
// Exit normally terminates the process by calling os.Exit(1). If the package
|
||||
// is stubbed, it instead records a call in the testing spy.
|
||||
func Exit() {
|
||||
real()
|
||||
}
|
||||
|
||||
// A StubbedExit is a testing fake for os.Exit.
|
||||
type StubbedExit struct {
|
||||
Exited bool
|
||||
prev func()
|
||||
}
|
||||
|
||||
// Stub substitutes a fake for the call to os.Exit(1).
|
||||
func Stub() *StubbedExit {
|
||||
s := &StubbedExit{prev: real}
|
||||
real = s.exit
|
||||
return s
|
||||
}
|
||||
|
||||
// WithStub runs the supplied function with Exit stubbed. It returns the stub
|
||||
// used, so that users can test whether the process would have crashed.
|
||||
func WithStub(f func()) *StubbedExit {
|
||||
s := Stub()
|
||||
defer s.Unstub()
|
||||
f()
|
||||
return s
|
||||
}
|
||||
|
||||
// Unstub restores the previous exit function.
|
||||
func (se *StubbedExit) Unstub() {
|
||||
real = se.prev
|
||||
}
|
||||
|
||||
func (se *StubbedExit) exit() {
|
||||
se.Exited = true
|
||||
}
|
132
vendor/go.uber.org/zap/level.go
generated
vendored
Normal file
132
vendor/go.uber.org/zap/level.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"go.uber.org/atomic"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
const (
|
||||
// DebugLevel logs are typically voluminous, and are usually disabled in
|
||||
// production.
|
||||
DebugLevel = zapcore.DebugLevel
|
||||
// InfoLevel is the default logging priority.
|
||||
InfoLevel = zapcore.InfoLevel
|
||||
// WarnLevel logs are more important than Info, but don't need individual
|
||||
// human review.
|
||||
WarnLevel = zapcore.WarnLevel
|
||||
// ErrorLevel logs are high-priority. If an application is running smoothly,
|
||||
// it shouldn't generate any error-level logs.
|
||||
ErrorLevel = zapcore.ErrorLevel
|
||||
// DPanicLevel logs are particularly important errors. In development the
|
||||
// logger panics after writing the message.
|
||||
DPanicLevel = zapcore.DPanicLevel
|
||||
// PanicLevel logs a message, then panics.
|
||||
PanicLevel = zapcore.PanicLevel
|
||||
// FatalLevel logs a message, then calls os.Exit(1).
|
||||
FatalLevel = zapcore.FatalLevel
|
||||
)
|
||||
|
||||
// LevelEnablerFunc is a convenient way to implement zapcore.LevelEnabler with
|
||||
// an anonymous function.
|
||||
//
|
||||
// It's particularly useful when splitting log output between different
|
||||
// outputs (e.g., standard error and standard out). For sample code, see the
|
||||
// package-level AdvancedConfiguration example.
|
||||
type LevelEnablerFunc func(zapcore.Level) bool
|
||||
|
||||
// Enabled calls the wrapped function.
|
||||
func (f LevelEnablerFunc) Enabled(lvl zapcore.Level) bool { return f(lvl) }
|
||||
|
||||
// An AtomicLevel is an atomically changeable, dynamic logging level. It lets
|
||||
// you safely change the log level of a tree of loggers (the root logger and
|
||||
// any children created by adding context) at runtime.
|
||||
//
|
||||
// The AtomicLevel itself is an http.Handler that serves a JSON endpoint to
|
||||
// alter its level.
|
||||
//
|
||||
// AtomicLevels must be created with the NewAtomicLevel constructor to allocate
|
||||
// their internal atomic pointer.
|
||||
type AtomicLevel struct {
|
||||
l *atomic.Int32
|
||||
}
|
||||
|
||||
// NewAtomicLevel creates an AtomicLevel with InfoLevel and above logging
|
||||
// enabled.
|
||||
func NewAtomicLevel() AtomicLevel {
|
||||
return AtomicLevel{
|
||||
l: atomic.NewInt32(int32(InfoLevel)),
|
||||
}
|
||||
}
|
||||
|
||||
// NewAtomicLevelAt is a convenience function that creates an AtomicLevel
|
||||
// and then calls SetLevel with the given level.
|
||||
func NewAtomicLevelAt(l zapcore.Level) AtomicLevel {
|
||||
a := NewAtomicLevel()
|
||||
a.SetLevel(l)
|
||||
return a
|
||||
}
|
||||
|
||||
// Enabled implements the zapcore.LevelEnabler interface, which allows the
|
||||
// AtomicLevel to be used in place of traditional static levels.
|
||||
func (lvl AtomicLevel) Enabled(l zapcore.Level) bool {
|
||||
return lvl.Level().Enabled(l)
|
||||
}
|
||||
|
||||
// Level returns the minimum enabled log level.
|
||||
func (lvl AtomicLevel) Level() zapcore.Level {
|
||||
return zapcore.Level(int8(lvl.l.Load()))
|
||||
}
|
||||
|
||||
// SetLevel alters the logging level.
|
||||
func (lvl AtomicLevel) SetLevel(l zapcore.Level) {
|
||||
lvl.l.Store(int32(l))
|
||||
}
|
||||
|
||||
// String returns the string representation of the underlying Level.
|
||||
func (lvl AtomicLevel) String() string {
|
||||
return lvl.Level().String()
|
||||
}
|
||||
|
||||
// UnmarshalText unmarshals the text to an AtomicLevel. It uses the same text
|
||||
// representations as the static zapcore.Levels ("debug", "info", "warn",
|
||||
// "error", "dpanic", "panic", and "fatal").
|
||||
func (lvl *AtomicLevel) UnmarshalText(text []byte) error {
|
||||
if lvl.l == nil {
|
||||
lvl.l = &atomic.Int32{}
|
||||
}
|
||||
|
||||
var l zapcore.Level
|
||||
if err := l.UnmarshalText(text); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lvl.SetLevel(l)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText marshals the AtomicLevel to a byte slice. It uses the same
|
||||
// text representation as the static zapcore.Levels ("debug", "info", "warn",
|
||||
// "error", "dpanic", "panic", and "fatal").
|
||||
func (lvl AtomicLevel) MarshalText() (text []byte, err error) {
|
||||
return lvl.Level().MarshalText()
|
||||
}
|
305
vendor/go.uber.org/zap/logger.go
generated
vendored
Normal file
305
vendor/go.uber.org/zap/logger.go
generated
vendored
Normal file
@ -0,0 +1,305 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// A Logger provides fast, leveled, structured logging. All methods are safe
|
||||
// for concurrent use.
|
||||
//
|
||||
// The Logger is designed for contexts in which every microsecond and every
|
||||
// allocation matters, so its API intentionally favors performance and type
|
||||
// safety over brevity. For most applications, the SugaredLogger strikes a
|
||||
// better balance between performance and ergonomics.
|
||||
type Logger struct {
|
||||
core zapcore.Core
|
||||
|
||||
development bool
|
||||
name string
|
||||
errorOutput zapcore.WriteSyncer
|
||||
|
||||
addCaller bool
|
||||
addStack zapcore.LevelEnabler
|
||||
|
||||
callerSkip int
|
||||
}
|
||||
|
||||
// New constructs a new Logger from the provided zapcore.Core and Options. If
|
||||
// the passed zapcore.Core is nil, it falls back to using a no-op
|
||||
// implementation.
|
||||
//
|
||||
// This is the most flexible way to construct a Logger, but also the most
|
||||
// verbose. For typical use cases, the highly-opinionated presets
|
||||
// (NewProduction, NewDevelopment, and NewExample) or the Config struct are
|
||||
// more convenient.
|
||||
//
|
||||
// For sample code, see the package-level AdvancedConfiguration example.
|
||||
func New(core zapcore.Core, options ...Option) *Logger {
|
||||
if core == nil {
|
||||
return NewNop()
|
||||
}
|
||||
log := &Logger{
|
||||
core: core,
|
||||
errorOutput: zapcore.Lock(os.Stderr),
|
||||
addStack: zapcore.FatalLevel + 1,
|
||||
}
|
||||
return log.WithOptions(options...)
|
||||
}
|
||||
|
||||
// NewNop returns a no-op Logger. It never writes out logs or internal errors,
|
||||
// and it never runs user-defined hooks.
|
||||
//
|
||||
// Using WithOptions to replace the Core or error output of a no-op Logger can
|
||||
// re-enable logging.
|
||||
func NewNop() *Logger {
|
||||
return &Logger{
|
||||
core: zapcore.NewNopCore(),
|
||||
errorOutput: zapcore.AddSync(ioutil.Discard),
|
||||
addStack: zapcore.FatalLevel + 1,
|
||||
}
|
||||
}
|
||||
|
||||
// NewProduction builds a sensible production Logger that writes InfoLevel and
|
||||
// above logs to standard error as JSON.
|
||||
//
|
||||
// It's a shortcut for NewProductionConfig().Build(...Option).
|
||||
func NewProduction(options ...Option) (*Logger, error) {
|
||||
return NewProductionConfig().Build(options...)
|
||||
}
|
||||
|
||||
// NewDevelopment builds a development Logger that writes DebugLevel and above
|
||||
// logs to standard error in a human-friendly format.
|
||||
//
|
||||
// It's a shortcut for NewDevelopmentConfig().Build(...Option).
|
||||
func NewDevelopment(options ...Option) (*Logger, error) {
|
||||
return NewDevelopmentConfig().Build(options...)
|
||||
}
|
||||
|
||||
// NewExample builds a Logger that's designed for use in zap's testable
|
||||
// examples. It writes DebugLevel and above logs to standard out as JSON, but
|
||||
// omits the timestamp and calling function to keep example output
|
||||
// short and deterministic.
|
||||
func NewExample(options ...Option) *Logger {
|
||||
encoderCfg := zapcore.EncoderConfig{
|
||||
MessageKey: "msg",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger",
|
||||
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
||||
EncodeTime: zapcore.ISO8601TimeEncoder,
|
||||
EncodeDuration: zapcore.StringDurationEncoder,
|
||||
}
|
||||
core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), os.Stdout, DebugLevel)
|
||||
return New(core).WithOptions(options...)
|
||||
}
|
||||
|
||||
// Sugar wraps the Logger to provide a more ergonomic, but slightly slower,
|
||||
// API. Sugaring a Logger is quite inexpensive, so it's reasonable for a
|
||||
// single application to use both Loggers and SugaredLoggers, converting
|
||||
// between them on the boundaries of performance-sensitive code.
|
||||
func (log *Logger) Sugar() *SugaredLogger {
|
||||
core := log.clone()
|
||||
core.callerSkip += 2
|
||||
return &SugaredLogger{core}
|
||||
}
|
||||
|
||||
// Named adds a new path segment to the logger's name. Segments are joined by
|
||||
// periods. By default, Loggers are unnamed.
|
||||
func (log *Logger) Named(s string) *Logger {
|
||||
if s == "" {
|
||||
return log
|
||||
}
|
||||
l := log.clone()
|
||||
if log.name == "" {
|
||||
l.name = s
|
||||
} else {
|
||||
l.name = strings.Join([]string{l.name, s}, ".")
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// WithOptions clones the current Logger, applies the supplied Options, and
|
||||
// returns the resulting Logger. It's safe to use concurrently.
|
||||
func (log *Logger) WithOptions(opts ...Option) *Logger {
|
||||
c := log.clone()
|
||||
for _, opt := range opts {
|
||||
opt.apply(c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// With creates a child logger and adds structured context to it. Fields added
|
||||
// to the child don't affect the parent, and vice versa.
|
||||
func (log *Logger) With(fields ...Field) *Logger {
|
||||
if len(fields) == 0 {
|
||||
return log
|
||||
}
|
||||
l := log.clone()
|
||||
l.core = l.core.With(fields)
|
||||
return l
|
||||
}
|
||||
|
||||
// Check returns a CheckedEntry if logging a message at the specified level
|
||||
// is enabled. It's a completely optional optimization; in high-performance
|
||||
// applications, Check can help avoid allocating a slice to hold fields.
|
||||
func (log *Logger) Check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
|
||||
return log.check(lvl, msg)
|
||||
}
|
||||
|
||||
// Debug logs a message at DebugLevel. The message includes any fields passed
|
||||
// at the log site, as well as any fields accumulated on the logger.
|
||||
func (log *Logger) Debug(msg string, fields ...Field) {
|
||||
if ce := log.check(DebugLevel, msg); ce != nil {
|
||||
ce.Write(fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Info logs a message at InfoLevel. The message includes any fields passed
|
||||
// at the log site, as well as any fields accumulated on the logger.
|
||||
func (log *Logger) Info(msg string, fields ...Field) {
|
||||
if ce := log.check(InfoLevel, msg); ce != nil {
|
||||
ce.Write(fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Warn logs a message at WarnLevel. The message includes any fields passed
|
||||
// at the log site, as well as any fields accumulated on the logger.
|
||||
func (log *Logger) Warn(msg string, fields ...Field) {
|
||||
if ce := log.check(WarnLevel, msg); ce != nil {
|
||||
ce.Write(fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Error logs a message at ErrorLevel. The message includes any fields passed
|
||||
// at the log site, as well as any fields accumulated on the logger.
|
||||
func (log *Logger) Error(msg string, fields ...Field) {
|
||||
if ce := log.check(ErrorLevel, msg); ce != nil {
|
||||
ce.Write(fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// DPanic logs a message at DPanicLevel. The message includes any fields
|
||||
// passed at the log site, as well as any fields accumulated on the logger.
|
||||
//
|
||||
// If the logger is in development mode, it then panics (DPanic means
|
||||
// "development panic"). This is useful for catching errors that are
|
||||
// recoverable, but shouldn't ever happen.
|
||||
func (log *Logger) DPanic(msg string, fields ...Field) {
|
||||
if ce := log.check(DPanicLevel, msg); ce != nil {
|
||||
ce.Write(fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Panic logs a message at PanicLevel. The message includes any fields passed
|
||||
// at the log site, as well as any fields accumulated on the logger.
|
||||
//
|
||||
// The logger then panics, even if logging at PanicLevel is disabled.
|
||||
func (log *Logger) Panic(msg string, fields ...Field) {
|
||||
if ce := log.check(PanicLevel, msg); ce != nil {
|
||||
ce.Write(fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Fatal logs a message at FatalLevel. The message includes any fields passed
|
||||
// at the log site, as well as any fields accumulated on the logger.
|
||||
//
|
||||
// The logger then calls os.Exit(1), even if logging at FatalLevel is
|
||||
// disabled.
|
||||
func (log *Logger) Fatal(msg string, fields ...Field) {
|
||||
if ce := log.check(FatalLevel, msg); ce != nil {
|
||||
ce.Write(fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Sync calls the underlying Core's Sync method, flushing any buffered log
|
||||
// entries. Applications should take care to call Sync before exiting.
|
||||
func (log *Logger) Sync() error {
|
||||
return log.core.Sync()
|
||||
}
|
||||
|
||||
// Core returns the Logger's underlying zapcore.Core.
|
||||
func (log *Logger) Core() zapcore.Core {
|
||||
return log.core
|
||||
}
|
||||
|
||||
func (log *Logger) clone() *Logger {
|
||||
copy := *log
|
||||
return ©
|
||||
}
|
||||
|
||||
func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
|
||||
// check must always be called directly by a method in the Logger interface
|
||||
// (e.g., Check, Info, Fatal).
|
||||
const callerSkipOffset = 2
|
||||
|
||||
// Create basic checked entry thru the core; this will be non-nil if the
|
||||
// log message will actually be written somewhere.
|
||||
ent := zapcore.Entry{
|
||||
LoggerName: log.name,
|
||||
Time: time.Now(),
|
||||
Level: lvl,
|
||||
Message: msg,
|
||||
}
|
||||
ce := log.core.Check(ent, nil)
|
||||
willWrite := ce != nil
|
||||
|
||||
// Set up any required terminal behavior.
|
||||
switch ent.Level {
|
||||
case zapcore.PanicLevel:
|
||||
ce = ce.Should(ent, zapcore.WriteThenPanic)
|
||||
case zapcore.FatalLevel:
|
||||
ce = ce.Should(ent, zapcore.WriteThenFatal)
|
||||
case zapcore.DPanicLevel:
|
||||
if log.development {
|
||||
ce = ce.Should(ent, zapcore.WriteThenPanic)
|
||||
}
|
||||
}
|
||||
|
||||
// Only do further annotation if we're going to write this message; checked
|
||||
// entries that exist only for terminal behavior don't benefit from
|
||||
// annotation.
|
||||
if !willWrite {
|
||||
return ce
|
||||
}
|
||||
|
||||
// Thread the error output through to the CheckedEntry.
|
||||
ce.ErrorOutput = log.errorOutput
|
||||
if log.addCaller {
|
||||
ce.Entry.Caller = zapcore.NewEntryCaller(runtime.Caller(log.callerSkip + callerSkipOffset))
|
||||
if !ce.Entry.Caller.Defined {
|
||||
fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC())
|
||||
log.errorOutput.Sync()
|
||||
}
|
||||
}
|
||||
if log.addStack.Enabled(ce.Entry.Level) {
|
||||
ce.Entry.Stack = Stack("").String
|
||||
}
|
||||
|
||||
return ce
|
||||
}
|
109
vendor/go.uber.org/zap/options.go
generated
vendored
Normal file
109
vendor/go.uber.org/zap/options.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import "go.uber.org/zap/zapcore"
|
||||
|
||||
// An Option configures a Logger.
|
||||
type Option interface {
|
||||
apply(*Logger)
|
||||
}
|
||||
|
||||
// optionFunc wraps a func so it satisfies the Option interface.
|
||||
type optionFunc func(*Logger)
|
||||
|
||||
func (f optionFunc) apply(log *Logger) {
|
||||
f(log)
|
||||
}
|
||||
|
||||
// WrapCore wraps or replaces the Logger's underlying zapcore.Core.
|
||||
func WrapCore(f func(zapcore.Core) zapcore.Core) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.core = f(log.core)
|
||||
})
|
||||
}
|
||||
|
||||
// Hooks registers functions which will be called each time the Logger writes
|
||||
// out an Entry. Repeated use of Hooks is additive.
|
||||
//
|
||||
// Hooks are useful for simple side effects, like capturing metrics for the
|
||||
// number of emitted logs. More complex side effects, including anything that
|
||||
// requires access to the Entry's structured fields, should be implemented as
|
||||
// a zapcore.Core instead. See zapcore.RegisterHooks for details.
|
||||
func Hooks(hooks ...func(zapcore.Entry) error) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.core = zapcore.RegisterHooks(log.core, hooks...)
|
||||
})
|
||||
}
|
||||
|
||||
// Fields adds fields to the Logger.
|
||||
func Fields(fs ...Field) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.core = log.core.With(fs)
|
||||
})
|
||||
}
|
||||
|
||||
// ErrorOutput sets the destination for errors generated by the Logger. Note
|
||||
// that this option only affects internal errors; for sample code that sends
|
||||
// error-level logs to a different location from info- and debug-level logs,
|
||||
// see the package-level AdvancedConfiguration example.
|
||||
//
|
||||
// The supplied WriteSyncer must be safe for concurrent use. The Open and
|
||||
// zapcore.Lock functions are the simplest ways to protect files with a mutex.
|
||||
func ErrorOutput(w zapcore.WriteSyncer) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.errorOutput = w
|
||||
})
|
||||
}
|
||||
|
||||
// Development puts the logger in development mode, which makes DPanic-level
|
||||
// logs panic instead of simply logging an error.
|
||||
func Development() Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.development = true
|
||||
})
|
||||
}
|
||||
|
||||
// AddCaller configures the Logger to annotate each message with the filename
|
||||
// and line number of zap's caller.
|
||||
func AddCaller() Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.addCaller = true
|
||||
})
|
||||
}
|
||||
|
||||
// AddCallerSkip increases the number of callers skipped by caller annotation
|
||||
// (as enabled by the AddCaller option). When building wrappers around the
|
||||
// Logger and SugaredLogger, supplying this Option prevents zap from always
|
||||
// reporting the wrapper code as the caller.
|
||||
func AddCallerSkip(skip int) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.callerSkip += skip
|
||||
})
|
||||
}
|
||||
|
||||
// AddStacktrace configures the Logger to record a stack trace for all messages at
|
||||
// or above a given level.
|
||||
func AddStacktrace(lvl zapcore.LevelEnabler) Option {
|
||||
return optionFunc(func(log *Logger) {
|
||||
log.addStack = lvl
|
||||
})
|
||||
}
|
161
vendor/go.uber.org/zap/sink.go
generated
vendored
Normal file
161
vendor/go.uber.org/zap/sink.go
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
const schemeFile = "file"
|
||||
|
||||
var (
|
||||
_sinkMutex sync.RWMutex
|
||||
_sinkFactories map[string]func(*url.URL) (Sink, error) // keyed by scheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
resetSinkRegistry()
|
||||
}
|
||||
|
||||
func resetSinkRegistry() {
|
||||
_sinkMutex.Lock()
|
||||
defer _sinkMutex.Unlock()
|
||||
|
||||
_sinkFactories = map[string]func(*url.URL) (Sink, error){
|
||||
schemeFile: newFileSink,
|
||||
}
|
||||
}
|
||||
|
||||
// Sink defines the interface to write to and close logger destinations.
|
||||
type Sink interface {
|
||||
zapcore.WriteSyncer
|
||||
io.Closer
|
||||
}
|
||||
|
||||
type nopCloserSink struct{ zapcore.WriteSyncer }
|
||||
|
||||
func (nopCloserSink) Close() error { return nil }
|
||||
|
||||
type errSinkNotFound struct {
|
||||
scheme string
|
||||
}
|
||||
|
||||
func (e *errSinkNotFound) Error() string {
|
||||
return fmt.Sprintf("no sink found for scheme %q", e.scheme)
|
||||
}
|
||||
|
||||
// RegisterSink registers a user-supplied factory for all sinks with a
|
||||
// particular scheme.
|
||||
//
|
||||
// All schemes must be ASCII, valid under section 3.1 of RFC 3986
|
||||
// (https://tools.ietf.org/html/rfc3986#section-3.1), and must not already
|
||||
// have a factory registered. Zap automatically registers a factory for the
|
||||
// "file" scheme.
|
||||
func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error {
|
||||
_sinkMutex.Lock()
|
||||
defer _sinkMutex.Unlock()
|
||||
|
||||
if scheme == "" {
|
||||
return errors.New("can't register a sink factory for empty string")
|
||||
}
|
||||
normalized, err := normalizeScheme(scheme)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%q is not a valid scheme: %v", scheme, err)
|
||||
}
|
||||
if _, ok := _sinkFactories[normalized]; ok {
|
||||
return fmt.Errorf("sink factory already registered for scheme %q", normalized)
|
||||
}
|
||||
_sinkFactories[normalized] = factory
|
||||
return nil
|
||||
}
|
||||
|
||||
func newSink(rawURL string) (Sink, error) {
|
||||
u, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't parse %q as a URL: %v", rawURL, err)
|
||||
}
|
||||
if u.Scheme == "" {
|
||||
u.Scheme = schemeFile
|
||||
}
|
||||
|
||||
_sinkMutex.RLock()
|
||||
factory, ok := _sinkFactories[u.Scheme]
|
||||
_sinkMutex.RUnlock()
|
||||
if !ok {
|
||||
return nil, &errSinkNotFound{u.Scheme}
|
||||
}
|
||||
return factory(u)
|
||||
}
|
||||
|
||||
func newFileSink(u *url.URL) (Sink, error) {
|
||||
if u.User != nil {
|
||||
return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u)
|
||||
}
|
||||
if u.Fragment != "" {
|
||||
return nil, fmt.Errorf("fragments not allowed with file URLs: got %v", u)
|
||||
}
|
||||
if u.RawQuery != "" {
|
||||
return nil, fmt.Errorf("query parameters not allowed with file URLs: got %v", u)
|
||||
}
|
||||
// Error messages are better if we check hostname and port separately.
|
||||
if u.Port() != "" {
|
||||
return nil, fmt.Errorf("ports not allowed with file URLs: got %v", u)
|
||||
}
|
||||
if hn := u.Hostname(); hn != "" && hn != "localhost" {
|
||||
return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u)
|
||||
}
|
||||
switch u.Path {
|
||||
case "stdout":
|
||||
return nopCloserSink{os.Stdout}, nil
|
||||
case "stderr":
|
||||
return nopCloserSink{os.Stderr}, nil
|
||||
}
|
||||
return os.OpenFile(u.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||
}
|
||||
|
||||
func normalizeScheme(s string) (string, error) {
|
||||
// https://tools.ietf.org/html/rfc3986#section-3.1
|
||||
s = strings.ToLower(s)
|
||||
if first := s[0]; 'a' > first || 'z' < first {
|
||||
return "", errors.New("must start with a letter")
|
||||
}
|
||||
for i := 1; i < len(s); i++ { // iterate over bytes, not runes
|
||||
c := s[i]
|
||||
switch {
|
||||
case 'a' <= c && c <= 'z':
|
||||
continue
|
||||
case '0' <= c && c <= '9':
|
||||
continue
|
||||
case c == '.' || c == '+' || c == '-':
|
||||
continue
|
||||
}
|
||||
return "", fmt.Errorf("may not contain %q", c)
|
||||
}
|
||||
return s, nil
|
||||
}
|
126
vendor/go.uber.org/zap/stacktrace.go
generated
vendored
Normal file
126
vendor/go.uber.org/zap/stacktrace.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap/internal/bufferpool"
|
||||
)
|
||||
|
||||
const _zapPackage = "go.uber.org/zap"
|
||||
|
||||
var (
|
||||
_stacktracePool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return newProgramCounters(64)
|
||||
},
|
||||
}
|
||||
|
||||
// We add "." and "/" suffixes to the package name to ensure we only match
|
||||
// the exact package and not any package with the same prefix.
|
||||
_zapStacktracePrefixes = addPrefix(_zapPackage, ".", "/")
|
||||
_zapStacktraceVendorContains = addPrefix("/vendor/", _zapStacktracePrefixes...)
|
||||
)
|
||||
|
||||
func takeStacktrace() string {
|
||||
buffer := bufferpool.Get()
|
||||
defer buffer.Free()
|
||||
programCounters := _stacktracePool.Get().(*programCounters)
|
||||
defer _stacktracePool.Put(programCounters)
|
||||
|
||||
var numFrames int
|
||||
for {
|
||||
// Skip the call to runtime.Counters and takeStacktrace so that the
|
||||
// program counters start at the caller of takeStacktrace.
|
||||
numFrames = runtime.Callers(2, programCounters.pcs)
|
||||
if numFrames < len(programCounters.pcs) {
|
||||
break
|
||||
}
|
||||
// Don't put the too-short counter slice back into the pool; this lets
|
||||
// the pool adjust if we consistently take deep stacktraces.
|
||||
programCounters = newProgramCounters(len(programCounters.pcs) * 2)
|
||||
}
|
||||
|
||||
i := 0
|
||||
skipZapFrames := true // skip all consecutive zap frames at the beginning.
|
||||
frames := runtime.CallersFrames(programCounters.pcs[:numFrames])
|
||||
|
||||
// Note: On the last iteration, frames.Next() returns false, with a valid
|
||||
// frame, but we ignore this frame. The last frame is a a runtime frame which
|
||||
// adds noise, since it's only either runtime.main or runtime.goexit.
|
||||
for frame, more := frames.Next(); more; frame, more = frames.Next() {
|
||||
if skipZapFrames && isZapFrame(frame.Function) {
|
||||
continue
|
||||
} else {
|
||||
skipZapFrames = false
|
||||
}
|
||||
|
||||
if i != 0 {
|
||||
buffer.AppendByte('\n')
|
||||
}
|
||||
i++
|
||||
buffer.AppendString(frame.Function)
|
||||
buffer.AppendByte('\n')
|
||||
buffer.AppendByte('\t')
|
||||
buffer.AppendString(frame.File)
|
||||
buffer.AppendByte(':')
|
||||
buffer.AppendInt(int64(frame.Line))
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func isZapFrame(function string) bool {
|
||||
for _, prefix := range _zapStacktracePrefixes {
|
||||
if strings.HasPrefix(function, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// We can't use a prefix match here since the location of the vendor
|
||||
// directory affects the prefix. Instead we do a contains match.
|
||||
for _, contains := range _zapStacktraceVendorContains {
|
||||
if strings.Contains(function, contains) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type programCounters struct {
|
||||
pcs []uintptr
|
||||
}
|
||||
|
||||
func newProgramCounters(size int) *programCounters {
|
||||
return &programCounters{make([]uintptr, size)}
|
||||
}
|
||||
|
||||
func addPrefix(prefix string, ss ...string) []string {
|
||||
withPrefix := make([]string, len(ss))
|
||||
for i, s := range ss {
|
||||
withPrefix[i] = prefix + s
|
||||
}
|
||||
return withPrefix
|
||||
}
|
304
vendor/go.uber.org/zap/sugar.go
generated
vendored
Normal file
304
vendor/go.uber.org/zap/sugar.go
generated
vendored
Normal file
@ -0,0 +1,304 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"go.uber.org/multierr"
|
||||
)
|
||||
|
||||
const (
|
||||
_oddNumberErrMsg = "Ignored key without a value."
|
||||
_nonStringKeyErrMsg = "Ignored key-value pairs with non-string keys."
|
||||
)
|
||||
|
||||
// A SugaredLogger wraps the base Logger functionality in a slower, but less
|
||||
// verbose, API. Any Logger can be converted to a SugaredLogger with its Sugar
|
||||
// method.
|
||||
//
|
||||
// Unlike the Logger, the SugaredLogger doesn't insist on structured logging.
|
||||
// For each log level, it exposes three methods: one for loosely-typed
|
||||
// structured logging, one for println-style formatting, and one for
|
||||
// printf-style formatting. For example, SugaredLoggers can produce InfoLevel
|
||||
// output with Infow ("info with" structured context), Info, or Infof.
|
||||
type SugaredLogger struct {
|
||||
base *Logger
|
||||
}
|
||||
|
||||
// Desugar unwraps a SugaredLogger, exposing the original Logger. Desugaring
|
||||
// is quite inexpensive, so it's reasonable for a single application to use
|
||||
// both Loggers and SugaredLoggers, converting between them on the boundaries
|
||||
// of performance-sensitive code.
|
||||
func (s *SugaredLogger) Desugar() *Logger {
|
||||
base := s.base.clone()
|
||||
base.callerSkip -= 2
|
||||
return base
|
||||
}
|
||||
|
||||
// Named adds a sub-scope to the logger's name. See Logger.Named for details.
|
||||
func (s *SugaredLogger) Named(name string) *SugaredLogger {
|
||||
return &SugaredLogger{base: s.base.Named(name)}
|
||||
}
|
||||
|
||||
// With adds a variadic number of fields to the logging context. It accepts a
|
||||
// mix of strongly-typed Field objects and loosely-typed key-value pairs. When
|
||||
// processing pairs, the first element of the pair is used as the field key
|
||||
// and the second as the field value.
|
||||
//
|
||||
// For example,
|
||||
// sugaredLogger.With(
|
||||
// "hello", "world",
|
||||
// "failure", errors.New("oh no"),
|
||||
// Stack(),
|
||||
// "count", 42,
|
||||
// "user", User{Name: "alice"},
|
||||
// )
|
||||
// is the equivalent of
|
||||
// unsugared.With(
|
||||
// String("hello", "world"),
|
||||
// String("failure", "oh no"),
|
||||
// Stack(),
|
||||
// Int("count", 42),
|
||||
// Object("user", User{Name: "alice"}),
|
||||
// )
|
||||
//
|
||||
// Note that the keys in key-value pairs should be strings. In development,
|
||||
// passing a non-string key panics. In production, the logger is more
|
||||
// forgiving: a separate error is logged, but the key-value pair is skipped
|
||||
// and execution continues. Passing an orphaned key triggers similar behavior:
|
||||
// panics in development and errors in production.
|
||||
func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger {
|
||||
return &SugaredLogger{base: s.base.With(s.sweetenFields(args)...)}
|
||||
}
|
||||
|
||||
// Debug uses fmt.Sprint to construct and log a message.
|
||||
func (s *SugaredLogger) Debug(args ...interface{}) {
|
||||
s.log(DebugLevel, "", args, nil)
|
||||
}
|
||||
|
||||
// Info uses fmt.Sprint to construct and log a message.
|
||||
func (s *SugaredLogger) Info(args ...interface{}) {
|
||||
s.log(InfoLevel, "", args, nil)
|
||||
}
|
||||
|
||||
// Warn uses fmt.Sprint to construct and log a message.
|
||||
func (s *SugaredLogger) Warn(args ...interface{}) {
|
||||
s.log(WarnLevel, "", args, nil)
|
||||
}
|
||||
|
||||
// Error uses fmt.Sprint to construct and log a message.
|
||||
func (s *SugaredLogger) Error(args ...interface{}) {
|
||||
s.log(ErrorLevel, "", args, nil)
|
||||
}
|
||||
|
||||
// DPanic uses fmt.Sprint to construct and log a message. In development, the
|
||||
// logger then panics. (See DPanicLevel for details.)
|
||||
func (s *SugaredLogger) DPanic(args ...interface{}) {
|
||||
s.log(DPanicLevel, "", args, nil)
|
||||
}
|
||||
|
||||
// Panic uses fmt.Sprint to construct and log a message, then panics.
|
||||
func (s *SugaredLogger) Panic(args ...interface{}) {
|
||||
s.log(PanicLevel, "", args, nil)
|
||||
}
|
||||
|
||||
// Fatal uses fmt.Sprint to construct and log a message, then calls os.Exit.
|
||||
func (s *SugaredLogger) Fatal(args ...interface{}) {
|
||||
s.log(FatalLevel, "", args, nil)
|
||||
}
|
||||
|
||||
// Debugf uses fmt.Sprintf to log a templated message.
|
||||
func (s *SugaredLogger) Debugf(template string, args ...interface{}) {
|
||||
s.log(DebugLevel, template, args, nil)
|
||||
}
|
||||
|
||||
// Infof uses fmt.Sprintf to log a templated message.
|
||||
func (s *SugaredLogger) Infof(template string, args ...interface{}) {
|
||||
s.log(InfoLevel, template, args, nil)
|
||||
}
|
||||
|
||||
// Warnf uses fmt.Sprintf to log a templated message.
|
||||
func (s *SugaredLogger) Warnf(template string, args ...interface{}) {
|
||||
s.log(WarnLevel, template, args, nil)
|
||||
}
|
||||
|
||||
// Errorf uses fmt.Sprintf to log a templated message.
|
||||
func (s *SugaredLogger) Errorf(template string, args ...interface{}) {
|
||||
s.log(ErrorLevel, template, args, nil)
|
||||
}
|
||||
|
||||
// DPanicf uses fmt.Sprintf to log a templated message. In development, the
|
||||
// logger then panics. (See DPanicLevel for details.)
|
||||
func (s *SugaredLogger) DPanicf(template string, args ...interface{}) {
|
||||
s.log(DPanicLevel, template, args, nil)
|
||||
}
|
||||
|
||||
// Panicf uses fmt.Sprintf to log a templated message, then panics.
|
||||
func (s *SugaredLogger) Panicf(template string, args ...interface{}) {
|
||||
s.log(PanicLevel, template, args, nil)
|
||||
}
|
||||
|
||||
// Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit.
|
||||
func (s *SugaredLogger) Fatalf(template string, args ...interface{}) {
|
||||
s.log(FatalLevel, template, args, nil)
|
||||
}
|
||||
|
||||
// Debugw logs a message with some additional context. The variadic key-value
|
||||
// pairs are treated as they are in With.
|
||||
//
|
||||
// When debug-level logging is disabled, this is much faster than
|
||||
// s.With(keysAndValues).Debug(msg)
|
||||
func (s *SugaredLogger) Debugw(msg string, keysAndValues ...interface{}) {
|
||||
s.log(DebugLevel, msg, nil, keysAndValues)
|
||||
}
|
||||
|
||||
// Infow logs a message with some additional context. The variadic key-value
|
||||
// pairs are treated as they are in With.
|
||||
func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{}) {
|
||||
s.log(InfoLevel, msg, nil, keysAndValues)
|
||||
}
|
||||
|
||||
// Warnw logs a message with some additional context. The variadic key-value
|
||||
// pairs are treated as they are in With.
|
||||
func (s *SugaredLogger) Warnw(msg string, keysAndValues ...interface{}) {
|
||||
s.log(WarnLevel, msg, nil, keysAndValues)
|
||||
}
|
||||
|
||||
// Errorw logs a message with some additional context. The variadic key-value
|
||||
// pairs are treated as they are in With.
|
||||
func (s *SugaredLogger) Errorw(msg string, keysAndValues ...interface{}) {
|
||||
s.log(ErrorLevel, msg, nil, keysAndValues)
|
||||
}
|
||||
|
||||
// DPanicw logs a message with some additional context. In development, the
|
||||
// logger then panics. (See DPanicLevel for details.) The variadic key-value
|
||||
// pairs are treated as they are in With.
|
||||
func (s *SugaredLogger) DPanicw(msg string, keysAndValues ...interface{}) {
|
||||
s.log(DPanicLevel, msg, nil, keysAndValues)
|
||||
}
|
||||
|
||||
// Panicw logs a message with some additional context, then panics. The
|
||||
// variadic key-value pairs are treated as they are in With.
|
||||
func (s *SugaredLogger) Panicw(msg string, keysAndValues ...interface{}) {
|
||||
s.log(PanicLevel, msg, nil, keysAndValues)
|
||||
}
|
||||
|
||||
// Fatalw logs a message with some additional context, then calls os.Exit. The
|
||||
// variadic key-value pairs are treated as they are in With.
|
||||
func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{}) {
|
||||
s.log(FatalLevel, msg, nil, keysAndValues)
|
||||
}
|
||||
|
||||
// Sync flushes any buffered log entries.
|
||||
func (s *SugaredLogger) Sync() error {
|
||||
return s.base.Sync()
|
||||
}
|
||||
|
||||
func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interface{}, context []interface{}) {
|
||||
// If logging at this level is completely disabled, skip the overhead of
|
||||
// string formatting.
|
||||
if lvl < DPanicLevel && !s.base.Core().Enabled(lvl) {
|
||||
return
|
||||
}
|
||||
|
||||
// Format with Sprint, Sprintf, or neither.
|
||||
msg := template
|
||||
if msg == "" && len(fmtArgs) > 0 {
|
||||
msg = fmt.Sprint(fmtArgs...)
|
||||
} else if msg != "" && len(fmtArgs) > 0 {
|
||||
msg = fmt.Sprintf(template, fmtArgs...)
|
||||
}
|
||||
|
||||
if ce := s.base.Check(lvl, msg); ce != nil {
|
||||
ce.Write(s.sweetenFields(context)...)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Allocate enough space for the worst case; if users pass only structured
|
||||
// fields, we shouldn't penalize them with extra allocations.
|
||||
fields := make([]Field, 0, len(args))
|
||||
var invalid invalidPairs
|
||||
|
||||
for i := 0; i < len(args); {
|
||||
// This is a strongly-typed field. Consume it and move on.
|
||||
if f, ok := args[i].(Field); ok {
|
||||
fields = append(fields, f)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// Make sure this element isn't a dangling key.
|
||||
if i == len(args)-1 {
|
||||
s.base.DPanic(_oddNumberErrMsg, Any("ignored", args[i]))
|
||||
break
|
||||
}
|
||||
|
||||
// Consume this value and the next, treating them as a key-value pair. If the
|
||||
// key isn't a string, add this pair to the slice of invalid pairs.
|
||||
key, val := args[i], args[i+1]
|
||||
if keyStr, ok := key.(string); !ok {
|
||||
// Subsequent errors are likely, so allocate once up front.
|
||||
if cap(invalid) == 0 {
|
||||
invalid = make(invalidPairs, 0, len(args)/2)
|
||||
}
|
||||
invalid = append(invalid, invalidPair{i, key, val})
|
||||
} else {
|
||||
fields = append(fields, Any(keyStr, val))
|
||||
}
|
||||
i += 2
|
||||
}
|
||||
|
||||
// If we encountered any invalid key-value pairs, log an error.
|
||||
if len(invalid) > 0 {
|
||||
s.base.DPanic(_nonStringKeyErrMsg, Array("invalid", invalid))
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
type invalidPair struct {
|
||||
position int
|
||||
key, value interface{}
|
||||
}
|
||||
|
||||
func (p invalidPair) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
||||
enc.AddInt64("position", int64(p.position))
|
||||
Any("key", p.key).AddTo(enc)
|
||||
Any("value", p.value).AddTo(enc)
|
||||
return nil
|
||||
}
|
||||
|
||||
type invalidPairs []invalidPair
|
||||
|
||||
func (ps invalidPairs) MarshalLogArray(enc zapcore.ArrayEncoder) error {
|
||||
var err error
|
||||
for i := range ps {
|
||||
err = multierr.Append(err, enc.AppendObject(ps[i]))
|
||||
}
|
||||
return err
|
||||
}
|
27
vendor/go.uber.org/zap/time.go
generated
vendored
Normal file
27
vendor/go.uber.org/zap/time.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import "time"
|
||||
|
||||
func timeToMillis(t time.Time) int64 {
|
||||
return t.UnixNano() / int64(time.Millisecond)
|
||||
}
|
28
vendor/go.uber.org/zap/tools.go
generated
vendored
Normal file
28
vendor/go.uber.org/zap/tools.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
// +build tools
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
// Tools we use during development.
|
||||
_ "golang.org/x/lint/golint"
|
||||
)
|
99
vendor/go.uber.org/zap/writer.go
generated
vendored
Normal file
99
vendor/go.uber.org/zap/writer.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"go.uber.org/multierr"
|
||||
)
|
||||
|
||||
// Open is a high-level wrapper that takes a variadic number of URLs, opens or
|
||||
// creates each of the specified resources, and combines them into a locked
|
||||
// WriteSyncer. It also returns any error encountered and a function to close
|
||||
// any opened files.
|
||||
//
|
||||
// Passing no URLs returns a no-op WriteSyncer. Zap handles URLs without a
|
||||
// scheme and URLs with the "file" scheme. Third-party code may register
|
||||
// factories for other schemes using RegisterSink.
|
||||
//
|
||||
// URLs with the "file" scheme must use absolute paths on the local
|
||||
// filesystem. No user, password, port, fragments, or query parameters are
|
||||
// allowed, and the hostname must be empty or "localhost".
|
||||
//
|
||||
// Since it's common to write logs to the local filesystem, URLs without a
|
||||
// scheme (e.g., "/var/log/foo.log") are treated as local file paths. Without
|
||||
// a scheme, the special paths "stdout" and "stderr" are interpreted as
|
||||
// os.Stdout and os.Stderr. When specified without a scheme, relative file
|
||||
// paths also work.
|
||||
func Open(paths ...string) (zapcore.WriteSyncer, func(), error) {
|
||||
writers, close, err := open(paths)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
writer := CombineWriteSyncers(writers...)
|
||||
return writer, close, nil
|
||||
}
|
||||
|
||||
func open(paths []string) ([]zapcore.WriteSyncer, func(), error) {
|
||||
writers := make([]zapcore.WriteSyncer, 0, len(paths))
|
||||
closers := make([]io.Closer, 0, len(paths))
|
||||
close := func() {
|
||||
for _, c := range closers {
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
var openErr error
|
||||
for _, path := range paths {
|
||||
sink, err := newSink(path)
|
||||
if err != nil {
|
||||
openErr = multierr.Append(openErr, fmt.Errorf("couldn't open sink %q: %v", path, err))
|
||||
continue
|
||||
}
|
||||
writers = append(writers, sink)
|
||||
closers = append(closers, sink)
|
||||
}
|
||||
if openErr != nil {
|
||||
close()
|
||||
return writers, nil, openErr
|
||||
}
|
||||
|
||||
return writers, close, nil
|
||||
}
|
||||
|
||||
// CombineWriteSyncers is a utility that combines multiple WriteSyncers into a
|
||||
// single, locked WriteSyncer. If no inputs are supplied, it returns a no-op
|
||||
// WriteSyncer.
|
||||
//
|
||||
// It's provided purely as a convenience; the result is no different from
|
||||
// using zapcore.NewMultiWriteSyncer and zapcore.Lock individually.
|
||||
func CombineWriteSyncers(writers ...zapcore.WriteSyncer) zapcore.WriteSyncer {
|
||||
if len(writers) == 0 {
|
||||
return zapcore.AddSync(ioutil.Discard)
|
||||
}
|
||||
return zapcore.Lock(zapcore.NewMultiWriteSyncer(writers...))
|
||||
}
|
147
vendor/go.uber.org/zap/zapcore/console_encoder.go
generated
vendored
Normal file
147
vendor/go.uber.org/zap/zapcore/console_encoder.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap/buffer"
|
||||
"go.uber.org/zap/internal/bufferpool"
|
||||
)
|
||||
|
||||
var _sliceEncoderPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &sliceArrayEncoder{elems: make([]interface{}, 0, 2)}
|
||||
},
|
||||
}
|
||||
|
||||
func getSliceEncoder() *sliceArrayEncoder {
|
||||
return _sliceEncoderPool.Get().(*sliceArrayEncoder)
|
||||
}
|
||||
|
||||
func putSliceEncoder(e *sliceArrayEncoder) {
|
||||
e.elems = e.elems[:0]
|
||||
_sliceEncoderPool.Put(e)
|
||||
}
|
||||
|
||||
type consoleEncoder struct {
|
||||
*jsonEncoder
|
||||
}
|
||||
|
||||
// NewConsoleEncoder creates an encoder whose output is designed for human -
|
||||
// rather than machine - consumption. It serializes the core log entry data
|
||||
// (message, level, timestamp, etc.) in a plain-text format and leaves the
|
||||
// structured context as JSON.
|
||||
//
|
||||
// Note that although the console encoder doesn't use the keys specified in the
|
||||
// encoder configuration, it will omit any element whose key is set to the empty
|
||||
// string.
|
||||
func NewConsoleEncoder(cfg EncoderConfig) Encoder {
|
||||
return consoleEncoder{newJSONEncoder(cfg, true)}
|
||||
}
|
||||
|
||||
func (c consoleEncoder) Clone() Encoder {
|
||||
return consoleEncoder{c.jsonEncoder.Clone().(*jsonEncoder)}
|
||||
}
|
||||
|
||||
func (c consoleEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) {
|
||||
line := bufferpool.Get()
|
||||
|
||||
// We don't want the entry's metadata to be quoted and escaped (if it's
|
||||
// encoded as strings), which means that we can't use the JSON encoder. The
|
||||
// simplest option is to use the memory encoder and fmt.Fprint.
|
||||
//
|
||||
// If this ever becomes a performance bottleneck, we can implement
|
||||
// ArrayEncoder for our plain-text format.
|
||||
arr := getSliceEncoder()
|
||||
if c.TimeKey != "" && c.EncodeTime != nil {
|
||||
c.EncodeTime(ent.Time, arr)
|
||||
}
|
||||
if c.LevelKey != "" && c.EncodeLevel != nil {
|
||||
c.EncodeLevel(ent.Level, arr)
|
||||
}
|
||||
if ent.LoggerName != "" && c.NameKey != "" {
|
||||
nameEncoder := c.EncodeName
|
||||
|
||||
if nameEncoder == nil {
|
||||
// Fall back to FullNameEncoder for backward compatibility.
|
||||
nameEncoder = FullNameEncoder
|
||||
}
|
||||
|
||||
nameEncoder(ent.LoggerName, arr)
|
||||
}
|
||||
if ent.Caller.Defined && c.CallerKey != "" && c.EncodeCaller != nil {
|
||||
c.EncodeCaller(ent.Caller, arr)
|
||||
}
|
||||
for i := range arr.elems {
|
||||
if i > 0 {
|
||||
line.AppendByte('\t')
|
||||
}
|
||||
fmt.Fprint(line, arr.elems[i])
|
||||
}
|
||||
putSliceEncoder(arr)
|
||||
|
||||
// Add the message itself.
|
||||
if c.MessageKey != "" {
|
||||
c.addTabIfNecessary(line)
|
||||
line.AppendString(ent.Message)
|
||||
}
|
||||
|
||||
// Add any structured context.
|
||||
c.writeContext(line, fields)
|
||||
|
||||
// If there's no stacktrace key, honor that; this allows users to force
|
||||
// single-line output.
|
||||
if ent.Stack != "" && c.StacktraceKey != "" {
|
||||
line.AppendByte('\n')
|
||||
line.AppendString(ent.Stack)
|
||||
}
|
||||
|
||||
if c.LineEnding != "" {
|
||||
line.AppendString(c.LineEnding)
|
||||
} else {
|
||||
line.AppendString(DefaultLineEnding)
|
||||
}
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func (c consoleEncoder) writeContext(line *buffer.Buffer, extra []Field) {
|
||||
context := c.jsonEncoder.Clone().(*jsonEncoder)
|
||||
defer context.buf.Free()
|
||||
|
||||
addFields(context, extra)
|
||||
context.closeOpenNamespaces()
|
||||
if context.buf.Len() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
c.addTabIfNecessary(line)
|
||||
line.AppendByte('{')
|
||||
line.Write(context.buf.Bytes())
|
||||
line.AppendByte('}')
|
||||
}
|
||||
|
||||
func (c consoleEncoder) addTabIfNecessary(line *buffer.Buffer) {
|
||||
if line.Len() > 0 {
|
||||
line.AppendByte('\t')
|
||||
}
|
||||
}
|
113
vendor/go.uber.org/zap/zapcore/core.go
generated
vendored
Normal file
113
vendor/go.uber.org/zap/zapcore/core.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
// Core is a minimal, fast logger interface. It's designed for library authors
|
||||
// to wrap in a more user-friendly API.
|
||||
type Core interface {
|
||||
LevelEnabler
|
||||
|
||||
// With adds structured context to the Core.
|
||||
With([]Field) Core
|
||||
// Check determines whether the supplied Entry should be logged (using the
|
||||
// embedded LevelEnabler and possibly some extra logic). If the entry
|
||||
// should be logged, the Core adds itself to the CheckedEntry and returns
|
||||
// the result.
|
||||
//
|
||||
// Callers must use Check before calling Write.
|
||||
Check(Entry, *CheckedEntry) *CheckedEntry
|
||||
// Write serializes the Entry and any Fields supplied at the log site and
|
||||
// writes them to their destination.
|
||||
//
|
||||
// If called, Write should always log the Entry and Fields; it should not
|
||||
// replicate the logic of Check.
|
||||
Write(Entry, []Field) error
|
||||
// Sync flushes buffered logs (if any).
|
||||
Sync() error
|
||||
}
|
||||
|
||||
type nopCore struct{}
|
||||
|
||||
// NewNopCore returns a no-op Core.
|
||||
func NewNopCore() Core { return nopCore{} }
|
||||
func (nopCore) Enabled(Level) bool { return false }
|
||||
func (n nopCore) With([]Field) Core { return n }
|
||||
func (nopCore) Check(_ Entry, ce *CheckedEntry) *CheckedEntry { return ce }
|
||||
func (nopCore) Write(Entry, []Field) error { return nil }
|
||||
func (nopCore) Sync() error { return nil }
|
||||
|
||||
// NewCore creates a Core that writes logs to a WriteSyncer.
|
||||
func NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core {
|
||||
return &ioCore{
|
||||
LevelEnabler: enab,
|
||||
enc: enc,
|
||||
out: ws,
|
||||
}
|
||||
}
|
||||
|
||||
type ioCore struct {
|
||||
LevelEnabler
|
||||
enc Encoder
|
||||
out WriteSyncer
|
||||
}
|
||||
|
||||
func (c *ioCore) With(fields []Field) Core {
|
||||
clone := c.clone()
|
||||
addFields(clone.enc, fields)
|
||||
return clone
|
||||
}
|
||||
|
||||
func (c *ioCore) Check(ent Entry, ce *CheckedEntry) *CheckedEntry {
|
||||
if c.Enabled(ent.Level) {
|
||||
return ce.AddCore(ent, c)
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
||||
func (c *ioCore) Write(ent Entry, fields []Field) error {
|
||||
buf, err := c.enc.EncodeEntry(ent, fields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.out.Write(buf.Bytes())
|
||||
buf.Free()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ent.Level > ErrorLevel {
|
||||
// Since we may be crashing the program, sync the output. Ignore Sync
|
||||
// errors, pending a clean solution to issue #370.
|
||||
c.Sync()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ioCore) Sync() error {
|
||||
return c.out.Sync()
|
||||
}
|
||||
|
||||
func (c *ioCore) clone() *ioCore {
|
||||
return &ioCore{
|
||||
LevelEnabler: c.LevelEnabler,
|
||||
enc: c.enc.Clone(),
|
||||
out: c.out,
|
||||
}
|
||||
}
|
24
vendor/go.uber.org/zap/zapcore/doc.go
generated
vendored
Normal file
24
vendor/go.uber.org/zap/zapcore/doc.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package zapcore defines and implements the low-level interfaces upon which
|
||||
// zap is built. By providing alternate implementations of these interfaces,
|
||||
// external packages can extend zap's capabilities.
|
||||
package zapcore // import "go.uber.org/zap/zapcore"
|
371
vendor/go.uber.org/zap/zapcore/encoder.go
generated
vendored
Normal file
371
vendor/go.uber.org/zap/zapcore/encoder.go
generated
vendored
Normal file
@ -0,0 +1,371 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap/buffer"
|
||||
)
|
||||
|
||||
// DefaultLineEnding defines the default line ending when writing logs.
|
||||
// Alternate line endings specified in EncoderConfig can override this
|
||||
// behavior.
|
||||
const DefaultLineEnding = "\n"
|
||||
|
||||
// OmitKey defines the key to use when callers want to remove a key from log output.
|
||||
const OmitKey = ""
|
||||
|
||||
// A LevelEncoder serializes a Level to a primitive type.
|
||||
type LevelEncoder func(Level, PrimitiveArrayEncoder)
|
||||
|
||||
// LowercaseLevelEncoder serializes a Level to a lowercase string. For example,
|
||||
// InfoLevel is serialized to "info".
|
||||
func LowercaseLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendString(l.String())
|
||||
}
|
||||
|
||||
// LowercaseColorLevelEncoder serializes a Level to a lowercase string and adds coloring.
|
||||
// For example, InfoLevel is serialized to "info" and colored blue.
|
||||
func LowercaseColorLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
|
||||
s, ok := _levelToLowercaseColorString[l]
|
||||
if !ok {
|
||||
s = _unknownLevelColor.Add(l.String())
|
||||
}
|
||||
enc.AppendString(s)
|
||||
}
|
||||
|
||||
// CapitalLevelEncoder serializes a Level to an all-caps string. For example,
|
||||
// InfoLevel is serialized to "INFO".
|
||||
func CapitalLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendString(l.CapitalString())
|
||||
}
|
||||
|
||||
// CapitalColorLevelEncoder serializes a Level to an all-caps string and adds color.
|
||||
// For example, InfoLevel is serialized to "INFO" and colored blue.
|
||||
func CapitalColorLevelEncoder(l Level, enc PrimitiveArrayEncoder) {
|
||||
s, ok := _levelToCapitalColorString[l]
|
||||
if !ok {
|
||||
s = _unknownLevelColor.Add(l.CapitalString())
|
||||
}
|
||||
enc.AppendString(s)
|
||||
}
|
||||
|
||||
// UnmarshalText unmarshals text to a LevelEncoder. "capital" is unmarshaled to
|
||||
// CapitalLevelEncoder, "coloredCapital" is unmarshaled to CapitalColorLevelEncoder,
|
||||
// "colored" is unmarshaled to LowercaseColorLevelEncoder, and anything else
|
||||
// is unmarshaled to LowercaseLevelEncoder.
|
||||
func (e *LevelEncoder) UnmarshalText(text []byte) error {
|
||||
switch string(text) {
|
||||
case "capital":
|
||||
*e = CapitalLevelEncoder
|
||||
case "capitalColor":
|
||||
*e = CapitalColorLevelEncoder
|
||||
case "color":
|
||||
*e = LowercaseColorLevelEncoder
|
||||
default:
|
||||
*e = LowercaseLevelEncoder
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A TimeEncoder serializes a time.Time to a primitive type.
|
||||
type TimeEncoder func(time.Time, PrimitiveArrayEncoder)
|
||||
|
||||
// EpochTimeEncoder serializes a time.Time to a floating-point number of seconds
|
||||
// since the Unix epoch.
|
||||
func EpochTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||
nanos := t.UnixNano()
|
||||
sec := float64(nanos) / float64(time.Second)
|
||||
enc.AppendFloat64(sec)
|
||||
}
|
||||
|
||||
// EpochMillisTimeEncoder serializes a time.Time to a floating-point number of
|
||||
// milliseconds since the Unix epoch.
|
||||
func EpochMillisTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||
nanos := t.UnixNano()
|
||||
millis := float64(nanos) / float64(time.Millisecond)
|
||||
enc.AppendFloat64(millis)
|
||||
}
|
||||
|
||||
// EpochNanosTimeEncoder serializes a time.Time to an integer number of
|
||||
// nanoseconds since the Unix epoch.
|
||||
func EpochNanosTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendInt64(t.UnixNano())
|
||||
}
|
||||
|
||||
// ISO8601TimeEncoder serializes a time.Time to an ISO8601-formatted string
|
||||
// with millisecond precision.
|
||||
func ISO8601TimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendString(t.Format("2006-01-02T15:04:05.000Z0700"))
|
||||
}
|
||||
|
||||
// RFC3339TimeEncoder serializes a time.Time to an RFC3339-formatted string.
|
||||
func RFC3339TimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendString(t.Format(time.RFC3339))
|
||||
}
|
||||
|
||||
// RFC3339NanoTimeEncoder serializes a time.Time to an RFC3339-formatted string
|
||||
// with nanosecond precision.
|
||||
func RFC3339NanoTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendString(t.Format(time.RFC3339Nano))
|
||||
}
|
||||
|
||||
// UnmarshalText unmarshals text to a TimeEncoder.
|
||||
// "rfc3339nano" and "RFC3339Nano" are unmarshaled to RFC3339NanoTimeEncoder.
|
||||
// "rfc3339" and "RFC3339" are unmarshaled to RFC3339TimeEncoder.
|
||||
// "iso8601" and "ISO8601" are unmarshaled to ISO8601TimeEncoder.
|
||||
// "millis" is unmarshaled to EpochMillisTimeEncoder.
|
||||
// "nanos" is unmarshaled to EpochNanosEncoder.
|
||||
// Anything else is unmarshaled to EpochTimeEncoder.
|
||||
func (e *TimeEncoder) UnmarshalText(text []byte) error {
|
||||
switch string(text) {
|
||||
case "rfc3339nano", "RFC3339Nano":
|
||||
*e = RFC3339NanoTimeEncoder
|
||||
case "rfc3339", "RFC3339":
|
||||
*e = RFC3339TimeEncoder
|
||||
case "iso8601", "ISO8601":
|
||||
*e = ISO8601TimeEncoder
|
||||
case "millis":
|
||||
*e = EpochMillisTimeEncoder
|
||||
case "nanos":
|
||||
*e = EpochNanosTimeEncoder
|
||||
default:
|
||||
*e = EpochTimeEncoder
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A DurationEncoder serializes a time.Duration to a primitive type.
|
||||
type DurationEncoder func(time.Duration, PrimitiveArrayEncoder)
|
||||
|
||||
// SecondsDurationEncoder serializes a time.Duration to a floating-point number of seconds elapsed.
|
||||
func SecondsDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendFloat64(float64(d) / float64(time.Second))
|
||||
}
|
||||
|
||||
// NanosDurationEncoder serializes a time.Duration to an integer number of
|
||||
// nanoseconds elapsed.
|
||||
func NanosDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendInt64(int64(d))
|
||||
}
|
||||
|
||||
// StringDurationEncoder serializes a time.Duration using its built-in String
|
||||
// method.
|
||||
func StringDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendString(d.String())
|
||||
}
|
||||
|
||||
// UnmarshalText unmarshals text to a DurationEncoder. "string" is unmarshaled
|
||||
// to StringDurationEncoder, and anything else is unmarshaled to
|
||||
// NanosDurationEncoder.
|
||||
func (e *DurationEncoder) UnmarshalText(text []byte) error {
|
||||
switch string(text) {
|
||||
case "string":
|
||||
*e = StringDurationEncoder
|
||||
case "nanos":
|
||||
*e = NanosDurationEncoder
|
||||
default:
|
||||
*e = SecondsDurationEncoder
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A CallerEncoder serializes an EntryCaller to a primitive type.
|
||||
type CallerEncoder func(EntryCaller, PrimitiveArrayEncoder)
|
||||
|
||||
// FullCallerEncoder serializes a caller in /full/path/to/package/file:line
|
||||
// format.
|
||||
func FullCallerEncoder(caller EntryCaller, enc PrimitiveArrayEncoder) {
|
||||
// TODO: consider using a byte-oriented API to save an allocation.
|
||||
enc.AppendString(caller.String())
|
||||
}
|
||||
|
||||
// ShortCallerEncoder serializes a caller in package/file:line format, trimming
|
||||
// all but the final directory from the full path.
|
||||
func ShortCallerEncoder(caller EntryCaller, enc PrimitiveArrayEncoder) {
|
||||
// TODO: consider using a byte-oriented API to save an allocation.
|
||||
enc.AppendString(caller.TrimmedPath())
|
||||
}
|
||||
|
||||
// UnmarshalText unmarshals text to a CallerEncoder. "full" is unmarshaled to
|
||||
// FullCallerEncoder and anything else is unmarshaled to ShortCallerEncoder.
|
||||
func (e *CallerEncoder) UnmarshalText(text []byte) error {
|
||||
switch string(text) {
|
||||
case "full":
|
||||
*e = FullCallerEncoder
|
||||
default:
|
||||
*e = ShortCallerEncoder
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A NameEncoder serializes a period-separated logger name to a primitive
|
||||
// type.
|
||||
type NameEncoder func(string, PrimitiveArrayEncoder)
|
||||
|
||||
// FullNameEncoder serializes the logger name as-is.
|
||||
func FullNameEncoder(loggerName string, enc PrimitiveArrayEncoder) {
|
||||
enc.AppendString(loggerName)
|
||||
}
|
||||
|
||||
// UnmarshalText unmarshals text to a NameEncoder. Currently, everything is
|
||||
// unmarshaled to FullNameEncoder.
|
||||
func (e *NameEncoder) UnmarshalText(text []byte) error {
|
||||
switch string(text) {
|
||||
case "full":
|
||||
*e = FullNameEncoder
|
||||
default:
|
||||
*e = FullNameEncoder
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// An EncoderConfig allows users to configure the concrete encoders supplied by
|
||||
// zapcore.
|
||||
type EncoderConfig struct {
|
||||
// Set the keys used for each log entry. If any key is empty, that portion
|
||||
// of the entry is omitted.
|
||||
MessageKey string `json:"messageKey" yaml:"messageKey"`
|
||||
LevelKey string `json:"levelKey" yaml:"levelKey"`
|
||||
TimeKey string `json:"timeKey" yaml:"timeKey"`
|
||||
NameKey string `json:"nameKey" yaml:"nameKey"`
|
||||
CallerKey string `json:"callerKey" yaml:"callerKey"`
|
||||
StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"`
|
||||
LineEnding string `json:"lineEnding" yaml:"lineEnding"`
|
||||
// Configure the primitive representations of common complex types. For
|
||||
// example, some users may want all time.Times serialized as floating-point
|
||||
// seconds since epoch, while others may prefer ISO8601 strings.
|
||||
EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"`
|
||||
EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"`
|
||||
EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
|
||||
EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"`
|
||||
// Unlike the other primitive type encoders, EncodeName is optional. The
|
||||
// zero value falls back to FullNameEncoder.
|
||||
EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
|
||||
}
|
||||
|
||||
// ObjectEncoder is a strongly-typed, encoding-agnostic interface for adding a
|
||||
// map- or struct-like object to the logging context. Like maps, ObjectEncoders
|
||||
// aren't safe for concurrent use (though typical use shouldn't require locks).
|
||||
type ObjectEncoder interface {
|
||||
// Logging-specific marshalers.
|
||||
AddArray(key string, marshaler ArrayMarshaler) error
|
||||
AddObject(key string, marshaler ObjectMarshaler) error
|
||||
|
||||
// Built-in types.
|
||||
AddBinary(key string, value []byte) // for arbitrary bytes
|
||||
AddByteString(key string, value []byte) // for UTF-8 encoded bytes
|
||||
AddBool(key string, value bool)
|
||||
AddComplex128(key string, value complex128)
|
||||
AddComplex64(key string, value complex64)
|
||||
AddDuration(key string, value time.Duration)
|
||||
AddFloat64(key string, value float64)
|
||||
AddFloat32(key string, value float32)
|
||||
AddInt(key string, value int)
|
||||
AddInt64(key string, value int64)
|
||||
AddInt32(key string, value int32)
|
||||
AddInt16(key string, value int16)
|
||||
AddInt8(key string, value int8)
|
||||
AddString(key, value string)
|
||||
AddTime(key string, value time.Time)
|
||||
AddUint(key string, value uint)
|
||||
AddUint64(key string, value uint64)
|
||||
AddUint32(key string, value uint32)
|
||||
AddUint16(key string, value uint16)
|
||||
AddUint8(key string, value uint8)
|
||||
AddUintptr(key string, value uintptr)
|
||||
|
||||
// AddReflected uses reflection to serialize arbitrary objects, so it can be
|
||||
// slow and allocation-heavy.
|
||||
AddReflected(key string, value interface{}) error
|
||||
// OpenNamespace opens an isolated namespace where all subsequent fields will
|
||||
// be added. Applications can use namespaces to prevent key collisions when
|
||||
// injecting loggers into sub-components or third-party libraries.
|
||||
OpenNamespace(key string)
|
||||
}
|
||||
|
||||
// ArrayEncoder is a strongly-typed, encoding-agnostic interface for adding
|
||||
// array-like objects to the logging context. Of note, it supports mixed-type
|
||||
// arrays even though they aren't typical in Go. Like slices, ArrayEncoders
|
||||
// aren't safe for concurrent use (though typical use shouldn't require locks).
|
||||
type ArrayEncoder interface {
|
||||
// Built-in types.
|
||||
PrimitiveArrayEncoder
|
||||
|
||||
// Time-related types.
|
||||
AppendDuration(time.Duration)
|
||||
AppendTime(time.Time)
|
||||
|
||||
// Logging-specific marshalers.
|
||||
AppendArray(ArrayMarshaler) error
|
||||
AppendObject(ObjectMarshaler) error
|
||||
|
||||
// AppendReflected uses reflection to serialize arbitrary objects, so it's
|
||||
// slow and allocation-heavy.
|
||||
AppendReflected(value interface{}) error
|
||||
}
|
||||
|
||||
// PrimitiveArrayEncoder is the subset of the ArrayEncoder interface that deals
|
||||
// only in Go's built-in types. It's included only so that Duration- and
|
||||
// TimeEncoders cannot trigger infinite recursion.
|
||||
type PrimitiveArrayEncoder interface {
|
||||
// Built-in types.
|
||||
AppendBool(bool)
|
||||
AppendByteString([]byte) // for UTF-8 encoded bytes
|
||||
AppendComplex128(complex128)
|
||||
AppendComplex64(complex64)
|
||||
AppendFloat64(float64)
|
||||
AppendFloat32(float32)
|
||||
AppendInt(int)
|
||||
AppendInt64(int64)
|
||||
AppendInt32(int32)
|
||||
AppendInt16(int16)
|
||||
AppendInt8(int8)
|
||||
AppendString(string)
|
||||
AppendUint(uint)
|
||||
AppendUint64(uint64)
|
||||
AppendUint32(uint32)
|
||||
AppendUint16(uint16)
|
||||
AppendUint8(uint8)
|
||||
AppendUintptr(uintptr)
|
||||
}
|
||||
|
||||
// Encoder is a format-agnostic interface for all log entry marshalers. Since
|
||||
// log encoders don't need to support the same wide range of use cases as
|
||||
// general-purpose marshalers, it's possible to make them faster and
|
||||
// lower-allocation.
|
||||
//
|
||||
// Implementations of the ObjectEncoder interface's methods can, of course,
|
||||
// freely modify the receiver. However, the Clone and EncodeEntry methods will
|
||||
// be called concurrently and shouldn't modify the receiver.
|
||||
type Encoder interface {
|
||||
ObjectEncoder
|
||||
|
||||
// Clone copies the encoder, ensuring that adding fields to the copy doesn't
|
||||
// affect the original.
|
||||
Clone() Encoder
|
||||
|
||||
// EncodeEntry encodes an entry and fields, along with any accumulated
|
||||
// context, into a byte buffer and returns it. Any fields that are empty,
|
||||
// including fields on the `Entry` type, should be omitted.
|
||||
EncodeEntry(Entry, []Field) (*buffer.Buffer, error)
|
||||
}
|
258
vendor/go.uber.org/zap/zapcore/entry.go
generated
vendored
Normal file
258
vendor/go.uber.org/zap/zapcore/entry.go
generated
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap/internal/bufferpool"
|
||||
"go.uber.org/zap/internal/exit"
|
||||
|
||||
"go.uber.org/multierr"
|
||||
)
|
||||
|
||||
var (
|
||||
_cePool = sync.Pool{New: func() interface{} {
|
||||
// Pre-allocate some space for cores.
|
||||
return &CheckedEntry{
|
||||
cores: make([]Core, 4),
|
||||
}
|
||||
}}
|
||||
)
|
||||
|
||||
func getCheckedEntry() *CheckedEntry {
|
||||
ce := _cePool.Get().(*CheckedEntry)
|
||||
ce.reset()
|
||||
return ce
|
||||
}
|
||||
|
||||
func putCheckedEntry(ce *CheckedEntry) {
|
||||
if ce == nil {
|
||||
return
|
||||
}
|
||||
_cePool.Put(ce)
|
||||
}
|
||||
|
||||
// NewEntryCaller makes an EntryCaller from the return signature of
|
||||
// runtime.Caller.
|
||||
func NewEntryCaller(pc uintptr, file string, line int, ok bool) EntryCaller {
|
||||
if !ok {
|
||||
return EntryCaller{}
|
||||
}
|
||||
return EntryCaller{
|
||||
PC: pc,
|
||||
File: file,
|
||||
Line: line,
|
||||
Defined: true,
|
||||
}
|
||||
}
|
||||
|
||||
// EntryCaller represents the caller of a logging function.
|
||||
type EntryCaller struct {
|
||||
Defined bool
|
||||
PC uintptr
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
|
||||
// String returns the full path and line number of the caller.
|
||||
func (ec EntryCaller) String() string {
|
||||
return ec.FullPath()
|
||||
}
|
||||
|
||||
// FullPath returns a /full/path/to/package/file:line description of the
|
||||
// caller.
|
||||
func (ec EntryCaller) FullPath() string {
|
||||
if !ec.Defined {
|
||||
return "undefined"
|
||||
}
|
||||
buf := bufferpool.Get()
|
||||
buf.AppendString(ec.File)
|
||||
buf.AppendByte(':')
|
||||
buf.AppendInt(int64(ec.Line))
|
||||
caller := buf.String()
|
||||
buf.Free()
|
||||
return caller
|
||||
}
|
||||
|
||||
// TrimmedPath returns a package/file:line description of the caller,
|
||||
// preserving only the leaf directory name and file name.
|
||||
func (ec EntryCaller) TrimmedPath() string {
|
||||
if !ec.Defined {
|
||||
return "undefined"
|
||||
}
|
||||
// nb. To make sure we trim the path correctly on Windows too, we
|
||||
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
|
||||
// because the path given originates from Go stdlib, specifically
|
||||
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
|
||||
// Windows.
|
||||
//
|
||||
// See https://github.com/golang/go/issues/3335
|
||||
// and https://github.com/golang/go/issues/18151
|
||||
//
|
||||
// for discussion on the issue on Go side.
|
||||
//
|
||||
// Find the last separator.
|
||||
//
|
||||
idx := strings.LastIndexByte(ec.File, '/')
|
||||
if idx == -1 {
|
||||
return ec.FullPath()
|
||||
}
|
||||
// Find the penultimate separator.
|
||||
idx = strings.LastIndexByte(ec.File[:idx], '/')
|
||||
if idx == -1 {
|
||||
return ec.FullPath()
|
||||
}
|
||||
buf := bufferpool.Get()
|
||||
// Keep everything after the penultimate separator.
|
||||
buf.AppendString(ec.File[idx+1:])
|
||||
buf.AppendByte(':')
|
||||
buf.AppendInt(int64(ec.Line))
|
||||
caller := buf.String()
|
||||
buf.Free()
|
||||
return caller
|
||||
}
|
||||
|
||||
// An Entry represents a complete log message. The entry's structured context
|
||||
// is already serialized, but the log level, time, message, and call site
|
||||
// information are available for inspection and modification. Any fields left
|
||||
// empty will be omitted when encoding.
|
||||
//
|
||||
// Entries are pooled, so any functions that accept them MUST be careful not to
|
||||
// retain references to them.
|
||||
type Entry struct {
|
||||
Level Level
|
||||
Time time.Time
|
||||
LoggerName string
|
||||
Message string
|
||||
Caller EntryCaller
|
||||
Stack string
|
||||
}
|
||||
|
||||
// CheckWriteAction indicates what action to take after a log entry is
|
||||
// processed. Actions are ordered in increasing severity.
|
||||
type CheckWriteAction uint8
|
||||
|
||||
const (
|
||||
// WriteThenNoop indicates that nothing special needs to be done. It's the
|
||||
// default behavior.
|
||||
WriteThenNoop CheckWriteAction = iota
|
||||
// WriteThenPanic causes a panic after Write.
|
||||
WriteThenPanic
|
||||
// WriteThenFatal causes a fatal os.Exit after Write.
|
||||
WriteThenFatal
|
||||
)
|
||||
|
||||
// CheckedEntry is an Entry together with a collection of Cores that have
|
||||
// already agreed to log it.
|
||||
//
|
||||
// CheckedEntry references should be created by calling AddCore or Should on a
|
||||
// nil *CheckedEntry. References are returned to a pool after Write, and MUST
|
||||
// NOT be retained after calling their Write method.
|
||||
type CheckedEntry struct {
|
||||
Entry
|
||||
ErrorOutput WriteSyncer
|
||||
dirty bool // best-effort detection of pool misuse
|
||||
should CheckWriteAction
|
||||
cores []Core
|
||||
}
|
||||
|
||||
func (ce *CheckedEntry) reset() {
|
||||
ce.Entry = Entry{}
|
||||
ce.ErrorOutput = nil
|
||||
ce.dirty = false
|
||||
ce.should = WriteThenNoop
|
||||
for i := range ce.cores {
|
||||
// don't keep references to cores
|
||||
ce.cores[i] = nil
|
||||
}
|
||||
ce.cores = ce.cores[:0]
|
||||
}
|
||||
|
||||
// Write writes the entry to the stored Cores, returns any errors, and returns
|
||||
// the CheckedEntry reference to a pool for immediate re-use. Finally, it
|
||||
// executes any required CheckWriteAction.
|
||||
func (ce *CheckedEntry) Write(fields ...Field) {
|
||||
if ce == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if ce.dirty {
|
||||
if ce.ErrorOutput != nil {
|
||||
// Make a best effort to detect unsafe re-use of this CheckedEntry.
|
||||
// If the entry is dirty, log an internal error; because the
|
||||
// CheckedEntry is being used after it was returned to the pool,
|
||||
// the message may be an amalgamation from multiple call sites.
|
||||
fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", time.Now(), ce.Entry)
|
||||
ce.ErrorOutput.Sync()
|
||||
}
|
||||
return
|
||||
}
|
||||
ce.dirty = true
|
||||
|
||||
var err error
|
||||
for i := range ce.cores {
|
||||
err = multierr.Append(err, ce.cores[i].Write(ce.Entry, fields))
|
||||
}
|
||||
if ce.ErrorOutput != nil {
|
||||
if err != nil {
|
||||
fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", time.Now(), err)
|
||||
ce.ErrorOutput.Sync()
|
||||
}
|
||||
}
|
||||
|
||||
should, msg := ce.should, ce.Message
|
||||
putCheckedEntry(ce)
|
||||
|
||||
switch should {
|
||||
case WriteThenPanic:
|
||||
panic(msg)
|
||||
case WriteThenFatal:
|
||||
exit.Exit()
|
||||
}
|
||||
}
|
||||
|
||||
// AddCore adds a Core that has agreed to log this CheckedEntry. It's intended to be
|
||||
// used by Core.Check implementations, and is safe to call on nil CheckedEntry
|
||||
// references.
|
||||
func (ce *CheckedEntry) AddCore(ent Entry, core Core) *CheckedEntry {
|
||||
if ce == nil {
|
||||
ce = getCheckedEntry()
|
||||
ce.Entry = ent
|
||||
}
|
||||
ce.cores = append(ce.cores, core)
|
||||
return ce
|
||||
}
|
||||
|
||||
// Should sets this CheckedEntry's CheckWriteAction, which controls whether a
|
||||
// Core will panic or fatal after writing this log entry. Like AddCore, it's
|
||||
// safe to call on nil CheckedEntry references.
|
||||
func (ce *CheckedEntry) Should(ent Entry, should CheckWriteAction) *CheckedEntry {
|
||||
if ce == nil {
|
||||
ce = getCheckedEntry()
|
||||
ce.Entry = ent
|
||||
}
|
||||
ce.should = should
|
||||
return ce
|
||||
}
|
120
vendor/go.uber.org/zap/zapcore/error.go
generated
vendored
Normal file
120
vendor/go.uber.org/zap/zapcore/error.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Encodes the given error into fields of an object. A field with the given
|
||||
// name is added for the error message.
|
||||
//
|
||||
// If the error implements fmt.Formatter, a field with the name ${key}Verbose
|
||||
// is also added with the full verbose error message.
|
||||
//
|
||||
// Finally, if the error implements errorGroup (from go.uber.org/multierr) or
|
||||
// causer (from github.com/pkg/errors), a ${key}Causes field is added with an
|
||||
// array of objects containing the errors this error was comprised of.
|
||||
//
|
||||
// {
|
||||
// "error": err.Error(),
|
||||
// "errorVerbose": fmt.Sprintf("%+v", err),
|
||||
// "errorCauses": [
|
||||
// ...
|
||||
// ],
|
||||
// }
|
||||
func encodeError(key string, err error, enc ObjectEncoder) error {
|
||||
basic := err.Error()
|
||||
enc.AddString(key, basic)
|
||||
|
||||
switch e := err.(type) {
|
||||
case errorGroup:
|
||||
return enc.AddArray(key+"Causes", errArray(e.Errors()))
|
||||
case fmt.Formatter:
|
||||
verbose := fmt.Sprintf("%+v", e)
|
||||
if verbose != basic {
|
||||
// This is a rich error type, like those produced by
|
||||
// github.com/pkg/errors.
|
||||
enc.AddString(key+"Verbose", verbose)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type errorGroup interface {
|
||||
// Provides read-only access to the underlying list of errors, preferably
|
||||
// without causing any allocs.
|
||||
Errors() []error
|
||||
}
|
||||
|
||||
type causer interface {
|
||||
// Provides access to the error that caused this error.
|
||||
Cause() error
|
||||
}
|
||||
|
||||
// Note that errArry and errArrayElem are very similar to the version
|
||||
// implemented in the top-level error.go file. We can't re-use this because
|
||||
// that would require exporting errArray as part of the zapcore API.
|
||||
|
||||
// Encodes a list of errors using the standard error encoding logic.
|
||||
type errArray []error
|
||||
|
||||
func (errs errArray) MarshalLogArray(arr ArrayEncoder) error {
|
||||
for i := range errs {
|
||||
if errs[i] == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
el := newErrArrayElem(errs[i])
|
||||
arr.AppendObject(el)
|
||||
el.Free()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _errArrayElemPool = sync.Pool{New: func() interface{} {
|
||||
return &errArrayElem{}
|
||||
}}
|
||||
|
||||
// Encodes any error into a {"error": ...} re-using the same errors logic.
|
||||
//
|
||||
// May be passed in place of an array to build a single-element array.
|
||||
type errArrayElem struct{ err error }
|
||||
|
||||
func newErrArrayElem(err error) *errArrayElem {
|
||||
e := _errArrayElemPool.Get().(*errArrayElem)
|
||||
e.err = err
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *errArrayElem) MarshalLogArray(arr ArrayEncoder) error {
|
||||
return arr.AppendObject(e)
|
||||
}
|
||||
|
||||
func (e *errArrayElem) MarshalLogObject(enc ObjectEncoder) error {
|
||||
return encodeError("error", e.err, enc)
|
||||
}
|
||||
|
||||
func (e *errArrayElem) Free() {
|
||||
e.err = nil
|
||||
_errArrayElemPool.Put(e)
|
||||
}
|
212
vendor/go.uber.org/zap/zapcore/field.go
generated
vendored
Normal file
212
vendor/go.uber.org/zap/zapcore/field.go
generated
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A FieldType indicates which member of the Field union struct should be used
|
||||
// and how it should be serialized.
|
||||
type FieldType uint8
|
||||
|
||||
const (
|
||||
// UnknownType is the default field type. Attempting to add it to an encoder will panic.
|
||||
UnknownType FieldType = iota
|
||||
// ArrayMarshalerType indicates that the field carries an ArrayMarshaler.
|
||||
ArrayMarshalerType
|
||||
// ObjectMarshalerType indicates that the field carries an ObjectMarshaler.
|
||||
ObjectMarshalerType
|
||||
// BinaryType indicates that the field carries an opaque binary blob.
|
||||
BinaryType
|
||||
// BoolType indicates that the field carries a bool.
|
||||
BoolType
|
||||
// ByteStringType indicates that the field carries UTF-8 encoded bytes.
|
||||
ByteStringType
|
||||
// Complex128Type indicates that the field carries a complex128.
|
||||
Complex128Type
|
||||
// Complex64Type indicates that the field carries a complex128.
|
||||
Complex64Type
|
||||
// DurationType indicates that the field carries a time.Duration.
|
||||
DurationType
|
||||
// Float64Type indicates that the field carries a float64.
|
||||
Float64Type
|
||||
// Float32Type indicates that the field carries a float32.
|
||||
Float32Type
|
||||
// Int64Type indicates that the field carries an int64.
|
||||
Int64Type
|
||||
// Int32Type indicates that the field carries an int32.
|
||||
Int32Type
|
||||
// Int16Type indicates that the field carries an int16.
|
||||
Int16Type
|
||||
// Int8Type indicates that the field carries an int8.
|
||||
Int8Type
|
||||
// StringType indicates that the field carries a string.
|
||||
StringType
|
||||
// TimeType indicates that the field carries a time.Time.
|
||||
TimeType
|
||||
// Uint64Type indicates that the field carries a uint64.
|
||||
Uint64Type
|
||||
// Uint32Type indicates that the field carries a uint32.
|
||||
Uint32Type
|
||||
// Uint16Type indicates that the field carries a uint16.
|
||||
Uint16Type
|
||||
// Uint8Type indicates that the field carries a uint8.
|
||||
Uint8Type
|
||||
// UintptrType indicates that the field carries a uintptr.
|
||||
UintptrType
|
||||
// ReflectType indicates that the field carries an interface{}, which should
|
||||
// be serialized using reflection.
|
||||
ReflectType
|
||||
// NamespaceType signals the beginning of an isolated namespace. All
|
||||
// subsequent fields should be added to the new namespace.
|
||||
NamespaceType
|
||||
// StringerType indicates that the field carries a fmt.Stringer.
|
||||
StringerType
|
||||
// ErrorType indicates that the field carries an error.
|
||||
ErrorType
|
||||
// SkipType indicates that the field is a no-op.
|
||||
SkipType
|
||||
)
|
||||
|
||||
// A Field is a marshaling operation used to add a key-value pair to a logger's
|
||||
// context. Most fields are lazily marshaled, so it's inexpensive to add fields
|
||||
// to disabled debug-level log statements.
|
||||
type Field struct {
|
||||
Key string
|
||||
Type FieldType
|
||||
Integer int64
|
||||
String string
|
||||
Interface interface{}
|
||||
}
|
||||
|
||||
// AddTo exports a field through the ObjectEncoder interface. It's primarily
|
||||
// useful to library authors, and shouldn't be necessary in most applications.
|
||||
func (f Field) AddTo(enc ObjectEncoder) {
|
||||
var err error
|
||||
|
||||
switch f.Type {
|
||||
case ArrayMarshalerType:
|
||||
err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))
|
||||
case ObjectMarshalerType:
|
||||
err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))
|
||||
case BinaryType:
|
||||
enc.AddBinary(f.Key, f.Interface.([]byte))
|
||||
case BoolType:
|
||||
enc.AddBool(f.Key, f.Integer == 1)
|
||||
case ByteStringType:
|
||||
enc.AddByteString(f.Key, f.Interface.([]byte))
|
||||
case Complex128Type:
|
||||
enc.AddComplex128(f.Key, f.Interface.(complex128))
|
||||
case Complex64Type:
|
||||
enc.AddComplex64(f.Key, f.Interface.(complex64))
|
||||
case DurationType:
|
||||
enc.AddDuration(f.Key, time.Duration(f.Integer))
|
||||
case Float64Type:
|
||||
enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer)))
|
||||
case Float32Type:
|
||||
enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer)))
|
||||
case Int64Type:
|
||||
enc.AddInt64(f.Key, f.Integer)
|
||||
case Int32Type:
|
||||
enc.AddInt32(f.Key, int32(f.Integer))
|
||||
case Int16Type:
|
||||
enc.AddInt16(f.Key, int16(f.Integer))
|
||||
case Int8Type:
|
||||
enc.AddInt8(f.Key, int8(f.Integer))
|
||||
case StringType:
|
||||
enc.AddString(f.Key, f.String)
|
||||
case TimeType:
|
||||
if f.Interface != nil {
|
||||
enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))
|
||||
} else {
|
||||
// Fall back to UTC if location is nil.
|
||||
enc.AddTime(f.Key, time.Unix(0, f.Integer))
|
||||
}
|
||||
case Uint64Type:
|
||||
enc.AddUint64(f.Key, uint64(f.Integer))
|
||||
case Uint32Type:
|
||||
enc.AddUint32(f.Key, uint32(f.Integer))
|
||||
case Uint16Type:
|
||||
enc.AddUint16(f.Key, uint16(f.Integer))
|
||||
case Uint8Type:
|
||||
enc.AddUint8(f.Key, uint8(f.Integer))
|
||||
case UintptrType:
|
||||
enc.AddUintptr(f.Key, uintptr(f.Integer))
|
||||
case ReflectType:
|
||||
err = enc.AddReflected(f.Key, f.Interface)
|
||||
case NamespaceType:
|
||||
enc.OpenNamespace(f.Key)
|
||||
case StringerType:
|
||||
err = encodeStringer(f.Key, f.Interface, enc)
|
||||
case ErrorType:
|
||||
encodeError(f.Key, f.Interface.(error), enc)
|
||||
case SkipType:
|
||||
break
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown field type: %v", f))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Equals returns whether two fields are equal. For non-primitive types such as
|
||||
// errors, marshalers, or reflect types, it uses reflect.DeepEqual.
|
||||
func (f Field) Equals(other Field) bool {
|
||||
if f.Type != other.Type {
|
||||
return false
|
||||
}
|
||||
if f.Key != other.Key {
|
||||
return false
|
||||
}
|
||||
|
||||
switch f.Type {
|
||||
case BinaryType, ByteStringType:
|
||||
return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte))
|
||||
case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType:
|
||||
return reflect.DeepEqual(f.Interface, other.Interface)
|
||||
default:
|
||||
return f == other
|
||||
}
|
||||
}
|
||||
|
||||
func addFields(enc ObjectEncoder, fields []Field) {
|
||||
for i := range fields {
|
||||
fields[i].AddTo(enc)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (err error) {
|
||||
defer func() {
|
||||
if v := recover(); v != nil {
|
||||
err = fmt.Errorf("PANIC=%v", v)
|
||||
}
|
||||
}()
|
||||
|
||||
enc.AddString(key, stringer.(fmt.Stringer).String())
|
||||
return
|
||||
}
|
68
vendor/go.uber.org/zap/zapcore/hook.go
generated
vendored
Normal file
68
vendor/go.uber.org/zap/zapcore/hook.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
import "go.uber.org/multierr"
|
||||
|
||||
type hooked struct {
|
||||
Core
|
||||
funcs []func(Entry) error
|
||||
}
|
||||
|
||||
// RegisterHooks wraps a Core and runs a collection of user-defined callback
|
||||
// hooks each time a message is logged. Execution of the callbacks is blocking.
|
||||
//
|
||||
// This offers users an easy way to register simple callbacks (e.g., metrics
|
||||
// collection) without implementing the full Core interface.
|
||||
func RegisterHooks(core Core, hooks ...func(Entry) error) Core {
|
||||
funcs := append([]func(Entry) error{}, hooks...)
|
||||
return &hooked{
|
||||
Core: core,
|
||||
funcs: funcs,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *hooked) Check(ent Entry, ce *CheckedEntry) *CheckedEntry {
|
||||
// Let the wrapped Core decide whether to log this message or not. This
|
||||
// also gives the downstream a chance to register itself directly with the
|
||||
// CheckedEntry.
|
||||
if downstream := h.Core.Check(ent, ce); downstream != nil {
|
||||
return downstream.AddCore(ent, h)
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
||||
func (h *hooked) With(fields []Field) Core {
|
||||
return &hooked{
|
||||
Core: h.Core.With(fields),
|
||||
funcs: h.funcs,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *hooked) Write(ent Entry, _ []Field) error {
|
||||
// Since our downstream had a chance to register itself directly with the
|
||||
// CheckedMessage, we don't need to call it here.
|
||||
var err error
|
||||
for i := range h.funcs {
|
||||
err = multierr.Append(err, h.funcs[i](ent))
|
||||
}
|
||||
return err
|
||||
}
|
517
vendor/go.uber.org/zap/zapcore/json_encoder.go
generated
vendored
Normal file
517
vendor/go.uber.org/zap/zapcore/json_encoder.go
generated
vendored
Normal file
@ -0,0 +1,517 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"go.uber.org/zap/buffer"
|
||||
"go.uber.org/zap/internal/bufferpool"
|
||||
)
|
||||
|
||||
// For JSON-escaping; see jsonEncoder.safeAddString below.
|
||||
const _hex = "0123456789abcdef"
|
||||
|
||||
var _jsonPool = sync.Pool{New: func() interface{} {
|
||||
return &jsonEncoder{}
|
||||
}}
|
||||
|
||||
func getJSONEncoder() *jsonEncoder {
|
||||
return _jsonPool.Get().(*jsonEncoder)
|
||||
}
|
||||
|
||||
func putJSONEncoder(enc *jsonEncoder) {
|
||||
if enc.reflectBuf != nil {
|
||||
enc.reflectBuf.Free()
|
||||
}
|
||||
enc.EncoderConfig = nil
|
||||
enc.buf = nil
|
||||
enc.spaced = false
|
||||
enc.openNamespaces = 0
|
||||
enc.reflectBuf = nil
|
||||
enc.reflectEnc = nil
|
||||
_jsonPool.Put(enc)
|
||||
}
|
||||
|
||||
type jsonEncoder struct {
|
||||
*EncoderConfig
|
||||
buf *buffer.Buffer
|
||||
spaced bool // include spaces after colons and commas
|
||||
openNamespaces int
|
||||
|
||||
// for encoding generic values by reflection
|
||||
reflectBuf *buffer.Buffer
|
||||
reflectEnc *json.Encoder
|
||||
}
|
||||
|
||||
// NewJSONEncoder creates a fast, low-allocation JSON encoder. The encoder
|
||||
// appropriately escapes all field keys and values.
|
||||
//
|
||||
// Note that the encoder doesn't deduplicate keys, so it's possible to produce
|
||||
// a message like
|
||||
// {"foo":"bar","foo":"baz"}
|
||||
// This is permitted by the JSON specification, but not encouraged. Many
|
||||
// libraries will ignore duplicate key-value pairs (typically keeping the last
|
||||
// pair) when unmarshaling, but users should attempt to avoid adding duplicate
|
||||
// keys.
|
||||
func NewJSONEncoder(cfg EncoderConfig) Encoder {
|
||||
return newJSONEncoder(cfg, false)
|
||||
}
|
||||
|
||||
func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder {
|
||||
return &jsonEncoder{
|
||||
EncoderConfig: &cfg,
|
||||
buf: bufferpool.Get(),
|
||||
spaced: spaced,
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddArray(key string, arr ArrayMarshaler) error {
|
||||
enc.addKey(key)
|
||||
return enc.AppendArray(arr)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddObject(key string, obj ObjectMarshaler) error {
|
||||
enc.addKey(key)
|
||||
return enc.AppendObject(obj)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddBinary(key string, val []byte) {
|
||||
enc.AddString(key, base64.StdEncoding.EncodeToString(val))
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddByteString(key string, val []byte) {
|
||||
enc.addKey(key)
|
||||
enc.AppendByteString(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddBool(key string, val bool) {
|
||||
enc.addKey(key)
|
||||
enc.AppendBool(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddComplex128(key string, val complex128) {
|
||||
enc.addKey(key)
|
||||
enc.AppendComplex128(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddDuration(key string, val time.Duration) {
|
||||
enc.addKey(key)
|
||||
enc.AppendDuration(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddFloat64(key string, val float64) {
|
||||
enc.addKey(key)
|
||||
enc.AppendFloat64(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddInt64(key string, val int64) {
|
||||
enc.addKey(key)
|
||||
enc.AppendInt64(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) resetReflectBuf() {
|
||||
if enc.reflectBuf == nil {
|
||||
enc.reflectBuf = bufferpool.Get()
|
||||
enc.reflectEnc = json.NewEncoder(enc.reflectBuf)
|
||||
|
||||
// For consistency with our custom JSON encoder.
|
||||
enc.reflectEnc.SetEscapeHTML(false)
|
||||
} else {
|
||||
enc.reflectBuf.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
var nullLiteralBytes = []byte("null")
|
||||
|
||||
// Only invoke the standard JSON encoder if there is actually something to
|
||||
// encode; otherwise write JSON null literal directly.
|
||||
func (enc *jsonEncoder) encodeReflected(obj interface{}) ([]byte, error) {
|
||||
if obj == nil {
|
||||
return nullLiteralBytes, nil
|
||||
}
|
||||
enc.resetReflectBuf()
|
||||
if err := enc.reflectEnc.Encode(obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
enc.reflectBuf.TrimNewline()
|
||||
return enc.reflectBuf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error {
|
||||
valueBytes, err := enc.encodeReflected(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enc.addKey(key)
|
||||
_, err = enc.buf.Write(valueBytes)
|
||||
return err
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) OpenNamespace(key string) {
|
||||
enc.addKey(key)
|
||||
enc.buf.AppendByte('{')
|
||||
enc.openNamespaces++
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddString(key, val string) {
|
||||
enc.addKey(key)
|
||||
enc.AppendString(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddTime(key string, val time.Time) {
|
||||
enc.addKey(key)
|
||||
enc.AppendTime(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddUint64(key string, val uint64) {
|
||||
enc.addKey(key)
|
||||
enc.AppendUint64(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendArray(arr ArrayMarshaler) error {
|
||||
enc.addElementSeparator()
|
||||
enc.buf.AppendByte('[')
|
||||
err := arr.MarshalLogArray(enc)
|
||||
enc.buf.AppendByte(']')
|
||||
return err
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendObject(obj ObjectMarshaler) error {
|
||||
enc.addElementSeparator()
|
||||
enc.buf.AppendByte('{')
|
||||
err := obj.MarshalLogObject(enc)
|
||||
enc.buf.AppendByte('}')
|
||||
return err
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendBool(val bool) {
|
||||
enc.addElementSeparator()
|
||||
enc.buf.AppendBool(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendByteString(val []byte) {
|
||||
enc.addElementSeparator()
|
||||
enc.buf.AppendByte('"')
|
||||
enc.safeAddByteString(val)
|
||||
enc.buf.AppendByte('"')
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendComplex128(val complex128) {
|
||||
enc.addElementSeparator()
|
||||
// Cast to a platform-independent, fixed-size type.
|
||||
r, i := float64(real(val)), float64(imag(val))
|
||||
enc.buf.AppendByte('"')
|
||||
// Because we're always in a quoted string, we can use strconv without
|
||||
// special-casing NaN and +/-Inf.
|
||||
enc.buf.AppendFloat(r, 64)
|
||||
enc.buf.AppendByte('+')
|
||||
enc.buf.AppendFloat(i, 64)
|
||||
enc.buf.AppendByte('i')
|
||||
enc.buf.AppendByte('"')
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendDuration(val time.Duration) {
|
||||
cur := enc.buf.Len()
|
||||
enc.EncodeDuration(val, enc)
|
||||
if cur == enc.buf.Len() {
|
||||
// User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep
|
||||
// JSON valid.
|
||||
enc.AppendInt64(int64(val))
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendInt64(val int64) {
|
||||
enc.addElementSeparator()
|
||||
enc.buf.AppendInt(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendReflected(val interface{}) error {
|
||||
valueBytes, err := enc.encodeReflected(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enc.addElementSeparator()
|
||||
_, err = enc.buf.Write(valueBytes)
|
||||
return err
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendString(val string) {
|
||||
enc.addElementSeparator()
|
||||
enc.buf.AppendByte('"')
|
||||
enc.safeAddString(val)
|
||||
enc.buf.AppendByte('"')
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendTime(val time.Time) {
|
||||
cur := enc.buf.Len()
|
||||
enc.EncodeTime(val, enc)
|
||||
if cur == enc.buf.Len() {
|
||||
// User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep
|
||||
// output JSON valid.
|
||||
enc.AppendInt64(val.UnixNano())
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AppendUint64(val uint64) {
|
||||
enc.addElementSeparator()
|
||||
enc.buf.AppendUint(val)
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) }
|
||||
func (enc *jsonEncoder) AddFloat32(k string, v float32) { enc.AddFloat64(k, float64(v)) }
|
||||
func (enc *jsonEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) }
|
||||
func (enc *jsonEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) }
|
||||
func (enc *jsonEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) }
|
||||
func (enc *jsonEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) }
|
||||
func (enc *jsonEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) }
|
||||
func (enc *jsonEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) }
|
||||
func (enc *jsonEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) }
|
||||
func (enc *jsonEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) }
|
||||
func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) }
|
||||
func (enc *jsonEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) }
|
||||
func (enc *jsonEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) }
|
||||
func (enc *jsonEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) }
|
||||
func (enc *jsonEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) }
|
||||
func (enc *jsonEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) }
|
||||
func (enc *jsonEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) }
|
||||
func (enc *jsonEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) }
|
||||
func (enc *jsonEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) }
|
||||
func (enc *jsonEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) }
|
||||
func (enc *jsonEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) }
|
||||
func (enc *jsonEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) }
|
||||
func (enc *jsonEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) }
|
||||
|
||||
func (enc *jsonEncoder) Clone() Encoder {
|
||||
clone := enc.clone()
|
||||
clone.buf.Write(enc.buf.Bytes())
|
||||
return clone
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) clone() *jsonEncoder {
|
||||
clone := getJSONEncoder()
|
||||
clone.EncoderConfig = enc.EncoderConfig
|
||||
clone.spaced = enc.spaced
|
||||
clone.openNamespaces = enc.openNamespaces
|
||||
clone.buf = bufferpool.Get()
|
||||
return clone
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) {
|
||||
final := enc.clone()
|
||||
final.buf.AppendByte('{')
|
||||
|
||||
if final.LevelKey != "" {
|
||||
final.addKey(final.LevelKey)
|
||||
cur := final.buf.Len()
|
||||
final.EncodeLevel(ent.Level, final)
|
||||
if cur == final.buf.Len() {
|
||||
// User-supplied EncodeLevel was a no-op. Fall back to strings to keep
|
||||
// output JSON valid.
|
||||
final.AppendString(ent.Level.String())
|
||||
}
|
||||
}
|
||||
if final.TimeKey != "" {
|
||||
final.AddTime(final.TimeKey, ent.Time)
|
||||
}
|
||||
if ent.LoggerName != "" && final.NameKey != "" {
|
||||
final.addKey(final.NameKey)
|
||||
cur := final.buf.Len()
|
||||
nameEncoder := final.EncodeName
|
||||
|
||||
// if no name encoder provided, fall back to FullNameEncoder for backwards
|
||||
// compatibility
|
||||
if nameEncoder == nil {
|
||||
nameEncoder = FullNameEncoder
|
||||
}
|
||||
|
||||
nameEncoder(ent.LoggerName, final)
|
||||
if cur == final.buf.Len() {
|
||||
// User-supplied EncodeName was a no-op. Fall back to strings to
|
||||
// keep output JSON valid.
|
||||
final.AppendString(ent.LoggerName)
|
||||
}
|
||||
}
|
||||
if ent.Caller.Defined && final.CallerKey != "" {
|
||||
final.addKey(final.CallerKey)
|
||||
cur := final.buf.Len()
|
||||
final.EncodeCaller(ent.Caller, final)
|
||||
if cur == final.buf.Len() {
|
||||
// User-supplied EncodeCaller was a no-op. Fall back to strings to
|
||||
// keep output JSON valid.
|
||||
final.AppendString(ent.Caller.String())
|
||||
}
|
||||
}
|
||||
if final.MessageKey != "" {
|
||||
final.addKey(enc.MessageKey)
|
||||
final.AppendString(ent.Message)
|
||||
}
|
||||
if enc.buf.Len() > 0 {
|
||||
final.addElementSeparator()
|
||||
final.buf.Write(enc.buf.Bytes())
|
||||
}
|
||||
addFields(final, fields)
|
||||
final.closeOpenNamespaces()
|
||||
if ent.Stack != "" && final.StacktraceKey != "" {
|
||||
final.AddString(final.StacktraceKey, ent.Stack)
|
||||
}
|
||||
final.buf.AppendByte('}')
|
||||
if final.LineEnding != "" {
|
||||
final.buf.AppendString(final.LineEnding)
|
||||
} else {
|
||||
final.buf.AppendString(DefaultLineEnding)
|
||||
}
|
||||
|
||||
ret := final.buf
|
||||
putJSONEncoder(final)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) truncate() {
|
||||
enc.buf.Reset()
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) closeOpenNamespaces() {
|
||||
for i := 0; i < enc.openNamespaces; i++ {
|
||||
enc.buf.AppendByte('}')
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) addKey(key string) {
|
||||
enc.addElementSeparator()
|
||||
enc.buf.AppendByte('"')
|
||||
enc.safeAddString(key)
|
||||
enc.buf.AppendByte('"')
|
||||
enc.buf.AppendByte(':')
|
||||
if enc.spaced {
|
||||
enc.buf.AppendByte(' ')
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) addElementSeparator() {
|
||||
last := enc.buf.Len() - 1
|
||||
if last < 0 {
|
||||
return
|
||||
}
|
||||
switch enc.buf.Bytes()[last] {
|
||||
case '{', '[', ':', ',', ' ':
|
||||
return
|
||||
default:
|
||||
enc.buf.AppendByte(',')
|
||||
if enc.spaced {
|
||||
enc.buf.AppendByte(' ')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) appendFloat(val float64, bitSize int) {
|
||||
enc.addElementSeparator()
|
||||
switch {
|
||||
case math.IsNaN(val):
|
||||
enc.buf.AppendString(`"NaN"`)
|
||||
case math.IsInf(val, 1):
|
||||
enc.buf.AppendString(`"+Inf"`)
|
||||
case math.IsInf(val, -1):
|
||||
enc.buf.AppendString(`"-Inf"`)
|
||||
default:
|
||||
enc.buf.AppendFloat(val, bitSize)
|
||||
}
|
||||
}
|
||||
|
||||
// safeAddString JSON-escapes a string and appends it to the internal buffer.
|
||||
// Unlike the standard library's encoder, it doesn't attempt to protect the
|
||||
// user from browser vulnerabilities or JSONP-related problems.
|
||||
func (enc *jsonEncoder) safeAddString(s string) {
|
||||
for i := 0; i < len(s); {
|
||||
if enc.tryAddRuneSelf(s[i]) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
r, size := utf8.DecodeRuneInString(s[i:])
|
||||
if enc.tryAddRuneError(r, size) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
enc.buf.AppendString(s[i : i+size])
|
||||
i += size
|
||||
}
|
||||
}
|
||||
|
||||
// safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte.
|
||||
func (enc *jsonEncoder) safeAddByteString(s []byte) {
|
||||
for i := 0; i < len(s); {
|
||||
if enc.tryAddRuneSelf(s[i]) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
r, size := utf8.DecodeRune(s[i:])
|
||||
if enc.tryAddRuneError(r, size) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
enc.buf.Write(s[i : i+size])
|
||||
i += size
|
||||
}
|
||||
}
|
||||
|
||||
// tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte.
|
||||
func (enc *jsonEncoder) tryAddRuneSelf(b byte) bool {
|
||||
if b >= utf8.RuneSelf {
|
||||
return false
|
||||
}
|
||||
if 0x20 <= b && b != '\\' && b != '"' {
|
||||
enc.buf.AppendByte(b)
|
||||
return true
|
||||
}
|
||||
switch b {
|
||||
case '\\', '"':
|
||||
enc.buf.AppendByte('\\')
|
||||
enc.buf.AppendByte(b)
|
||||
case '\n':
|
||||
enc.buf.AppendByte('\\')
|
||||
enc.buf.AppendByte('n')
|
||||
case '\r':
|
||||
enc.buf.AppendByte('\\')
|
||||
enc.buf.AppendByte('r')
|
||||
case '\t':
|
||||
enc.buf.AppendByte('\\')
|
||||
enc.buf.AppendByte('t')
|
||||
default:
|
||||
// Encode bytes < 0x20, except for the escape sequences above.
|
||||
enc.buf.AppendString(`\u00`)
|
||||
enc.buf.AppendByte(_hex[b>>4])
|
||||
enc.buf.AppendByte(_hex[b&0xF])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (enc *jsonEncoder) tryAddRuneError(r rune, size int) bool {
|
||||
if r == utf8.RuneError && size == 1 {
|
||||
enc.buf.AppendString(`\ufffd`)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
175
vendor/go.uber.org/zap/zapcore/level.go
generated
vendored
Normal file
175
vendor/go.uber.org/zap/zapcore/level.go
generated
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zapcore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var errUnmarshalNilLevel = errors.New("can't unmarshal a nil *Level")
|
||||
|
||||
// A Level is a logging priority. Higher levels are more important.
|
||||
type Level int8
|
||||
|
||||
const (
|
||||
// DebugLevel logs are typically voluminous, and are usually disabled in
|
||||
// production.
|
||||
DebugLevel Level = iota - 1
|
||||
// InfoLevel is the default logging priority.
|
||||
InfoLevel
|
||||
// WarnLevel logs are more important than Info, but don't need individual
|
||||
// human review.
|
||||
WarnLevel
|
||||
// ErrorLevel logs are high-priority. If an application is running smoothly,
|
||||
// it shouldn't generate any error-level logs.
|
||||
ErrorLevel
|
||||
// DPanicLevel logs are particularly important errors. In development the
|
||||
// logger panics after writing the message.
|
||||
DPanicLevel
|
||||
// PanicLevel logs a message, then panics.
|
||||
PanicLevel
|
||||
// FatalLevel logs a message, then calls os.Exit(1).
|
||||
FatalLevel
|
||||
|
||||
_minLevel = DebugLevel
|
||||
_maxLevel = FatalLevel
|
||||
)
|
||||
|
||||
// String returns a lower-case ASCII representation of the log level.
|
||||
func (l Level) String() string {
|
||||
switch l {
|
||||
case DebugLevel:
|
||||
return "debug"
|
||||
case InfoLevel:
|
||||
return "info"
|
||||
case WarnLevel:
|
||||
return "warn"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case DPanicLevel:
|
||||
return "dpanic"
|
||||
case PanicLevel:
|
||||
return "panic"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
default:
|
||||
return fmt.Sprintf("Level(%d)", l)
|
||||
}
|
||||
}
|
||||
|
||||
// CapitalString returns an all-caps ASCII representation of the log level.
|
||||
func (l Level) CapitalString() string {
|
||||
// Printing levels in all-caps is common enough that we should export this
|
||||
// functionality.
|
||||
switch l {
|
||||
case DebugLevel:
|
||||
return "DEBUG"
|
||||
case InfoLevel:
|
||||
return "INFO"
|
||||
case WarnLevel:
|
||||
return "WARN"
|
||||
case ErrorLevel:
|
||||
return "ERROR"
|
||||
case DPanicLevel:
|
||||
return "DPANIC"
|
||||
case PanicLevel:
|
||||
return "PANIC"
|
||||
case FatalLevel:
|
||||
return "FATAL"
|
||||
default:
|
||||
return fmt.Sprintf("LEVEL(%d)", l)
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalText marshals the Level to text. Note that the text representation
|
||||
// drops the -Level suffix (see example).
|
||||
func (l Level) MarshalText() ([]byte, error) {
|
||||
return []byte(l.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText unmarshals text to a level. Like MarshalText, UnmarshalText
|
||||
// expects the text representation of a Level to drop the -Level suffix (see
|
||||
// example).
|
||||
//
|
||||
// In particular, this makes it easy to configure logging levels using YAML,
|
||||
// TOML, or JSON files.
|
||||
func (l *Level) UnmarshalText(text []byte) error {
|
||||
if l == nil {
|
||||
return errUnmarshalNilLevel
|
||||
}
|
||||
if !l.unmarshalText(text) && !l.unmarshalText(bytes.ToLower(text)) {
|
||||
return fmt.Errorf("unrecognized level: %q", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Level) unmarshalText(text []byte) bool {
|
||||
switch string(text) {
|
||||
case "debug", "DEBUG":
|
||||
*l = DebugLevel
|
||||
case "info", "INFO", "": // make the zero value useful
|
||||
*l = InfoLevel
|
||||
case "warn", "WARN":
|
||||
*l = WarnLevel
|
||||
case "error", "ERROR":
|
||||
*l = ErrorLevel
|
||||
case "dpanic", "DPANIC":
|
||||
*l = DPanicLevel
|
||||
case "panic", "PANIC":
|
||||
*l = PanicLevel
|
||||
case "fatal", "FATAL":
|
||||
*l = FatalLevel
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Set sets the level for the flag.Value interface.
|
||||
func (l *Level) Set(s string) error {
|
||||
return l.UnmarshalText([]byte(s))
|
||||
}
|
||||
|
||||
// Get gets the level for the flag.Getter interface.
|
||||
func (l *Level) Get() interface{} {
|
||||
return *l
|
||||
}
|
||||
|
||||
// Enabled returns true if the given level is at or above this level.
|
||||
func (l Level) Enabled(lvl Level) bool {
|
||||
return lvl >= l
|
||||
}
|
||||
|
||||
// LevelEnabler decides whether a given logging level is enabled when logging a
|
||||
// message.
|
||||
//
|
||||
// Enablers are intended to be used to implement deterministic filters;
|
||||
// concerns like sampling are better implemented as a Core.
|
||||
//
|
||||
// Each concrete Level value implements a static LevelEnabler which returns
|
||||
// true for itself and all higher logging levels. For example WarnLevel.Enabled()
|
||||
// will return true for WarnLevel, ErrorLevel, DPanicLevel, PanicLevel, and
|
||||
// FatalLevel, but return false for InfoLevel and DebugLevel.
|
||||
type LevelEnabler interface {
|
||||
Enabled(Level) bool
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user