update go modules
This commit is contained in:
parent
fceaa9ccf9
commit
6708641942
5
go.mod
5
go.mod
|
@ -57,6 +57,7 @@ require (
|
||||||
github.com/gophercloud/utils v0.0.0-20190124192022-a5c25e7a53a6
|
github.com/gophercloud/utils v0.0.0-20190124192022-a5c25e7a53a6
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
|
||||||
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 // indirect
|
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 // indirect
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
|
||||||
github.com/hashicorp/consul v1.4.0
|
github.com/hashicorp/consul v1.4.0
|
||||||
github.com/hashicorp/errwrap v1.0.0
|
github.com/hashicorp/errwrap v1.0.0
|
||||||
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de
|
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de
|
||||||
|
@ -114,7 +115,7 @@ require (
|
||||||
github.com/outscale/osc-go v0.0.1
|
github.com/outscale/osc-go v0.0.1
|
||||||
github.com/packer-community/winrmcp v0.0.0-20180921204643-0fd363d6159a
|
github.com/packer-community/winrmcp v0.0.0-20180921204643-0fd363d6159a
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible
|
github.com/pierrec/lz4 v2.0.5+incompatible
|
||||||
github.com/pkg/errors v0.8.0
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca
|
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca
|
||||||
github.com/posener/complete v1.1.1
|
github.com/posener/complete v1.1.1
|
||||||
github.com/profitbricks/profitbricks-sdk-go v4.0.2+incompatible
|
github.com/profitbricks/profitbricks-sdk-go v4.0.2+incompatible
|
||||||
|
@ -127,7 +128,7 @@ require (
|
||||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
|
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
|
||||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect
|
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.4.0
|
||||||
github.com/temoto/robotstxt v1.1.1 // indirect
|
github.com/temoto/robotstxt v1.1.1 // indirect
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible
|
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible
|
||||||
github.com/ucloud/ucloud-sdk-go v0.8.7
|
github.com/ucloud/ucloud-sdk-go v0.8.7
|
||||||
|
|
17
go.sum
17
go.sum
|
@ -127,6 +127,7 @@ github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
|
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
|
||||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=
|
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
|
@ -171,6 +172,8 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 h1:JIM+OacoOJRU30xpjMf8sulYqjr0ViA3WDrTX6j/yDI=
|
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 h1:JIM+OacoOJRU30xpjMf8sulYqjr0ViA3WDrTX6j/yDI=
|
||||||
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/hashicorp/consul v1.4.0 h1:PQTW4xCuAExEiSbhrsFsikzbW5gVBoi74BjUvYFyKHw=
|
github.com/hashicorp/consul v1.4.0 h1:PQTW4xCuAExEiSbhrsFsikzbW5gVBoi74BjUvYFyKHw=
|
||||||
|
@ -246,6 +249,8 @@ github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/
|
||||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
|
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
|
||||||
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
|
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77 h1:rJnR80lkojFgjdg/oQPhbZoY8t8uM51XMz8DrJrjabk=
|
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77 h1:rJnR80lkojFgjdg/oQPhbZoY8t8uM51XMz8DrJrjabk=
|
||||||
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/cpuid v0.0.0-20160106104451-349c67577817 h1:/7pPahIC+GoCm/euDCi2Pm29bAj9tc6TcK4Zcc8D3WI=
|
github.com/klauspost/cpuid v0.0.0-20160106104451-349c67577817 h1:/7pPahIC+GoCm/euDCi2Pm29bAj9tc6TcK4Zcc8D3WI=
|
||||||
|
@ -326,6 +331,7 @@ github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/oracle/oci-go-sdk v1.8.0 h1:4SO45bKV0I3/Mn1os3ANDZmV0eSE5z5CLdSUIkxtyzs=
|
github.com/oracle/oci-go-sdk v1.8.0 h1:4SO45bKV0I3/Mn1os3ANDZmV0eSE5z5CLdSUIkxtyzs=
|
||||||
github.com/oracle/oci-go-sdk v1.8.0/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
github.com/oracle/oci-go-sdk v1.8.0/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
github.com/outscale/osc-go v0.0.1 h1:hvBtORyu7sWSKW1norGlfIP8C7c2aegI2Vkq75SRPCE=
|
github.com/outscale/osc-go v0.0.1 h1:hvBtORyu7sWSKW1norGlfIP8C7c2aegI2Vkq75SRPCE=
|
||||||
|
@ -338,6 +344,8 @@ github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca h1:k8gsErq3rkcbAyCnpOycQsbw88NjCHk7L3KfBZKhQDQ=
|
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca h1:k8gsErq3rkcbAyCnpOycQsbw88NjCHk7L3KfBZKhQDQ=
|
||||||
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
|
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
@ -366,6 +374,8 @@ github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+D
|
||||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||||
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
||||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w=
|
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w=
|
||||||
|
@ -377,6 +387,8 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/temoto/robotstxt v1.1.1 h1:Gh8RCs8ouX3hRSxxK7B1mO5RFByQ4CmJZDwgom++JaA=
|
github.com/temoto/robotstxt v1.1.1 h1:Gh8RCs8ouX3hRSxxK7B1mO5RFByQ4CmJZDwgom++JaA=
|
||||||
github.com/temoto/robotstxt v1.1.1/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
|
github.com/temoto/robotstxt v1.1.1/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible h1:9sIWfe6ZC7xoSlshYWNGicPqomK7N+CsHMa1YFWBCWU=
|
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible h1:9sIWfe6ZC7xoSlshYWNGicPqomK7N+CsHMa1YFWBCWU=
|
||||||
|
@ -399,6 +411,9 @@ go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
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/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3 h1:KYQXGkl6vs02hK7pK4eIbw0NpNPedieTSTEiJ//bwGs=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3 h1:KYQXGkl6vs02hK7pK4eIbw0NpNPedieTSTEiJ//bwGs=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
@ -462,6 +477,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
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-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-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-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -477,6 +493,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuA
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/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=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Go template
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
||||||
|
### Windows template
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
### Kate template
|
||||||
|
# Swap Files #
|
||||||
|
.*.kate-swp
|
||||||
|
.swp.*
|
||||||
|
### SublimeText template
|
||||||
|
# cache files for sublime text
|
||||||
|
*.tmlanguage.cache
|
||||||
|
*.tmPreferences.cache
|
||||||
|
*.stTheme.cache
|
||||||
|
|
||||||
|
# workspace files are user-specific
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# project files should be checked into the repository, unless a significant
|
||||||
|
# proportion of contributors will probably not be using SublimeText
|
||||||
|
# *.sublime-project
|
||||||
|
|
||||||
|
# sftp configuration file
|
||||||
|
sftp-config.json
|
||||||
|
### Linux template
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff:
|
||||||
|
.idea
|
||||||
|
.idea/tasks.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
.idea/vcs.xml
|
||||||
|
.idea/jsLibraryMappings.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
.idea/dataSources.ids
|
||||||
|
.idea/dataSources.xml
|
||||||
|
.idea/dataSources.local.xml
|
||||||
|
.idea/sqlDataSources.xml
|
||||||
|
.idea/dynamic.xml
|
||||||
|
.idea/uiDesigner.xml
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
.idea/gradle.xml
|
||||||
|
.idea/libraries
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
.idea/mongoSettings.xml
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
### Xcode template
|
||||||
|
# Xcode
|
||||||
|
#
|
||||||
|
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||||
|
|
||||||
|
## Build generated
|
||||||
|
build/
|
||||||
|
DerivedData/
|
||||||
|
|
||||||
|
## Various settings
|
||||||
|
*.pbxuser
|
||||||
|
!default.pbxuser
|
||||||
|
*.mode1v3
|
||||||
|
!default.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
!default.mode2v3
|
||||||
|
*.perspectivev3
|
||||||
|
!default.perspectivev3
|
||||||
|
xcuserdata/
|
||||||
|
|
||||||
|
## Other
|
||||||
|
*.moved-aside
|
||||||
|
*.xccheckout
|
||||||
|
*.xcscmblueprint
|
||||||
|
### Eclipse template
|
||||||
|
|
||||||
|
.metadata
|
||||||
|
bin/
|
||||||
|
tmp/
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*~.nib
|
||||||
|
local.properties
|
||||||
|
.settings/
|
||||||
|
.loadpath
|
||||||
|
.recommenders
|
||||||
|
|
||||||
|
# Eclipse Core
|
||||||
|
.project
|
||||||
|
|
||||||
|
# External tool builders
|
||||||
|
.externalToolBuilders/
|
||||||
|
|
||||||
|
# Locally stored "Eclipse launch configurations"
|
||||||
|
*.launch
|
||||||
|
|
||||||
|
# PyDev specific (Python IDE for Eclipse)
|
||||||
|
*.pydevproject
|
||||||
|
|
||||||
|
# CDT-specific (C/C++ Development Tooling)
|
||||||
|
.cproject
|
||||||
|
|
||||||
|
# JDT-specific (Eclipse Java Development Tools)
|
||||||
|
.classpath
|
||||||
|
|
||||||
|
# Java annotation processor (APT)
|
||||||
|
.factorypath
|
||||||
|
|
||||||
|
# PDT-specific (PHP Development Tools)
|
||||||
|
.buildpath
|
||||||
|
|
||||||
|
# sbteclipse plugin
|
||||||
|
.target
|
||||||
|
|
||||||
|
# Tern plugin
|
||||||
|
.tern-project
|
||||||
|
|
||||||
|
# TeXlipse plugin
|
||||||
|
.texlipse
|
||||||
|
|
||||||
|
# STS (Spring Tool Suite)
|
||||||
|
.springBeans
|
||||||
|
|
||||||
|
# Code Recommenders
|
||||||
|
.recommenders/
|
||||||
|
|
||||||
|
|
||||||
|
coverage.txt
|
||||||
|
|
||||||
|
#vendor
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
.envrc
|
|
@ -0,0 +1,15 @@
|
||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.11.x
|
||||||
|
- 1.12.x
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- GO111MODULE=on
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make test
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Changelog
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
Types of changes:
|
||||||
|
- `Added` for new features.
|
||||||
|
- `Changed` for changes in existing functionality.
|
||||||
|
- `Deprecated` for soon-to-be removed features.
|
||||||
|
- `Removed` for now removed features.
|
||||||
|
- `Fixed` for any bug fixes.
|
||||||
|
- `Security` in case of vulnerabilities.
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
### Added
|
||||||
|
- This CHANGELOG file to keep track of changes.
|
||||||
|
- Support for go modules.
|
||||||
|
|
||||||
|
## 1.0.0 - 2018-05-08
|
||||||
|
### Added
|
||||||
|
- grpc_auth
|
||||||
|
- grpc_ctxtags
|
||||||
|
- grpc_zap
|
||||||
|
- grpc_logrus
|
||||||
|
- grpc_opentracing
|
||||||
|
- grpc_retry
|
||||||
|
- grpc_validator
|
||||||
|
- grpc_recovery
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/grpc-ecosystem/go-grpc-middleware/compare/v1.0.0...HEAD
|
20
vendor/github.com/grpc-ecosystem/go-grpc-middleware/CONTRIBUTING.md
generated
vendored
Normal file
20
vendor/github.com/grpc-ecosystem/go-grpc-middleware/CONTRIBUTING.md
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
We would love to have people submit pull requests and help make `grpc-ecosystem/go-grpc-middleware` even better 👍.
|
||||||
|
|
||||||
|
Fork, then clone the repo:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git@github.com:your-username/go-grpc-middleware.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Before checking in please run the following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make all
|
||||||
|
```
|
||||||
|
|
||||||
|
This will `vet`, `fmt`, regenerate documentation and run all tests.
|
||||||
|
|
||||||
|
|
||||||
|
Push to your fork and open a pull request.
|
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,85 @@
|
||||||
|
# Go gRPC Middleware
|
||||||
|
|
||||||
|
[![Travis Build](https://travis-ci.org/grpc-ecosystem/go-grpc-middleware.svg?branch=master)](https://travis-ci.org/grpc-ecosystem/go-grpc-middleware)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/grpc-ecosystem/go-grpc-middleware)](https://goreportcard.com/report/github.com/grpc-ecosystem/go-grpc-middleware)
|
||||||
|
[![GoDoc](http://img.shields.io/badge/GoDoc-Reference-blue.svg)](https://godoc.org/github.com/grpc-ecosystem/go-grpc-middleware)
|
||||||
|
[![SourceGraph](https://sourcegraph.com/github.com/grpc-ecosystem/go-grpc-middleware/-/badge.svg)](https://sourcegraph.com/github.com/grpc-ecosystem/go-grpc-middleware/?badge)
|
||||||
|
[![codecov](https://codecov.io/gh/grpc-ecosystem/go-grpc-middleware/branch/master/graph/badge.svg)](https://codecov.io/gh/grpc-ecosystem/go-grpc-middleware)
|
||||||
|
[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
|
||||||
|
[![quality: production](https://img.shields.io/badge/quality-production-orange.svg)](#status)
|
||||||
|
[![Slack](slack.png)](https://join.slack.com/t/improbable-eng/shared_invite/enQtMzQ1ODcyMzQ5MjM4LWY5ZWZmNGM2ODc5MmViNmQ3ZTA3ZTY3NzQwOTBlMTkzZmIxZTIxODk0OWU3YjZhNWVlNDU3MDlkZGViZjhkMjc)
|
||||||
|
|
||||||
|
[gRPC Go](https://github.com/grpc/grpc-go) Middleware: interceptors, helpers, utilities.
|
||||||
|
|
||||||
|
## Middleware
|
||||||
|
|
||||||
|
[gRPC Go](https://github.com/grpc/grpc-go) recently acquired support for
|
||||||
|
Interceptors, i.e. [middleware](https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81#.gv7tdlghs)
|
||||||
|
that is executed either on the gRPC Server before the request is passed onto the user's application logic, or on the gRPC client either around the user call. It is a perfect way to implement
|
||||||
|
common patterns: auth, logging, message, validation, retries or monitoring.
|
||||||
|
|
||||||
|
These are generic building blocks that make it easy to build multiple microservices easily.
|
||||||
|
The purpose of this repository is to act as a go-to point for such reusable functionality. It contains
|
||||||
|
some of them itself, but also will link to useful external repos.
|
||||||
|
|
||||||
|
`grpc_middleware` itself provides support for chaining interceptors, here's an example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||||
|
|
||||||
|
myServer := grpc.NewServer(
|
||||||
|
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
||||||
|
grpc_ctxtags.StreamServerInterceptor(),
|
||||||
|
grpc_opentracing.StreamServerInterceptor(),
|
||||||
|
grpc_prometheus.StreamServerInterceptor,
|
||||||
|
grpc_zap.StreamServerInterceptor(zapLogger),
|
||||||
|
grpc_auth.StreamServerInterceptor(myAuthFunction),
|
||||||
|
grpc_recovery.StreamServerInterceptor(),
|
||||||
|
)),
|
||||||
|
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
||||||
|
grpc_ctxtags.UnaryServerInterceptor(),
|
||||||
|
grpc_opentracing.UnaryServerInterceptor(),
|
||||||
|
grpc_prometheus.UnaryServerInterceptor,
|
||||||
|
grpc_zap.UnaryServerInterceptor(zapLogger),
|
||||||
|
grpc_auth.UnaryServerInterceptor(myAuthFunction),
|
||||||
|
grpc_recovery.UnaryServerInterceptor(),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Interceptors
|
||||||
|
|
||||||
|
*Please send a PR to add new interceptors or middleware to this list*
|
||||||
|
|
||||||
|
#### Auth
|
||||||
|
* [`grpc_auth`](auth) - a customizable (via `AuthFunc`) piece of auth middleware
|
||||||
|
|
||||||
|
#### Logging
|
||||||
|
* [`grpc_ctxtags`](tags/) - a library that adds a `Tag` map to context, with data populated from request body
|
||||||
|
* [`grpc_zap`](logging/zap/) - integration of [zap](https://github.com/uber-go/zap) logging library into gRPC handlers.
|
||||||
|
* [`grpc_logrus`](logging/logrus/) - integration of [logrus](https://github.com/sirupsen/logrus) logging library into gRPC handlers.
|
||||||
|
|
||||||
|
|
||||||
|
#### Monitoring
|
||||||
|
* [`grpc_prometheus`⚡](https://github.com/grpc-ecosystem/go-grpc-prometheus) - Prometheus client-side and server-side monitoring middleware
|
||||||
|
* [`otgrpc`⚡](https://github.com/grpc-ecosystem/grpc-opentracing/tree/master/go/otgrpc) - [OpenTracing](http://opentracing.io/) client-side and server-side interceptors
|
||||||
|
* [`grpc_opentracing`](tracing/opentracing) - [OpenTracing](http://opentracing.io/) client-side and server-side interceptors with support for streaming and handler-returned tags
|
||||||
|
|
||||||
|
#### Client
|
||||||
|
* [`grpc_retry`](retry/) - a generic gRPC response code retry mechanism, client-side middleware
|
||||||
|
|
||||||
|
#### Server
|
||||||
|
* [`grpc_validator`](validator/) - codegen inbound message validation from `.proto` options
|
||||||
|
* [`grpc_recovery`](recovery/) - turn panics into gRPC errors
|
||||||
|
* [`ratelimit`](ratelimit/) - grpc rate limiting by your own limiter
|
||||||
|
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
This code has been running in *production* since May 2016 as the basis of the gRPC micro services stack at [Improbable](https://improbable.io).
|
||||||
|
|
||||||
|
Additional tooling will be added, and contributions are welcome.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
`go-grpc-middleware` is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
|
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright 2016 Michal Witkowski. All Rights Reserved.
|
||||||
|
// See LICENSE for licensing terms.
|
||||||
|
|
||||||
|
// gRPC Server Interceptor chaining middleware.
|
||||||
|
|
||||||
|
package grpc_middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChainUnaryServer creates a single interceptor out of a chain of many interceptors.
|
||||||
|
//
|
||||||
|
// Execution is done in left-to-right order, including passing of context.
|
||||||
|
// For example ChainUnaryServer(one, two, three) will execute one before two before three, and three
|
||||||
|
// will see context changes of one and two.
|
||||||
|
func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor {
|
||||||
|
n := len(interceptors)
|
||||||
|
|
||||||
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
|
chainer := func(currentInter grpc.UnaryServerInterceptor, currentHandler grpc.UnaryHandler) grpc.UnaryHandler {
|
||||||
|
return func(currentCtx context.Context, currentReq interface{}) (interface{}, error) {
|
||||||
|
return currentInter(currentCtx, currentReq, info, currentHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chainedHandler := handler
|
||||||
|
for i := n - 1; i >= 0; i-- {
|
||||||
|
chainedHandler = chainer(interceptors[i], chainedHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
return chainedHandler(ctx, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainStreamServer creates a single interceptor out of a chain of many interceptors.
|
||||||
|
//
|
||||||
|
// Execution is done in left-to-right order, including passing of context.
|
||||||
|
// For example ChainUnaryServer(one, two, three) will execute one before two before three.
|
||||||
|
// If you want to pass context between interceptors, use WrapServerStream.
|
||||||
|
func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor {
|
||||||
|
n := len(interceptors)
|
||||||
|
|
||||||
|
return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||||
|
chainer := func(currentInter grpc.StreamServerInterceptor, currentHandler grpc.StreamHandler) grpc.StreamHandler {
|
||||||
|
return func(currentSrv interface{}, currentStream grpc.ServerStream) error {
|
||||||
|
return currentInter(currentSrv, currentStream, info, currentHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chainedHandler := handler
|
||||||
|
for i := n - 1; i >= 0; i-- {
|
||||||
|
chainedHandler = chainer(interceptors[i], chainedHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
return chainedHandler(srv, ss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainUnaryClient creates a single interceptor out of a chain of many interceptors.
|
||||||
|
//
|
||||||
|
// Execution is done in left-to-right order, including passing of context.
|
||||||
|
// For example ChainUnaryClient(one, two, three) will execute one before two before three.
|
||||||
|
func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor {
|
||||||
|
n := len(interceptors)
|
||||||
|
|
||||||
|
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||||
|
chainer := func(currentInter grpc.UnaryClientInterceptor, currentInvoker grpc.UnaryInvoker) grpc.UnaryInvoker {
|
||||||
|
return func(currentCtx context.Context, currentMethod string, currentReq, currentRepl interface{}, currentConn *grpc.ClientConn, currentOpts ...grpc.CallOption) error {
|
||||||
|
return currentInter(currentCtx, currentMethod, currentReq, currentRepl, currentConn, currentInvoker, currentOpts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chainedInvoker := invoker
|
||||||
|
for i := n - 1; i >= 0; i-- {
|
||||||
|
chainedInvoker = chainer(interceptors[i], chainedInvoker)
|
||||||
|
}
|
||||||
|
|
||||||
|
return chainedInvoker(ctx, method, req, reply, cc, opts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainStreamClient creates a single interceptor out of a chain of many interceptors.
|
||||||
|
//
|
||||||
|
// Execution is done in left-to-right order, including passing of context.
|
||||||
|
// For example ChainStreamClient(one, two, three) will execute one before two before three.
|
||||||
|
func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor {
|
||||||
|
n := len(interceptors)
|
||||||
|
|
||||||
|
return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||||
|
chainer := func(currentInter grpc.StreamClientInterceptor, currentStreamer grpc.Streamer) grpc.Streamer {
|
||||||
|
return func(currentCtx context.Context, currentDesc *grpc.StreamDesc, currentConn *grpc.ClientConn, currentMethod string, currentOpts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||||
|
return currentInter(currentCtx, currentDesc, currentConn, currentMethod, currentStreamer, currentOpts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chainedStreamer := streamer
|
||||||
|
for i := n - 1; i >= 0; i-- {
|
||||||
|
chainedStreamer = chainer(interceptors[i], chainedStreamer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return chainedStreamer(ctx, desc, cc, method, opts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chain creates a single interceptor out of a chain of many interceptors.
|
||||||
|
//
|
||||||
|
// WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors.
|
||||||
|
// Basically syntactic sugar.
|
||||||
|
func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption {
|
||||||
|
return grpc.UnaryInterceptor(ChainUnaryServer(interceptors...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStreamServerChain is a grpc.Server config option that accepts multiple stream interceptors.
|
||||||
|
// Basically syntactic sugar.
|
||||||
|
func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption {
|
||||||
|
return grpc.StreamInterceptor(ChainStreamServer(interceptors...))
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright 2016 Michal Witkowski. All Rights Reserved.
|
||||||
|
// See LICENSE for licensing terms.
|
||||||
|
|
||||||
|
/*
|
||||||
|
`grpc_middleware` is a collection of gRPC middleware packages: interceptors, helpers and tools.
|
||||||
|
|
||||||
|
Middleware
|
||||||
|
|
||||||
|
gRPC is a fantastic RPC middleware, which sees a lot of adoption in the Golang world. However, the
|
||||||
|
upstream gRPC codebase is relatively bare bones.
|
||||||
|
|
||||||
|
This package, and most of its child packages provides commonly needed middleware for gRPC:
|
||||||
|
client-side interceptors for retires, server-side interceptors for input validation and auth,
|
||||||
|
functions for chaining said interceptors, metadata convenience methods and more.
|
||||||
|
|
||||||
|
Chaining
|
||||||
|
|
||||||
|
By default, gRPC doesn't allow one to have more than one interceptor either on the client nor on
|
||||||
|
the server side. `grpc_middleware` provides convenient chaining methods
|
||||||
|
|
||||||
|
Simple way of turning a multiple interceptors into a single interceptor. Here's an example for
|
||||||
|
server chaining:
|
||||||
|
|
||||||
|
myServer := grpc.NewServer(
|
||||||
|
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(loggingStream, monitoringStream, authStream)),
|
||||||
|
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(loggingUnary, monitoringUnary, authUnary),
|
||||||
|
)
|
||||||
|
|
||||||
|
These interceptors will be executed from left to right: logging, monitoring and auth.
|
||||||
|
|
||||||
|
Here's an example for client side chaining:
|
||||||
|
|
||||||
|
clientConn, err = grpc.Dial(
|
||||||
|
address,
|
||||||
|
grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(monitoringClientUnary, retryUnary)),
|
||||||
|
grpc.WithStreamInterceptor(grpc_middleware.ChainStreamClient(monitoringClientStream, retryStream)),
|
||||||
|
)
|
||||||
|
client = pb_testproto.NewTestServiceClient(clientConn)
|
||||||
|
resp, err := client.PingEmpty(s.ctx, &myservice.Request{Msg: "hello"})
|
||||||
|
|
||||||
|
These interceptors will be executed from left to right: monitoring and then retry logic.
|
||||||
|
|
||||||
|
The retry interceptor will call every interceptor that follows it whenever when a retry happens.
|
||||||
|
|
||||||
|
Writing Your Own
|
||||||
|
|
||||||
|
Implementing your own interceptor is pretty trivial: there are interfaces for that. But the interesting
|
||||||
|
bit exposing common data to handlers (and other middleware), similarly to HTTP Middleware design.
|
||||||
|
For example, you may want to pass the identity of the caller from the auth interceptor all the way
|
||||||
|
to the handling function.
|
||||||
|
|
||||||
|
For example, a client side interceptor example for auth looks like:
|
||||||
|
|
||||||
|
func FakeAuthUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
|
newCtx := context.WithValue(ctx, "user_id", "john@example.com")
|
||||||
|
return handler(newCtx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
Unfortunately, it's not as easy for streaming RPCs. These have the `context.Context` embedded within
|
||||||
|
the `grpc.ServerStream` object. To pass values through context, a wrapper (`WrappedServerStream`) is
|
||||||
|
needed. For example:
|
||||||
|
|
||||||
|
func FakeAuthStreamingInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||||
|
newStream := grpc_middleware.WrapServerStream(stream)
|
||||||
|
newStream.WrappedContext = context.WithValue(ctx, "user_id", "john@example.com")
|
||||||
|
return handler(srv, stream)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
package grpc_middleware
|
|
@ -0,0 +1,17 @@
|
||||||
|
module github.com/grpc-ecosystem/go-grpc-middleware
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gogo/protobuf v1.2.1
|
||||||
|
github.com/golang/protobuf v1.3.2
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0
|
||||||
|
github.com/pkg/errors v0.8.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.4.2
|
||||||
|
github.com/stretchr/testify v1.4.0
|
||||||
|
go.uber.org/atomic v1.4.0 // indirect
|
||||||
|
go.uber.org/multierr v1.1.0 // indirect
|
||||||
|
go.uber.org/zap v1.10.0
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect
|
||||||
|
google.golang.org/grpc v1.19.0
|
||||||
|
)
|
|
@ -0,0 +1,78 @@
|
||||||
|
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
|
||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
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/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||||
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
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/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
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.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||||
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
||||||
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||||
|
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=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
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/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
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/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.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
@ -0,0 +1,17 @@
|
||||||
|
SHELL=/bin/bash
|
||||||
|
|
||||||
|
GOFILES_NOVENDOR = $(shell go list ./... | grep -v /vendor/)
|
||||||
|
|
||||||
|
all: vet fmt test
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
go fmt $(GOFILES_NOVENDOR)
|
||||||
|
|
||||||
|
vet:
|
||||||
|
# do not check lostcancel, they are intentional.
|
||||||
|
go vet -lostcancel=false $(GOFILES_NOVENDOR)
|
||||||
|
|
||||||
|
test: vet
|
||||||
|
./scripts/test_all.sh
|
||||||
|
|
||||||
|
.PHONY: all test
|
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2016 Michal Witkowski. All Rights Reserved.
|
||||||
|
// See LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package grpc_middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WrappedServerStream is a thin wrapper around grpc.ServerStream that allows modifying context.
|
||||||
|
type WrappedServerStream struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
// WrappedContext is the wrapper's own Context. You can assign it.
|
||||||
|
WrappedContext context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context returns the wrapper's WrappedContext, overwriting the nested grpc.ServerStream.Context()
|
||||||
|
func (w *WrappedServerStream) Context() context.Context {
|
||||||
|
return w.WrappedContext
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapServerStream returns a ServerStream that has the ability to overwrite context.
|
||||||
|
func WrapServerStream(stream grpc.ServerStream) *WrappedServerStream {
|
||||||
|
if existing, ok := stream.(*WrappedServerStream); ok {
|
||||||
|
return existing
|
||||||
|
}
|
||||||
|
return &WrappedServerStream{ServerStream: stream, WrappedContext: stream.Context()}
|
||||||
|
}
|
|
@ -1,10 +1,14 @@
|
||||||
language: go
|
language: go
|
||||||
go_import_path: github.com/pkg/errors
|
go_import_path: github.com/pkg/errors
|
||||||
go:
|
go:
|
||||||
- 1.4.3
|
- 1.4.x
|
||||||
- 1.5.4
|
- 1.5.x
|
||||||
- 1.6.2
|
- 1.6.x
|
||||||
- 1.7.1
|
- 1.7.x
|
||||||
|
- 1.8.x
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
- 1.11.x
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors)
|
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
|
||||||
|
|
||||||
Package errors provides simple error handling primitives.
|
Package errors provides simple error handling primitives.
|
||||||
|
|
||||||
|
@ -47,6 +47,6 @@ We welcome pull requests, bug fixes and issue reports. With that said, the bar f
|
||||||
|
|
||||||
Before proposing a change, please discuss your change by raising an issue.
|
Before proposing a change, please discuss your change by raising an issue.
|
||||||
|
|
||||||
## Licence
|
## License
|
||||||
|
|
||||||
BSD-2-Clause
|
BSD-2-Clause
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// return err
|
// return err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// which applied recursively up the call stack results in error reports
|
// which when applied recursively up the call stack results in error reports
|
||||||
// without context or debugging information. The errors package allows
|
// without context or debugging information. The errors package allows
|
||||||
// programmers to add context to the failure path in their code in a way
|
// programmers to add context to the failure path in their code in a way
|
||||||
// that does not destroy the original value of the error.
|
// that does not destroy the original value of the error.
|
||||||
|
@ -15,16 +15,17 @@
|
||||||
//
|
//
|
||||||
// The errors.Wrap function returns a new error that adds context to the
|
// The errors.Wrap function returns a new error that adds context to the
|
||||||
// original error by recording a stack trace at the point Wrap is called,
|
// original error by recording a stack trace at the point Wrap is called,
|
||||||
// and the supplied message. For example
|
// together with the supplied message. For example
|
||||||
//
|
//
|
||||||
// _, err := ioutil.ReadAll(r)
|
// _, err := ioutil.ReadAll(r)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return errors.Wrap(err, "read failed")
|
// return errors.Wrap(err, "read failed")
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// If additional control is required the errors.WithStack and errors.WithMessage
|
// If additional control is required, the errors.WithStack and
|
||||||
// functions destructure errors.Wrap into its component operations of annotating
|
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||||
// an error with a stack trace and an a message, respectively.
|
// operations: annotating an error with a stack trace and with a message,
|
||||||
|
// respectively.
|
||||||
//
|
//
|
||||||
// Retrieving the cause of an error
|
// Retrieving the cause of an error
|
||||||
//
|
//
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||||
// the topmost error which does not implement causer, which is assumed to be
|
// the topmost error that does not implement causer, which is assumed to be
|
||||||
// the original cause. For example:
|
// the original cause. For example:
|
||||||
//
|
//
|
||||||
// switch err := errors.Cause(err).(type) {
|
// switch err := errors.Cause(err).(type) {
|
||||||
|
@ -48,16 +49,16 @@
|
||||||
// // unknown error
|
// // unknown error
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// causer interface is not exported by this package, but is considered a part
|
// Although the causer interface is not exported by this package, it is
|
||||||
// of stable public API.
|
// considered a part of its stable public interface.
|
||||||
//
|
//
|
||||||
// Formatted printing of errors
|
// Formatted printing of errors
|
||||||
//
|
//
|
||||||
// All error values returned from this package implement fmt.Formatter and can
|
// All error values returned from this package implement fmt.Formatter and can
|
||||||
// be formatted by the fmt package. The following verbs are supported
|
// be formatted by the fmt package. The following verbs are supported:
|
||||||
//
|
//
|
||||||
// %s print the error. If the error has a Cause it will be
|
// %s print the error. If the error has a Cause it will be
|
||||||
// printed recursively
|
// printed recursively.
|
||||||
// %v see %s
|
// %v see %s
|
||||||
// %+v extended format. Each Frame of the error's StackTrace will
|
// %+v extended format. Each Frame of the error's StackTrace will
|
||||||
// be printed in detail.
|
// be printed in detail.
|
||||||
|
@ -65,13 +66,13 @@
|
||||||
// Retrieving the stack trace of an error or wrapper
|
// Retrieving the stack trace of an error or wrapper
|
||||||
//
|
//
|
||||||
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||||
// invoked. This information can be retrieved with the following interface.
|
// invoked. This information can be retrieved with the following interface:
|
||||||
//
|
//
|
||||||
// type stackTracer interface {
|
// type stackTracer interface {
|
||||||
// StackTrace() errors.StackTrace
|
// StackTrace() errors.StackTrace
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Where errors.StackTrace is defined as
|
// The returned errors.StackTrace type is defined as
|
||||||
//
|
//
|
||||||
// type StackTrace []Frame
|
// type StackTrace []Frame
|
||||||
//
|
//
|
||||||
|
@ -85,8 +86,8 @@
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// stackTracer interface is not exported by this package, but is considered a part
|
// Although the stackTracer interface is not exported by this package, it is
|
||||||
// of stable public API.
|
// considered a part of its stable public interface.
|
||||||
//
|
//
|
||||||
// See the documentation for Frame.Format for more details.
|
// See the documentation for Frame.Format for more details.
|
||||||
package errors
|
package errors
|
||||||
|
@ -192,7 +193,7 @@ func Wrap(err error, message string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapf returns an error annotating err with a stack trace
|
// Wrapf returns an error annotating err with a stack trace
|
||||||
// at the point Wrapf is call, and the format specifier.
|
// at the point Wrapf is called, and the format specifier.
|
||||||
// If err is nil, Wrapf returns nil.
|
// If err is nil, Wrapf returns nil.
|
||||||
func Wrapf(err error, format string, args ...interface{}) error {
|
func Wrapf(err error, format string, args ...interface{}) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -220,6 +221,18 @@ func WithMessage(err error, message string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMessagef annotates err with the format specifier.
|
||||||
|
// If err is nil, WithMessagef returns nil.
|
||||||
|
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type withMessage struct {
|
type withMessage struct {
|
||||||
cause error
|
cause error
|
||||||
msg string
|
msg string
|
||||||
|
|
|
@ -46,7 +46,8 @@ func (f Frame) line() int {
|
||||||
//
|
//
|
||||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
//
|
//
|
||||||
// %+s path of source file relative to the compile time GOPATH
|
// %+s function name and path of source file relative to the compile time
|
||||||
|
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||||
// %+v equivalent to %+s:%d
|
// %+v equivalent to %+s:%d
|
||||||
func (f Frame) Format(s fmt.State, verb rune) {
|
func (f Frame) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
|
@ -79,6 +80,14 @@ func (f Frame) Format(s fmt.State, verb rune) {
|
||||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||||
type StackTrace []Frame
|
type StackTrace []Frame
|
||||||
|
|
||||||
|
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s lists source files for each Frame in the stack
|
||||||
|
// %v lists the source file and line number for each Frame in the stack
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 'v':
|
case 'v':
|
||||||
|
@ -136,43 +145,3 @@ func funcname(name string) string {
|
||||||
i = strings.Index(name, ".")
|
i = strings.Index(name, ".")
|
||||||
return name[i+1:]
|
return name[i+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func trimGOPATH(name, file string) string {
|
|
||||||
// Here we want to get the source file path relative to the compile time
|
|
||||||
// GOPATH. As of Go 1.6.x there is no direct way to know the compiled
|
|
||||||
// GOPATH at runtime, but we can infer the number of path segments in the
|
|
||||||
// GOPATH. We note that fn.Name() returns the function name qualified by
|
|
||||||
// the import path, which does not include the GOPATH. Thus we can trim
|
|
||||||
// segments from the beginning of the file path until the number of path
|
|
||||||
// separators remaining is one more than the number of path separators in
|
|
||||||
// the function name. For example, given:
|
|
||||||
//
|
|
||||||
// GOPATH /home/user
|
|
||||||
// file /home/user/src/pkg/sub/file.go
|
|
||||||
// fn.Name() pkg/sub.Type.Method
|
|
||||||
//
|
|
||||||
// We want to produce:
|
|
||||||
//
|
|
||||||
// pkg/sub/file.go
|
|
||||||
//
|
|
||||||
// From this we can easily see that fn.Name() has one less path separator
|
|
||||||
// than our desired output. We count separators from the end of the file
|
|
||||||
// path until it finds two more than in the function name and then move
|
|
||||||
// one character forward to preserve the initial path segment without a
|
|
||||||
// leading separator.
|
|
||||||
const sep = "/"
|
|
||||||
goal := strings.Count(name, sep) + 2
|
|
||||||
i := len(file)
|
|
||||||
for n := 0; n < goal; n++ {
|
|
||||||
i = strings.LastIndex(file[:i], sep)
|
|
||||||
if i == -1 {
|
|
||||||
// not enough separators found, set i so that the slice expression
|
|
||||||
// below leaves file unmodified
|
|
||||||
i = -len(sep)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// get back to 0 or trim the leading separator
|
|
||||||
file = file[i+len(sep):]
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,52 +1,25 @@
|
||||||
language: go
|
language: go
|
||||||
go_import_path: github.com/sirupsen/logrus
|
go_import_path: github.com/sirupsen/logrus
|
||||||
|
git:
|
||||||
|
depth: 1
|
||||||
env:
|
env:
|
||||||
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
- GO111MODULE=on
|
||||||
|
- GO111MODULE=off
|
||||||
|
go: [ 1.11.x, 1.12.x ]
|
||||||
|
os: [ linux, osx ]
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
exclude:
|
||||||
- go: 1.10.x
|
- go: 1.12.x
|
||||||
install:
|
|
||||||
- go get github.com/stretchr/testify/assert
|
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
|
||||||
- go get golang.org/x/sys/unix
|
|
||||||
- go get golang.org/x/sys/windows
|
|
||||||
script:
|
|
||||||
- go test -race -v ./...
|
|
||||||
- go: 1.11.x
|
|
||||||
env: GO111MODULE=on
|
|
||||||
install:
|
|
||||||
- go mod download
|
|
||||||
script:
|
|
||||||
- go test -race -v ./...
|
|
||||||
- go: 1.11.x
|
|
||||||
env: GO111MODULE=off
|
env: GO111MODULE=off
|
||||||
install:
|
|
||||||
- go get github.com/stretchr/testify/assert
|
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
|
||||||
- go get golang.org/x/sys/unix
|
|
||||||
- go get golang.org/x/sys/windows
|
|
||||||
script:
|
|
||||||
- go test -race -v ./...
|
|
||||||
- go: 1.10.x
|
|
||||||
install:
|
|
||||||
- go get github.com/stretchr/testify/assert
|
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
|
||||||
- go get golang.org/x/sys/unix
|
|
||||||
- go get golang.org/x/sys/windows
|
|
||||||
script:
|
|
||||||
- go test -race -v -tags appengine ./...
|
|
||||||
- go: 1.11.x
|
- go: 1.11.x
|
||||||
env: GO111MODULE=on
|
os: osx
|
||||||
install:
|
install:
|
||||||
- go mod download
|
- ./travis/install.sh
|
||||||
script:
|
- if [[ "$GO111MODULE" == "on" ]]; then go mod download; fi
|
||||||
- go test -race -v -tags appengine ./...
|
- if [[ "$GO111MODULE" == "off" ]]; then go get github.com/stretchr/testify/assert golang.org/x/sys/unix github.com/konsorten/go-windows-terminal-sequences; fi
|
||||||
- go: 1.11.x
|
script:
|
||||||
env: GO111MODULE=off
|
- ./travis/cross_build.sh
|
||||||
install:
|
- export GOMAXPROCS=4
|
||||||
- go get github.com/stretchr/testify/assert
|
- export GORACE=halt_on_error=1
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
- go test -race -v ./...
|
||||||
- go get golang.org/x/sys/unix
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then go test -race -v -tags appengine ./... ; fi
|
||||||
- go get golang.org/x/sys/windows
|
|
||||||
script:
|
|
||||||
- go test -race -v -tags appengine ./...
|
|
||||||
|
|
|
@ -1,3 +1,38 @@
|
||||||
|
# 1.4.2
|
||||||
|
* Fixes build break for plan9, nacl, solaris
|
||||||
|
# 1.4.1
|
||||||
|
This new release introduces:
|
||||||
|
* Enhance TextFormatter to not print caller information when they are empty (#944)
|
||||||
|
* Remove dependency on golang.org/x/crypto (#932, #943)
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
* Fix Entry.WithContext method to return a copy of the initial entry (#941)
|
||||||
|
|
||||||
|
# 1.4.0
|
||||||
|
This new release introduces:
|
||||||
|
* Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
|
||||||
|
* Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter (#909, #911)
|
||||||
|
* Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919).
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
* Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893).
|
||||||
|
* Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903)
|
||||||
|
* Fix infinite recursion on unknown `Level.String()` (#907)
|
||||||
|
* Fix race condition in `getCaller` (#916).
|
||||||
|
|
||||||
|
|
||||||
|
# 1.3.0
|
||||||
|
This new release introduces:
|
||||||
|
* Log, Logf, Logln functions for Logger and Entry that take a Level
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
* Building prometheus node_exporter on AIX (#840)
|
||||||
|
* Race condition in TextFormatter (#468)
|
||||||
|
* Travis CI import path (#868)
|
||||||
|
* Remove coloured output on Windows (#862)
|
||||||
|
* Pointer to func as field in JSONFormatter (#870)
|
||||||
|
* Properly marshal Levels (#873)
|
||||||
|
|
||||||
# 1.2.0
|
# 1.2.0
|
||||||
This new release introduces:
|
This new release introduces:
|
||||||
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
|
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
|
||||||
|
|
|
@ -365,6 +365,7 @@ Third party logging formatters:
|
||||||
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
||||||
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||||
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
|
||||||
|
|
||||||
You can define your formatter by implementing the `Formatter` interface,
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
|
|
@ -51,9 +51,9 @@ func Exit(code int) {
|
||||||
os.Exit(code)
|
os.Exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
|
// RegisterExitHandler appends a Logrus Exit handler to the list of handlers,
|
||||||
// all handlers. The handlers will also be invoked when any Fatal log entry is
|
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
|
||||||
// made.
|
// any Fatal log entry is made.
|
||||||
//
|
//
|
||||||
// This method is useful when a caller wishes to use logrus to log a fatal
|
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||||
// message but also needs to gracefully shutdown. An example usecase could be
|
// message but also needs to gracefully shutdown. An example usecase could be
|
||||||
|
@ -62,3 +62,15 @@ func Exit(code int) {
|
||||||
func RegisterExitHandler(handler func()) {
|
func RegisterExitHandler(handler func()) {
|
||||||
handlers = append(handlers, handler)
|
handlers = append(handlers, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeferExitHandler prepends a Logrus Exit handler to the list of handlers,
|
||||||
|
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
|
||||||
|
// any Fatal log entry is made.
|
||||||
|
//
|
||||||
|
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||||
|
// message but also needs to gracefully shutdown. An example usecase could be
|
||||||
|
// closing database connections, or sending a alert that the application is
|
||||||
|
// closing.
|
||||||
|
func DeferExitHandler(handler func()) {
|
||||||
|
handlers = append([]func(){handler}, handlers...)
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -69,6 +70,9 @@ type Entry struct {
|
||||||
// When formatter is called in entry.log(), a Buffer may be set to entry
|
// When formatter is called in entry.log(), a Buffer may be set to entry
|
||||||
Buffer *bytes.Buffer
|
Buffer *bytes.Buffer
|
||||||
|
|
||||||
|
// Contains the context set by the user. Useful for hook processing etc.
|
||||||
|
Context context.Context
|
||||||
|
|
||||||
// err may contain a field formatting error
|
// err may contain a field formatting error
|
||||||
err string
|
err string
|
||||||
}
|
}
|
||||||
|
@ -97,6 +101,11 @@ func (entry *Entry) WithError(err error) *Entry {
|
||||||
return entry.WithField(ErrorKey, err)
|
return entry.WithField(ErrorKey, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a context to the Entry.
|
||||||
|
func (entry *Entry) WithContext(ctx context.Context) *Entry {
|
||||||
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: entry.Time, err: entry.err, Context: ctx}
|
||||||
|
}
|
||||||
|
|
||||||
// Add a single field to the Entry.
|
// Add a single field to the Entry.
|
||||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
return entry.WithFields(Fields{key: value})
|
return entry.WithFields(Fields{key: value})
|
||||||
|
@ -130,12 +139,12 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr}
|
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overrides the time of the Entry.
|
// Overrides the time of the Entry.
|
||||||
func (entry *Entry) WithTime(t time.Time) *Entry {
|
func (entry *Entry) WithTime(t time.Time) *Entry {
|
||||||
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err}
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err, Context: entry.Context}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPackageName reduces a fully qualified function name to the package name
|
// getPackageName reduces a fully qualified function name to the package name
|
||||||
|
@ -156,20 +165,23 @@ func getPackageName(f string) string {
|
||||||
|
|
||||||
// getCaller retrieves the name of the first non-logrus calling function
|
// getCaller retrieves the name of the first non-logrus calling function
|
||||||
func getCaller() *runtime.Frame {
|
func getCaller() *runtime.Frame {
|
||||||
|
|
||||||
|
// cache this package's fully-qualified name
|
||||||
|
callerInitOnce.Do(func() {
|
||||||
|
pcs := make([]uintptr, 2)
|
||||||
|
_ = runtime.Callers(0, pcs)
|
||||||
|
logrusPackage = getPackageName(runtime.FuncForPC(pcs[1]).Name())
|
||||||
|
|
||||||
|
// now that we have the cache, we can skip a minimum count of known-logrus functions
|
||||||
|
// XXX this is dubious, the number of frames may vary
|
||||||
|
minimumCallerDepth = knownLogrusFrames
|
||||||
|
})
|
||||||
|
|
||||||
// Restrict the lookback frames to avoid runaway lookups
|
// Restrict the lookback frames to avoid runaway lookups
|
||||||
pcs := make([]uintptr, maximumCallerDepth)
|
pcs := make([]uintptr, maximumCallerDepth)
|
||||||
depth := runtime.Callers(minimumCallerDepth, pcs)
|
depth := runtime.Callers(minimumCallerDepth, pcs)
|
||||||
frames := runtime.CallersFrames(pcs[:depth])
|
frames := runtime.CallersFrames(pcs[:depth])
|
||||||
|
|
||||||
// cache this package's fully-qualified name
|
|
||||||
callerInitOnce.Do(func() {
|
|
||||||
logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
|
|
||||||
|
|
||||||
// now that we have the cache, we can skip a minimum count of known-logrus functions
|
|
||||||
// XXX this is dubious, the number of frames may vary store an entry in a logger interface
|
|
||||||
minimumCallerDepth = knownLogrusFrames
|
|
||||||
})
|
|
||||||
|
|
||||||
for f, again := frames.Next(); again; f, again = frames.Next() {
|
for f, again := frames.Next(); again; f, again = frames.Next() {
|
||||||
pkg := getPackageName(f.Function)
|
pkg := getPackageName(f.Function)
|
||||||
|
|
||||||
|
@ -298,7 +310,9 @@ func (entry *Entry) Panic(args ...interface{}) {
|
||||||
// Entry Printf family functions
|
// Entry Printf family functions
|
||||||
|
|
||||||
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
||||||
entry.Log(level, fmt.Sprintf(format, args...))
|
if entry.Logger.IsLevelEnabled(level) {
|
||||||
|
entry.Log(level, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -55,6 +56,11 @@ func WithError(err error) *Entry {
|
||||||
return std.WithField(ErrorKey, err)
|
return std.WithField(ErrorKey, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithContext creates an entry from the standard logger and adds a context to it.
|
||||||
|
func WithContext(ctx context.Context) *Entry {
|
||||||
|
return std.WithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// WithField creates an entry from the standard logger and adds a field to
|
// WithField creates an entry from the standard logger and adds a field to
|
||||||
// it. If you want multiple fields, use `WithFields`.
|
// it. If you want multiple fields, use `WithFields`.
|
||||||
//
|
//
|
||||||
|
|
|
@ -6,6 +6,5 @@ require (
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/stretchr/objx v0.1.1 // indirect
|
github.com/stretchr/objx v0.1.1 // indirect
|
||||||
github.com/stretchr/testify v1.2.2
|
github.com/stretchr/testify v1.2.2
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@ 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs=
|
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -9,7 +10,7 @@ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
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=
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fieldKey string
|
type fieldKey string
|
||||||
|
@ -42,6 +43,12 @@ type JSONFormatter struct {
|
||||||
// }
|
// }
|
||||||
FieldMap FieldMap
|
FieldMap FieldMap
|
||||||
|
|
||||||
|
// CallerPrettyfier can be set by the user to modify the content
|
||||||
|
// of the function and file keys in the json data when ReportCaller is
|
||||||
|
// activated. If any of the returned value is the empty string the
|
||||||
|
// corresponding key will be removed from json fields.
|
||||||
|
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
||||||
|
|
||||||
// PrettyPrint will indent all json logs
|
// PrettyPrint will indent all json logs
|
||||||
PrettyPrint bool
|
PrettyPrint bool
|
||||||
}
|
}
|
||||||
|
@ -82,8 +89,17 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
||||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
||||||
if entry.HasCaller() {
|
if entry.HasCaller() {
|
||||||
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
|
funcVal := entry.Caller.Function
|
||||||
data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
if f.CallerPrettyfier != nil {
|
||||||
|
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||||
|
}
|
||||||
|
if funcVal != "" {
|
||||||
|
data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
|
||||||
|
}
|
||||||
|
if fileVal != "" {
|
||||||
|
data[f.FieldMap.resolve(FieldKeyFile)] = fileVal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var b *bytes.Buffer
|
var b *bytes.Buffer
|
||||||
|
@ -98,7 +114,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
encoder.SetIndent("", " ")
|
encoder.SetIndent("", " ")
|
||||||
}
|
}
|
||||||
if err := encoder.Encode(data); err != nil {
|
if err := encoder.Encode(data); err != nil {
|
||||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -124,6 +125,13 @@ func (logger *Logger) WithError(err error) *Entry {
|
||||||
return entry.WithError(err)
|
return entry.WithError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a context to the log entry.
|
||||||
|
func (logger *Logger) WithContext(ctx context.Context) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// Overrides the time of the log entry.
|
// Overrides the time of the log entry.
|
||||||
func (logger *Logger) WithTime(t time.Time) *Entry {
|
func (logger *Logger) WithTime(t time.Time) *Entry {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
|
@ -200,7 +208,7 @@ func (logger *Logger) Info(args ...interface{}) {
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
entry.Info(args...)
|
entry.Print(args...)
|
||||||
logger.releaseEntry(entry)
|
logger.releaseEntry(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +264,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
logger.Warn(args...)
|
logger.Warnln(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (level Level) MarshalText() ([]byte, error) {
|
||||||
return []byte("panic"), nil
|
return []byte("panic"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("not a valid lorus level %q", level)
|
return nil, fmt.Errorf("not a valid logrus level %d", level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A constant exposing all logging levels
|
// A constant exposing all logging levels
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// +build !appengine,!js,!windows,aix
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// +build darwin dragonfly freebsd netbsd openbsd
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
const ioctlReadTermios = unix.TIOCGETA
|
||||||
|
|
||||||
|
func isTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build js
|
// +build js nacl plan9
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
// +build !appengine,!js,!windows,!aix
|
// +build !appengine,!js,!windows,!nacl,!plan9
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
switch v := w.(type) {
|
switch v := w.(type) {
|
||||||
case *os.File:
|
case *os.File:
|
||||||
return terminal.IsTerminal(int(v.Fd()))
|
return isTerminal(int(v.Fd()))
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func isTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
|
||||||
|
return err == nil
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// +build linux aix
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
const ioctlReadTermios = unix.TCGETS
|
||||||
|
|
||||||
|
func isTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
|
@ -6,15 +6,29 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func initTerminal(w io.Writer) {
|
||||||
|
switch v := w.(type) {
|
||||||
|
case *os.File:
|
||||||
|
sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
var ret bool
|
||||||
switch v := w.(type) {
|
switch v := w.(type) {
|
||||||
case *os.File:
|
case *os.File:
|
||||||
var mode uint32
|
var mode uint32
|
||||||
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
|
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
|
||||||
return err == nil
|
ret = (err == nil)
|
||||||
default:
|
default:
|
||||||
return false
|
ret = false
|
||||||
}
|
}
|
||||||
|
if ret {
|
||||||
|
initTerminal(w)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func initTerminal(w io.Writer) {
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// +build !appengine,!js,windows
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
|
||||||
)
|
|
||||||
|
|
||||||
func initTerminal(w io.Writer) {
|
|
||||||
switch v := w.(type) {
|
|
||||||
case *os.File:
|
|
||||||
sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,18 +12,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
nocolor = 0
|
red = 31
|
||||||
red = 31
|
yellow = 33
|
||||||
green = 32
|
blue = 36
|
||||||
yellow = 33
|
gray = 37
|
||||||
blue = 36
|
|
||||||
gray = 37
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var baseTimestamp time.Time
|
||||||
baseTimestamp time.Time
|
|
||||||
emptyFieldMap FieldMap
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseTimestamp = time.Now()
|
baseTimestamp = time.Now()
|
||||||
|
@ -77,16 +72,18 @@ type TextFormatter struct {
|
||||||
// FieldKeyMsg: "@message"}}
|
// FieldKeyMsg: "@message"}}
|
||||||
FieldMap FieldMap
|
FieldMap FieldMap
|
||||||
|
|
||||||
|
// CallerPrettyfier can be set by the user to modify the content
|
||||||
|
// of the function and file keys in the data when ReportCaller is
|
||||||
|
// activated. If any of the returned value is the empty string the
|
||||||
|
// corresponding key will be removed from fields.
|
||||||
|
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
||||||
|
|
||||||
terminalInitOnce sync.Once
|
terminalInitOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) init(entry *Entry) {
|
func (f *TextFormatter) init(entry *Entry) {
|
||||||
if entry.Logger != nil {
|
if entry.Logger != nil {
|
||||||
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
||||||
|
|
||||||
if f.isTerminal {
|
|
||||||
initTerminal(entry.Logger.Out)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +115,8 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var funcVal, fileVal string
|
||||||
|
|
||||||
fixedKeys := make([]string, 0, 4+len(data))
|
fixedKeys := make([]string, 0, 4+len(data))
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
||||||
|
@ -130,8 +129,19 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
||||||
}
|
}
|
||||||
if entry.HasCaller() {
|
if entry.HasCaller() {
|
||||||
fixedKeys = append(fixedKeys,
|
if f.CallerPrettyfier != nil {
|
||||||
f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile))
|
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||||
|
} else {
|
||||||
|
funcVal = entry.Caller.Function
|
||||||
|
fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if funcVal != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc))
|
||||||
|
}
|
||||||
|
if fileVal != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !f.DisableSorting {
|
if !f.DisableSorting {
|
||||||
|
@ -166,6 +176,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
if f.isColored() {
|
if f.isColored() {
|
||||||
f.printColored(b, entry, keys, data, timestampFormat)
|
f.printColored(b, entry, keys, data, timestampFormat)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for _, key := range fixedKeys {
|
for _, key := range fixedKeys {
|
||||||
var value interface{}
|
var value interface{}
|
||||||
switch {
|
switch {
|
||||||
|
@ -178,9 +189,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
||||||
value = entry.err
|
value = entry.err
|
||||||
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
||||||
value = entry.Caller.Function
|
value = funcVal
|
||||||
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
||||||
value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
value = fileVal
|
||||||
default:
|
default:
|
||||||
value = data[key]
|
value = data[key]
|
||||||
}
|
}
|
||||||
|
@ -215,10 +226,21 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
||||||
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
||||||
|
|
||||||
caller := ""
|
caller := ""
|
||||||
|
|
||||||
if entry.HasCaller() {
|
if entry.HasCaller() {
|
||||||
caller = fmt.Sprintf("%s:%d %s()",
|
funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
|
||||||
entry.Caller.File, entry.Caller.Line, entry.Caller.Function)
|
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
|
||||||
|
if f.CallerPrettyfier != nil {
|
||||||
|
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fileVal == "" {
|
||||||
|
caller = funcVal
|
||||||
|
} else if funcVal == "" {
|
||||||
|
caller = fileVal
|
||||||
|
} else {
|
||||||
|
caller = fileVal + " " + funcVal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.DisableTimestamp {
|
if f.DisableTimestamp {
|
||||||
|
|
|
@ -113,6 +113,17 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
||||||
return Error(t, err, append([]interface{}{msg}, args...)...)
|
return Error(t, err, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eventuallyf asserts that given condition will be met in waitFor time,
|
||||||
|
// periodically checking target function each tick.
|
||||||
|
//
|
||||||
|
// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||||
|
func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
// Exactlyf asserts that two objects are equal in value and type.
|
// Exactlyf asserts that two objects are equal in value and type.
|
||||||
//
|
//
|
||||||
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
|
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
|
||||||
|
@ -157,6 +168,31 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool
|
||||||
return FileExists(t, path, append([]interface{}{msg}, args...)...)
|
return FileExists(t, path, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Greaterf asserts that the first element is greater than the second
|
||||||
|
//
|
||||||
|
// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
|
||||||
|
// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
|
||||||
|
// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
|
||||||
|
func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Greater(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
|
||||||
|
//
|
||||||
|
// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
|
||||||
|
// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
|
||||||
|
// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
|
||||||
|
// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
|
||||||
|
func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
// HTTPBodyContainsf asserts that a specified handler returns a
|
// HTTPBodyContainsf asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
|
@ -289,6 +325,14 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
|
||||||
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||||
|
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
// Lenf asserts that the specified object has specific length.
|
// Lenf asserts that the specified object has specific length.
|
||||||
// Lenf also fails if the object has a type that len() not accept.
|
// Lenf also fails if the object has a type that len() not accept.
|
||||||
//
|
//
|
||||||
|
@ -300,6 +344,31 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
|
||||||
return Len(t, object, length, append([]interface{}{msg}, args...)...)
|
return Len(t, object, length, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lessf asserts that the first element is less than the second
|
||||||
|
//
|
||||||
|
// assert.Lessf(t, 1, 2, "error message %s", "formatted")
|
||||||
|
// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
|
||||||
|
// assert.Lessf(t, "a", "b", "error message %s", "formatted")
|
||||||
|
func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Less(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqualf asserts that the first element is less than or equal to the second
|
||||||
|
//
|
||||||
|
// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
|
||||||
|
// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
|
||||||
|
// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
|
||||||
|
// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
|
||||||
|
func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
// Nilf asserts that the specified object is nil.
|
// Nilf asserts that the specified object is nil.
|
||||||
//
|
//
|
||||||
// assert.Nilf(t, err, "error message %s", "formatted")
|
// assert.Nilf(t, err, "error message %s", "formatted")
|
||||||
|
@ -444,6 +513,19 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
|
||||||
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Samef asserts that two pointers reference the same object.
|
||||||
|
//
|
||||||
|
// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||||
|
// determined based on the equality of both type and value.
|
||||||
|
func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
// Subsetf asserts that the specified list(array, slice...) contains all
|
// Subsetf asserts that the specified list(array, slice...) contains all
|
||||||
// elements given in the specified subset(array, slice...).
|
// elements given in the specified subset(array, slice...).
|
||||||
//
|
//
|
||||||
|
|
|
@ -215,6 +215,28 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
|
||||||
return Errorf(a.t, err, msg, args...)
|
return Errorf(a.t, err, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eventually asserts that given condition will be met in waitFor time,
|
||||||
|
// periodically checking target function each tick.
|
||||||
|
//
|
||||||
|
// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
|
||||||
|
func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eventuallyf asserts that given condition will be met in waitFor time,
|
||||||
|
// periodically checking target function each tick.
|
||||||
|
//
|
||||||
|
// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||||
|
func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Exactly asserts that two objects are equal in value and type.
|
// Exactly asserts that two objects are equal in value and type.
|
||||||
//
|
//
|
||||||
// a.Exactly(int32(123), int64(123))
|
// a.Exactly(int32(123), int64(123))
|
||||||
|
@ -303,6 +325,56 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) b
|
||||||
return FileExistsf(a.t, path, msg, args...)
|
return FileExistsf(a.t, path, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Greater asserts that the first element is greater than the second
|
||||||
|
//
|
||||||
|
// a.Greater(2, 1)
|
||||||
|
// a.Greater(float64(2), float64(1))
|
||||||
|
// a.Greater("b", "a")
|
||||||
|
func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Greater(a.t, e1, e2, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqual asserts that the first element is greater than or equal to the second
|
||||||
|
//
|
||||||
|
// a.GreaterOrEqual(2, 1)
|
||||||
|
// a.GreaterOrEqual(2, 2)
|
||||||
|
// a.GreaterOrEqual("b", "a")
|
||||||
|
// a.GreaterOrEqual("b", "b")
|
||||||
|
func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
|
||||||
|
//
|
||||||
|
// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
|
||||||
|
// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
|
||||||
|
// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
|
||||||
|
// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
|
||||||
|
func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return GreaterOrEqualf(a.t, e1, e2, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Greaterf asserts that the first element is greater than the second
|
||||||
|
//
|
||||||
|
// a.Greaterf(2, 1, "error message %s", "formatted")
|
||||||
|
// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
|
||||||
|
// a.Greaterf("b", "a", "error message %s", "formatted")
|
||||||
|
func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Greaterf(a.t, e1, e2, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// HTTPBodyContains asserts that a specified handler returns a
|
// HTTPBodyContains asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
|
@ -567,6 +639,22 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
|
||||||
return JSONEqf(a.t, expected, actual, msg, args...)
|
return JSONEqf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// YAMLEq asserts that two YAML strings are equivalent.
|
||||||
|
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||||
|
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return YAMLEqf(a.t, expected, actual, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Len asserts that the specified object has specific length.
|
// Len asserts that the specified object has specific length.
|
||||||
// Len also fails if the object has a type that len() not accept.
|
// Len also fails if the object has a type that len() not accept.
|
||||||
//
|
//
|
||||||
|
@ -589,6 +677,56 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
|
||||||
return Lenf(a.t, object, length, msg, args...)
|
return Lenf(a.t, object, length, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Less asserts that the first element is less than the second
|
||||||
|
//
|
||||||
|
// a.Less(1, 2)
|
||||||
|
// a.Less(float64(1), float64(2))
|
||||||
|
// a.Less("a", "b")
|
||||||
|
func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Less(a.t, e1, e2, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqual asserts that the first element is less than or equal to the second
|
||||||
|
//
|
||||||
|
// a.LessOrEqual(1, 2)
|
||||||
|
// a.LessOrEqual(2, 2)
|
||||||
|
// a.LessOrEqual("a", "b")
|
||||||
|
// a.LessOrEqual("b", "b")
|
||||||
|
func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return LessOrEqual(a.t, e1, e2, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqualf asserts that the first element is less than or equal to the second
|
||||||
|
//
|
||||||
|
// a.LessOrEqualf(1, 2, "error message %s", "formatted")
|
||||||
|
// a.LessOrEqualf(2, 2, "error message %s", "formatted")
|
||||||
|
// a.LessOrEqualf("a", "b", "error message %s", "formatted")
|
||||||
|
// a.LessOrEqualf("b", "b", "error message %s", "formatted")
|
||||||
|
func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return LessOrEqualf(a.t, e1, e2, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lessf asserts that the first element is less than the second
|
||||||
|
//
|
||||||
|
// a.Lessf(1, 2, "error message %s", "formatted")
|
||||||
|
// a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
|
||||||
|
// a.Lessf("a", "b", "error message %s", "formatted")
|
||||||
|
func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Lessf(a.t, e1, e2, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Nil asserts that the specified object is nil.
|
// Nil asserts that the specified object is nil.
|
||||||
//
|
//
|
||||||
// a.Nil(err)
|
// a.Nil(err)
|
||||||
|
@ -877,6 +1015,32 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
|
||||||
return Regexpf(a.t, rx, str, msg, args...)
|
return Regexpf(a.t, rx, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same asserts that two pointers reference the same object.
|
||||||
|
//
|
||||||
|
// a.Same(ptr1, ptr2)
|
||||||
|
//
|
||||||
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||||
|
// determined based on the equality of both type and value.
|
||||||
|
func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Same(a.t, expected, actual, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samef asserts that two pointers reference the same object.
|
||||||
|
//
|
||||||
|
// a.Samef(ptr1, ptr2, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||||
|
// determined based on the equality of both type and value.
|
||||||
|
func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Samef(a.t, expected, actual, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Subset asserts that the specified list(array, slice...) contains all
|
// Subset asserts that the specified list(array, slice...) contains all
|
||||||
// elements given in the specified subset(array, slice...).
|
// elements given in the specified subset(array, slice...).
|
||||||
//
|
//
|
||||||
|
|
|
@ -0,0 +1,309 @@
|
||||||
|
package assert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
|
||||||
|
switch kind {
|
||||||
|
case reflect.Int:
|
||||||
|
{
|
||||||
|
intobj1 := obj1.(int)
|
||||||
|
intobj2 := obj2.(int)
|
||||||
|
if intobj1 > intobj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if intobj1 == intobj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if intobj1 < intobj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int8:
|
||||||
|
{
|
||||||
|
int8obj1 := obj1.(int8)
|
||||||
|
int8obj2 := obj2.(int8)
|
||||||
|
if int8obj1 > int8obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if int8obj1 == int8obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if int8obj1 < int8obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int16:
|
||||||
|
{
|
||||||
|
int16obj1 := obj1.(int16)
|
||||||
|
int16obj2 := obj2.(int16)
|
||||||
|
if int16obj1 > int16obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if int16obj1 == int16obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if int16obj1 < int16obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int32:
|
||||||
|
{
|
||||||
|
int32obj1 := obj1.(int32)
|
||||||
|
int32obj2 := obj2.(int32)
|
||||||
|
if int32obj1 > int32obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if int32obj1 == int32obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if int32obj1 < int32obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int64:
|
||||||
|
{
|
||||||
|
int64obj1 := obj1.(int64)
|
||||||
|
int64obj2 := obj2.(int64)
|
||||||
|
if int64obj1 > int64obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if int64obj1 == int64obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if int64obj1 < int64obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint:
|
||||||
|
{
|
||||||
|
uintobj1 := obj1.(uint)
|
||||||
|
uintobj2 := obj2.(uint)
|
||||||
|
if uintobj1 > uintobj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if uintobj1 == uintobj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if uintobj1 < uintobj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint8:
|
||||||
|
{
|
||||||
|
uint8obj1 := obj1.(uint8)
|
||||||
|
uint8obj2 := obj2.(uint8)
|
||||||
|
if uint8obj1 > uint8obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if uint8obj1 == uint8obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if uint8obj1 < uint8obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint16:
|
||||||
|
{
|
||||||
|
uint16obj1 := obj1.(uint16)
|
||||||
|
uint16obj2 := obj2.(uint16)
|
||||||
|
if uint16obj1 > uint16obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if uint16obj1 == uint16obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if uint16obj1 < uint16obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint32:
|
||||||
|
{
|
||||||
|
uint32obj1 := obj1.(uint32)
|
||||||
|
uint32obj2 := obj2.(uint32)
|
||||||
|
if uint32obj1 > uint32obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if uint32obj1 == uint32obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if uint32obj1 < uint32obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint64:
|
||||||
|
{
|
||||||
|
uint64obj1 := obj1.(uint64)
|
||||||
|
uint64obj2 := obj2.(uint64)
|
||||||
|
if uint64obj1 > uint64obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if uint64obj1 == uint64obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if uint64obj1 < uint64obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Float32:
|
||||||
|
{
|
||||||
|
float32obj1 := obj1.(float32)
|
||||||
|
float32obj2 := obj2.(float32)
|
||||||
|
if float32obj1 > float32obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if float32obj1 == float32obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if float32obj1 < float32obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Float64:
|
||||||
|
{
|
||||||
|
float64obj1 := obj1.(float64)
|
||||||
|
float64obj2 := obj2.(float64)
|
||||||
|
if float64obj1 > float64obj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if float64obj1 == float64obj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if float64obj1 < float64obj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
{
|
||||||
|
stringobj1 := obj1.(string)
|
||||||
|
stringobj2 := obj2.(string)
|
||||||
|
if stringobj1 > stringobj2 {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
if stringobj1 == stringobj2 {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if stringobj1 < stringobj2 {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Greater asserts that the first element is greater than the second
|
||||||
|
//
|
||||||
|
// assert.Greater(t, 2, 1)
|
||||||
|
// assert.Greater(t, float64(2), float64(1))
|
||||||
|
// assert.Greater(t, "b", "a")
|
||||||
|
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
e1Kind := reflect.ValueOf(e1).Kind()
|
||||||
|
e2Kind := reflect.ValueOf(e2).Kind()
|
||||||
|
if e1Kind != e2Kind {
|
||||||
|
return Fail(t, "Elements should be the same type", msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, isComparable := compare(e1, e2, e1Kind)
|
||||||
|
if !isComparable {
|
||||||
|
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res != -1 {
|
||||||
|
return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqual asserts that the first element is greater than or equal to the second
|
||||||
|
//
|
||||||
|
// assert.GreaterOrEqual(t, 2, 1)
|
||||||
|
// assert.GreaterOrEqual(t, 2, 2)
|
||||||
|
// assert.GreaterOrEqual(t, "b", "a")
|
||||||
|
// assert.GreaterOrEqual(t, "b", "b")
|
||||||
|
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
e1Kind := reflect.ValueOf(e1).Kind()
|
||||||
|
e2Kind := reflect.ValueOf(e2).Kind()
|
||||||
|
if e1Kind != e2Kind {
|
||||||
|
return Fail(t, "Elements should be the same type", msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, isComparable := compare(e1, e2, e1Kind)
|
||||||
|
if !isComparable {
|
||||||
|
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res != -1 && res != 0 {
|
||||||
|
return Fail(t, fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less asserts that the first element is less than the second
|
||||||
|
//
|
||||||
|
// assert.Less(t, 1, 2)
|
||||||
|
// assert.Less(t, float64(1), float64(2))
|
||||||
|
// assert.Less(t, "a", "b")
|
||||||
|
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
e1Kind := reflect.ValueOf(e1).Kind()
|
||||||
|
e2Kind := reflect.ValueOf(e2).Kind()
|
||||||
|
if e1Kind != e2Kind {
|
||||||
|
return Fail(t, "Elements should be the same type", msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, isComparable := compare(e1, e2, e1Kind)
|
||||||
|
if !isComparable {
|
||||||
|
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res != 1 {
|
||||||
|
return Fail(t, fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqual asserts that the first element is less than or equal to the second
|
||||||
|
//
|
||||||
|
// assert.LessOrEqual(t, 1, 2)
|
||||||
|
// assert.LessOrEqual(t, 2, 2)
|
||||||
|
// assert.LessOrEqual(t, "a", "b")
|
||||||
|
// assert.LessOrEqual(t, "b", "b")
|
||||||
|
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
e1Kind := reflect.ValueOf(e1).Kind()
|
||||||
|
e2Kind := reflect.ValueOf(e2).Kind()
|
||||||
|
if e1Kind != e2Kind {
|
||||||
|
return Fail(t, "Elements should be the same type", msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, isComparable := compare(e1, e2, e1Kind)
|
||||||
|
if !isComparable {
|
||||||
|
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res != 1 && res != 0 {
|
||||||
|
return Fail(t, fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import (
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/pmezard/go-difflib/difflib"
|
"github.com/pmezard/go-difflib/difflib"
|
||||||
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
|
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
|
||||||
|
@ -350,6 +351,37 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same asserts that two pointers reference the same object.
|
||||||
|
//
|
||||||
|
// assert.Same(t, ptr1, ptr2)
|
||||||
|
//
|
||||||
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||||
|
// determined based on the equality of both type and value.
|
||||||
|
func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual)
|
||||||
|
if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr {
|
||||||
|
return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual)
|
||||||
|
if expectedType != actualType {
|
||||||
|
return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v",
|
||||||
|
expectedType, actualType), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
return Fail(t, fmt.Sprintf("Not same: \n"+
|
||||||
|
"expected: %p %#v\n"+
|
||||||
|
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// formatUnequalValues takes two values of arbitrary types and returns string
|
// formatUnequalValues takes two values of arbitrary types and returns string
|
||||||
// representations appropriate to be presented to the user.
|
// representations appropriate to be presented to the user.
|
||||||
//
|
//
|
||||||
|
@ -479,14 +511,14 @@ func isEmpty(object interface{}) bool {
|
||||||
// collection types are empty when they have no element
|
// collection types are empty when they have no element
|
||||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
||||||
return objValue.Len() == 0
|
return objValue.Len() == 0
|
||||||
// pointers are empty if nil or if the value they point to is empty
|
// pointers are empty if nil or if the value they point to is empty
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
if objValue.IsNil() {
|
if objValue.IsNil() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
deref := objValue.Elem().Interface()
|
deref := objValue.Elem().Interface()
|
||||||
return isEmpty(deref)
|
return isEmpty(deref)
|
||||||
// for all other types, compare against the zero value
|
// for all other types, compare against the zero value
|
||||||
default:
|
default:
|
||||||
zero := reflect.Zero(objValue.Type())
|
zero := reflect.Zero(objValue.Type())
|
||||||
return reflect.DeepEqual(object, zero.Interface())
|
return reflect.DeepEqual(object, zero.Interface())
|
||||||
|
@ -629,7 +661,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
|
||||||
func includeElement(list interface{}, element interface{}) (ok, found bool) {
|
func includeElement(list interface{}, element interface{}) (ok, found bool) {
|
||||||
|
|
||||||
listValue := reflect.ValueOf(list)
|
listValue := reflect.ValueOf(list)
|
||||||
elementValue := reflect.ValueOf(element)
|
listKind := reflect.TypeOf(list).Kind()
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
ok = false
|
ok = false
|
||||||
|
@ -637,11 +669,12 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if reflect.TypeOf(list).Kind() == reflect.String {
|
if listKind == reflect.String {
|
||||||
|
elementValue := reflect.ValueOf(element)
|
||||||
return true, strings.Contains(listValue.String(), elementValue.String())
|
return true, strings.Contains(listValue.String(), elementValue.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect.TypeOf(list).Kind() == reflect.Map {
|
if listKind == reflect.Map {
|
||||||
mapKeys := listValue.MapKeys()
|
mapKeys := listValue.MapKeys()
|
||||||
for i := 0; i < len(mapKeys); i++ {
|
for i := 0; i < len(mapKeys); i++ {
|
||||||
if ObjectsAreEqual(mapKeys[i].Interface(), element) {
|
if ObjectsAreEqual(mapKeys[i].Interface(), element) {
|
||||||
|
@ -1337,6 +1370,24 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
|
||||||
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
|
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// YAMLEq asserts that two YAML strings are equivalent.
|
||||||
|
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
|
||||||
|
return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
|
||||||
|
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
|
func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
|
||||||
t := reflect.TypeOf(v)
|
t := reflect.TypeOf(v)
|
||||||
k := t.Kind()
|
k := t.Kind()
|
||||||
|
@ -1371,8 +1422,8 @@ func diff(expected interface{}, actual interface{}) string {
|
||||||
e = spewConfig.Sdump(expected)
|
e = spewConfig.Sdump(expected)
|
||||||
a = spewConfig.Sdump(actual)
|
a = spewConfig.Sdump(actual)
|
||||||
} else {
|
} else {
|
||||||
e = expected.(string)
|
e = reflect.ValueOf(expected).String()
|
||||||
a = actual.(string)
|
a = reflect.ValueOf(actual).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
||||||
|
@ -1414,3 +1465,34 @@ var spewConfig = spew.ConfigState{
|
||||||
type tHelper interface {
|
type tHelper interface {
|
||||||
Helper()
|
Helper()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eventually asserts that given condition will be met in waitFor time,
|
||||||
|
// periodically checking target function each tick.
|
||||||
|
//
|
||||||
|
// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
|
||||||
|
func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
timer := time.NewTimer(waitFor)
|
||||||
|
ticker := time.NewTicker(tick)
|
||||||
|
checkPassed := make(chan bool)
|
||||||
|
defer timer.Stop()
|
||||||
|
defer ticker.Stop()
|
||||||
|
defer close(checkPassed)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
return Fail(t, "Condition never satisfied", msgAndArgs...)
|
||||||
|
case result := <-checkPassed:
|
||||||
|
if result {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case <-ticker.C:
|
||||||
|
go func() {
|
||||||
|
checkPassed <- condition()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
{{.Comment}}
|
{{.Comment}}
|
||||||
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
|
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
|
||||||
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
|
|
||||||
if h, ok := t.(tHelper); ok { h.Helper() }
|
if h, ok := t.(tHelper); ok { h.Helper() }
|
||||||
|
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,28 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
|
||||||
Errorf(a.t, err, msg, args...)
|
Errorf(a.t, err, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eventually asserts that given condition will be met in waitFor time,
|
||||||
|
// periodically checking target function each tick.
|
||||||
|
//
|
||||||
|
// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
|
||||||
|
func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eventuallyf asserts that given condition will be met in waitFor time,
|
||||||
|
// periodically checking target function each tick.
|
||||||
|
//
|
||||||
|
// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||||
|
func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Exactly asserts that two objects are equal in value and type.
|
// Exactly asserts that two objects are equal in value and type.
|
||||||
//
|
//
|
||||||
// a.Exactly(int32(123), int64(123))
|
// a.Exactly(int32(123), int64(123))
|
||||||
|
@ -304,6 +326,56 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
|
||||||
FileExistsf(a.t, path, msg, args...)
|
FileExistsf(a.t, path, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Greater asserts that the first element is greater than the second
|
||||||
|
//
|
||||||
|
// a.Greater(2, 1)
|
||||||
|
// a.Greater(float64(2), float64(1))
|
||||||
|
// a.Greater("b", "a")
|
||||||
|
func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
Greater(a.t, e1, e2, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqual asserts that the first element is greater than or equal to the second
|
||||||
|
//
|
||||||
|
// a.GreaterOrEqual(2, 1)
|
||||||
|
// a.GreaterOrEqual(2, 2)
|
||||||
|
// a.GreaterOrEqual("b", "a")
|
||||||
|
// a.GreaterOrEqual("b", "b")
|
||||||
|
func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
|
||||||
|
//
|
||||||
|
// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
|
||||||
|
// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
|
||||||
|
// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
|
||||||
|
// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
|
||||||
|
func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
GreaterOrEqualf(a.t, e1, e2, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Greaterf asserts that the first element is greater than the second
|
||||||
|
//
|
||||||
|
// a.Greaterf(2, 1, "error message %s", "formatted")
|
||||||
|
// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
|
||||||
|
// a.Greaterf("b", "a", "error message %s", "formatted")
|
||||||
|
func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
Greaterf(a.t, e1, e2, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// HTTPBodyContains asserts that a specified handler returns a
|
// HTTPBodyContains asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
|
@ -568,6 +640,22 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
|
||||||
JSONEqf(a.t, expected, actual, msg, args...)
|
JSONEqf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// YAMLEq asserts that two YAML strings are equivalent.
|
||||||
|
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||||
|
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
YAMLEqf(a.t, expected, actual, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Len asserts that the specified object has specific length.
|
// Len asserts that the specified object has specific length.
|
||||||
// Len also fails if the object has a type that len() not accept.
|
// Len also fails if the object has a type that len() not accept.
|
||||||
//
|
//
|
||||||
|
@ -590,6 +678,56 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
|
||||||
Lenf(a.t, object, length, msg, args...)
|
Lenf(a.t, object, length, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Less asserts that the first element is less than the second
|
||||||
|
//
|
||||||
|
// a.Less(1, 2)
|
||||||
|
// a.Less(float64(1), float64(2))
|
||||||
|
// a.Less("a", "b")
|
||||||
|
func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
Less(a.t, e1, e2, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqual asserts that the first element is less than or equal to the second
|
||||||
|
//
|
||||||
|
// a.LessOrEqual(1, 2)
|
||||||
|
// a.LessOrEqual(2, 2)
|
||||||
|
// a.LessOrEqual("a", "b")
|
||||||
|
// a.LessOrEqual("b", "b")
|
||||||
|
func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
LessOrEqual(a.t, e1, e2, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqualf asserts that the first element is less than or equal to the second
|
||||||
|
//
|
||||||
|
// a.LessOrEqualf(1, 2, "error message %s", "formatted")
|
||||||
|
// a.LessOrEqualf(2, 2, "error message %s", "formatted")
|
||||||
|
// a.LessOrEqualf("a", "b", "error message %s", "formatted")
|
||||||
|
// a.LessOrEqualf("b", "b", "error message %s", "formatted")
|
||||||
|
func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
LessOrEqualf(a.t, e1, e2, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lessf asserts that the first element is less than the second
|
||||||
|
//
|
||||||
|
// a.Lessf(1, 2, "error message %s", "formatted")
|
||||||
|
// a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
|
||||||
|
// a.Lessf("a", "b", "error message %s", "formatted")
|
||||||
|
func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
Lessf(a.t, e1, e2, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Nil asserts that the specified object is nil.
|
// Nil asserts that the specified object is nil.
|
||||||
//
|
//
|
||||||
// a.Nil(err)
|
// a.Nil(err)
|
||||||
|
@ -878,6 +1016,32 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
|
||||||
Regexpf(a.t, rx, str, msg, args...)
|
Regexpf(a.t, rx, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same asserts that two pointers reference the same object.
|
||||||
|
//
|
||||||
|
// a.Same(ptr1, ptr2)
|
||||||
|
//
|
||||||
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||||
|
// determined based on the equality of both type and value.
|
||||||
|
func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
Same(a.t, expected, actual, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samef asserts that two pointers reference the same object.
|
||||||
|
//
|
||||||
|
// a.Samef(ptr1, ptr2, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||||
|
// determined based on the equality of both type and value.
|
||||||
|
func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
Samef(a.t, expected, actual, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Subset asserts that the specified list(array, slice...) contains all
|
// Subset asserts that the specified list(array, slice...) contains all
|
||||||
// elements given in the specified subset(array, slice...).
|
// elements given in the specified subset(array, slice...).
|
||||||
//
|
//
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package retry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackoffFunc func(attempt int) time.Duration
|
||||||
|
|
||||||
|
func BackoffLinearWithJitter(waitBetween time.Duration, jitterFraction float64) BackoffFunc {
|
||||||
|
return func(attempt int) time.Duration {
|
||||||
|
return jitterAround(waitBetween, jitterFraction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BackoffExponentialWithJitter(base time.Duration, cap time.Duration) BackoffFunc {
|
||||||
|
return func(attempt int) time.Duration {
|
||||||
|
to := getExponentialTimeout(attempt, base)
|
||||||
|
// Using float types here, because exponential time can be really big, and converting it to time.Duration may
|
||||||
|
// result in undefined behaviour. Its safe conversion, when we have compared it to our 'cap' value.
|
||||||
|
if to > float64(cap) {
|
||||||
|
to = float64(cap)
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Duration(to * rand.Float64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExponentialTimeout(attempt int, base time.Duration) float64 {
|
||||||
|
mult := math.Pow(2, float64(attempt))
|
||||||
|
return float64(base) * mult
|
||||||
|
}
|
||||||
|
|
||||||
|
func jitterAround(duration time.Duration, jitter float64) time.Duration {
|
||||||
|
multiplier := jitter * (rand.Float64()*2 - 1)
|
||||||
|
return time.Duration(float64(duration) * (1 + multiplier))
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
package retry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interceptor returns retry interceptor, that can be parametrized by specific call options.
|
||||||
|
// Without any option, it uses default options, that basically retries nothing.
|
||||||
|
// Default retry quantity is 0, backoff function is nil, retry codes are DefaultRetriableCodes, AttemptHeader is false, and perCallTimeout is 0.
|
||||||
|
func Interceptor(callOpts ...grpc.CallOption) grpc.UnaryClientInterceptor {
|
||||||
|
i := unaryInterceptor{opts: *defaultOptions.applyOptions(callOpts)}
|
||||||
|
return i.InterceptUnary
|
||||||
|
}
|
||||||
|
|
||||||
|
type unaryInterceptor struct {
|
||||||
|
opts options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *unaryInterceptor) InterceptUnary(ctx context.Context, method string, req, reply interface{}, conn *grpc.ClientConn, invoker grpc.UnaryInvoker, callOpts ...grpc.CallOption) error {
|
||||||
|
opts := i.opts.applyOptions(callOpts)
|
||||||
|
ctx = addIdempotencyToken(ctx)
|
||||||
|
caller := grpcCaller{ctx, method, req, reply, conn, invoker, callOpts}
|
||||||
|
|
||||||
|
// TODO(seukyaso): consider adding some configurable callbacks for notifying/logging purpose
|
||||||
|
callContextIsDone, err := caller.Call(0, opts)
|
||||||
|
|
||||||
|
for r := 0; opts.maxRetryCount < 0 || r < opts.maxRetryCount; r++ {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for parent context errors, return if context is Cancelled or Deadline exceeded
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return contextErrorToGRPCError(ctx.Err())
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always retry if call context is Done (cancelled or Deadline exceeded).
|
||||||
|
// Thus, we ignore call errors in this case.
|
||||||
|
if !callContextIsDone && !opts.isRetriable(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = opts.waitBackoff(ctx, r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
callContextIsDone, err = caller.Call(r+1, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type grpcCaller struct {
|
||||||
|
ctx context.Context
|
||||||
|
method string
|
||||||
|
req interface{}
|
||||||
|
reply interface{}
|
||||||
|
conn *grpc.ClientConn
|
||||||
|
invoker grpc.UnaryInvoker
|
||||||
|
callOpts []grpc.CallOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *grpcCaller) Call(attempt int, opts *options) (callContextIsDone bool, err error) {
|
||||||
|
callCtx := c.ctx
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
|
||||||
|
if attempt > 0 {
|
||||||
|
callCtx = opts.addRetryAttemptToHeader(callCtx, attempt)
|
||||||
|
|
||||||
|
if opts.perCallTimeout > 0 {
|
||||||
|
callCtx, cancel = context.WithTimeout(callCtx, opts.perCallTimeout)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.invoker(callCtx, c.method, c.req, c.reply, c.conn, c.callOpts...)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-callCtx.Done():
|
||||||
|
callContextIsDone = true
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *options) applyOptions(callOpts []grpc.CallOption) *options {
|
||||||
|
ret := *opts
|
||||||
|
for _, opt := range callOpts {
|
||||||
|
if do, ok := opt.(interceptorOption); ok {
|
||||||
|
do.applyFunc(&ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextErrorToGRPCError(err error) error {
|
||||||
|
switch err {
|
||||||
|
case context.DeadlineExceeded:
|
||||||
|
return status.Error(codes.DeadlineExceeded, err.Error())
|
||||||
|
case context.Canceled:
|
||||||
|
return status.Error(codes.Canceled, err.Error())
|
||||||
|
default:
|
||||||
|
return status.Error(codes.Unknown, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *options) waitBackoff(ctx context.Context, attempt int) error {
|
||||||
|
if opts.backoffFunc == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
waitTime := opts.backoffFunc(attempt)
|
||||||
|
if waitTime > 0 {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return contextErrorToGRPCError(ctx.Err())
|
||||||
|
case <-time.After(waitTime):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *options) isRetriable(err error) bool {
|
||||||
|
errCode := status.Code(err)
|
||||||
|
|
||||||
|
for _, code := range opts.retriableCodes {
|
||||||
|
if errCode == code {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func addIdempotencyToken(ctx context.Context) context.Context {
|
||||||
|
const idempotencyTokenMetadataKey = "idempotency-key"
|
||||||
|
|
||||||
|
idempotencyTokenPresent := false
|
||||||
|
md, ok := metadata.FromOutgoingContext(ctx)
|
||||||
|
if ok {
|
||||||
|
_, idempotencyTokenPresent = md[idempotencyTokenMetadataKey]
|
||||||
|
}
|
||||||
|
|
||||||
|
if !idempotencyTokenPresent {
|
||||||
|
ctx = metadata.AppendToOutgoingContext(ctx, idempotencyTokenMetadataKey, uuid.New().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *options) addRetryAttemptToHeader(ctx context.Context, attempt int) context.Context {
|
||||||
|
const AttemptMetadataKey = "x-retry-attempt"
|
||||||
|
|
||||||
|
if opts.addCountToHeader {
|
||||||
|
ctx = metadata.AppendToOutgoingContext(ctx, AttemptMetadataKey, strconv.Itoa(attempt))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
package retry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithDefaultInterceptor returns interceptor that DOESN'T retry anything.
|
||||||
|
// Its possible to change its behaviour with call options.
|
||||||
|
func WithDefaultInterceptor() grpc.DialOption {
|
||||||
|
return grpc.WithUnaryInterceptor(Interceptor())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMax option sets quantity of retry attempts.
|
||||||
|
// It handles negative maxRetryCount as INFINITE retries.
|
||||||
|
func WithMax(maxRetryCount int) grpc.CallOption {
|
||||||
|
return newOption(setRetryQuantity(maxRetryCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCodes overrides the whole retriable codes list.
|
||||||
|
func WithCodes(codes ...codes.Code) grpc.CallOption {
|
||||||
|
return newOption(setRetriableCodes(codes...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAttemptHeader adds retry attempt number to context outgoing metadata, with key "x-retry-attempt".
|
||||||
|
func WithAttemptHeader(enable bool) grpc.CallOption {
|
||||||
|
return newOption(setAttemptHeader(enable))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPerCallTimeout adds timeout for retry calls.
|
||||||
|
func WithPerCallTimeout(to time.Duration) grpc.CallOption {
|
||||||
|
return newOption(setPerCallTimeout(to))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBackoff sets up interceptor with custom defined backoff function
|
||||||
|
func WithBackoff(f BackoffFunc) grpc.CallOption {
|
||||||
|
return newOption(setBackoff(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultBackoff uses exponential backoff with jitter, with base = 50ms, and maximum timeout = 1 minute.
|
||||||
|
func DefaultBackoff() BackoffFunc {
|
||||||
|
return DefaultExponentialJitterBackoff()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefaultExponentialJitterBackoff same as WithDefaultBackoff
|
||||||
|
func DefaultExponentialJitterBackoff() BackoffFunc {
|
||||||
|
return BackoffExponentialWithJitter(defaultExponentialBackoffBase, defaultExponentialBackoffCap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultLinearJitterBackoff uses linear backoff with base = 50ms, and jitter = +-10%
|
||||||
|
func DefaultLinearJitterBackoff() BackoffFunc {
|
||||||
|
return BackoffLinearWithJitter(defaultLinearBackoffTimeout, defaultLinearBackoffJitter)
|
||||||
|
}
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
maxRetryCount int
|
||||||
|
retriableCodes []codes.Code
|
||||||
|
addCountToHeader bool
|
||||||
|
perCallTimeout time.Duration
|
||||||
|
backoffFunc BackoffFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// TODO(seukyaso): Consider adding some non-zero default retry options
|
||||||
|
DefaultRetriableCodes = []codes.Code{codes.ResourceExhausted, codes.Unavailable}
|
||||||
|
|
||||||
|
defaultOptions = &options{
|
||||||
|
maxRetryCount: 0,
|
||||||
|
retriableCodes: DefaultRetriableCodes,
|
||||||
|
addCountToHeader: false,
|
||||||
|
perCallTimeout: 0,
|
||||||
|
backoffFunc: nil,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultLinearBackoffTimeout = 50 * time.Millisecond
|
||||||
|
defaultLinearBackoffJitter = 0.1
|
||||||
|
defaultExponentialBackoffBase = 50 * time.Millisecond
|
||||||
|
defaultExponentialBackoffCap = 1 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
type applyOptionFunc func(opt *options)
|
||||||
|
|
||||||
|
type interceptorOption struct {
|
||||||
|
grpc.EmptyCallOption
|
||||||
|
applyFunc applyOptionFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOption(f applyOptionFunc) grpc.CallOption {
|
||||||
|
return interceptorOption{applyFunc: f}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setRetryQuantity(r int) applyOptionFunc {
|
||||||
|
return func(opt *options) {
|
||||||
|
opt.maxRetryCount = r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setRetriableCodes(codes ...codes.Code) applyOptionFunc {
|
||||||
|
return func(opt *options) {
|
||||||
|
opt.retriableCodes = codes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAttemptHeader(enable bool) applyOptionFunc {
|
||||||
|
return func(opt *options) {
|
||||||
|
opt.addCountToHeader = enable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPerCallTimeout(to time.Duration) applyOptionFunc {
|
||||||
|
return func(opt *options) {
|
||||||
|
opt.perCallTimeout = to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setBackoff(f BackoffFunc) applyOptionFunc {
|
||||||
|
return func(opt *options) {
|
||||||
|
opt.backoffFunc = f
|
||||||
|
}
|
||||||
|
}
|
|
@ -267,6 +267,8 @@ github.com/gophercloud/gophercloud/pagination
|
||||||
github.com/gophercloud/utils/openstack/clientconfig
|
github.com/gophercloud/utils/openstack/clientconfig
|
||||||
# github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777
|
# github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777
|
||||||
github.com/gorilla/websocket
|
github.com/gorilla/websocket
|
||||||
|
# github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware
|
||||||
# github.com/grpc-ecosystem/grpc-gateway v1.8.5
|
# github.com/grpc-ecosystem/grpc-gateway v1.8.5
|
||||||
github.com/grpc-ecosystem/grpc-gateway/internal
|
github.com/grpc-ecosystem/grpc-gateway/internal
|
||||||
github.com/grpc-ecosystem/grpc-gateway/runtime
|
github.com/grpc-ecosystem/grpc-gateway/runtime
|
||||||
|
@ -431,7 +433,7 @@ github.com/packer-community/winrmcp/winrmcp
|
||||||
# github.com/pierrec/lz4 v2.0.5+incompatible
|
# github.com/pierrec/lz4 v2.0.5+incompatible
|
||||||
github.com/pierrec/lz4
|
github.com/pierrec/lz4
|
||||||
github.com/pierrec/lz4/internal/xxh32
|
github.com/pierrec/lz4/internal/xxh32
|
||||||
# github.com/pkg/errors v0.8.0
|
# github.com/pkg/errors v0.8.1
|
||||||
github.com/pkg/errors
|
github.com/pkg/errors
|
||||||
# github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca
|
# github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca
|
||||||
github.com/pkg/sftp
|
github.com/pkg/sftp
|
||||||
|
@ -465,9 +467,9 @@ github.com/shirou/gopsutil/net
|
||||||
github.com/shirou/gopsutil/process
|
github.com/shirou/gopsutil/process
|
||||||
# github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4
|
# github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4
|
||||||
github.com/shirou/w32
|
github.com/shirou/w32
|
||||||
# github.com/sirupsen/logrus v1.3.0
|
# github.com/sirupsen/logrus v1.4.2
|
||||||
github.com/sirupsen/logrus
|
github.com/sirupsen/logrus
|
||||||
# github.com/stretchr/testify v1.3.0
|
# github.com/stretchr/testify v1.4.0
|
||||||
github.com/stretchr/testify/assert
|
github.com/stretchr/testify/assert
|
||||||
github.com/stretchr/testify/require
|
github.com/stretchr/testify/require
|
||||||
# github.com/temoto/robotstxt v1.1.1
|
# github.com/temoto/robotstxt v1.1.1
|
||||||
|
@ -568,6 +570,7 @@ github.com/yandex-cloud/go-sdk/iamkey
|
||||||
github.com/yandex-cloud/go-sdk/operation
|
github.com/yandex-cloud/go-sdk/operation
|
||||||
github.com/yandex-cloud/go-sdk/pkg/grpcclient
|
github.com/yandex-cloud/go-sdk/pkg/grpcclient
|
||||||
github.com/yandex-cloud/go-sdk/pkg/requestid
|
github.com/yandex-cloud/go-sdk/pkg/requestid
|
||||||
|
github.com/yandex-cloud/go-sdk/pkg/retry
|
||||||
github.com/yandex-cloud/go-sdk/pkg/sdkerrors
|
github.com/yandex-cloud/go-sdk/pkg/sdkerrors
|
||||||
github.com/yandex-cloud/go-sdk/pkg/singleflight
|
github.com/yandex-cloud/go-sdk/pkg/singleflight
|
||||||
github.com/yandex-cloud/go-sdk/sdkresolvers
|
github.com/yandex-cloud/go-sdk/sdkresolvers
|
||||||
|
|
Loading…
Reference in New Issue