You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by to...@apache.org on 2020/12/09 07:23:10 UTC
[apisix-ingress-controller] branch master updated: chore: introduce
a log package (#64)
This is an automated email from the ASF dual-hosted git repository.
tokers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git
The following commit(s) were added to refs/heads/master by this push:
new 4ffef79 chore: introduce a log package (#64)
4ffef79 is described below
commit 4ffef796a0560daa7b8861bbfa6cbe15b5ba046a
Author: Alex Zhang <zc...@gmail.com>
AuthorDate: Wed Dec 9 15:23:03 2020 +0800
chore: introduce a log package (#64)
* chore: introduce a log package
* test: add more test cases.
* fix: style
---
go.mod | 1 +
go.sum | 29 ++---
pkg/log/default_logger.go | 110 +++++++++++++++++
pkg/log/default_logger_test.go | 82 +++++++++++++
pkg/log/logger.go | 271 +++++++++++++++++++++++++++++++++++++++++
pkg/log/logger_test.go | 102 ++++++++++++++++
pkg/log/options.go | 54 ++++++++
7 files changed, 635 insertions(+), 14 deletions(-)
diff --git a/go.mod b/go.mod
index bd84afe..8fa7ae8 100644
--- a/go.mod
+++ b/go.mod
@@ -14,6 +14,7 @@ require (
github.com/spf13/cobra v1.1.1
github.com/stretchr/testify v1.4.0
github.com/tidwall/gjson v1.6.4
+ go.uber.org/zap v1.13.0
gopkg.in/yaml.v2 v2.2.8
k8s.io/api v0.0.0-20190819141258-3544db3b9e44
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d
diff --git a/go.sum b/go.sum
index 47c702e..4bf044b 100644
--- a/go.sum
+++ b/go.sum
@@ -12,6 +12,7 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@@ -112,12 +113,10 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
-github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -133,7 +132,6 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be h1:AHimNtVIpiBjPUhEF5KNCkrUyqTSA5zWUl8sQ2bfGBE=
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -189,6 +187,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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=
@@ -222,7 +221,6 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -253,13 +251,20 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+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.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+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=
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-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -276,6 +281,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+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/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -300,7 +306,6 @@ golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQ
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -319,23 +324,18 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
@@ -357,6 +357,9 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/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-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -367,7 +370,6 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
@@ -400,15 +402,14 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/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=
k8s.io/api v0.0.0-20190819141258-3544db3b9e44 h1:7Gz7/nQ7X2qmPXMyN0bNq7Zm9Uip+UnFuMZTd2l3vms=
k8s.io/api v0.0.0-20190819141258-3544db3b9e44/go.mod h1:AOxZTnaXR/xiarlQL0JUfwQPxjmKDvVYoRp58cA7lUo=
diff --git a/pkg/log/default_logger.go b/pkg/log/default_logger.go
new file mode 100644
index 0000000..03d20d9
--- /dev/null
+++ b/pkg/log/default_logger.go
@@ -0,0 +1,110 @@
+package log
+
+import "go.uber.org/zap/zapcore"
+
+var (
+ // DefaultLogger is the default logger, which logs message to stderr and with
+ // the minimal level "warn".
+ DefaultLogger *Logger
+)
+
+func init() {
+ l, err := NewLogger(
+ WithOutputFile("stderr"),
+ WithLogLevel("warn"),
+ )
+ if err != nil {
+ panic(err)
+ }
+ DefaultLogger = l
+}
+
+// Debug uses the fmt.Sprint to construct and log a message using the DefaultLogger.
+func Debug(args ...interface{}) {
+ DefaultLogger.Debug(args...)
+}
+
+// Debugf uses the fmt.Sprintf to log a templated message using the DefaultLogger.
+func Debugf(template string, args ...interface{}) {
+ DefaultLogger.Debugf(template, args...)
+}
+
+// Debugw logs a message with some additional context using the DefaultLogger.
+func Debugw(message string, fields ...zapcore.Field) {
+ DefaultLogger.Debugw(message, fields...)
+}
+
+// Info uses the fmt.Sprint to construct and log a message using the DefaultLogger.
+func Info(args ...interface{}) {
+ DefaultLogger.Info(args...)
+}
+
+// Infof uses the fmt.Sprintf to log a templated message using the DefaultLogger.
+func Infof(template string, args ...interface{}) {
+ DefaultLogger.Infof(template, args...)
+}
+
+// Infow logs a message with some additional context using the DefaultLogger.
+func Infow(message string, fields ...zapcore.Field) {
+ DefaultLogger.Infow(message, fields...)
+}
+
+// Warn uses the fmt.Sprint to construct and log a message using the DefaultLogger.
+func Warn(args ...interface{}) {
+ DefaultLogger.Warn(args...)
+}
+
+// Warnf uses the fmt.Sprintf to log a templated message using the DefaultLogger.
+func Warnf(template string, args ...interface{}) {
+ DefaultLogger.Warnf(template, args...)
+}
+
+// Warnw logs a message with some additional context using the DefaultLogger.
+func Warnw(message string, fields ...zapcore.Field) {
+ DefaultLogger.Warnw(message, fields...)
+}
+
+// Error uses the fmt.Sprint to construct and log a message using the DefaultLogger.
+func Error(args ...interface{}) {
+ DefaultLogger.Error(args...)
+}
+
+// Errorf uses the fmt.Sprintf to log a templated message using the DefaultLogger.
+func Errorf(template string, args ...interface{}) {
+ DefaultLogger.Errorf(template, args...)
+}
+
+// Errorw logs a message with some additional context using the DefaultLogger.
+func Errorw(message string, fields ...zapcore.Field) {
+ DefaultLogger.Errorw(message, fields...)
+}
+
+// Panic uses the fmt.Sprint to construct and log a message using the DefaultLogger.
+func Panic(args ...interface{}) {
+ DefaultLogger.Panic(args...)
+}
+
+// Panicf uses the fmt.Sprintf to log a templated message using the DefaultLogger.
+func Panicf(template string, args ...interface{}) {
+ DefaultLogger.Panicf(template, args...)
+}
+
+// Panicw logs a message with some additional context using the DefaultLogger.
+func Panicw(message string, fields ...zapcore.Field) {
+ DefaultLogger.Panicw(message, fields...)
+}
+
+// Fatal uses the fmt.Sprint to construct and log a message using the DefaultLogger.
+func Fatal(args ...interface{}) {
+ DefaultLogger.Fatal(args...)
+}
+
+// Fatalf uses the fmt.Sprintf to log a templated message using the DefaultLogger.
+func Fatalf(template string, args ...interface{}) {
+ DefaultLogger.Fatalf(template, args...)
+}
+
+// Fatalw logs a message with some additional context using the DefaultLogger.
+func Fatalw(message string, fields ...zapcore.Field) {
+ DefaultLogger.Fatalw(message, fields...)
+}
diff --git a/pkg/log/default_logger_test.go b/pkg/log/default_logger_test.go
new file mode 100644
index 0000000..58a1aff
--- /dev/null
+++ b/pkg/log/default_logger_test.go
@@ -0,0 +1,82 @@
+package log
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+var (
+ logHandler = map[string][]reflect.Value{
+ zapcore.DebugLevel.String(): {
+ reflect.ValueOf(Debug),
+ reflect.ValueOf(Debugf),
+ reflect.ValueOf(Debugw),
+ },
+ zapcore.InfoLevel.String(): {
+ reflect.ValueOf(Info),
+ reflect.ValueOf(Infof),
+ reflect.ValueOf(Infow),
+ },
+ zapcore.WarnLevel.String(): {
+ reflect.ValueOf(Warn),
+ reflect.ValueOf(Warnf),
+ reflect.ValueOf(Warnw),
+ },
+ zapcore.ErrorLevel.String(): {
+ reflect.ValueOf(Error),
+ reflect.ValueOf(Errorf),
+ reflect.ValueOf(Errorw),
+ },
+ zapcore.PanicLevel.String(): {
+ reflect.ValueOf(Panic),
+ reflect.ValueOf(Panicf),
+ reflect.ValueOf(Panicw),
+ },
+ zapcore.FatalLevel.String(): {
+ reflect.ValueOf(Fatal),
+ reflect.ValueOf(Fatalf),
+ reflect.ValueOf(Fatalw),
+ },
+ }
+)
+
+func TestDefaultLogger(t *testing.T) {
+ for level, handlers := range logHandler {
+ t.Run("test log with level "+level, func(t *testing.T) {
+ fws := &fakeWriteSyncer{}
+ logger, err := NewLogger(WithLogLevel(level), WithWriteSyncer(fws))
+ assert.Nil(t, err, "failed to new logger: ", err)
+ defer logger.Close()
+ // Reset default logger
+ DefaultLogger = logger
+
+ handlers[0].Call([]reflect.Value{reflect.ValueOf("hello")})
+ assert.Nil(t, logger.Sync(), "failed to sync logger")
+
+ fields := unmarshalLogMessage(t, fws.bytes())
+ assert.Equal(t, fields.Level, level, "bad log level ", fields.Level)
+ assert.Equal(t, fields.Message, "hello", "bad log message ", fields.Message)
+
+ handlers[1].Call([]reflect.Value{reflect.ValueOf("hello I am %s"), reflect.ValueOf("alex")})
+ assert.Nil(t, logger.Sync(), "failed to sync logger")
+
+ fields = unmarshalLogMessage(t, fws.bytes())
+ assert.Equal(t, fields.Level, level, "bad log level ", fields.Level)
+ assert.Equal(t, fields.Message, "hello I am alex", "bad log message ", fields.Message)
+
+ handlers[2].Call([]reflect.Value{reflect.ValueOf("hello"), reflect.ValueOf(zap.String("name", "alex")), reflect.ValueOf(zap.Int("age", 3))})
+
+ assert.Nil(t, logger.Sync(), "failed to sync logger")
+
+ fields = unmarshalLogMessage(t, fws.bytes())
+ assert.Equal(t, fields.Level, level, "bad log level ", fields.Level)
+ assert.Equal(t, fields.Message, "hello", "bad log message ", fields.Message)
+ assert.Equal(t, fields.Name, "alex", "bad name field ", fields.Name)
+ assert.Equal(t, fields.Age, 3, "bad age field ", fields.Age)
+ })
+ }
+}
diff --git a/pkg/log/logger.go b/pkg/log/logger.go
new file mode 100644
index 0000000..6a46127
--- /dev/null
+++ b/pkg/log/logger.go
@@ -0,0 +1,271 @@
+package log
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+ "time"
+
+ "go.uber.org/zap/zapcore"
+)
+
+var (
+ levelMap = map[string]zapcore.Level{
+ zapcore.DebugLevel.String(): zapcore.DebugLevel,
+ zapcore.InfoLevel.String(): zapcore.InfoLevel,
+ zapcore.WarnLevel.String(): zapcore.WarnLevel,
+ zapcore.ErrorLevel.String(): zapcore.ErrorLevel,
+ zapcore.PanicLevel.String(): zapcore.PanicLevel,
+ zapcore.FatalLevel.String(): zapcore.FatalLevel,
+ }
+)
+
+// Logger is a log object, which exposes standard APIs like
+// errorf, error, warn, warnf and etcd.
+type Logger struct {
+ writer io.Writer
+ core zapcore.Core
+ level zapcore.Level
+}
+
+func (logger *Logger) write(level zapcore.Level, message string, fields []zapcore.Field) {
+ e := zapcore.Entry{
+ Level: level,
+ Time: time.Now(),
+ Message: message,
+ Caller: zapcore.NewEntryCaller(runtime.Caller(2)),
+ }
+
+ _ = logger.core.Write(e, fields)
+}
+
+// Sync flushes all buffered logs to the their destination.
+func (logger *Logger) Sync() (err error) {
+ file, ok := logger.writer.(*os.File)
+ if ok && file != os.Stdout && file != os.Stderr {
+ err = logger.core.Sync()
+ }
+ return
+}
+
+// Close flushes all buffered logs and closes the underlying writer.
+func (logger *Logger) Close() (err error) {
+ closer, ok := logger.writer.(io.Closer)
+ if ok {
+ return closer.Close()
+ }
+ return nil
+}
+
+// Debug uses the fmt.Sprint to construct and log a message.
+func (logger *Logger) Debug(args ...interface{}) {
+ if logger.level <= zapcore.DebugLevel {
+ msg := fmt.Sprint(args...)
+ logger.write(zapcore.DebugLevel, msg, nil)
+ }
+}
+
+// Debugf uses the fmt.Sprintf to log a templated message.
+func (logger *Logger) Debugf(template string, args ...interface{}) {
+ if logger.level <= zapcore.DebugLevel {
+ msg := fmt.Sprintf(template, args...)
+ logger.write(zapcore.DebugLevel, msg, nil)
+ }
+}
+
+// Debugw logs a message with some additional context.
+func (logger *Logger) Debugw(message string, fields ...zapcore.Field) {
+ if logger.level <= zapcore.DebugLevel {
+ logger.write(zapcore.DebugLevel, message, fields)
+ }
+}
+
+// Info uses the fmt.Sprint to construct and log a message.
+func (logger *Logger) Info(args ...interface{}) {
+ if logger.level <= zapcore.InfoLevel {
+ msg := fmt.Sprint(args...)
+ logger.write(zapcore.InfoLevel, msg, nil)
+ }
+}
+
+// Infof uses the fmt.Sprintf to log a templated message.
+func (logger *Logger) Infof(template string, args ...interface{}) {
+ if logger.level <= zapcore.InfoLevel {
+ msg := fmt.Sprintf(template, args...)
+ logger.write(zapcore.InfoLevel, msg, nil)
+ }
+}
+
+// Infow logs a message with some additional context.
+func (logger *Logger) Infow(message string, fields ...zapcore.Field) {
+ if logger.level <= zapcore.InfoLevel {
+ logger.write(zapcore.InfoLevel, message, fields)
+ }
+}
+
+// Warn uses the fmt.Sprint to construct and log a message.
+func (logger *Logger) Warn(args ...interface{}) {
+ if logger.level <= zapcore.WarnLevel {
+ msg := fmt.Sprint(args...)
+ logger.write(zapcore.WarnLevel, msg, nil)
+ }
+}
+
+// Warnf uses the fmt.Sprintf to log a templated message.
+func (logger *Logger) Warnf(template string, args ...interface{}) {
+ if logger.level <= zapcore.WarnLevel {
+ msg := fmt.Sprintf(template, args...)
+ logger.write(zapcore.WarnLevel, msg, nil)
+ }
+}
+
+// Warnw logs a message with some additional context.
+func (logger *Logger) Warnw(message string, fields ...zapcore.Field) {
+ if logger.level <= zapcore.WarnLevel {
+ logger.write(zapcore.WarnLevel, message, fields)
+ }
+}
+
+// Error uses the fmt.Sprint to construct and log a message.
+func (logger *Logger) Error(args ...interface{}) {
+ if logger.level <= zapcore.ErrorLevel {
+ msg := fmt.Sprint(args...)
+ logger.write(zapcore.ErrorLevel, msg, nil)
+ }
+}
+
+// Errorf uses the fmt.Sprintf to log a templated message.
+func (logger *Logger) Errorf(template string, args ...interface{}) {
+ if logger.level <= zapcore.ErrorLevel {
+ msg := fmt.Sprintf(template, args...)
+ logger.write(zapcore.ErrorLevel, msg, nil)
+ }
+}
+
+// Errorw logs a message with some additional context.
+func (logger *Logger) Errorw(message string, fields ...zapcore.Field) {
+ if logger.level <= zapcore.ErrorLevel {
+ logger.write(zapcore.ErrorLevel, message, fields)
+ }
+}
+
+// Panic uses the fmt.Sprint to construct and log a message.
+func (logger *Logger) Panic(args ...interface{}) {
+ if logger.level <= zapcore.PanicLevel {
+ msg := fmt.Sprint(args...)
+ logger.write(zapcore.PanicLevel, msg, nil)
+ }
+}
+
+// Panicf uses the fmt.Sprintf to log a templated message.
+func (logger *Logger) Panicf(template string, args ...interface{}) {
+ if logger.level <= zapcore.PanicLevel {
+ msg := fmt.Sprintf(template, args...)
+ logger.write(zapcore.PanicLevel, msg, nil)
+ }
+}
+
+// Panicw logs a message with some additional context.
+func (logger *Logger) Panicw(message string, fields ...zapcore.Field) {
+ if logger.level <= zapcore.PanicLevel {
+ logger.write(zapcore.PanicLevel, message, fields)
+ }
+}
+
+// Fatal uses the fmt.Sprint to construct and log a message.
+func (logger *Logger) Fatal(args ...interface{}) {
+ if logger.level <= zapcore.FatalLevel {
+ msg := fmt.Sprint(args...)
+ logger.write(zapcore.FatalLevel, msg, nil)
+ }
+}
+
+// Fatalf uses the fmt.Sprintf to log a templated message.
+func (logger *Logger) Fatalf(template string, args ...interface{}) {
+ if logger.level <= zapcore.FatalLevel {
+ msg := fmt.Sprintf(template, args...)
+ logger.write(zapcore.FatalLevel, msg, nil)
+ }
+}
+
+// Fatalw logs a message with some additional context.
+func (logger *Logger) Fatalw(message string, fields ...zapcore.Field) {
+ if logger.level <= zapcore.FatalLevel {
+ logger.write(zapcore.FatalLevel, message, fields)
+ }
+}
+
+// NewLogger sets up a Logger object according to a series of options.
+func NewLogger(opts ...Option) (*Logger, error) {
+ var (
+ writer zapcore.WriteSyncer
+ enc zapcore.Encoder
+ )
+
+ o := &options{
+ logLevel: "warn",
+ outputFile: "stderr",
+ }
+ for _, opt := range opts {
+ opt.apply(o)
+ }
+
+ level, ok := levelMap[o.logLevel]
+ if !ok {
+ return nil, fmt.Errorf("unknown log level %s", o.logLevel)
+ }
+
+ logger := &Logger{
+ level: level,
+ }
+
+ if o.writeSyncer != nil {
+ writer = o.writeSyncer
+ } else {
+ if o.outputFile == "stdout" {
+ writer = os.Stdout
+ } else if o.outputFile == "stderr" {
+ writer = os.Stderr
+ } else {
+ file, err := os.OpenFile(o.outputFile, os.O_WRONLY|os.O_APPEND, 0644)
+ if err != nil {
+ return nil, err
+ }
+ writer = file
+ }
+ }
+
+ if writer == os.Stdout || writer == os.Stderr {
+ enc = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
+ MessageKey: "message",
+ LevelKey: "level",
+ TimeKey: "time",
+ NameKey: "context",
+ CallerKey: "caller",
+ StacktraceKey: "backtrace",
+ LineEnding: zapcore.DefaultLineEnding,
+ EncodeLevel: zapcore.LowercaseColorLevelEncoder,
+ EncodeTime: zapcore.RFC3339TimeEncoder,
+ EncodeDuration: zapcore.StringDurationEncoder,
+ EncodeCaller: zapcore.ShortCallerEncoder,
+ })
+ } else {
+ enc = zapcore.NewJSONEncoder(zapcore.EncoderConfig{
+ MessageKey: "message",
+ LevelKey: "level",
+ TimeKey: "time",
+ NameKey: "context",
+ CallerKey: "caller",
+ StacktraceKey: "backtrace",
+ LineEnding: zapcore.DefaultLineEnding,
+ EncodeLevel: zapcore.LowercaseLevelEncoder,
+ EncodeTime: zapcore.RFC3339NanoTimeEncoder,
+ EncodeDuration: zapcore.StringDurationEncoder,
+ EncodeCaller: zapcore.ShortCallerEncoder,
+ })
+ }
+ logger.writer = writer
+ logger.core = zapcore.NewCore(enc, writer, level)
+ return logger, nil
+}
diff --git a/pkg/log/logger_test.go b/pkg/log/logger_test.go
new file mode 100644
index 0000000..3f3f258
--- /dev/null
+++ b/pkg/log/logger_test.go
@@ -0,0 +1,102 @@
+package log
+
+import (
+ "bytes"
+ "encoding/json"
+ "net/http"
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "go.uber.org/zap"
+)
+
+type fakeWriteSyncer struct {
+ buf bytes.Buffer
+}
+
+type fields struct {
+ Level string
+ Time string
+ Message string
+ Name string
+ Age int
+}
+
+func (fws *fakeWriteSyncer) Sync() error {
+ return nil
+}
+
+func (fws *fakeWriteSyncer) Write(p []byte) (int, error) {
+ return fws.buf.Write(p)
+}
+
+func (fws *fakeWriteSyncer) bytes() (p []byte) {
+ s := fws.buf.Bytes()
+ p = make([]byte, len(s))
+ copy(p, s)
+ fws.buf.Reset()
+ return
+}
+
+func unmarshalLogMessage(t *testing.T, data []byte) *fields {
+ var f fields
+ err := json.Unmarshal(data, &f)
+ assert.Nil(t, err, "failed to unmarshal log message: ", err)
+ return &f
+}
+
+func TestLogger(t *testing.T) {
+ for level := range levelMap {
+ t.Run("test log with level "+level, func(t *testing.T) {
+ fws := &fakeWriteSyncer{}
+ logger, err := NewLogger(WithLogLevel(level), WithWriteSyncer(fws))
+ assert.Nil(t, err, "failed to new logger: ", err)
+ defer logger.Close()
+
+ rv := reflect.ValueOf(logger)
+
+ handler := rv.MethodByName(http.CanonicalHeaderKey(level))
+ handler.Call([]reflect.Value{reflect.ValueOf("hello")})
+
+ assert.Nil(t, logger.Sync(), "failed to sync logger")
+
+ fields := unmarshalLogMessage(t, fws.bytes())
+ assert.Equal(t, fields.Level, level, "bad log level ", fields.Level)
+ assert.Equal(t, fields.Message, "hello", "bad log message ", fields.Message)
+
+ handler = rv.MethodByName(http.CanonicalHeaderKey(level) + "f")
+ handler.Call([]reflect.Value{reflect.ValueOf("hello I am %s"), reflect.ValueOf("alex")})
+
+ assert.Nil(t, logger.Sync(), "failed to sync logger")
+
+ fields = unmarshalLogMessage(t, fws.bytes())
+ assert.Equal(t, fields.Level, level, "bad log level ", fields.Level)
+ assert.Equal(t, fields.Message, "hello I am alex", "bad log message ", fields.Message)
+
+ handler = rv.MethodByName(http.CanonicalHeaderKey(level) + "w")
+ handler.Call([]reflect.Value{reflect.ValueOf("hello"), reflect.ValueOf(zap.String("name", "alex")), reflect.ValueOf(zap.Int("age", 3))})
+
+ assert.Nil(t, logger.Sync(), "failed to sync logger")
+
+ fields = unmarshalLogMessage(t, fws.bytes())
+ assert.Equal(t, fields.Level, level, "bad log level ", fields.Level)
+ assert.Equal(t, fields.Message, "hello", "bad log message ", fields.Message)
+ assert.Equal(t, fields.Name, "alex", "bad name field ", fields.Name)
+ assert.Equal(t, fields.Age, 3, "bad age field ", fields.Age)
+ })
+ }
+}
+
+func TestLogLevel(t *testing.T) {
+ fws := &fakeWriteSyncer{}
+ logger, err := NewLogger(WithLogLevel("error"), WithWriteSyncer(fws))
+ assert.Nil(t, err, "failed to new logger: ", err)
+ defer logger.Close()
+
+ logger.Warn("this message should be dropped")
+ assert.Nil(t, logger.Sync(), "failed to sync logger")
+
+ p := fws.bytes()
+ assert.Len(t, p, 0, "saw a message which should be dropped")
+}
diff --git a/pkg/log/options.go b/pkg/log/options.go
new file mode 100644
index 0000000..940e615
--- /dev/null
+++ b/pkg/log/options.go
@@ -0,0 +1,54 @@
+package log
+
+import (
+ "go.uber.org/zap/zapcore"
+)
+
+// Option configures how to set up logger.
+type Option interface {
+ apply(*options)
+}
+
+type funcOption struct {
+ do func(*options)
+}
+
+func (fo *funcOption) apply(o *options) {
+ fo.do(o)
+}
+
+type options struct {
+ writeSyncer zapcore.WriteSyncer
+ outputFile string
+ logLevel string
+ context string
+}
+
+// WithLogLevel sets the log level.
+func WithLogLevel(level string) Option {
+ return &funcOption{
+ do: func(o *options) {
+ o.logLevel = level
+ },
+ }
+}
+
+// WithOutputFile sets the output file path.
+func WithOutputFile(file string) Option {
+ return &funcOption{
+ do: func(o *options) {
+ o.outputFile = file
+ },
+ }
+}
+
+// WithWriteSyncer is a low level API which sets the underlying
+// WriteSyncer by providing a zapcore.WriterSyncer,
+// which has high priority than WithOutputFile.
+func WithWriteSyncer(ws zapcore.WriteSyncer) Option {
+ return &funcOption{
+ do: func(o *options) {
+ o.writeSyncer = ws
+ },
+ }
+}