Merge pull request #43752 from thaJeztah/less_replaces
vendor: reduce replace rules, and update some dependencies
This commit is contained in:
commit
1ed7999cb0
132 changed files with 8638 additions and 1765 deletions
34
vendor.mod
34
vendor.mod
|
@ -43,7 +43,7 @@ require (
|
|||
github.com/hashicorp/go-immutable-radix v1.3.1
|
||||
github.com/hashicorp/go-memdb v1.3.2
|
||||
github.com/hashicorp/memberlist v0.2.4
|
||||
github.com/hashicorp/serf v0.8.2
|
||||
github.com/hashicorp/serf v0.8.5
|
||||
github.com/imdario/mergo v0.3.12
|
||||
github.com/ishidawataru/sctp v0.0.0-20210707070123-9a39160e9062
|
||||
github.com/klauspost/compress v1.15.1
|
||||
|
@ -120,7 +120,7 @@ require (
|
|||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.5.3 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.5.5 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
|
@ -137,7 +137,6 @@ require (
|
|||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
||||
github.com/tinylib/msgp v1.1.0 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.2 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.2 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.2 // indirect
|
||||
|
@ -163,28 +162,17 @@ require (
|
|||
google.golang.org/api v0.54.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
labix.org/v2/mgo v0.0.0-20140701140051-000000000287 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/armon/go-metrics => github.com/armon/go-metrics v0.0.0-20150106224455-eb0af217e5e9
|
||||
// More recent versions result in a panic in libnetwork.
|
||||
// FIXME(thaJeztah): we need to fix how we use this library or replace it; see https://github.com/moby/moby/issues/43753
|
||||
github.com/armon/go-radix => github.com/armon/go-radix v0.0.0-20150105235045-e39d623f12e8
|
||||
github.com/coreos/go-systemd => github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7
|
||||
github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea
|
||||
github.com/hashicorp/go-msgpack => github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67
|
||||
github.com/hashicorp/go-multierror => github.com/hashicorp/go-multierror v1.0.0
|
||||
github.com/hashicorp/serf => github.com/hashicorp/serf v0.7.1-0.20160317193612-598c54895cc5
|
||||
github.com/matttproud/golang_protobuf_extensions => github.com/matttproud/golang_protobuf_extensions v1.0.1
|
||||
github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.6.0
|
||||
github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.11
|
||||
go.opencensus.io => go.opencensus.io v0.22.3
|
||||
// Resolve dependency hell with github.com/cloudflare/cfssl (transitive via
|
||||
// swarmkit) by pinning the certificate-transparency-go version. Remove once
|
||||
// module go.etcd.io/etcd/server/v3 has upgraded its dependency on
|
||||
// go.opentelemetry.io/otel to v1.
|
||||
github.com/google/certificate-transparency-go => github.com/google/certificate-transparency-go v1.0.20
|
||||
// Removes etcd dependency
|
||||
github.com/rexray/gocsi => github.com/dperny/gocsi v1.2.3-pre
|
||||
)
|
||||
|
||||
// Removes etcd dependency
|
||||
replace github.com/rexray/gocsi => github.com/dperny/gocsi v1.2.3-pre
|
||||
|
||||
// Resolve dependency hell with github.com/cloudflare/cfssl (transitive via
|
||||
// swarmkit) by pinning the certificate-transparency-go version. Remove once
|
||||
// module go.etcd.io/etcd/server/v3 has upgraded its dependency on
|
||||
// go.opentelemetry.io/otel to v1.
|
||||
replace github.com/google/certificate-transparency-go => github.com/google/certificate-transparency-go v1.0.20
|
||||
|
|
106
vendor.sum
106
vendor.sum
|
@ -114,17 +114,20 @@ github.com/akutz/gosync v0.1.0 h1:naxPT/aDYDh79PMwM3XmencmNQeYmpNFSZy4ZE9zIW0=
|
|||
github.com/akutz/gosync v0.1.0/go.mod h1:I8I4aiqJI1nqaeYOOB1WS+CgRJVVPqhct9Y4njywM84=
|
||||
github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
|
||||
github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
||||
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs=
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20150106224455-eb0af217e5e9 h1:j0r1R47jEcPk5M3GY3tFbv7q5J6j0Ppler3q4Guh6C0=
|
||||
github.com/armon/go-metrics v0.0.0-20150106224455-eb0af217e5e9/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20150105235045-e39d623f12e8 h1:XGHqlQXxwVly7mpcroyCGuEaGv/yvtS6r4PSHryDgxU=
|
||||
github.com/armon/go-radix v0.0.0-20150105235045-e39d623f12e8/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
|
@ -133,6 +136,8 @@ github.com/aws/aws-sdk-go v1.31.6 h1:nKjQbpXhdImctBh1e0iLg9iQW/X297LPPuY/9f92R2k
|
|||
github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
|
@ -315,12 +320,15 @@ github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFE
|
|||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
|
@ -344,6 +352,7 @@ github.com/deckarep/golang-set v0.0.0-20141123011944-ef32fa3046d9/go.mod h1:93vs
|
|||
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v20.10.13+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
|
@ -422,8 +431,10 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9
|
|||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
|
@ -466,6 +477,7 @@ github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/
|
|||
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
|
||||
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
|
||||
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
|
@ -524,6 +536,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
|
@ -601,27 +614,36 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ
|
|||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-memdb v1.3.2 h1:RBKHOsnSszpU6vxq80LzC2BaQjuuvoyaQbkLTf7V7g8=
|
||||
github.com/hashicorp/go-memdb v1.3.2/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g=
|
||||
github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67 h1:uUGuA3Cnfp7qbFpIMOCDVz3TaWIF4lLYM8PE3YHpoA4=
|
||||
github.com/hashicorp/go-msgpack v0.0.0-20140221154404-71c2886f5a67/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
|
||||
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/memberlist v0.2.4 h1:OOhYzSvFnkFQXm1ysE8RjXTHsqSRDyP4emusC9K7DYg=
|
||||
github.com/hashicorp/memberlist v0.2.4/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/serf v0.7.1-0.20160317193612-598c54895cc5 h1:c0ibg28HTeX1LYjzYBkMzdnXuPn+iGx3huEB//PkB08=
|
||||
github.com/hashicorp/serf v0.7.1-0.20160317193612-598c54895cc5/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hashicorp/serf v0.8.5 h1:ZynDUIQiA8usmRgPdGPHFdPnb1wgGI9tK3mO9hcAJjc=
|
||||
github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
|
@ -655,7 +677,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqo
|
|||
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
|
@ -702,8 +723,9 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
|
|||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
|
||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
|
@ -712,6 +734,7 @@ github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcK
|
|||
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
|
||||
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
|
||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
|
@ -723,8 +746,11 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
|||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
||||
github.com/moby/buildkit v0.10.3 h1:/dGykD8FW+H4p++q5+KqKEo6gAkYKyBQHdawdjVwVAU=
|
||||
|
@ -773,6 +799,7 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
|
|||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
@ -834,6 +861,7 @@ github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuh
|
|||
github.com/opencontainers/selinux v1.10.1 h1:09LIPVRP3uuZGQvgR+SgMSNBd1Eb3vlRbGqQpoHsF8w=
|
||||
github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
|
@ -845,6 +873,7 @@ github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee h1:P6U24L02WMfj9ym
|
|||
github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY=
|
||||
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
|
@ -853,21 +882,45 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A=
|
||||
github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
|
||||
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
|
||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
|
@ -877,6 +930,7 @@ github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
|||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||
|
@ -979,8 +1033,6 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17
|
|||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
|
@ -1022,8 +1074,14 @@ go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVd
|
|||
go.etcd.io/etcd/server/v3 v3.5.2 h1:B6ytJvS4Fmt8nkjzS2/8POf4tuPhFMluE0lWd4dx/7U=
|
||||
go.etcd.io/etcd/server/v3 v3.5.2/go.mod h1:mlG8znIEz4N/28GABrohZCBM11FqgGVQcpbcyJgh0j0=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w=
|
||||
|
@ -1084,6 +1142,7 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
|||
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
@ -1138,12 +1197,16 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
|
@ -1225,6 +1288,7 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -1245,6 +1309,7 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -1273,12 +1338,12 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -1317,6 +1382,7 @@ golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -1678,8 +1744,6 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
|
|||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
labix.org/v2/mgo v0.0.0-20140701140051-000000000287 h1:L0cnkNl4TfAXzvdrqsYEmxOHOCv2p5I3taaReO8BWFs=
|
||||
labix.org/v2/mgo v0.0.0-20140701140051-000000000287/go.mod h1:Lg7AYkt1uXJoR9oeSZ3W/8IXLdvOfIITgZnommstyz4=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
2
vendor/github.com/armon/go-metrics/.gitignore
generated
vendored
2
vendor/github.com/armon/go-metrics/.gitignore
generated
vendored
|
@ -20,3 +20,5 @@ _cgo_export.*
|
|||
_testmain.go
|
||||
|
||||
*.exe
|
||||
|
||||
/metrics.out
|
||||
|
|
87
vendor/github.com/armon/go-metrics/README.md
generated
vendored
87
vendor/github.com/armon/go-metrics/README.md
generated
vendored
|
@ -4,14 +4,17 @@ go-metrics
|
|||
This library provides a `metrics` package which can be used to instrument code,
|
||||
expose application metrics, and profile runtime performance in a flexible manner.
|
||||
|
||||
Current API: [](https://godoc.org/github.com/armon/go-metrics)
|
||||
|
||||
Sinks
|
||||
=====
|
||||
-----
|
||||
|
||||
The `metrics` package makes use of a `MetricSink` interface to support delivery
|
||||
to any type of backend. Currently the following sinks are provided:
|
||||
|
||||
* StatsiteSink : Sinks to a statsite instance (TCP)
|
||||
* StatsdSink: Sinks to a statsd / statsite instance (UDP)
|
||||
* StatsiteSink : Sinks to a [statsite](https://github.com/armon/statsite/) instance (TCP)
|
||||
* StatsdSink: Sinks to a [StatsD](https://github.com/etsy/statsd/) / statsite instance (UDP)
|
||||
* PrometheusSink: Sinks to a [Prometheus](http://prometheus.io/) metrics endpoint (exposed via HTTP for scrapes)
|
||||
* InmemSink : Provides in-memory aggregation, can be used to export stats
|
||||
* FanoutSink : Sinks to multiple sinks. Enables writing to multiple statsite instances for example.
|
||||
* BlackholeSink : Sinks to nowhere
|
||||
|
@ -20,49 +23,69 @@ In addition to the sinks, the `InmemSignal` can be used to catch a signal,
|
|||
and dump a formatted output of recent metrics. For example, when a process gets
|
||||
a SIGUSR1, it can dump to stderr recent performance metrics for debugging.
|
||||
|
||||
Labels
|
||||
------
|
||||
|
||||
Most metrics do have an equivalent ending with `WithLabels`, such methods
|
||||
allow to push metrics with labels and use some features of underlying Sinks
|
||||
(ex: translated into Prometheus labels).
|
||||
|
||||
Since some of these labels may increase greatly cardinality of metrics, the
|
||||
library allow to filter labels using a blacklist/whitelist filtering system
|
||||
which is global to all metrics.
|
||||
|
||||
* If `Config.AllowedLabels` is not nil, then only labels specified in this value will be sent to underlying Sink, otherwise, all labels are sent by default.
|
||||
* If `Config.BlockedLabels` is not nil, any label specified in this value will not be sent to underlying Sinks.
|
||||
|
||||
By default, both `Config.AllowedLabels` and `Config.BlockedLabels` are nil, meaning that
|
||||
no tags are filetered at all, but it allow to a user to globally block some tags with high
|
||||
cardinality at application level.
|
||||
|
||||
Examples
|
||||
========
|
||||
--------
|
||||
|
||||
Here is an example of using the package:
|
||||
|
||||
func SlowMethod() {
|
||||
// Profiling the runtime of a method
|
||||
defer metrics.MeasureSince([]string{"SlowMethod"}, time.Now())
|
||||
}
|
||||
```go
|
||||
func SlowMethod() {
|
||||
// Profiling the runtime of a method
|
||||
defer metrics.MeasureSince([]string{"SlowMethod"}, time.Now())
|
||||
}
|
||||
|
||||
// Configure a statsite sink as the global metrics sink
|
||||
sink, _ := metrics.NewStatsiteSink("statsite:8125")
|
||||
metrics.NewGlobal(metrics.DefaultConfig("service-name"), sink)
|
||||
// Configure a statsite sink as the global metrics sink
|
||||
sink, _ := metrics.NewStatsiteSink("statsite:8125")
|
||||
metrics.NewGlobal(metrics.DefaultConfig("service-name"), sink)
|
||||
|
||||
// Emit a Key/Value pair
|
||||
metrics.EmitKey([]string{"questions", "meaning of life"}, 42)
|
||||
// Emit a Key/Value pair
|
||||
metrics.EmitKey([]string{"questions", "meaning of life"}, 42)
|
||||
```
|
||||
|
||||
Here is an example of setting up a signal handler:
|
||||
|
||||
Here is an example of setting up an signal handler:
|
||||
```go
|
||||
// Setup the inmem sink and signal handler
|
||||
inm := metrics.NewInmemSink(10*time.Second, time.Minute)
|
||||
sig := metrics.DefaultInmemSignal(inm)
|
||||
metrics.NewGlobal(metrics.DefaultConfig("service-name"), inm)
|
||||
|
||||
// Setup the inmem sink and signal handler
|
||||
inm := NewInmemSink(10*time.Second, time.Minute)
|
||||
sig := DefaultInmemSignal(inm)
|
||||
metrics.NewGlobal(metrics.DefaultConfig("service-name"), inm)
|
||||
// Run some code
|
||||
inm.SetGauge([]string{"foo"}, 42)
|
||||
inm.EmitKey([]string{"bar"}, 30)
|
||||
|
||||
// Run some code
|
||||
inm.SetGauge([]string{"foo"}, 42)
|
||||
inm.EmitKey([]string{"bar"}, 30)
|
||||
inm.IncrCounter([]string{"baz"}, 42)
|
||||
inm.IncrCounter([]string{"baz"}, 1)
|
||||
inm.IncrCounter([]string{"baz"}, 80)
|
||||
|
||||
inm.IncrCounter([]string{"baz"}, 42)
|
||||
inm.IncrCounter([]string{"baz"}, 1)
|
||||
inm.IncrCounter([]string{"baz"}, 80)
|
||||
inm.AddSample([]string{"method", "wow"}, 42)
|
||||
inm.AddSample([]string{"method", "wow"}, 100)
|
||||
inm.AddSample([]string{"method", "wow"}, 22)
|
||||
|
||||
inm.AddSample([]string{"method", "wow"}, 42)
|
||||
inm.AddSample([]string{"method", "wow"}, 100)
|
||||
inm.AddSample([]string{"method", "wow"}, 22)
|
||||
|
||||
....
|
||||
....
|
||||
```
|
||||
|
||||
When a signal comes in, output like the following will be dumped to stderr:
|
||||
|
||||
[2014-01-28 14:57:33.04 -0800 PST][G] 'foo': 42.000
|
||||
[2014-01-28 14:57:33.04 -0800 PST][P] 'bar': 30.000
|
||||
[2014-01-28 14:57:33.04 -0800 PST][C] 'baz': Count: 3 Min: 1.000 Mean: 41.000 Max: 80.000 Stddev: 39.509
|
||||
[2014-01-28 14:57:33.04 -0800 PST][S] 'method.wow': Count: 3 Min: 22.000 Mean: 54.667 Max: 100.000 Stddev: 40.513
|
||||
|
||||
[2014-01-28 14:57:33.04 -0800 PST][C] 'baz': Count: 3 Min: 1.000 Mean: 41.000 Max: 80.000 Stddev: 39.509
|
||||
[2014-01-28 14:57:33.04 -0800 PST][S] 'method.wow': Count: 3 Min: 22.000 Mean: 54.667 Max: 100.000 Stddev: 40.513
|
171
vendor/github.com/armon/go-metrics/inmem.go
generated
vendored
171
vendor/github.com/armon/go-metrics/inmem.go
generated
vendored
|
@ -1,8 +1,10 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -25,6 +27,8 @@ type InmemSink struct {
|
|||
// intervals is a slice of the retained intervals
|
||||
intervals []*IntervalMetrics
|
||||
intervalLock sync.RWMutex
|
||||
|
||||
rateDenom float64
|
||||
}
|
||||
|
||||
// IntervalMetrics stores the aggregated metrics
|
||||
|
@ -36,7 +40,7 @@ type IntervalMetrics struct {
|
|||
Interval time.Time
|
||||
|
||||
// Gauges maps the key to the last set value
|
||||
Gauges map[string]float32
|
||||
Gauges map[string]GaugeValue
|
||||
|
||||
// Points maps the string to the list of emitted values
|
||||
// from EmitKey
|
||||
|
@ -44,32 +48,34 @@ type IntervalMetrics struct {
|
|||
|
||||
// Counters maps the string key to a sum of the counter
|
||||
// values
|
||||
Counters map[string]*AggregateSample
|
||||
Counters map[string]SampledValue
|
||||
|
||||
// Samples maps the key to an AggregateSample,
|
||||
// which has the rolled up view of a sample
|
||||
Samples map[string]*AggregateSample
|
||||
Samples map[string]SampledValue
|
||||
}
|
||||
|
||||
// NewIntervalMetrics creates a new IntervalMetrics for a given interval
|
||||
func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
|
||||
return &IntervalMetrics{
|
||||
Interval: intv,
|
||||
Gauges: make(map[string]float32),
|
||||
Gauges: make(map[string]GaugeValue),
|
||||
Points: make(map[string][]float32),
|
||||
Counters: make(map[string]*AggregateSample),
|
||||
Samples: make(map[string]*AggregateSample),
|
||||
Counters: make(map[string]SampledValue),
|
||||
Samples: make(map[string]SampledValue),
|
||||
}
|
||||
}
|
||||
|
||||
// AggregateSample is used to hold aggregate metrics
|
||||
// about a sample
|
||||
type AggregateSample struct {
|
||||
Count int // The count of emitted pairs
|
||||
Sum float64 // The sum of values
|
||||
SumSq float64 // The sum of squared values
|
||||
Min float64 // Minimum value
|
||||
Max float64 // Maximum value
|
||||
Count int // The count of emitted pairs
|
||||
Rate float64 // The values rate per time unit (usually 1 second)
|
||||
Sum float64 // The sum of values
|
||||
SumSq float64 `json:"-"` // The sum of squared values
|
||||
Min float64 // Minimum value
|
||||
Max float64 // Maximum value
|
||||
LastUpdated time.Time `json:"-"` // When value was last updated
|
||||
}
|
||||
|
||||
// Computes a Stddev of the values
|
||||
|
@ -91,7 +97,7 @@ func (a *AggregateSample) Mean() float64 {
|
|||
}
|
||||
|
||||
// Ingest is used to update a sample
|
||||
func (a *AggregateSample) Ingest(v float64) {
|
||||
func (a *AggregateSample) Ingest(v float64, rateDenom float64) {
|
||||
a.Count++
|
||||
a.Sum += v
|
||||
a.SumSq += (v * v)
|
||||
|
@ -101,38 +107,64 @@ func (a *AggregateSample) Ingest(v float64) {
|
|||
if v > a.Max || a.Count == 1 {
|
||||
a.Max = v
|
||||
}
|
||||
a.Rate = float64(a.Sum) / rateDenom
|
||||
a.LastUpdated = time.Now()
|
||||
}
|
||||
|
||||
func (a *AggregateSample) String() string {
|
||||
if a.Count == 0 {
|
||||
return "Count: 0"
|
||||
} else if a.Stddev() == 0 {
|
||||
return fmt.Sprintf("Count: %d Sum: %0.3f", a.Count, a.Sum)
|
||||
return fmt.Sprintf("Count: %d Sum: %0.3f LastUpdated: %s", a.Count, a.Sum, a.LastUpdated)
|
||||
} else {
|
||||
return fmt.Sprintf("Count: %d Min: %0.3f Mean: %0.3f Max: %0.3f Stddev: %0.3f Sum: %0.3f",
|
||||
a.Count, a.Min, a.Mean(), a.Max, a.Stddev(), a.Sum)
|
||||
return fmt.Sprintf("Count: %d Min: %0.3f Mean: %0.3f Max: %0.3f Stddev: %0.3f Sum: %0.3f LastUpdated: %s",
|
||||
a.Count, a.Min, a.Mean(), a.Max, a.Stddev(), a.Sum, a.LastUpdated)
|
||||
}
|
||||
}
|
||||
|
||||
// NewInmemSinkFromURL creates an InmemSink from a URL. It is used
|
||||
// (and tested) from NewMetricSinkFromURL.
|
||||
func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
|
||||
params := u.Query()
|
||||
|
||||
interval, err := time.ParseDuration(params.Get("interval"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Bad 'interval' param: %s", err)
|
||||
}
|
||||
|
||||
retain, err := time.ParseDuration(params.Get("retain"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Bad 'retain' param: %s", err)
|
||||
}
|
||||
|
||||
return NewInmemSink(interval, retain), nil
|
||||
}
|
||||
|
||||
// NewInmemSink is used to construct a new in-memory sink.
|
||||
// Uses an aggregation interval and maximum retention period.
|
||||
func NewInmemSink(interval, retain time.Duration) *InmemSink {
|
||||
rateTimeUnit := time.Second
|
||||
i := &InmemSink{
|
||||
interval: interval,
|
||||
retain: retain,
|
||||
maxIntervals: int(retain / interval),
|
||||
rateDenom: float64(interval.Nanoseconds()) / float64(rateTimeUnit.Nanoseconds()),
|
||||
}
|
||||
i.intervals = make([]*IntervalMetrics, 0, i.maxIntervals)
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *InmemSink) SetGauge(key []string, val float32) {
|
||||
k := i.flattenKey(key)
|
||||
i.SetGaugeWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (i *InmemSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
|
||||
k, name := i.flattenKeyLabels(key, labels)
|
||||
intv := i.getInterval()
|
||||
|
||||
intv.Lock()
|
||||
defer intv.Unlock()
|
||||
intv.Gauges[k] = val
|
||||
intv.Gauges[k] = GaugeValue{Name: name, Value: val, Labels: labels}
|
||||
}
|
||||
|
||||
func (i *InmemSink) EmitKey(key []string, val float32) {
|
||||
|
@ -146,33 +178,49 @@ func (i *InmemSink) EmitKey(key []string, val float32) {
|
|||
}
|
||||
|
||||
func (i *InmemSink) IncrCounter(key []string, val float32) {
|
||||
k := i.flattenKey(key)
|
||||
i.IncrCounterWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (i *InmemSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
|
||||
k, name := i.flattenKeyLabels(key, labels)
|
||||
intv := i.getInterval()
|
||||
|
||||
intv.Lock()
|
||||
defer intv.Unlock()
|
||||
|
||||
agg := intv.Counters[k]
|
||||
if agg == nil {
|
||||
agg = &AggregateSample{}
|
||||
agg, ok := intv.Counters[k]
|
||||
if !ok {
|
||||
agg = SampledValue{
|
||||
Name: name,
|
||||
AggregateSample: &AggregateSample{},
|
||||
Labels: labels,
|
||||
}
|
||||
intv.Counters[k] = agg
|
||||
}
|
||||
agg.Ingest(float64(val))
|
||||
agg.Ingest(float64(val), i.rateDenom)
|
||||
}
|
||||
|
||||
func (i *InmemSink) AddSample(key []string, val float32) {
|
||||
k := i.flattenKey(key)
|
||||
i.AddSampleWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (i *InmemSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
|
||||
k, name := i.flattenKeyLabels(key, labels)
|
||||
intv := i.getInterval()
|
||||
|
||||
intv.Lock()
|
||||
defer intv.Unlock()
|
||||
|
||||
agg := intv.Samples[k]
|
||||
if agg == nil {
|
||||
agg = &AggregateSample{}
|
||||
agg, ok := intv.Samples[k]
|
||||
if !ok {
|
||||
agg = SampledValue{
|
||||
Name: name,
|
||||
AggregateSample: &AggregateSample{},
|
||||
Labels: labels,
|
||||
}
|
||||
intv.Samples[k] = agg
|
||||
}
|
||||
agg.Ingest(float64(val))
|
||||
agg.Ingest(float64(val), i.rateDenom)
|
||||
}
|
||||
|
||||
// Data is used to retrieve all the aggregated metrics
|
||||
|
@ -184,8 +232,37 @@ func (i *InmemSink) Data() []*IntervalMetrics {
|
|||
i.intervalLock.RLock()
|
||||
defer i.intervalLock.RUnlock()
|
||||
|
||||
intervals := make([]*IntervalMetrics, len(i.intervals))
|
||||
copy(intervals, i.intervals)
|
||||
n := len(i.intervals)
|
||||
intervals := make([]*IntervalMetrics, n)
|
||||
|
||||
copy(intervals[:n-1], i.intervals[:n-1])
|
||||
current := i.intervals[n-1]
|
||||
|
||||
// make its own copy for current interval
|
||||
intervals[n-1] = &IntervalMetrics{}
|
||||
copyCurrent := intervals[n-1]
|
||||
current.RLock()
|
||||
*copyCurrent = *current
|
||||
|
||||
copyCurrent.Gauges = make(map[string]GaugeValue, len(current.Gauges))
|
||||
for k, v := range current.Gauges {
|
||||
copyCurrent.Gauges[k] = v
|
||||
}
|
||||
// saved values will be not change, just copy its link
|
||||
copyCurrent.Points = make(map[string][]float32, len(current.Points))
|
||||
for k, v := range current.Points {
|
||||
copyCurrent.Points[k] = v
|
||||
}
|
||||
copyCurrent.Counters = make(map[string]SampledValue, len(current.Counters))
|
||||
for k, v := range current.Counters {
|
||||
copyCurrent.Counters[k] = v
|
||||
}
|
||||
copyCurrent.Samples = make(map[string]SampledValue, len(current.Samples))
|
||||
for k, v := range current.Samples {
|
||||
copyCurrent.Samples[k] = v
|
||||
}
|
||||
current.RUnlock()
|
||||
|
||||
return intervals
|
||||
}
|
||||
|
||||
|
@ -234,6 +311,38 @@ func (i *InmemSink) getInterval() *IntervalMetrics {
|
|||
|
||||
// Flattens the key for formatting, removes spaces
|
||||
func (i *InmemSink) flattenKey(parts []string) string {
|
||||
joined := strings.Join(parts, ".")
|
||||
return strings.Replace(joined, " ", "_", -1)
|
||||
buf := &bytes.Buffer{}
|
||||
replacer := strings.NewReplacer(" ", "_")
|
||||
|
||||
if len(parts) > 0 {
|
||||
replacer.WriteString(buf, parts[0])
|
||||
}
|
||||
for _, part := range parts[1:] {
|
||||
replacer.WriteString(buf, ".")
|
||||
replacer.WriteString(buf, part)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Flattens the key for formatting along with its labels, removes spaces
|
||||
func (i *InmemSink) flattenKeyLabels(parts []string, labels []Label) (string, string) {
|
||||
buf := &bytes.Buffer{}
|
||||
replacer := strings.NewReplacer(" ", "_")
|
||||
|
||||
if len(parts) > 0 {
|
||||
replacer.WriteString(buf, parts[0])
|
||||
}
|
||||
for _, part := range parts[1:] {
|
||||
replacer.WriteString(buf, ".")
|
||||
replacer.WriteString(buf, part)
|
||||
}
|
||||
|
||||
key := buf.String()
|
||||
|
||||
for _, label := range labels {
|
||||
replacer.WriteString(buf, fmt.Sprintf(";%s=%s", label.Name, label.Value))
|
||||
}
|
||||
|
||||
return buf.String(), key
|
||||
}
|
||||
|
|
118
vendor/github.com/armon/go-metrics/inmem_endpoint.go
generated
vendored
Normal file
118
vendor/github.com/armon/go-metrics/inmem_endpoint.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MetricsSummary holds a roll-up of metrics info for a given interval
|
||||
type MetricsSummary struct {
|
||||
Timestamp string
|
||||
Gauges []GaugeValue
|
||||
Points []PointValue
|
||||
Counters []SampledValue
|
||||
Samples []SampledValue
|
||||
}
|
||||
|
||||
type GaugeValue struct {
|
||||
Name string
|
||||
Hash string `json:"-"`
|
||||
Value float32
|
||||
|
||||
Labels []Label `json:"-"`
|
||||
DisplayLabels map[string]string `json:"Labels"`
|
||||
}
|
||||
|
||||
type PointValue struct {
|
||||
Name string
|
||||
Points []float32
|
||||
}
|
||||
|
||||
type SampledValue struct {
|
||||
Name string
|
||||
Hash string `json:"-"`
|
||||
*AggregateSample
|
||||
Mean float64
|
||||
Stddev float64
|
||||
|
||||
Labels []Label `json:"-"`
|
||||
DisplayLabels map[string]string `json:"Labels"`
|
||||
}
|
||||
|
||||
// DisplayMetrics returns a summary of the metrics from the most recent finished interval.
|
||||
func (i *InmemSink) DisplayMetrics(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
data := i.Data()
|
||||
|
||||
var interval *IntervalMetrics
|
||||
n := len(data)
|
||||
switch {
|
||||
case n == 0:
|
||||
return nil, fmt.Errorf("no metric intervals have been initialized yet")
|
||||
case n == 1:
|
||||
// Show the current interval if it's all we have
|
||||
interval = i.intervals[0]
|
||||
default:
|
||||
// Show the most recent finished interval if we have one
|
||||
interval = i.intervals[n-2]
|
||||
}
|
||||
|
||||
summary := MetricsSummary{
|
||||
Timestamp: interval.Interval.Round(time.Second).UTC().String(),
|
||||
Gauges: make([]GaugeValue, 0, len(interval.Gauges)),
|
||||
Points: make([]PointValue, 0, len(interval.Points)),
|
||||
}
|
||||
|
||||
// Format and sort the output of each metric type, so it gets displayed in a
|
||||
// deterministic order.
|
||||
for name, points := range interval.Points {
|
||||
summary.Points = append(summary.Points, PointValue{name, points})
|
||||
}
|
||||
sort.Slice(summary.Points, func(i, j int) bool {
|
||||
return summary.Points[i].Name < summary.Points[j].Name
|
||||
})
|
||||
|
||||
for hash, value := range interval.Gauges {
|
||||
value.Hash = hash
|
||||
value.DisplayLabels = make(map[string]string)
|
||||
for _, label := range value.Labels {
|
||||
value.DisplayLabels[label.Name] = label.Value
|
||||
}
|
||||
value.Labels = nil
|
||||
|
||||
summary.Gauges = append(summary.Gauges, value)
|
||||
}
|
||||
sort.Slice(summary.Gauges, func(i, j int) bool {
|
||||
return summary.Gauges[i].Hash < summary.Gauges[j].Hash
|
||||
})
|
||||
|
||||
summary.Counters = formatSamples(interval.Counters)
|
||||
summary.Samples = formatSamples(interval.Samples)
|
||||
|
||||
return summary, nil
|
||||
}
|
||||
|
||||
func formatSamples(source map[string]SampledValue) []SampledValue {
|
||||
output := make([]SampledValue, 0, len(source))
|
||||
for hash, sample := range source {
|
||||
displayLabels := make(map[string]string)
|
||||
for _, label := range sample.Labels {
|
||||
displayLabels[label.Name] = label.Value
|
||||
}
|
||||
|
||||
output = append(output, SampledValue{
|
||||
Name: sample.Name,
|
||||
Hash: hash,
|
||||
AggregateSample: sample.AggregateSample,
|
||||
Mean: sample.AggregateSample.Mean(),
|
||||
Stddev: sample.AggregateSample.Stddev(),
|
||||
DisplayLabels: displayLabels,
|
||||
})
|
||||
}
|
||||
sort.Slice(output, func(i, j int) bool {
|
||||
return output[i].Hash < output[j].Hash
|
||||
})
|
||||
|
||||
return output
|
||||
}
|
33
vendor/github.com/armon/go-metrics/inmem_signal.go
generated
vendored
33
vendor/github.com/armon/go-metrics/inmem_signal.go
generated
vendored
|
@ -6,6 +6,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
@ -75,22 +76,25 @@ func (i *InmemSignal) dumpStats() {
|
|||
|
||||
data := i.inm.Data()
|
||||
// Skip the last period which is still being aggregated
|
||||
for i := 0; i < len(data)-1; i++ {
|
||||
intv := data[i]
|
||||
for j := 0; j < len(data)-1; j++ {
|
||||
intv := data[j]
|
||||
intv.RLock()
|
||||
for name, val := range intv.Gauges {
|
||||
fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val)
|
||||
for _, val := range intv.Gauges {
|
||||
name := i.flattenLabels(val.Name, val.Labels)
|
||||
fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val.Value)
|
||||
}
|
||||
for name, vals := range intv.Points {
|
||||
for _, val := range vals {
|
||||
fmt.Fprintf(buf, "[%v][P] '%s': %0.3f\n", intv.Interval, name, val)
|
||||
}
|
||||
}
|
||||
for name, agg := range intv.Counters {
|
||||
fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg)
|
||||
for _, agg := range intv.Counters {
|
||||
name := i.flattenLabels(agg.Name, agg.Labels)
|
||||
fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg.AggregateSample)
|
||||
}
|
||||
for name, agg := range intv.Samples {
|
||||
fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg)
|
||||
for _, agg := range intv.Samples {
|
||||
name := i.flattenLabels(agg.Name, agg.Labels)
|
||||
fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg.AggregateSample)
|
||||
}
|
||||
intv.RUnlock()
|
||||
}
|
||||
|
@ -98,3 +102,16 @@ func (i *InmemSignal) dumpStats() {
|
|||
// Write out the bytes
|
||||
i.w.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
// Flattens the key for formatting along with its labels, removes spaces
|
||||
func (i *InmemSignal) flattenLabels(name string, labels []Label) string {
|
||||
buf := bytes.NewBufferString(name)
|
||||
replacer := strings.NewReplacer(" ", "_", ":", "_")
|
||||
|
||||
for _, label := range labels {
|
||||
replacer.WriteString(buf, ".")
|
||||
replacer.WriteString(buf, label.Value)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
|
183
vendor/github.com/armon/go-metrics/metrics.go
generated
vendored
183
vendor/github.com/armon/go-metrics/metrics.go
generated
vendored
|
@ -2,20 +2,44 @@ package metrics
|
|||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-immutable-radix"
|
||||
)
|
||||
|
||||
type Label struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
func (m *Metrics) SetGauge(key []string, val float32) {
|
||||
if m.HostName != "" && m.EnableHostname {
|
||||
key = insert(0, m.HostName, key)
|
||||
m.SetGaugeWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (m *Metrics) SetGaugeWithLabels(key []string, val float32, labels []Label) {
|
||||
if m.HostName != "" {
|
||||
if m.EnableHostnameLabel {
|
||||
labels = append(labels, Label{"host", m.HostName})
|
||||
} else if m.EnableHostname {
|
||||
key = insert(0, m.HostName, key)
|
||||
}
|
||||
}
|
||||
if m.EnableTypePrefix {
|
||||
key = insert(0, "gauge", key)
|
||||
}
|
||||
if m.ServiceName != "" {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
if m.EnableServiceLabel {
|
||||
labels = append(labels, Label{"service", m.ServiceName})
|
||||
} else {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
}
|
||||
}
|
||||
m.sink.SetGauge(key, val)
|
||||
allowed, labelsFiltered := m.allowMetric(key, labels)
|
||||
if !allowed {
|
||||
return
|
||||
}
|
||||
m.sink.SetGaugeWithLabels(key, val, labelsFiltered)
|
||||
}
|
||||
|
||||
func (m *Metrics) EmitKey(key []string, val float32) {
|
||||
|
@ -25,40 +49,179 @@ func (m *Metrics) EmitKey(key []string, val float32) {
|
|||
if m.ServiceName != "" {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
}
|
||||
allowed, _ := m.allowMetric(key, nil)
|
||||
if !allowed {
|
||||
return
|
||||
}
|
||||
m.sink.EmitKey(key, val)
|
||||
}
|
||||
|
||||
func (m *Metrics) IncrCounter(key []string, val float32) {
|
||||
m.IncrCounterWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (m *Metrics) IncrCounterWithLabels(key []string, val float32, labels []Label) {
|
||||
if m.HostName != "" && m.EnableHostnameLabel {
|
||||
labels = append(labels, Label{"host", m.HostName})
|
||||
}
|
||||
if m.EnableTypePrefix {
|
||||
key = insert(0, "counter", key)
|
||||
}
|
||||
if m.ServiceName != "" {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
if m.EnableServiceLabel {
|
||||
labels = append(labels, Label{"service", m.ServiceName})
|
||||
} else {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
}
|
||||
}
|
||||
m.sink.IncrCounter(key, val)
|
||||
allowed, labelsFiltered := m.allowMetric(key, labels)
|
||||
if !allowed {
|
||||
return
|
||||
}
|
||||
m.sink.IncrCounterWithLabels(key, val, labelsFiltered)
|
||||
}
|
||||
|
||||
func (m *Metrics) AddSample(key []string, val float32) {
|
||||
m.AddSampleWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (m *Metrics) AddSampleWithLabels(key []string, val float32, labels []Label) {
|
||||
if m.HostName != "" && m.EnableHostnameLabel {
|
||||
labels = append(labels, Label{"host", m.HostName})
|
||||
}
|
||||
if m.EnableTypePrefix {
|
||||
key = insert(0, "sample", key)
|
||||
}
|
||||
if m.ServiceName != "" {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
if m.EnableServiceLabel {
|
||||
labels = append(labels, Label{"service", m.ServiceName})
|
||||
} else {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
}
|
||||
}
|
||||
m.sink.AddSample(key, val)
|
||||
allowed, labelsFiltered := m.allowMetric(key, labels)
|
||||
if !allowed {
|
||||
return
|
||||
}
|
||||
m.sink.AddSampleWithLabels(key, val, labelsFiltered)
|
||||
}
|
||||
|
||||
func (m *Metrics) MeasureSince(key []string, start time.Time) {
|
||||
m.MeasureSinceWithLabels(key, start, nil)
|
||||
}
|
||||
|
||||
func (m *Metrics) MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
|
||||
if m.HostName != "" && m.EnableHostnameLabel {
|
||||
labels = append(labels, Label{"host", m.HostName})
|
||||
}
|
||||
if m.EnableTypePrefix {
|
||||
key = insert(0, "timer", key)
|
||||
}
|
||||
if m.ServiceName != "" {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
if m.EnableServiceLabel {
|
||||
labels = append(labels, Label{"service", m.ServiceName})
|
||||
} else {
|
||||
key = insert(0, m.ServiceName, key)
|
||||
}
|
||||
}
|
||||
allowed, labelsFiltered := m.allowMetric(key, labels)
|
||||
if !allowed {
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
elapsed := now.Sub(start)
|
||||
msec := float32(elapsed.Nanoseconds()) / float32(m.TimerGranularity)
|
||||
m.sink.AddSample(key, msec)
|
||||
m.sink.AddSampleWithLabels(key, msec, labelsFiltered)
|
||||
}
|
||||
|
||||
// UpdateFilter overwrites the existing filter with the given rules.
|
||||
func (m *Metrics) UpdateFilter(allow, block []string) {
|
||||
m.UpdateFilterAndLabels(allow, block, m.AllowedLabels, m.BlockedLabels)
|
||||
}
|
||||
|
||||
// UpdateFilterAndLabels overwrites the existing filter with the given rules.
|
||||
func (m *Metrics) UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
|
||||
m.filterLock.Lock()
|
||||
defer m.filterLock.Unlock()
|
||||
|
||||
m.AllowedPrefixes = allow
|
||||
m.BlockedPrefixes = block
|
||||
|
||||
if allowedLabels == nil {
|
||||
// Having a white list means we take only elements from it
|
||||
m.allowedLabels = nil
|
||||
} else {
|
||||
m.allowedLabels = make(map[string]bool)
|
||||
for _, v := range allowedLabels {
|
||||
m.allowedLabels[v] = true
|
||||
}
|
||||
}
|
||||
m.blockedLabels = make(map[string]bool)
|
||||
for _, v := range blockedLabels {
|
||||
m.blockedLabels[v] = true
|
||||
}
|
||||
m.AllowedLabels = allowedLabels
|
||||
m.BlockedLabels = blockedLabels
|
||||
|
||||
m.filter = iradix.New()
|
||||
for _, prefix := range m.AllowedPrefixes {
|
||||
m.filter, _, _ = m.filter.Insert([]byte(prefix), true)
|
||||
}
|
||||
for _, prefix := range m.BlockedPrefixes {
|
||||
m.filter, _, _ = m.filter.Insert([]byte(prefix), false)
|
||||
}
|
||||
}
|
||||
|
||||
// labelIsAllowed return true if a should be included in metric
|
||||
// the caller should lock m.filterLock while calling this method
|
||||
func (m *Metrics) labelIsAllowed(label *Label) bool {
|
||||
labelName := (*label).Name
|
||||
if m.blockedLabels != nil {
|
||||
_, ok := m.blockedLabels[labelName]
|
||||
if ok {
|
||||
// If present, let's remove this label
|
||||
return false
|
||||
}
|
||||
}
|
||||
if m.allowedLabels != nil {
|
||||
_, ok := m.allowedLabels[labelName]
|
||||
return ok
|
||||
}
|
||||
// Allow by default
|
||||
return true
|
||||
}
|
||||
|
||||
// filterLabels return only allowed labels
|
||||
// the caller should lock m.filterLock while calling this method
|
||||
func (m *Metrics) filterLabels(labels []Label) []Label {
|
||||
if labels == nil {
|
||||
return nil
|
||||
}
|
||||
toReturn := labels[:0]
|
||||
for _, label := range labels {
|
||||
if m.labelIsAllowed(&label) {
|
||||
toReturn = append(toReturn, label)
|
||||
}
|
||||
}
|
||||
return toReturn
|
||||
}
|
||||
|
||||
// Returns whether the metric should be allowed based on configured prefix filters
|
||||
// Also return the applicable labels
|
||||
func (m *Metrics) allowMetric(key []string, labels []Label) (bool, []Label) {
|
||||
m.filterLock.RLock()
|
||||
defer m.filterLock.RUnlock()
|
||||
|
||||
if m.filter == nil || m.filter.Len() == 0 {
|
||||
return m.Config.FilterDefault, m.filterLabels(labels)
|
||||
}
|
||||
|
||||
_, allowed, ok := m.filter.Root().LongestPrefix([]byte(strings.Join(key, ".")))
|
||||
if !ok {
|
||||
return m.Config.FilterDefault, m.filterLabels(labels)
|
||||
}
|
||||
|
||||
return allowed.(bool), m.filterLabels(labels)
|
||||
}
|
||||
|
||||
// Periodically collects runtime stats to publish
|
||||
|
|
77
vendor/github.com/armon/go-metrics/sink.go
generated
vendored
77
vendor/github.com/armon/go-metrics/sink.go
generated
vendored
|
@ -1,35 +1,50 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// The MetricSink interface is used to transmit metrics information
|
||||
// to an external system
|
||||
type MetricSink interface {
|
||||
// A Gauge should retain the last value it is set to
|
||||
SetGauge(key []string, val float32)
|
||||
SetGaugeWithLabels(key []string, val float32, labels []Label)
|
||||
|
||||
// Should emit a Key/Value pair for each call
|
||||
EmitKey(key []string, val float32)
|
||||
|
||||
// Counters should accumulate values
|
||||
IncrCounter(key []string, val float32)
|
||||
IncrCounterWithLabels(key []string, val float32, labels []Label)
|
||||
|
||||
// Samples are for timing information, where quantiles are used
|
||||
AddSample(key []string, val float32)
|
||||
AddSampleWithLabels(key []string, val float32, labels []Label)
|
||||
}
|
||||
|
||||
// BlackholeSink is used to just blackhole messages
|
||||
type BlackholeSink struct{}
|
||||
|
||||
func (*BlackholeSink) SetGauge(key []string, val float32) {}
|
||||
func (*BlackholeSink) EmitKey(key []string, val float32) {}
|
||||
func (*BlackholeSink) IncrCounter(key []string, val float32) {}
|
||||
func (*BlackholeSink) AddSample(key []string, val float32) {}
|
||||
func (*BlackholeSink) SetGauge(key []string, val float32) {}
|
||||
func (*BlackholeSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {}
|
||||
func (*BlackholeSink) EmitKey(key []string, val float32) {}
|
||||
func (*BlackholeSink) IncrCounter(key []string, val float32) {}
|
||||
func (*BlackholeSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {}
|
||||
func (*BlackholeSink) AddSample(key []string, val float32) {}
|
||||
func (*BlackholeSink) AddSampleWithLabels(key []string, val float32, labels []Label) {}
|
||||
|
||||
// FanoutSink is used to sink to fanout values to multiple sinks
|
||||
type FanoutSink []MetricSink
|
||||
|
||||
func (fh FanoutSink) SetGauge(key []string, val float32) {
|
||||
fh.SetGaugeWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (fh FanoutSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
|
||||
for _, s := range fh {
|
||||
s.SetGauge(key, val)
|
||||
s.SetGaugeWithLabels(key, val, labels)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,13 +55,61 @@ func (fh FanoutSink) EmitKey(key []string, val float32) {
|
|||
}
|
||||
|
||||
func (fh FanoutSink) IncrCounter(key []string, val float32) {
|
||||
fh.IncrCounterWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (fh FanoutSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
|
||||
for _, s := range fh {
|
||||
s.IncrCounter(key, val)
|
||||
s.IncrCounterWithLabels(key, val, labels)
|
||||
}
|
||||
}
|
||||
|
||||
func (fh FanoutSink) AddSample(key []string, val float32) {
|
||||
fh.AddSampleWithLabels(key, val, nil)
|
||||
}
|
||||
|
||||
func (fh FanoutSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
|
||||
for _, s := range fh {
|
||||
s.AddSample(key, val)
|
||||
s.AddSampleWithLabels(key, val, labels)
|
||||
}
|
||||
}
|
||||
|
||||
// sinkURLFactoryFunc is an generic interface around the *SinkFromURL() function provided
|
||||
// by each sink type
|
||||
type sinkURLFactoryFunc func(*url.URL) (MetricSink, error)
|
||||
|
||||
// sinkRegistry supports the generic NewMetricSink function by mapping URL
|
||||
// schemes to metric sink factory functions
|
||||
var sinkRegistry = map[string]sinkURLFactoryFunc{
|
||||
"statsd": NewStatsdSinkFromURL,
|
||||
"statsite": NewStatsiteSinkFromURL,
|
||||
"inmem": NewInmemSinkFromURL,
|
||||
}
|
||||
|
||||
// NewMetricSinkFromURL allows a generic URL input to configure any of the
|
||||
// supported sinks. The scheme of the URL identifies the type of the sink, the
|
||||
// and query parameters are used to set options.
|
||||
//
|
||||
// "statsd://" - Initializes a StatsdSink. The host and port are passed through
|
||||
// as the "addr" of the sink
|
||||
//
|
||||
// "statsite://" - Initializes a StatsiteSink. The host and port become the
|
||||
// "addr" of the sink
|
||||
//
|
||||
// "inmem://" - Initializes an InmemSink. The host and port are ignored. The
|
||||
// "interval" and "duration" query parameters must be specified with valid
|
||||
// durations, see NewInmemSink for details.
|
||||
func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
|
||||
u, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sinkURLFactoryFunc := sinkRegistry[u.Scheme]
|
||||
if sinkURLFactoryFunc == nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot create metric sink, unrecognized sink name: %q", u.Scheme)
|
||||
}
|
||||
|
||||
return sinkURLFactoryFunc(u)
|
||||
}
|
||||
|
|
68
vendor/github.com/armon/go-metrics/start.go
generated
vendored
68
vendor/github.com/armon/go-metrics/start.go
generated
vendored
|
@ -2,34 +2,50 @@ package metrics
|
|||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-immutable-radix"
|
||||
)
|
||||
|
||||
// Config is used to configure metrics settings
|
||||
type Config struct {
|
||||
ServiceName string // Prefixed with keys to seperate services
|
||||
ServiceName string // Prefixed with keys to separate services
|
||||
HostName string // Hostname to use. If not provided and EnableHostname, it will be os.Hostname
|
||||
EnableHostname bool // Enable prefixing gauge values with hostname
|
||||
EnableHostnameLabel bool // Enable adding hostname to labels
|
||||
EnableServiceLabel bool // Enable adding service to labels
|
||||
EnableRuntimeMetrics bool // Enables profiling of runtime metrics (GC, Goroutines, Memory)
|
||||
EnableTypePrefix bool // Prefixes key with a type ("counter", "gauge", "timer")
|
||||
TimerGranularity time.Duration // Granularity of timers.
|
||||
ProfileInterval time.Duration // Interval to profile runtime metrics
|
||||
|
||||
AllowedPrefixes []string // A list of metric prefixes to allow, with '.' as the separator
|
||||
BlockedPrefixes []string // A list of metric prefixes to block, with '.' as the separator
|
||||
AllowedLabels []string // A list of metric labels to allow, with '.' as the separator
|
||||
BlockedLabels []string // A list of metric labels to block, with '.' as the separator
|
||||
FilterDefault bool // Whether to allow metrics by default
|
||||
}
|
||||
|
||||
// Metrics represents an instance of a metrics sink that can
|
||||
// be used to emit
|
||||
type Metrics struct {
|
||||
Config
|
||||
lastNumGC uint32
|
||||
sink MetricSink
|
||||
lastNumGC uint32
|
||||
sink MetricSink
|
||||
filter *iradix.Tree
|
||||
allowedLabels map[string]bool
|
||||
blockedLabels map[string]bool
|
||||
filterLock sync.RWMutex // Lock filters and allowedLabels/blockedLabels access
|
||||
}
|
||||
|
||||
// Shared global metrics instance
|
||||
var globalMetrics *Metrics
|
||||
var globalMetrics atomic.Value // *Metrics
|
||||
|
||||
func init() {
|
||||
// Initialize to a blackhole sink to avoid errors
|
||||
globalMetrics = &Metrics{sink: &BlackholeSink{}}
|
||||
globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
|
||||
}
|
||||
|
||||
// DefaultConfig provides a sane default configuration
|
||||
|
@ -42,6 +58,7 @@ func DefaultConfig(serviceName string) *Config {
|
|||
EnableTypePrefix: false, // Disable type prefix
|
||||
TimerGranularity: time.Millisecond, // Timers are in milliseconds
|
||||
ProfileInterval: time.Second, // Poll runtime every second
|
||||
FilterDefault: true, // Don't filter metrics by default
|
||||
}
|
||||
|
||||
// Try to get the hostname
|
||||
|
@ -55,6 +72,7 @@ func New(conf *Config, sink MetricSink) (*Metrics, error) {
|
|||
met := &Metrics{}
|
||||
met.Config = *conf
|
||||
met.sink = sink
|
||||
met.UpdateFilterAndLabels(conf.AllowedPrefixes, conf.BlockedPrefixes, conf.AllowedLabels, conf.BlockedLabels)
|
||||
|
||||
// Start the runtime collector
|
||||
if conf.EnableRuntimeMetrics {
|
||||
|
@ -68,28 +86,56 @@ func New(conf *Config, sink MetricSink) (*Metrics, error) {
|
|||
func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
|
||||
metrics, err := New(conf, sink)
|
||||
if err == nil {
|
||||
globalMetrics = metrics
|
||||
globalMetrics.Store(metrics)
|
||||
}
|
||||
return metrics, err
|
||||
}
|
||||
|
||||
// Proxy all the methods to the globalMetrics instance
|
||||
func SetGauge(key []string, val float32) {
|
||||
globalMetrics.SetGauge(key, val)
|
||||
globalMetrics.Load().(*Metrics).SetGauge(key, val)
|
||||
}
|
||||
|
||||
func SetGaugeWithLabels(key []string, val float32, labels []Label) {
|
||||
globalMetrics.Load().(*Metrics).SetGaugeWithLabels(key, val, labels)
|
||||
}
|
||||
|
||||
func EmitKey(key []string, val float32) {
|
||||
globalMetrics.EmitKey(key, val)
|
||||
globalMetrics.Load().(*Metrics).EmitKey(key, val)
|
||||
}
|
||||
|
||||
func IncrCounter(key []string, val float32) {
|
||||
globalMetrics.IncrCounter(key, val)
|
||||
globalMetrics.Load().(*Metrics).IncrCounter(key, val)
|
||||
}
|
||||
|
||||
func IncrCounterWithLabels(key []string, val float32, labels []Label) {
|
||||
globalMetrics.Load().(*Metrics).IncrCounterWithLabels(key, val, labels)
|
||||
}
|
||||
|
||||
func AddSample(key []string, val float32) {
|
||||
globalMetrics.AddSample(key, val)
|
||||
globalMetrics.Load().(*Metrics).AddSample(key, val)
|
||||
}
|
||||
|
||||
func AddSampleWithLabels(key []string, val float32, labels []Label) {
|
||||
globalMetrics.Load().(*Metrics).AddSampleWithLabels(key, val, labels)
|
||||
}
|
||||
|
||||
func MeasureSince(key []string, start time.Time) {
|
||||
globalMetrics.MeasureSince(key, start)
|
||||
globalMetrics.Load().(*Metrics).MeasureSince(key, start)
|
||||
}
|
||||
|
||||
func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
|
||||
globalMetrics.Load().(*Metrics).MeasureSinceWithLabels(key, start, labels)
|
||||
}
|
||||
|
||||
func UpdateFilter(allow, block []string) {
|
||||
globalMetrics.Load().(*Metrics).UpdateFilter(allow, block)
|
||||
}
|
||||
|
||||
// UpdateFilterAndLabels set allow/block prefixes of metrics while allowedLabels
|
||||
// and blockedLabels - when not nil - allow filtering of labels in order to
|
||||
// block/allow globally labels (especially useful when having large number of
|
||||
// values for a given label). See README.md for more information about usage.
|
||||
func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
|
||||
globalMetrics.Load().(*Metrics).UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
|
||||
}
|
||||
|
|
30
vendor/github.com/armon/go-metrics/statsd.go
generated
vendored
30
vendor/github.com/armon/go-metrics/statsd.go
generated
vendored
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
@ -23,6 +24,12 @@ type StatsdSink struct {
|
|||
metricQueue chan string
|
||||
}
|
||||
|
||||
// NewStatsdSinkFromURL creates an StatsdSink from a URL. It is used
|
||||
// (and tested) from NewMetricSinkFromURL.
|
||||
func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
|
||||
return NewStatsdSink(u.Host)
|
||||
}
|
||||
|
||||
// NewStatsdSink is used to create a new StatsdSink
|
||||
func NewStatsdSink(addr string) (*StatsdSink, error) {
|
||||
s := &StatsdSink{
|
||||
|
@ -43,6 +50,11 @@ func (s *StatsdSink) SetGauge(key []string, val float32) {
|
|||
s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsdSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
|
||||
flatKey := s.flattenKeyLabels(key, labels)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsdSink) EmitKey(key []string, val float32) {
|
||||
flatKey := s.flattenKey(key)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
|
||||
|
@ -53,11 +65,21 @@ func (s *StatsdSink) IncrCounter(key []string, val float32) {
|
|||
s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsdSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
|
||||
flatKey := s.flattenKeyLabels(key, labels)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsdSink) AddSample(key []string, val float32) {
|
||||
flatKey := s.flattenKey(key)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsdSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
|
||||
flatKey := s.flattenKeyLabels(key, labels)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
|
||||
}
|
||||
|
||||
// Flattens the key for formatting, removes spaces
|
||||
func (s *StatsdSink) flattenKey(parts []string) string {
|
||||
joined := strings.Join(parts, ".")
|
||||
|
@ -73,6 +95,14 @@ func (s *StatsdSink) flattenKey(parts []string) string {
|
|||
}, joined)
|
||||
}
|
||||
|
||||
// Flattens the key along with labels for formatting, removes spaces
|
||||
func (s *StatsdSink) flattenKeyLabels(parts []string, labels []Label) string {
|
||||
for _, label := range labels {
|
||||
parts = append(parts, label.Value)
|
||||
}
|
||||
return s.flattenKey(parts)
|
||||
}
|
||||
|
||||
// Does a non-blocking push to the metrics queue
|
||||
func (s *StatsdSink) pushMetric(m string) {
|
||||
select {
|
||||
|
|
30
vendor/github.com/armon/go-metrics/statsite.go
generated
vendored
30
vendor/github.com/armon/go-metrics/statsite.go
generated
vendored
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
@ -16,6 +17,12 @@ const (
|
|||
flushInterval = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
// NewStatsiteSinkFromURL creates an StatsiteSink from a URL. It is used
|
||||
// (and tested) from NewMetricSinkFromURL.
|
||||
func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
|
||||
return NewStatsiteSink(u.Host)
|
||||
}
|
||||
|
||||
// StatsiteSink provides a MetricSink that can be used with a
|
||||
// statsite metrics server
|
||||
type StatsiteSink struct {
|
||||
|
@ -43,6 +50,11 @@ func (s *StatsiteSink) SetGauge(key []string, val float32) {
|
|||
s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsiteSink) SetGaugeWithLabels(key []string, val float32, labels []Label) {
|
||||
flatKey := s.flattenKeyLabels(key, labels)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsiteSink) EmitKey(key []string, val float32) {
|
||||
flatKey := s.flattenKey(key)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
|
||||
|
@ -53,11 +65,21 @@ func (s *StatsiteSink) IncrCounter(key []string, val float32) {
|
|||
s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsiteSink) IncrCounterWithLabels(key []string, val float32, labels []Label) {
|
||||
flatKey := s.flattenKeyLabels(key, labels)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsiteSink) AddSample(key []string, val float32) {
|
||||
flatKey := s.flattenKey(key)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
|
||||
}
|
||||
|
||||
func (s *StatsiteSink) AddSampleWithLabels(key []string, val float32, labels []Label) {
|
||||
flatKey := s.flattenKeyLabels(key, labels)
|
||||
s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
|
||||
}
|
||||
|
||||
// Flattens the key for formatting, removes spaces
|
||||
func (s *StatsiteSink) flattenKey(parts []string) string {
|
||||
joined := strings.Join(parts, ".")
|
||||
|
@ -73,6 +95,14 @@ func (s *StatsiteSink) flattenKey(parts []string) string {
|
|||
}, joined)
|
||||
}
|
||||
|
||||
// Flattens the key along with labels for formatting, removes spaces
|
||||
func (s *StatsiteSink) flattenKeyLabels(parts []string, labels []Label) string {
|
||||
for _, label := range labels {
|
||||
parts = append(parts, label.Value)
|
||||
}
|
||||
return s.flattenKey(parts)
|
||||
}
|
||||
|
||||
// Does a non-blocking push to the metrics queue
|
||||
func (s *StatsiteSink) pushMetric(m string) {
|
||||
select {
|
||||
|
|
2
vendor/github.com/hashicorp/go-msgpack/codec/decode.go
generated
vendored
2
vendor/github.com/hashicorp/go-msgpack/codec/decode.go
generated
vendored
|
@ -527,7 +527,7 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
|
|||
}
|
||||
}
|
||||
rvv := rv.MapIndex(rvk)
|
||||
if !rvv.IsValid() {
|
||||
if !rvv.IsValid() || !rvv.CanSet() {
|
||||
rvv = reflect.New(vtype).Elem()
|
||||
}
|
||||
|
||||
|
|
7
vendor/github.com/hashicorp/go-msgpack/codec/helper.go
generated
vendored
7
vendor/github.com/hashicorp/go-msgpack/codec/helper.go
generated
vendored
|
@ -45,6 +45,13 @@ const (
|
|||
// for debugging, set this to false, to catch panic traces.
|
||||
// Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic.
|
||||
recoverPanicToErr = true
|
||||
|
||||
// if checkStructForEmptyValue, check structs fields to see if an empty value.
|
||||
// This could be an expensive call, so possibly disable it.
|
||||
checkStructForEmptyValue = false
|
||||
|
||||
// if derefForIsEmptyValue, deref pointers and interfaces when checking isEmptyValue
|
||||
derefForIsEmptyValue = false
|
||||
)
|
||||
|
||||
type charEncoding uint8
|
||||
|
|
13
vendor/github.com/hashicorp/go-msgpack/codec/helper_internal.go
generated
vendored
13
vendor/github.com/hashicorp/go-msgpack/codec/helper_internal.go
generated
vendored
|
@ -33,8 +33,10 @@ func panicValToErr(panicVal interface{}, err *error) {
|
|||
return
|
||||
}
|
||||
|
||||
func isEmptyValueDeref(v reflect.Value, deref bool) bool {
|
||||
func hIsEmptyValue(v reflect.Value, deref, checkStruct bool) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
return true
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
|
@ -50,18 +52,21 @@ func isEmptyValueDeref(v reflect.Value, deref bool) bool {
|
|||
if v.IsNil() {
|
||||
return true
|
||||
}
|
||||
return isEmptyValueDeref(v.Elem(), deref)
|
||||
return hIsEmptyValue(v.Elem(), deref, checkStruct)
|
||||
} else {
|
||||
return v.IsNil()
|
||||
}
|
||||
case reflect.Struct:
|
||||
if !checkStruct {
|
||||
return false
|
||||
}
|
||||
// return true if all fields are empty. else return false.
|
||||
|
||||
// we cannot use equality check, because some fields may be maps/slices/etc
|
||||
// and consequently the structs are not comparable.
|
||||
// return v.Interface() == reflect.Zero(v.Type()).Interface()
|
||||
for i, n := 0, v.NumField(); i < n; i++ {
|
||||
if !isEmptyValueDeref(v.Field(i), deref) {
|
||||
if !hIsEmptyValue(v.Field(i), deref, checkStruct) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +76,7 @@ func isEmptyValueDeref(v reflect.Value, deref bool) bool {
|
|||
}
|
||||
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
return isEmptyValueDeref(v, true)
|
||||
return hIsEmptyValue(v, derefForIsEmptyValue, checkStructForEmptyValue)
|
||||
}
|
||||
|
||||
func debugf(format string, args ...interface{}) {
|
||||
|
|
12
vendor/github.com/hashicorp/go-multierror/.travis.yml
generated
vendored
12
vendor/github.com/hashicorp/go-multierror/.travis.yml
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
sudo: false
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.x
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
script: make test testrace
|
69
vendor/github.com/hashicorp/go-multierror/README.md
generated
vendored
69
vendor/github.com/hashicorp/go-multierror/README.md
generated
vendored
|
@ -1,10 +1,11 @@
|
|||
# go-multierror
|
||||
|
||||
[][travis]
|
||||
[][godocs]
|
||||
[](https://circleci.com/gh/hashicorp/go-multierror)
|
||||
[](https://pkg.go.dev/github.com/hashicorp/go-multierror)
|
||||

|
||||
|
||||
[travis]: https://travis-ci.org/hashicorp/go-multierror
|
||||
[godocs]: https://godoc.org/github.com/hashicorp/go-multierror
|
||||
[circleci]: https://app.circleci.com/pipelines/github/hashicorp/go-multierror
|
||||
[godocs]: https://pkg.go.dev/github.com/hashicorp/go-multierror
|
||||
|
||||
`go-multierror` is a package for Go that provides a mechanism for
|
||||
representing a list of `error` values as a single `error`.
|
||||
|
@ -14,16 +15,35 @@ be a list of errors. If the caller knows this, they can unwrap the
|
|||
list and access the errors. If the caller doesn't know, the error
|
||||
formats to a nice human-readable format.
|
||||
|
||||
`go-multierror` implements the
|
||||
[errwrap](https://github.com/hashicorp/errwrap) interface so that it can
|
||||
be used with that library, as well.
|
||||
`go-multierror` is fully compatible with the Go standard library
|
||||
[errors](https://golang.org/pkg/errors/) package, including the
|
||||
functions `As`, `Is`, and `Unwrap`. This provides a standardized approach
|
||||
for introspecting on error values.
|
||||
|
||||
## Installation and Docs
|
||||
|
||||
Install using `go get github.com/hashicorp/go-multierror`.
|
||||
|
||||
Full documentation is available at
|
||||
http://godoc.org/github.com/hashicorp/go-multierror
|
||||
https://pkg.go.dev/github.com/hashicorp/go-multierror
|
||||
|
||||
### Requires go version 1.13 or newer
|
||||
|
||||
`go-multierror` requires go version 1.13 or newer. Go 1.13 introduced
|
||||
[error wrapping](https://golang.org/doc/go1.13#error_wrapping), which
|
||||
this library takes advantage of.
|
||||
|
||||
If you need to use an earlier version of go, you can use the
|
||||
[v1.0.0](https://github.com/hashicorp/go-multierror/tree/v1.0.0)
|
||||
tag, which doesn't rely on features in go 1.13.
|
||||
|
||||
If you see compile errors that look like the below, it's likely that
|
||||
you're on an older version of go:
|
||||
|
||||
```
|
||||
/go/src/github.com/hashicorp/go-multierror/multierror.go:112:9: undefined: errors.As
|
||||
/go/src/github.com/hashicorp/go-multierror/multierror.go:117:9: undefined: errors.Is
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -81,6 +101,39 @@ if err := something(); err != nil {
|
|||
}
|
||||
```
|
||||
|
||||
You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap)
|
||||
function. This will continue to unwrap into subsequent errors until none exist.
|
||||
|
||||
**Extracting an error**
|
||||
|
||||
The standard library [`errors.As`](https://golang.org/pkg/errors/#As)
|
||||
function can be used directly with a multierror to extract a specific error:
|
||||
|
||||
```go
|
||||
// Assume err is a multierror value
|
||||
err := somefunc()
|
||||
|
||||
// We want to know if "err" has a "RichErrorType" in it and extract it.
|
||||
var errRich RichErrorType
|
||||
if errors.As(err, &errRich) {
|
||||
// It has it, and now errRich is populated.
|
||||
}
|
||||
```
|
||||
|
||||
**Checking for an exact error value**
|
||||
|
||||
Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables)
|
||||
error in the `os` package. You can check if this error is present by using
|
||||
the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function.
|
||||
|
||||
```go
|
||||
// Assume err is a multierror value
|
||||
err := somefunc()
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// err contains os.ErrNotExist
|
||||
}
|
||||
```
|
||||
|
||||
**Returning a multierror only if there are errors**
|
||||
|
||||
If you build a `multierror.Error`, you can use the `ErrorOrNil` function
|
||||
|
|
2
vendor/github.com/hashicorp/go-multierror/append.go
generated
vendored
2
vendor/github.com/hashicorp/go-multierror/append.go
generated
vendored
|
@ -6,6 +6,8 @@ package multierror
|
|||
// If err is not a multierror.Error, then it will be turned into
|
||||
// one. If any of the errs are multierr.Error, they will be flattened
|
||||
// one level into err.
|
||||
// Any nil errors within errs will be ignored. If err is nil, a new
|
||||
// *Error will be returned.
|
||||
func Append(err error, errs ...error) *Error {
|
||||
switch err := err.(type) {
|
||||
case *Error:
|
||||
|
|
38
vendor/github.com/hashicorp/go-multierror/group.go
generated
vendored
Normal file
38
vendor/github.com/hashicorp/go-multierror/group.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
package multierror
|
||||
|
||||
import "sync"
|
||||
|
||||
// Group is a collection of goroutines which return errors that need to be
|
||||
// coalesced.
|
||||
type Group struct {
|
||||
mutex sync.Mutex
|
||||
err *Error
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// Go calls the given function in a new goroutine.
|
||||
//
|
||||
// If the function returns an error it is added to the group multierror which
|
||||
// is returned by Wait.
|
||||
func (g *Group) Go(f func() error) {
|
||||
g.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer g.wg.Done()
|
||||
|
||||
if err := f(); err != nil {
|
||||
g.mutex.Lock()
|
||||
g.err = Append(g.err, err)
|
||||
g.mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait blocks until all function calls from the Go method have returned, then
|
||||
// returns the multierror.
|
||||
func (g *Group) Wait() *Error {
|
||||
g.wg.Wait()
|
||||
g.mutex.Lock()
|
||||
defer g.mutex.Unlock()
|
||||
return g.err
|
||||
}
|
82
vendor/github.com/hashicorp/go-multierror/multierror.go
generated
vendored
82
vendor/github.com/hashicorp/go-multierror/multierror.go
generated
vendored
|
@ -1,6 +1,7 @@
|
|||
package multierror
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
@ -39,13 +40,82 @@ func (e *Error) GoString() string {
|
|||
return fmt.Sprintf("*%#v", *e)
|
||||
}
|
||||
|
||||
// WrappedErrors returns the list of errors that this Error is wrapping.
|
||||
// It is an implementation of the errwrap.Wrapper interface so that
|
||||
// multierror.Error can be used with that library.
|
||||
// WrappedErrors returns the list of errors that this Error is wrapping. It is
|
||||
// an implementation of the errwrap.Wrapper interface so that multierror.Error
|
||||
// can be used with that library.
|
||||
//
|
||||
// This method is not safe to be called concurrently and is no different
|
||||
// than accessing the Errors field directly. It is implemented only to
|
||||
// satisfy the errwrap.Wrapper interface.
|
||||
// This method is not safe to be called concurrently. Unlike accessing the
|
||||
// Errors field directly, this function also checks if the multierror is nil to
|
||||
// prevent a null-pointer panic. It satisfies the errwrap.Wrapper interface.
|
||||
func (e *Error) WrappedErrors() []error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Errors
|
||||
}
|
||||
|
||||
// Unwrap returns an error from Error (or nil if there are no errors).
|
||||
// This error returned will further support Unwrap to get the next error,
|
||||
// etc. The order will match the order of Errors in the multierror.Error
|
||||
// at the time of calling.
|
||||
//
|
||||
// The resulting error supports errors.As/Is/Unwrap so you can continue
|
||||
// to use the stdlib errors package to introspect further.
|
||||
//
|
||||
// This will perform a shallow copy of the errors slice. Any errors appended
|
||||
// to this error after calling Unwrap will not be available until a new
|
||||
// Unwrap is called on the multierror.Error.
|
||||
func (e *Error) Unwrap() error {
|
||||
// If we have no errors then we do nothing
|
||||
if e == nil || len(e.Errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we have exactly one error, we can just return that directly.
|
||||
if len(e.Errors) == 1 {
|
||||
return e.Errors[0]
|
||||
}
|
||||
|
||||
// Shallow copy the slice
|
||||
errs := make([]error, len(e.Errors))
|
||||
copy(errs, e.Errors)
|
||||
return chain(errs)
|
||||
}
|
||||
|
||||
// chain implements the interfaces necessary for errors.Is/As/Unwrap to
|
||||
// work in a deterministic way with multierror. A chain tracks a list of
|
||||
// errors while accounting for the current represented error. This lets
|
||||
// Is/As be meaningful.
|
||||
//
|
||||
// Unwrap returns the next error. In the cleanest form, Unwrap would return
|
||||
// the wrapped error here but we can't do that if we want to properly
|
||||
// get access to all the errors. Instead, users are recommended to use
|
||||
// Is/As to get the correct error type out.
|
||||
//
|
||||
// Precondition: []error is non-empty (len > 0)
|
||||
type chain []error
|
||||
|
||||
// Error implements the error interface
|
||||
func (e chain) Error() string {
|
||||
return e[0].Error()
|
||||
}
|
||||
|
||||
// Unwrap implements errors.Unwrap by returning the next error in the
|
||||
// chain or nil if there are no more errors.
|
||||
func (e chain) Unwrap() error {
|
||||
if len(e) == 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return e[1:]
|
||||
}
|
||||
|
||||
// As implements errors.As by attempting to map to the current value.
|
||||
func (e chain) As(target interface{}) bool {
|
||||
return errors.As(e[0], target)
|
||||
}
|
||||
|
||||
// Is implements errors.Is by comparing the current value directly.
|
||||
func (e chain) Is(target error) bool {
|
||||
return errors.Is(e[0], target)
|
||||
}
|
||||
|
|
69
vendor/github.com/hashicorp/serf/coordinate/client.go
generated
vendored
69
vendor/github.com/hashicorp/serf/coordinate/client.go
generated
vendored
|
@ -6,6 +6,8 @@ import (
|
|||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
)
|
||||
|
||||
// Client manages the estimated network coordinate for a given node, and adjusts
|
||||
|
@ -34,10 +36,20 @@ type Client struct {
|
|||
// value to determine how many samples we keep, per node.
|
||||
latencyFilterSamples map[string][]float64
|
||||
|
||||
// stats is used to record events that occur when updating coordinates.
|
||||
stats ClientStats
|
||||
|
||||
// mutex enables safe concurrent access to the client.
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
// ClientStats is used to record events that occur when updating coordinates.
|
||||
type ClientStats struct {
|
||||
// Resets is incremented any time we reset our local coordinate because
|
||||
// our calculations have resulted in an invalid state.
|
||||
Resets int
|
||||
}
|
||||
|
||||
// NewClient creates a new Client and verifies the configuration is valid.
|
||||
func NewClient(config *Config) (*Client, error) {
|
||||
if !(config.Dimensionality > 0) {
|
||||
|
@ -63,11 +75,16 @@ func (c *Client) GetCoordinate() *Coordinate {
|
|||
}
|
||||
|
||||
// SetCoordinate forces the client's coordinate to a known state.
|
||||
func (c *Client) SetCoordinate(coord *Coordinate) {
|
||||
func (c *Client) SetCoordinate(coord *Coordinate) error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
if err := c.checkCoordinate(coord); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.coord = coord.Clone()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForgetNode removes any client state for the given node.
|
||||
|
@ -78,6 +95,29 @@ func (c *Client) ForgetNode(node string) {
|
|||
delete(c.latencyFilterSamples, node)
|
||||
}
|
||||
|
||||
// Stats returns a copy of stats for the client.
|
||||
func (c *Client) Stats() ClientStats {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
return c.stats
|
||||
}
|
||||
|
||||
// checkCoordinate returns an error if the coordinate isn't compatible with
|
||||
// this client, or if the coordinate itself isn't valid. This assumes the mutex
|
||||
// has been locked already.
|
||||
func (c *Client) checkCoordinate(coord *Coordinate) error {
|
||||
if !c.coord.IsCompatibleWith(coord) {
|
||||
return fmt.Errorf("dimensions aren't compatible")
|
||||
}
|
||||
|
||||
if !coord.IsValid() {
|
||||
return fmt.Errorf("coordinate is invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// latencyFilter applies a simple moving median filter with a new sample for
|
||||
// a node. This assumes that the mutex has been locked already.
|
||||
func (c *Client) latencyFilter(node string, rttSeconds float64) float64 {
|
||||
|
@ -159,15 +199,38 @@ func (c *Client) updateGravity() {
|
|||
// Update takes other, a coordinate for another node, and rtt, a round trip
|
||||
// time observation for a ping to that node, and updates the estimated position of
|
||||
// the client's coordinate. Returns the updated coordinate.
|
||||
func (c *Client) Update(node string, other *Coordinate, rtt time.Duration) *Coordinate {
|
||||
func (c *Client) Update(node string, other *Coordinate, rtt time.Duration) (*Coordinate, error) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
if err := c.checkCoordinate(other); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The code down below can handle zero RTTs, which we have seen in
|
||||
// https://github.com/hashicorp/consul/issues/3789, presumably in
|
||||
// environments with coarse-grained monotonic clocks (we are still
|
||||
// trying to pin this down). In any event, this is ok from a code PoV
|
||||
// so we don't need to alert operators with spammy messages. We did
|
||||
// add a counter so this is still observable, though.
|
||||
const maxRTT = 10 * time.Second
|
||||
if rtt < 0 || rtt > maxRTT {
|
||||
return nil, fmt.Errorf("round trip time not in valid range, duration %v is not a positive value less than %v ", rtt, maxRTT)
|
||||
}
|
||||
if rtt == 0 {
|
||||
metrics.IncrCounter([]string{"serf", "coordinate", "zero-rtt"}, 1)
|
||||
}
|
||||
|
||||
rttSeconds := c.latencyFilter(node, rtt.Seconds())
|
||||
c.updateVivaldi(other, rttSeconds)
|
||||
c.updateAdjustment(other, rttSeconds)
|
||||
c.updateGravity()
|
||||
return c.coord.Clone()
|
||||
if !c.coord.IsValid() {
|
||||
c.stats.Resets++
|
||||
c.coord = NewCoordinate(c.config)
|
||||
}
|
||||
|
||||
return c.coord.Clone(), nil
|
||||
}
|
||||
|
||||
// DistanceTo returns the estimated RTT from the client's coordinate to other, the
|
||||
|
|
2
vendor/github.com/hashicorp/serf/coordinate/config.go
generated
vendored
2
vendor/github.com/hashicorp/serf/coordinate/config.go
generated
vendored
|
@ -16,7 +16,7 @@ package coordinate
|
|||
type Config struct {
|
||||
// The dimensionality of the coordinate system. As discussed in [2], more
|
||||
// dimensions improves the accuracy of the estimates up to a point. Per [2]
|
||||
// we chose 4 dimensions plus a non-Euclidean height.
|
||||
// we chose 8 dimensions plus a non-Euclidean height.
|
||||
Dimensionality uint
|
||||
|
||||
// VivaldiErrorMax is the default error value when a node hasn't yet made
|
||||
|
|
30
vendor/github.com/hashicorp/serf/coordinate/coordinate.go
generated
vendored
30
vendor/github.com/hashicorp/serf/coordinate/coordinate.go
generated
vendored
|
@ -72,6 +72,26 @@ func (c *Coordinate) Clone() *Coordinate {
|
|||
}
|
||||
}
|
||||
|
||||
// componentIsValid returns false if a floating point value is a NaN or an
|
||||
// infinity.
|
||||
func componentIsValid(f float64) bool {
|
||||
return !math.IsInf(f, 0) && !math.IsNaN(f)
|
||||
}
|
||||
|
||||
// IsValid returns false if any component of a coordinate isn't valid, per the
|
||||
// componentIsValid() helper above.
|
||||
func (c *Coordinate) IsValid() bool {
|
||||
for i := range c.Vec {
|
||||
if !componentIsValid(c.Vec[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return componentIsValid(c.Error) &&
|
||||
componentIsValid(c.Adjustment) &&
|
||||
componentIsValid(c.Height)
|
||||
}
|
||||
|
||||
// IsCompatibleWith checks to see if the two coordinates are compatible
|
||||
// dimensionally. If this returns true then you are guaranteed to not get
|
||||
// any runtime errors operating on them.
|
||||
|
@ -122,7 +142,7 @@ func (c *Coordinate) rawDistanceTo(other *Coordinate) float64 {
|
|||
// already been checked to be compatible.
|
||||
func add(vec1 []float64, vec2 []float64) []float64 {
|
||||
ret := make([]float64, len(vec1))
|
||||
for i, _ := range ret {
|
||||
for i := range ret {
|
||||
ret[i] = vec1[i] + vec2[i]
|
||||
}
|
||||
return ret
|
||||
|
@ -132,7 +152,7 @@ func add(vec1 []float64, vec2 []float64) []float64 {
|
|||
// dimensions have already been checked to be compatible.
|
||||
func diff(vec1 []float64, vec2 []float64) []float64 {
|
||||
ret := make([]float64, len(vec1))
|
||||
for i, _ := range ret {
|
||||
for i := range ret {
|
||||
ret[i] = vec1[i] - vec2[i]
|
||||
}
|
||||
return ret
|
||||
|
@ -141,7 +161,7 @@ func diff(vec1 []float64, vec2 []float64) []float64 {
|
|||
// mul returns vec multiplied by a scalar factor.
|
||||
func mul(vec []float64, factor float64) []float64 {
|
||||
ret := make([]float64, len(vec))
|
||||
for i, _ := range vec {
|
||||
for i := range vec {
|
||||
ret[i] = vec[i] * factor
|
||||
}
|
||||
return ret
|
||||
|
@ -150,7 +170,7 @@ func mul(vec []float64, factor float64) []float64 {
|
|||
// magnitude computes the magnitude of the vec.
|
||||
func magnitude(vec []float64) float64 {
|
||||
sum := 0.0
|
||||
for i, _ := range vec {
|
||||
for i := range vec {
|
||||
sum += vec[i] * vec[i]
|
||||
}
|
||||
return math.Sqrt(sum)
|
||||
|
@ -168,7 +188,7 @@ func unitVectorAt(vec1 []float64, vec2 []float64) ([]float64, float64) {
|
|||
}
|
||||
|
||||
// Otherwise, just return a random unit vector.
|
||||
for i, _ := range ret {
|
||||
for i := range ret {
|
||||
ret[i] = rand.Float64() - 0.5
|
||||
}
|
||||
if mag := magnitude(ret); mag > zeroThreshold {
|
||||
|
|
3
vendor/github.com/hashicorp/serf/serf/broadcast.go
generated
vendored
3
vendor/github.com/hashicorp/serf/serf/broadcast.go
generated
vendored
|
@ -16,6 +16,9 @@ func (b *broadcast) Invalidates(other memberlist.Broadcast) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// implements memberlist.UniqueBroadcast
|
||||
func (b *broadcast) UniqueBroadcast() {}
|
||||
|
||||
func (b *broadcast) Message() []byte {
|
||||
return b.msg
|
||||
}
|
||||
|
|
56
vendor/github.com/hashicorp/serf/serf/config.go
generated
vendored
56
vendor/github.com/hashicorp/serf/serf/config.go
generated
vendored
|
@ -2,6 +2,7 @@ package serf
|
|||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
|
@ -15,6 +16,7 @@ var ProtocolVersionMap map[uint8]uint8
|
|||
|
||||
func init() {
|
||||
ProtocolVersionMap = map[uint8]uint8{
|
||||
5: 2,
|
||||
4: 2,
|
||||
3: 2,
|
||||
2: 2,
|
||||
|
@ -53,6 +55,13 @@ type Config struct {
|
|||
// set, a timeout of 5 seconds will be set.
|
||||
BroadcastTimeout time.Duration
|
||||
|
||||
// LeavePropagateDelay is for our leave (node dead) message to propagate
|
||||
// through the cluster. In particular, we want to stay up long enough to
|
||||
// service any probes from other nodes before they learn about us
|
||||
// leaving and stop probing. Otherwise, we risk getting node failures as
|
||||
// we leave.
|
||||
LeavePropagateDelay time.Duration
|
||||
|
||||
// The settings below relate to Serf's event coalescence feature. Serf
|
||||
// is able to coalesce multiple events into single events in order to
|
||||
// reduce the amount of noise that is sent along the EventCh. For example
|
||||
|
@ -103,6 +112,17 @@ type Config struct {
|
|||
ReconnectTimeout time.Duration
|
||||
TombstoneTimeout time.Duration
|
||||
|
||||
// FlapTimeout is the amount of time less than which we consider a node
|
||||
// being failed and rejoining looks like a flap for telemetry purposes.
|
||||
// This should be set less than a typical reboot time, but large enough
|
||||
// to see actual events, given our expected detection times for a failed
|
||||
// node.
|
||||
FlapTimeout time.Duration
|
||||
|
||||
// QueueCheckInterval is the interval at which we check the message
|
||||
// queue to apply the warning and max depth.
|
||||
QueueCheckInterval time.Duration
|
||||
|
||||
// QueueDepthWarning is used to generate warning message if the
|
||||
// number of queued messages to broadcast exceeds this number. This
|
||||
// is to provide the user feedback if events are being triggered
|
||||
|
@ -114,12 +134,18 @@ type Config struct {
|
|||
// prevent an unbounded growth of memory utilization
|
||||
MaxQueueDepth int
|
||||
|
||||
// RecentIntentBuffer is used to set the size of recent join and leave intent
|
||||
// messages that will be buffered. This is used to guard against
|
||||
// the case where Serf broadcasts an intent that arrives before the
|
||||
// Memberlist event. It is important that this not be too small to avoid
|
||||
// continuous rebroadcasting of dead events.
|
||||
RecentIntentBuffer int
|
||||
// MinQueueDepth, if >0 will enforce a lower limit for dropping messages
|
||||
// and then the max will be max(MinQueueDepth, 2*SizeOfCluster). This
|
||||
// defaults to 0 which disables this dynamic sizing feature. If this is
|
||||
// >0 then MaxQueueDepth will be ignored.
|
||||
MinQueueDepth int
|
||||
|
||||
// RecentIntentTimeout is used to determine how long we store recent
|
||||
// join and leave intents. This is used to guard against the case where
|
||||
// Serf broadcasts an intent that arrives before the Memberlist event.
|
||||
// It is important that this not be too short to avoid continuous
|
||||
// rebroadcasting of dead events.
|
||||
RecentIntentTimeout time.Duration
|
||||
|
||||
// EventBuffer is used to control how many events are buffered.
|
||||
// This is used to prevent re-delivery of events to a client. The buffer
|
||||
|
@ -175,6 +201,12 @@ type Config struct {
|
|||
// logs will go to stderr.
|
||||
LogOutput io.Writer
|
||||
|
||||
// Logger is a custom logger which you provide. If Logger is set, it will use
|
||||
// this for the internal logger. If Logger is not set, it will fall back to the
|
||||
// behavior for using LogOutput. You cannot specify both LogOutput and Logger
|
||||
// at the same time.
|
||||
Logger *log.Logger
|
||||
|
||||
// SnapshotPath if provided is used to snapshot live nodes as well
|
||||
// as lamport clock values. When Serf is started with a snapshot,
|
||||
// it will attempt to join all the previously known nodes until one
|
||||
|
@ -210,6 +242,10 @@ type Config struct {
|
|||
// Merge can be optionally provided to intercept a cluster merge
|
||||
// and conditionally abort the merge.
|
||||
Merge MergeDelegate
|
||||
|
||||
// UserEventSizeLimit is maximum byte size limit of user event `name` + `payload` in bytes.
|
||||
// It's optimal to be relatively small, since it's going to be gossiped through the cluster.
|
||||
UserEventSizeLimit int
|
||||
}
|
||||
|
||||
// Init allocates the subdata structures
|
||||
|
@ -230,22 +266,26 @@ func DefaultConfig() *Config {
|
|||
return &Config{
|
||||
NodeName: hostname,
|
||||
BroadcastTimeout: 5 * time.Second,
|
||||
LeavePropagateDelay: 1 * time.Second,
|
||||
EventBuffer: 512,
|
||||
QueryBuffer: 512,
|
||||
LogOutput: os.Stderr,
|
||||
ProtocolVersion: ProtocolVersionMax,
|
||||
ProtocolVersion: 4,
|
||||
ReapInterval: 15 * time.Second,
|
||||
RecentIntentBuffer: 128,
|
||||
RecentIntentTimeout: 5 * time.Minute,
|
||||
ReconnectInterval: 30 * time.Second,
|
||||
ReconnectTimeout: 24 * time.Hour,
|
||||
QueueCheckInterval: 30 * time.Second,
|
||||
QueueDepthWarning: 128,
|
||||
MaxQueueDepth: 4096,
|
||||
TombstoneTimeout: 24 * time.Hour,
|
||||
FlapTimeout: 60 * time.Second,
|
||||
MemberlistConfig: memberlist.DefaultLANConfig(),
|
||||
QueryTimeoutMult: 16,
|
||||
QueryResponseSizeLimit: 1024,
|
||||
QuerySizeLimit: 1024,
|
||||
EnableNameConflictResolution: true,
|
||||
DisableCoordinates: false,
|
||||
UserEventSizeLimit: 512,
|
||||
}
|
||||
}
|
||||
|
|
36
vendor/github.com/hashicorp/serf/serf/delegate.go
generated
vendored
36
vendor/github.com/hashicorp/serf/serf/delegate.go
generated
vendored
|
@ -1,9 +1,12 @@
|
|||
package serf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/go-msgpack/codec"
|
||||
"github.com/hashicorp/memberlist"
|
||||
)
|
||||
|
||||
// delegate is the memberlist.Delegate implementation that Serf uses.
|
||||
|
@ -11,6 +14,8 @@ type delegate struct {
|
|||
serf *Serf
|
||||
}
|
||||
|
||||
var _ memberlist.Delegate = &delegate{}
|
||||
|
||||
func (d *delegate) NodeMeta(limit int) []byte {
|
||||
roleBytes := d.serf.encodeTags(d.serf.config.Tags)
|
||||
if len(roleBytes) > limit {
|
||||
|
@ -83,6 +88,25 @@ func (d *delegate) NotifyMsg(buf []byte) {
|
|||
d.serf.logger.Printf("[DEBUG] serf: messageQueryResponseType: %v", resp.From)
|
||||
d.serf.handleQueryResponse(&resp)
|
||||
|
||||
case messageRelayType:
|
||||
var header relayHeader
|
||||
var handle codec.MsgpackHandle
|
||||
reader := bytes.NewReader(buf[1:])
|
||||
decoder := codec.NewDecoder(reader, &handle)
|
||||
if err := decoder.Decode(&header); err != nil {
|
||||
d.serf.logger.Printf("[ERR] serf: Error decoding relay header: %s", err)
|
||||
break
|
||||
}
|
||||
|
||||
// The remaining contents are the message itself, so forward that
|
||||
raw := make([]byte, reader.Len())
|
||||
reader.Read(raw)
|
||||
d.serf.logger.Printf("[DEBUG] serf: Relaying response to addr: %s", header.DestAddr.String())
|
||||
if err := d.serf.memberlist.SendTo(&header.DestAddr, raw); err != nil {
|
||||
d.serf.logger.Printf("[ERR] serf: Error forwarding message to %s: %s", header.DestAddr.String(), err)
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
d.serf.logger.Printf("[WARN] serf: Received message of unknown type: %d", t)
|
||||
}
|
||||
|
@ -202,13 +226,16 @@ func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) {
|
|||
d.serf.queryClock.Witness(pp.QueryLTime - 1)
|
||||
}
|
||||
|
||||
// Process the left nodes first to avoid the LTimes from being increment
|
||||
// in the wrong order
|
||||
// Process the left nodes first to avoid the LTimes from incrementing
|
||||
// in the wrong order. Note that we don't have the actual Lamport time
|
||||
// for the leave message, so we go one past the join time, since the
|
||||
// leave must have been accepted after that to get onto the left members
|
||||
// list. If we didn't do this then the message would not get processed.
|
||||
leftMap := make(map[string]struct{}, len(pp.LeftMembers))
|
||||
leave := messageLeave{}
|
||||
for _, name := range pp.LeftMembers {
|
||||
leftMap[name] = struct{}{}
|
||||
leave.LTime = pp.StatusLTimes[name]
|
||||
leave.LTime = pp.StatusLTimes[name] + 1
|
||||
leave.Node = name
|
||||
d.serf.handleNodeLeaveIntent(&leave)
|
||||
}
|
||||
|
@ -230,7 +257,8 @@ func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) {
|
|||
// If we are doing a join, and eventJoinIgnore is set
|
||||
// then we set the eventMinTime to the EventLTime. This
|
||||
// prevents any of the incoming events from being processed
|
||||
if isJoin && d.serf.eventJoinIgnore {
|
||||
eventJoinIgnore := d.serf.eventJoinIgnore.Load().(bool)
|
||||
if isJoin && eventJoinIgnore {
|
||||
d.serf.eventLock.Lock()
|
||||
if pp.EventLTime > d.serf.eventMinTime {
|
||||
d.serf.eventMinTime = pp.EventLTime
|
||||
|
|
94
vendor/github.com/hashicorp/serf/serf/event.go
generated
vendored
94
vendor/github.com/hashicorp/serf/serf/event.go
generated
vendored
|
@ -95,18 +95,19 @@ func (u UserEvent) String() string {
|
|||
return fmt.Sprintf("user-event: %s", u.Name)
|
||||
}
|
||||
|
||||
// Query is the struct used EventQuery type events
|
||||
// Query is the struct used by EventQuery type events
|
||||
type Query struct {
|
||||
LTime LamportTime
|
||||
Name string
|
||||
Payload []byte
|
||||
|
||||
serf *Serf
|
||||
id uint32 // ID is not exported, since it may change
|
||||
addr []byte // Address to respond to
|
||||
port uint16 // Port to respond to
|
||||
deadline time.Time // Must respond by this deadline
|
||||
respLock sync.Mutex
|
||||
serf *Serf
|
||||
id uint32 // ID is not exported, since it may change
|
||||
addr []byte // Address to respond to
|
||||
port uint16 // Port to respond to
|
||||
deadline time.Time // Must respond by this deadline
|
||||
relayFactor uint8 // Number of duplicate responses to relay back to sender
|
||||
respLock sync.Mutex
|
||||
}
|
||||
|
||||
func (q *Query) EventType() EventType {
|
||||
|
@ -122,47 +123,74 @@ func (q *Query) Deadline() time.Time {
|
|||
return q.deadline
|
||||
}
|
||||
|
||||
// Respond is used to send a response to the user query
|
||||
func (q *Query) Respond(buf []byte) error {
|
||||
q.respLock.Lock()
|
||||
defer q.respLock.Unlock()
|
||||
|
||||
// Check if we've already responded
|
||||
if q.deadline.IsZero() {
|
||||
return fmt.Errorf("Response already sent")
|
||||
}
|
||||
|
||||
// Ensure we aren't past our response deadline
|
||||
if time.Now().After(q.deadline) {
|
||||
return fmt.Errorf("Response is past the deadline")
|
||||
}
|
||||
|
||||
func (q *Query) createResponse(buf []byte) messageQueryResponse {
|
||||
// Create response
|
||||
resp := messageQueryResponse{
|
||||
return messageQueryResponse{
|
||||
LTime: q.LTime,
|
||||
ID: q.id,
|
||||
From: q.serf.config.NodeName,
|
||||
Payload: buf,
|
||||
}
|
||||
}
|
||||
|
||||
// Format the response
|
||||
raw, err := encodeMessage(messageQueryResponseType, &resp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to format response: %v", err)
|
||||
}
|
||||
|
||||
// Check the size limit
|
||||
if len(raw) > q.serf.config.QueryResponseSizeLimit {
|
||||
// Check response size
|
||||
func (q *Query) checkResponseSize(resp []byte) error {
|
||||
if len(resp) > q.serf.config.QueryResponseSizeLimit {
|
||||
return fmt.Errorf("response exceeds limit of %d bytes", q.serf.config.QueryResponseSizeLimit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Send the response
|
||||
func (q *Query) respondWithMessageAndResponse(raw []byte, resp messageQueryResponse) error {
|
||||
// Check the size limit
|
||||
if err := q.checkResponseSize(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
q.respLock.Lock()
|
||||
defer q.respLock.Unlock()
|
||||
|
||||
// Check if we've already responded
|
||||
if q.deadline.IsZero() {
|
||||
return fmt.Errorf("response already sent")
|
||||
}
|
||||
|
||||
// Ensure we aren't past our response deadline
|
||||
if time.Now().After(q.deadline) {
|
||||
return fmt.Errorf("response is past the deadline")
|
||||
}
|
||||
|
||||
// Send the response directly to the originator
|
||||
addr := net.UDPAddr{IP: q.addr, Port: int(q.port)}
|
||||
if err := q.serf.memberlist.SendTo(&addr, raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Clera the deadline, response sent
|
||||
// Relay the response through up to relayFactor other nodes
|
||||
if err := q.serf.relayResponse(q.relayFactor, addr, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Clear the deadline, responses sent
|
||||
q.deadline = time.Time{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Respond is used to send a response to the user query
|
||||
func (q *Query) Respond(buf []byte) error {
|
||||
// Create response
|
||||
resp := q.createResponse(buf)
|
||||
|
||||
// Encode response
|
||||
raw, err := encodeMessage(messageQueryResponseType, resp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to format response: %v", err)
|
||||
}
|
||||
|
||||
if err := q.respondWithMessageAndResponse(raw, resp); err != nil {
|
||||
return fmt.Errorf("failed to respond to key query: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
81
vendor/github.com/hashicorp/serf/serf/internal_query.go
generated
vendored
81
vendor/github.com/hashicorp/serf/serf/internal_query.go
generated
vendored
|
@ -2,6 +2,7 @@ package serf
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
@ -28,6 +29,13 @@ const (
|
|||
|
||||
// listKeysQuery is used to list all known keys in the cluster
|
||||
listKeysQuery = "list-keys"
|
||||
|
||||
// minEncodedKeyLength is used to compute the max number of keys in a list key
|
||||
// response. eg 1024/25 = 40. a message with max size of 1024 bytes cannot
|
||||
// contain more than 40 keys. There is a test
|
||||
// (TestSerfQueries_estimateMaxKeysInListKeyResponse) which does the
|
||||
// computation and in case of changes, the value can be adjusted.
|
||||
minEncodedKeyLength = 25
|
||||
)
|
||||
|
||||
// internalQueryName is used to generate a query name for an internal query
|
||||
|
@ -149,17 +157,62 @@ func (s *serfQueries) handleConflict(q *Query) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *serfQueries) keyListResponseWithCorrectSize(q *Query, resp *nodeKeyResponse) ([]byte, messageQueryResponse, error) {
|
||||
maxListKeys := q.serf.config.QueryResponseSizeLimit / minEncodedKeyLength
|
||||
actual := len(resp.Keys)
|
||||
for i := maxListKeys; i >= 0; i-- {
|
||||
buf, err := encodeMessage(messageKeyResponseType, resp)
|
||||
if err != nil {
|
||||
return nil, messageQueryResponse{}, err
|
||||
}
|
||||
|
||||
// Create response
|
||||
qresp := q.createResponse(buf)
|
||||
|
||||
// Encode response
|
||||
raw, err := encodeMessage(messageQueryResponseType, qresp)
|
||||
if err != nil {
|
||||
return nil, messageQueryResponse{}, err
|
||||
}
|
||||
|
||||
// Check the size limit
|
||||
if err = q.checkResponseSize(raw); err != nil {
|
||||
resp.Keys = resp.Keys[0:i]
|
||||
resp.Message = fmt.Sprintf("truncated key list response, showing first %d of %d keys", i, actual)
|
||||
continue
|
||||
}
|
||||
|
||||
if actual > i {
|
||||
s.logger.Printf("[WARN] serf: %s", resp.Message)
|
||||
}
|
||||
return raw, qresp, nil
|
||||
}
|
||||
return nil, messageQueryResponse{}, fmt.Errorf("Failed to truncate response so that it fits into message")
|
||||
}
|
||||
|
||||
// sendKeyResponse handles responding to key-related queries.
|
||||
func (s *serfQueries) sendKeyResponse(q *Query, resp *nodeKeyResponse) {
|
||||
buf, err := encodeMessage(messageKeyResponseType, resp)
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] serf: Failed to encode key response: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := q.Respond(buf); err != nil {
|
||||
s.logger.Printf("[ERR] serf: Failed to respond to key query: %v", err)
|
||||
return
|
||||
switch q.Name {
|
||||
case internalQueryName(listKeysQuery):
|
||||
raw, qresp, err := s.keyListResponseWithCorrectSize(q, resp)
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] serf: %v", err)
|
||||
return
|
||||
}
|
||||
if err := q.respondWithMessageAndResponse(raw, qresp); err != nil {
|
||||
s.logger.Printf("[ERR] serf: Failed to respond to key query: %v", err)
|
||||
return
|
||||
}
|
||||
default:
|
||||
buf, err := encodeMessage(messageKeyResponseType, resp)
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] serf: Failed to encode key response: %v", err)
|
||||
return
|
||||
}
|
||||
if err := q.Respond(buf); err != nil {
|
||||
s.logger.Printf("[ERR] serf: Failed to respond to key query: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,10 +245,12 @@ func (s *serfQueries) handleInstallKey(q *Query) {
|
|||
goto SEND
|
||||
}
|
||||
|
||||
if err := s.serf.writeKeyringFile(); err != nil {
|
||||
response.Message = err.Error()
|
||||
s.logger.Printf("[ERR] serf: Failed to write keyring file: %s", err)
|
||||
goto SEND
|
||||
if s.serf.config.KeyringFile != "" {
|
||||
if err := s.serf.writeKeyringFile(); err != nil {
|
||||
response.Message = err.Error()
|
||||
s.logger.Printf("[ERR] serf: Failed to write keyring file: %s", err)
|
||||
goto SEND
|
||||
}
|
||||
}
|
||||
|
||||
response.Result = true
|
||||
|
|
41
vendor/github.com/hashicorp/serf/serf/keymanager.go
generated
vendored
41
vendor/github.com/hashicorp/serf/serf/keymanager.go
generated
vendored
|
@ -33,6 +33,13 @@ type KeyResponse struct {
|
|||
Keys map[string]int
|
||||
}
|
||||
|
||||
// KeyRequestOptions is used to contain optional parameters for a keyring operation
|
||||
type KeyRequestOptions struct {
|
||||
// RelayFactor is the number of duplicate query responses to send by relaying through
|
||||
// other nodes, for redundancy
|
||||
RelayFactor uint8
|
||||
}
|
||||
|
||||
// streamKeyResp takes care of reading responses from a channel and composing
|
||||
// them into a KeyResponse. It will update a KeyResponse *in place* and
|
||||
// therefore has nothing to return.
|
||||
|
@ -61,6 +68,11 @@ func (k *KeyManager) streamKeyResp(resp *KeyResponse, ch <-chan NodeResponse) {
|
|||
resp.NumErr++
|
||||
}
|
||||
|
||||
if nodeResponse.Result && len(nodeResponse.Message) > 0 {
|
||||
resp.Messages[r.From] = nodeResponse.Message
|
||||
k.serf.logger.Println("[WARN] serf:", nodeResponse.Message)
|
||||
}
|
||||
|
||||
// Currently only used for key list queries, this adds keys to a counter
|
||||
// and increments them for each node response which contains them.
|
||||
for _, key := range nodeResponse.Keys {
|
||||
|
@ -83,7 +95,7 @@ func (k *KeyManager) streamKeyResp(resp *KeyResponse, ch <-chan NodeResponse) {
|
|||
// handleKeyRequest performs query broadcasting to all members for any type of
|
||||
// key operation and manages gathering responses and packing them up into a
|
||||
// KeyResponse for uniform response handling.
|
||||
func (k *KeyManager) handleKeyRequest(key, query string) (*KeyResponse, error) {
|
||||
func (k *KeyManager) handleKeyRequest(key, query string, opts *KeyRequestOptions) (*KeyResponse, error) {
|
||||
resp := &KeyResponse{
|
||||
Messages: make(map[string]string),
|
||||
Keys: make(map[string]int),
|
||||
|
@ -103,6 +115,9 @@ func (k *KeyManager) handleKeyRequest(key, query string) (*KeyResponse, error) {
|
|||
}
|
||||
|
||||
qParam := k.serf.DefaultQueryParams()
|
||||
if opts != nil {
|
||||
qParam.RelayFactor = opts.RelayFactor
|
||||
}
|
||||
queryResp, err := k.serf.Query(qName, req, qParam)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
|
@ -127,30 +142,42 @@ func (k *KeyManager) handleKeyRequest(key, query string) (*KeyResponse, error) {
|
|||
// responses from each of them, returning a list of messages from each node
|
||||
// and any applicable error conditions.
|
||||
func (k *KeyManager) InstallKey(key string) (*KeyResponse, error) {
|
||||
return k.InstallKeyWithOptions(key, nil)
|
||||
}
|
||||
|
||||
func (k *KeyManager) InstallKeyWithOptions(key string, opts *KeyRequestOptions) (*KeyResponse, error) {
|
||||
k.l.Lock()
|
||||
defer k.l.Unlock()
|
||||
|
||||
return k.handleKeyRequest(key, installKeyQuery)
|
||||
return k.handleKeyRequest(key, installKeyQuery, opts)
|
||||
}
|
||||
|
||||
// UseKey handles broadcasting a primary key change to all members in the
|
||||
// cluster, and gathering any response messages. If successful, there should
|
||||
// be an empty KeyResponse returned.
|
||||
func (k *KeyManager) UseKey(key string) (*KeyResponse, error) {
|
||||
return k.UseKeyWithOptions(key, nil)
|
||||
}
|
||||
|
||||
func (k *KeyManager) UseKeyWithOptions(key string, opts *KeyRequestOptions) (*KeyResponse, error) {
|
||||
k.l.Lock()
|
||||
defer k.l.Unlock()
|
||||
|
||||
return k.handleKeyRequest(key, useKeyQuery)
|
||||
return k.handleKeyRequest(key, useKeyQuery, opts)
|
||||
}
|
||||
|
||||
// RemoveKey handles broadcasting a key to the cluster for removal. Each member
|
||||
// will receive this event, and if they have the key in their keyring, remove
|
||||
// it. If any errors are encountered, RemoveKey will collect and relay them.
|
||||
func (k *KeyManager) RemoveKey(key string) (*KeyResponse, error) {
|
||||
return k.RemoveKeyWithOptions(key, nil)
|
||||
}
|
||||
|
||||
func (k *KeyManager) RemoveKeyWithOptions(key string, opts *KeyRequestOptions) (*KeyResponse, error) {
|
||||
k.l.Lock()
|
||||
defer k.l.Unlock()
|
||||
|
||||
return k.handleKeyRequest(key, removeKeyQuery)
|
||||
return k.handleKeyRequest(key, removeKeyQuery, opts)
|
||||
}
|
||||
|
||||
// ListKeys is used to collect installed keys from members in a Serf cluster
|
||||
|
@ -159,8 +186,12 @@ func (k *KeyManager) RemoveKey(key string) (*KeyResponse, error) {
|
|||
// Since having multiple keys installed can cause performance penalties in some
|
||||
// cases, it's important to verify this information and remove unneeded keys.
|
||||
func (k *KeyManager) ListKeys() (*KeyResponse, error) {
|
||||
return k.ListKeysWithOptions(nil)
|
||||
}
|
||||
|
||||
func (k *KeyManager) ListKeysWithOptions(opts *KeyRequestOptions) (*KeyResponse, error) {
|
||||
k.l.RLock()
|
||||
defer k.l.RUnlock()
|
||||
|
||||
return k.handleKeyRequest("", listKeysQuery)
|
||||
return k.handleKeyRequest("", listKeysQuery, opts)
|
||||
}
|
||||
|
|
47
vendor/github.com/hashicorp/serf/serf/messages.go
generated
vendored
47
vendor/github.com/hashicorp/serf/serf/messages.go
generated
vendored
|
@ -2,8 +2,10 @@ package serf
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/hashicorp/go-msgpack/codec"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-msgpack/codec"
|
||||
)
|
||||
|
||||
// messageType are the types of gossip messages Serf will send along
|
||||
|
@ -20,6 +22,7 @@ const (
|
|||
messageConflictResponseType
|
||||
messageKeyRequestType
|
||||
messageKeyResponseType
|
||||
messageRelayType
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -52,6 +55,7 @@ type messageJoin struct {
|
|||
type messageLeave struct {
|
||||
LTime LamportTime
|
||||
Node string
|
||||
Prune bool
|
||||
}
|
||||
|
||||
// messagePushPullType is used when doing a state exchange. This
|
||||
|
@ -75,15 +79,16 @@ type messageUserEvent struct {
|
|||
|
||||
// messageQuery is used for query events
|
||||
type messageQuery struct {
|
||||
LTime LamportTime // Event lamport time
|
||||
ID uint32 // Query ID, randomly generated
|
||||
Addr []byte // Source address, used for a direct reply
|
||||
Port uint16 // Source port, used for a direct reply
|
||||
Filters [][]byte // Potential query filters
|
||||
Flags uint32 // Used to provide various flags
|
||||
Timeout time.Duration // Maximum time between delivery and response
|
||||
Name string // Query name
|
||||
Payload []byte // Query payload
|
||||
LTime LamportTime // Event lamport time
|
||||
ID uint32 // Query ID, randomly generated
|
||||
Addr []byte // Source address, used for a direct reply
|
||||
Port uint16 // Source port, used for a direct reply
|
||||
Filters [][]byte // Potential query filters
|
||||
Flags uint32 // Used to provide various flags
|
||||
RelayFactor uint8 // Used to set the number of duplicate relayed responses
|
||||
Timeout time.Duration // Maximum time between delivery and response
|
||||
Name string // Query name
|
||||
Payload []byte // Query payload
|
||||
}
|
||||
|
||||
// Ack checks if the ack flag is set
|
||||
|
@ -136,6 +141,28 @@ func encodeMessage(t messageType, msg interface{}) ([]byte, error) {
|
|||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
// relayHeader is used to store the end destination of a relayed message
|
||||
type relayHeader struct {
|
||||
DestAddr net.UDPAddr
|
||||
}
|
||||
|
||||
// encodeRelayMessage wraps a message in the messageRelayType, adding the length and
|
||||
// address of the end recipient to the front of the message
|
||||
func encodeRelayMessage(t messageType, addr net.UDPAddr, msg interface{}) ([]byte, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
handle := codec.MsgpackHandle{}
|
||||
encoder := codec.NewEncoder(buf, &handle)
|
||||
|
||||
buf.WriteByte(uint8(messageRelayType))
|
||||
if err := encoder.Encode(relayHeader{DestAddr: addr}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf.WriteByte(uint8(t))
|
||||
err := encoder.Encode(msg)
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func encodeFilter(f filterType, filt interface{}) ([]byte, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
buf.WriteByte(uint8(f))
|
||||
|
|
49
vendor/github.com/hashicorp/serf/serf/ping_delegate.go
generated
vendored
49
vendor/github.com/hashicorp/serf/serf/ping_delegate.go
generated
vendored
|
@ -2,7 +2,6 @@ package serf
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
|
@ -37,7 +36,7 @@ func (p *pingDelegate) AckPayload() []byte {
|
|||
// The rest of the message is the serialized coordinate.
|
||||
enc := codec.NewEncoder(&buf, &codec.MsgpackHandle{})
|
||||
if err := enc.Encode(p.serf.coordClient.GetCoordinate()); err != nil {
|
||||
log.Printf("[ERR] serf: Failed to encode coordinate: %v\n", err)
|
||||
p.serf.logger.Printf("[ERR] serf: Failed to encode coordinate: %v\n", err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
@ -52,7 +51,7 @@ func (p *pingDelegate) NotifyPingComplete(other *memberlist.Node, rtt time.Durat
|
|||
// Verify ping version in the header.
|
||||
version := payload[0]
|
||||
if version != PingVersion {
|
||||
log.Printf("[ERR] serf: Unsupported ping version: %v", version)
|
||||
p.serf.logger.Printf("[ERR] serf: Unsupported ping version: %v", version)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -61,29 +60,31 @@ func (p *pingDelegate) NotifyPingComplete(other *memberlist.Node, rtt time.Durat
|
|||
dec := codec.NewDecoder(r, &codec.MsgpackHandle{})
|
||||
var coord coordinate.Coordinate
|
||||
if err := dec.Decode(&coord); err != nil {
|
||||
log.Printf("[ERR] serf: Failed to decode coordinate from ping: %v", err)
|
||||
p.serf.logger.Printf("[ERR] serf: Failed to decode coordinate from ping: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Apply the update. Since this is a coordinate coming from some place
|
||||
// else we harden this and look for dimensionality problems proactively.
|
||||
// Apply the update.
|
||||
before := p.serf.coordClient.GetCoordinate()
|
||||
if before.IsCompatibleWith(&coord) {
|
||||
after := p.serf.coordClient.Update(other.Name, &coord, rtt)
|
||||
|
||||
// Publish some metrics to give us an idea of how much we are
|
||||
// adjusting each time we update.
|
||||
d := float32(before.DistanceTo(after).Seconds() * 1.0e3)
|
||||
metrics.AddSample([]string{"serf", "coordinate", "adjustment-ms"}, d)
|
||||
|
||||
// Cache the coordinate for the other node, and add our own
|
||||
// to the cache as well since it just got updated. This lets
|
||||
// users call GetCachedCoordinate with our node name, which is
|
||||
// more friendly.
|
||||
p.serf.coordCacheLock.Lock()
|
||||
p.serf.coordCache[other.Name] = &coord
|
||||
p.serf.coordCache[p.serf.config.NodeName] = p.serf.coordClient.GetCoordinate()
|
||||
p.serf.coordCacheLock.Unlock()
|
||||
} else {
|
||||
log.Printf("[ERR] serf: Rejected bad coordinate: %v\n", coord)
|
||||
after, err := p.serf.coordClient.Update(other.Name, &coord, rtt)
|
||||
if err != nil {
|
||||
metrics.IncrCounter([]string{"serf", "coordinate", "rejected"}, 1)
|
||||
p.serf.logger.Printf("[TRACE] serf: Rejected coordinate from %s: %v\n",
|
||||
other.Name, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Publish some metrics to give us an idea of how much we are
|
||||
// adjusting each time we update.
|
||||
d := float32(before.DistanceTo(after).Seconds() * 1.0e3)
|
||||
metrics.AddSample([]string{"serf", "coordinate", "adjustment-ms"}, d)
|
||||
|
||||
// Cache the coordinate for the other node, and add our own
|
||||
// to the cache as well since it just got updated. This lets
|
||||
// users call GetCachedCoordinate with our node name, which is
|
||||
// more friendly.
|
||||
p.serf.coordCacheLock.Lock()
|
||||
p.serf.coordCache[other.Name] = &coord
|
||||
p.serf.coordCache[p.serf.config.NodeName] = p.serf.coordClient.GetCoordinate()
|
||||
p.serf.coordCacheLock.Unlock()
|
||||
}
|
||||
|
|
111
vendor/github.com/hashicorp/serf/serf/query.go
generated
vendored
111
vendor/github.com/hashicorp/serf/serf/query.go
generated
vendored
|
@ -1,7 +1,11 @@
|
|||
package serf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -24,6 +28,10 @@ type QueryParam struct {
|
|||
// send an ack.
|
||||
RequestAck bool
|
||||
|
||||
// RelayFactor controls the number of duplicate responses to relay
|
||||
// back to the sender through other nodes for redundancy.
|
||||
RelayFactor uint8
|
||||
|
||||
// The timeout limits how long the query is left open. If not provided,
|
||||
// then a default timeout is used based on the configuration of Serf
|
||||
Timeout time.Duration
|
||||
|
@ -93,6 +101,10 @@ type QueryResponse struct {
|
|||
// respCh is used to send a response from a node
|
||||
respCh chan NodeResponse
|
||||
|
||||
// acks/responses are used to track the nodes that have sent an ack/response
|
||||
acks map[string]struct{}
|
||||
responses map[string]struct{}
|
||||
|
||||
closed bool
|
||||
closeLock sync.Mutex
|
||||
}
|
||||
|
@ -100,13 +112,15 @@ type QueryResponse struct {
|
|||
// newQueryResponse is used to construct a new query response
|
||||
func newQueryResponse(n int, q *messageQuery) *QueryResponse {
|
||||
resp := &QueryResponse{
|
||||
deadline: time.Now().Add(q.Timeout),
|
||||
id: q.ID,
|
||||
lTime: q.LTime,
|
||||
respCh: make(chan NodeResponse, n),
|
||||
deadline: time.Now().Add(q.Timeout),
|
||||
id: q.ID,
|
||||
lTime: q.LTime,
|
||||
respCh: make(chan NodeResponse, n),
|
||||
responses: make(map[string]struct{}),
|
||||
}
|
||||
if q.Ack() {
|
||||
resp.ackCh = make(chan string, n)
|
||||
resp.acks = make(map[string]struct{})
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
@ -135,6 +149,8 @@ func (r *QueryResponse) Deadline() time.Time {
|
|||
|
||||
// Finished returns if the query is finished running
|
||||
func (r *QueryResponse) Finished() bool {
|
||||
r.closeLock.Lock()
|
||||
defer r.closeLock.Unlock()
|
||||
return r.closed || time.Now().After(r.deadline)
|
||||
}
|
||||
|
||||
|
@ -151,6 +167,22 @@ func (r *QueryResponse) ResponseCh() <-chan NodeResponse {
|
|||
return r.respCh
|
||||
}
|
||||
|
||||
// sendResponse sends a response on the response channel ensuring the channel is not closed.
|
||||
func (r *QueryResponse) sendResponse(nr NodeResponse) error {
|
||||
r.closeLock.Lock()
|
||||
defer r.closeLock.Unlock()
|
||||
if r.closed {
|
||||
return nil
|
||||
}
|
||||
select {
|
||||
case r.respCh <- nr:
|
||||
r.responses[nr.From] = struct{}{}
|
||||
default:
|
||||
return errors.New("serf: Failed to deliver query response, dropping")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeResponse is used to represent a single response from a node
|
||||
type NodeResponse struct {
|
||||
From string
|
||||
|
@ -208,3 +240,74 @@ func (s *Serf) shouldProcessQuery(filters [][]byte) bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// relayResponse will relay a copy of the given response to up to relayFactor
|
||||
// other members.
|
||||
func (s *Serf) relayResponse(relayFactor uint8, addr net.UDPAddr, resp *messageQueryResponse) error {
|
||||
if relayFactor == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Needs to be worth it; we need to have at least relayFactor *other*
|
||||
// nodes. If you have a tiny cluster then the relayFactor shouldn't
|
||||
// be needed.
|
||||
members := s.Members()
|
||||
if len(members) < int(relayFactor)+1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prep the relay message, which is a wrapped version of the original.
|
||||
raw, err := encodeRelayMessage(messageQueryResponseType, addr, &resp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to format relayed response: %v", err)
|
||||
}
|
||||
if len(raw) > s.config.QueryResponseSizeLimit {
|
||||
return fmt.Errorf("relayed response exceeds limit of %d bytes", s.config.QueryResponseSizeLimit)
|
||||
}
|
||||
|
||||
// Relay to a random set of peers.
|
||||
localName := s.LocalMember().Name
|
||||
relayMembers := kRandomMembers(int(relayFactor), members, func(m Member) bool {
|
||||
return m.Status != StatusAlive || m.ProtocolMax < 5 || m.Name == localName
|
||||
})
|
||||
for _, m := range relayMembers {
|
||||
relayAddr := net.UDPAddr{IP: m.Addr, Port: int(m.Port)}
|
||||
if err := s.memberlist.SendTo(&relayAddr, raw); err != nil {
|
||||
return fmt.Errorf("failed to send relay response: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// kRandomMembers selects up to k members from a given list, optionally
|
||||
// filtering by the given filterFunc
|
||||
func kRandomMembers(k int, members []Member, filterFunc func(Member) bool) []Member {
|
||||
n := len(members)
|
||||
kMembers := make([]Member, 0, k)
|
||||
OUTER:
|
||||
// Probe up to 3*n times, with large n this is not necessary
|
||||
// since k << n, but with small n we want search to be
|
||||
// exhaustive
|
||||
for i := 0; i < 3*n && len(kMembers) < k; i++ {
|
||||
// Get random member
|
||||
idx := rand.Intn(n)
|
||||
member := members[idx]
|
||||
|
||||
// Give the filter a shot at it.
|
||||
if filterFunc != nil && filterFunc(member) {
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
// Check if we have this member already
|
||||
for j := 0; j < len(kMembers); j++ {
|
||||
if member.Name == kMembers[j].Name {
|
||||
continue OUTER
|
||||
}
|
||||
}
|
||||
|
||||
// Append the member
|
||||
kMembers = append(kMembers, member)
|
||||
}
|
||||
|
||||
return kMembers
|
||||
}
|
||||
|
|
449
vendor/github.com/hashicorp/serf/serf/serf.go
generated
vendored
449
vendor/github.com/hashicorp/serf/serf/serf.go
generated
vendored
|
@ -10,8 +10,10 @@ import (
|
|||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
|
@ -25,7 +27,7 @@ import (
|
|||
// version to memberlist below.
|
||||
const (
|
||||
ProtocolVersionMin uint8 = 2
|
||||
ProtocolVersionMax = 4
|
||||
ProtocolVersionMax = 5
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -65,16 +67,15 @@ type Serf struct {
|
|||
memberLock sync.RWMutex
|
||||
members map[string]*memberState
|
||||
|
||||
// Circular buffers for recent intents, used
|
||||
// in case we get the intent before the relevant event
|
||||
recentLeave []nodeIntent
|
||||
recentLeaveIndex int
|
||||
recentJoin []nodeIntent
|
||||
recentJoinIndex int
|
||||
// recentIntents the lamport time and type of intent for a given node in
|
||||
// case we get an intent before the relevant memberlist event. This is
|
||||
// indexed by node, and always store the latest lamport time / intent
|
||||
// we've seen. The memberLock protects this structure.
|
||||
recentIntents map[string]nodeIntent
|
||||
|
||||
eventBroadcasts *memberlist.TransmitLimitedQueue
|
||||
eventBuffer []*userEvents
|
||||
eventJoinIgnore bool
|
||||
eventJoinIgnore atomic.Value
|
||||
eventMinTime LamportTime
|
||||
eventLock sync.RWMutex
|
||||
|
||||
|
@ -179,10 +180,18 @@ type memberState struct {
|
|||
leaveTime time.Time // wall clock time of leave
|
||||
}
|
||||
|
||||
// nodeIntent is used to buffer intents for out-of-order deliveries
|
||||
// nodeIntent is used to buffer intents for out-of-order deliveries.
|
||||
type nodeIntent struct {
|
||||
// Type is the intent being tracked. Only messageJoinType and
|
||||
// messageLeaveType are tracked.
|
||||
Type messageType
|
||||
|
||||
// WallTime is the wall clock time we saw this intent in order to
|
||||
// expire it from the buffer.
|
||||
WallTime time.Time
|
||||
|
||||
// LTime is the Lamport time, used for cluster-wide ordering of events.
|
||||
LTime LamportTime
|
||||
Node string
|
||||
}
|
||||
|
||||
// userEvent is used to buffer events to prevent re-delivery
|
||||
|
@ -214,8 +223,8 @@ type queries struct {
|
|||
}
|
||||
|
||||
const (
|
||||
UserEventSizeLimit = 512 // Maximum byte size for event name and payload
|
||||
snapshotSizeLimit = 128 * 1024 // Maximum 128 KB snapshot
|
||||
UserEventSizeLimit = 9 * 1024 // Maximum 9KB for event name and payload
|
||||
)
|
||||
|
||||
// Create creates a new Serf instance, starting all the background tasks
|
||||
|
@ -233,14 +242,28 @@ func Create(conf *Config) (*Serf, error) {
|
|||
conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax)
|
||||
}
|
||||
|
||||
if conf.UserEventSizeLimit > UserEventSizeLimit {
|
||||
return nil, fmt.Errorf("user event size limit exceeds limit of %d bytes", UserEventSizeLimit)
|
||||
}
|
||||
|
||||
logger := conf.Logger
|
||||
if logger == nil {
|
||||
logOutput := conf.LogOutput
|
||||
if logOutput == nil {
|
||||
logOutput = os.Stderr
|
||||
}
|
||||
logger = log.New(logOutput, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
serf := &Serf{
|
||||
config: conf,
|
||||
logger: log.New(conf.LogOutput, "", log.LstdFlags),
|
||||
logger: logger,
|
||||
members: make(map[string]*memberState),
|
||||
queryResponse: make(map[LamportTime]*QueryResponse),
|
||||
shutdownCh: make(chan struct{}),
|
||||
state: SerfAlive,
|
||||
}
|
||||
serf.eventJoinIgnore.Store(false)
|
||||
|
||||
// Check that the meta data length is okay
|
||||
if len(serf.encodeTags(conf.Tags)) > memberlist.MetaMaxSize {
|
||||
|
@ -295,7 +318,6 @@ func Create(conf *Config) (*Serf, error) {
|
|||
conf.RejoinAfterLeave,
|
||||
serf.logger,
|
||||
&serf.clock,
|
||||
serf.coordClient,
|
||||
conf.EventCh,
|
||||
serf.shutdownCh)
|
||||
if err != nil {
|
||||
|
@ -321,27 +343,20 @@ func Create(conf *Config) (*Serf, error) {
|
|||
// Setup the various broadcast queues, which we use to send our own
|
||||
// custom broadcasts along the gossip channel.
|
||||
serf.broadcasts = &memberlist.TransmitLimitedQueue{
|
||||
NumNodes: func() int {
|
||||
return len(serf.members)
|
||||
},
|
||||
NumNodes: serf.NumNodes,
|
||||
RetransmitMult: conf.MemberlistConfig.RetransmitMult,
|
||||
}
|
||||
serf.eventBroadcasts = &memberlist.TransmitLimitedQueue{
|
||||
NumNodes: func() int {
|
||||
return len(serf.members)
|
||||
},
|
||||
NumNodes: serf.NumNodes,
|
||||
RetransmitMult: conf.MemberlistConfig.RetransmitMult,
|
||||
}
|
||||
serf.queryBroadcasts = &memberlist.TransmitLimitedQueue{
|
||||
NumNodes: func() int {
|
||||
return len(serf.members)
|
||||
},
|
||||
NumNodes: serf.NumNodes,
|
||||
RetransmitMult: conf.MemberlistConfig.RetransmitMult,
|
||||
}
|
||||
|
||||
// Create the buffer for recent intents
|
||||
serf.recentJoin = make([]nodeIntent, conf.RecentIntentBuffer)
|
||||
serf.recentLeave = make([]nodeIntent, conf.RecentIntentBuffer)
|
||||
serf.recentIntents = make(map[string]nodeIntent)
|
||||
|
||||
// Create a buffer for events and queries
|
||||
serf.eventBuffer = make([]*userEvents, conf.EventBuffer)
|
||||
|
@ -426,14 +441,25 @@ func (s *Serf) KeyManager() *KeyManager {
|
|||
}
|
||||
|
||||
// UserEvent is used to broadcast a custom user event with a given
|
||||
// name and payload. The events must be fairly small, and if the
|
||||
// size limit is exceeded and error will be returned. If coalesce is enabled,
|
||||
// nodes are allowed to coalesce this event. Coalescing is only available
|
||||
// starting in v0.2
|
||||
// name and payload. If the configured size limit is exceeded and error will be returned.
|
||||
// If coalesce is enabled, nodes are allowed to coalesce this event.
|
||||
// Coalescing is only available starting in v0.2
|
||||
func (s *Serf) UserEvent(name string, payload []byte, coalesce bool) error {
|
||||
// Check the size limit
|
||||
if len(name)+len(payload) > UserEventSizeLimit {
|
||||
return fmt.Errorf("user event exceeds limit of %d bytes", UserEventSizeLimit)
|
||||
payloadSizeBeforeEncoding := len(name) + len(payload)
|
||||
|
||||
// Check size before encoding to prevent needless encoding and return early if it's over the specified limit.
|
||||
if payloadSizeBeforeEncoding > s.config.UserEventSizeLimit {
|
||||
return fmt.Errorf(
|
||||
"user event exceeds configured limit of %d bytes before encoding",
|
||||
s.config.UserEventSizeLimit,
|
||||
)
|
||||
}
|
||||
|
||||
if payloadSizeBeforeEncoding > UserEventSizeLimit {
|
||||
return fmt.Errorf(
|
||||
"user event exceeds sane limit of %d bytes before encoding",
|
||||
UserEventSizeLimit,
|
||||
)
|
||||
}
|
||||
|
||||
// Create a message
|
||||
|
@ -443,16 +469,34 @@ func (s *Serf) UserEvent(name string, payload []byte, coalesce bool) error {
|
|||
Payload: payload,
|
||||
CC: coalesce,
|
||||
}
|
||||
s.eventClock.Increment()
|
||||
|
||||
// Process update locally
|
||||
s.handleUserEvent(&msg)
|
||||
|
||||
// Start broadcasting the event
|
||||
raw, err := encodeMessage(messageUserEventType, &msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check the size after encoding to be sure again that
|
||||
// we're not attempting to send over the specified size limit.
|
||||
if len(raw) > s.config.UserEventSizeLimit {
|
||||
return fmt.Errorf(
|
||||
"encoded user event exceeds configured limit of %d bytes after encoding",
|
||||
s.config.UserEventSizeLimit,
|
||||
)
|
||||
}
|
||||
|
||||
if len(raw) > UserEventSizeLimit {
|
||||
return fmt.Errorf(
|
||||
"encoded user event exceeds sane limit of %d bytes before encoding",
|
||||
UserEventSizeLimit,
|
||||
)
|
||||
}
|
||||
|
||||
s.eventClock.Increment()
|
||||
|
||||
// Process update locally
|
||||
s.handleUserEvent(&msg)
|
||||
|
||||
s.eventBroadcasts.QueueBroadcast(&broadcast{
|
||||
msg: raw,
|
||||
})
|
||||
|
@ -493,15 +537,16 @@ func (s *Serf) Query(name string, payload []byte, params *QueryParam) (*QueryRes
|
|||
|
||||
// Create a message
|
||||
q := messageQuery{
|
||||
LTime: s.queryClock.Time(),
|
||||
ID: uint32(rand.Int31()),
|
||||
Addr: local.Addr,
|
||||
Port: local.Port,
|
||||
Filters: filters,
|
||||
Flags: flags,
|
||||
Timeout: params.Timeout,
|
||||
Name: name,
|
||||
Payload: payload,
|
||||
LTime: s.queryClock.Time(),
|
||||
ID: uint32(rand.Int31()),
|
||||
Addr: local.Addr,
|
||||
Port: local.Port,
|
||||
Filters: filters,
|
||||
Flags: flags,
|
||||
RelayFactor: params.RelayFactor,
|
||||
Timeout: params.Timeout,
|
||||
Name: name,
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
// Encode the query
|
||||
|
@ -582,9 +627,9 @@ func (s *Serf) Join(existing []string, ignoreOld bool) (int, error) {
|
|||
// Ignore any events from a potential join. This is safe since we hold
|
||||
// the joinLock and nobody else can be doing a Join
|
||||
if ignoreOld {
|
||||
s.eventJoinIgnore = true
|
||||
s.eventJoinIgnore.Store(true)
|
||||
defer func() {
|
||||
s.eventJoinIgnore = false
|
||||
s.eventJoinIgnore.Store(false)
|
||||
}()
|
||||
}
|
||||
|
||||
|
@ -679,6 +724,13 @@ func (s *Serf) Leave() error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Wait for the leave to propagate through the cluster. The broadcast
|
||||
// timeout is how long we wait for the message to go out from our own
|
||||
// queue, but this wait is for that message to propagate through the
|
||||
// cluster. In particular, we want to stay up long enough to service
|
||||
// any probes from other nodes before they learn about us leaving.
|
||||
time.Sleep(s.config.LeavePropagateDelay)
|
||||
|
||||
// Transition to Left only if we not already shutdown
|
||||
s.stateLock.Lock()
|
||||
if s.state != SerfShutdown {
|
||||
|
@ -729,15 +781,26 @@ func (s *Serf) Members() []Member {
|
|||
return members
|
||||
}
|
||||
|
||||
// RemoveFailedNode forcibly removes a failed node from the cluster
|
||||
// RemoveFailedNode is a backwards compatible form
|
||||
// of forceleave
|
||||
func (s *Serf) RemoveFailedNode(node string) error {
|
||||
return s.forceLeave(node, false)
|
||||
}
|
||||
|
||||
func (s *Serf) RemoveFailedNodePrune(node string) error {
|
||||
return s.forceLeave(node, true)
|
||||
}
|
||||
|
||||
// ForceLeave forcibly removes a failed node from the cluster
|
||||
// immediately, instead of waiting for the reaper to eventually reclaim it.
|
||||
// This also has the effect that Serf will no longer attempt to reconnect
|
||||
// to this node.
|
||||
func (s *Serf) RemoveFailedNode(node string) error {
|
||||
func (s *Serf) forceLeave(node string, prune bool) error {
|
||||
// Construct the message to broadcast
|
||||
msg := messageLeave{
|
||||
LTime: s.clock.Time(),
|
||||
Node: node,
|
||||
Prune: prune,
|
||||
}
|
||||
s.clock.Increment()
|
||||
|
||||
|
@ -785,13 +848,15 @@ func (s *Serf) Shutdown() error {
|
|||
s.logger.Printf("[WARN] serf: Shutdown without a Leave")
|
||||
}
|
||||
|
||||
// Wait to close the shutdown channel until after we've shut down the
|
||||
// memberlist and its associated network resources, since the shutdown
|
||||
// channel signals that we are cleaned up outside of Serf.
|
||||
s.state = SerfShutdown
|
||||
close(s.shutdownCh)
|
||||
|
||||
err := s.memberlist.Shutdown()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
close(s.shutdownCh)
|
||||
|
||||
// Wait for the snapshoter to finish if we have one
|
||||
if s.snapshotter != nil {
|
||||
|
@ -855,22 +920,25 @@ func (s *Serf) handleNodeJoin(n *memberlist.Node) {
|
|||
},
|
||||
}
|
||||
|
||||
// Check if we have a join intent and use the LTime
|
||||
if join := recentIntent(s.recentJoin, n.Name); join != nil {
|
||||
member.statusLTime = join.LTime
|
||||
// Check if we have a join or leave intent. The intent buffer
|
||||
// will only hold one event for this node, so the more recent
|
||||
// one will take effect.
|
||||
if join, ok := recentIntent(s.recentIntents, n.Name, messageJoinType); ok {
|
||||
member.statusLTime = join
|
||||
}
|
||||
|
||||
// Check if we have a leave intent
|
||||
if leave := recentIntent(s.recentLeave, n.Name); leave != nil {
|
||||
if leave.LTime > member.statusLTime {
|
||||
member.Status = StatusLeaving
|
||||
member.statusLTime = leave.LTime
|
||||
}
|
||||
if leave, ok := recentIntent(s.recentIntents, n.Name, messageLeaveType); ok {
|
||||
member.Status = StatusLeaving
|
||||
member.statusLTime = leave
|
||||
}
|
||||
|
||||
s.members[n.Name] = member
|
||||
} else {
|
||||
oldStatus = member.Status
|
||||
deadTime := time.Now().Sub(member.leaveTime)
|
||||
if oldStatus == StatusFailed && deadTime < s.config.FlapTimeout {
|
||||
metrics.IncrCounter([]string{"serf", "member", "flap"}, 1)
|
||||
}
|
||||
|
||||
member.Status = StatusAlive
|
||||
member.leaveTime = time.Time{}
|
||||
member.Addr = net.IP(n.Addr)
|
||||
|
@ -1003,6 +1071,7 @@ func (s *Serf) handleNodeUpdate(n *memberlist.Node) {
|
|||
|
||||
// handleNodeLeaveIntent is called when an intent to leave is received.
|
||||
func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool {
|
||||
|
||||
// Witness a potentially newer time
|
||||
s.clock.Witness(leaveMsg.LTime)
|
||||
|
||||
|
@ -1011,18 +1080,8 @@ func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool {
|
|||
|
||||
member, ok := s.members[leaveMsg.Node]
|
||||
if !ok {
|
||||
// If we've already seen this message don't rebroadcast
|
||||
if recentIntent(s.recentLeave, leaveMsg.Node) != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// We don't know this member so store it in a buffer for now
|
||||
s.recentLeave[s.recentLeaveIndex] = nodeIntent{
|
||||
LTime: leaveMsg.LTime,
|
||||
Node: leaveMsg.Node,
|
||||
}
|
||||
s.recentLeaveIndex = (s.recentLeaveIndex + 1) % len(s.recentLeave)
|
||||
return true
|
||||
// Rebroadcast only if this was an update we hadn't seen before.
|
||||
return upsertIntent(s.recentIntents, leaveMsg.Node, messageLeaveType, leaveMsg.LTime, time.Now)
|
||||
}
|
||||
|
||||
// If the message is old, then it is irrelevant and we can skip it
|
||||
|
@ -1043,6 +1102,10 @@ func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool {
|
|||
case StatusAlive:
|
||||
member.Status = StatusLeaving
|
||||
member.statusLTime = leaveMsg.LTime
|
||||
|
||||
if leaveMsg.Prune {
|
||||
s.handlePrune(member)
|
||||
}
|
||||
return true
|
||||
case StatusFailed:
|
||||
member.Status = StatusLeft
|
||||
|
@ -1051,6 +1114,7 @@ func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool {
|
|||
// Remove from the failed list and add to the left list. We add
|
||||
// to the left list so that when we do a sync, other nodes will
|
||||
// remove it from their failed list.
|
||||
|
||||
s.failedMembers = removeOldMember(s.failedMembers, member.Name)
|
||||
s.leftMembers = append(s.leftMembers, member)
|
||||
|
||||
|
@ -1065,12 +1129,40 @@ func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool {
|
|||
Members: []Member{member.Member},
|
||||
}
|
||||
}
|
||||
|
||||
if leaveMsg.Prune {
|
||||
s.handlePrune(member)
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case StatusLeaving, StatusLeft:
|
||||
if leaveMsg.Prune {
|
||||
s.handlePrune(member)
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// handlePrune waits for nodes that are leaving and then forcibly
|
||||
// erases a member from the list of members
|
||||
func (s *Serf) handlePrune(member *memberState) {
|
||||
if member.Status == StatusLeaving {
|
||||
time.Sleep(s.config.BroadcastTimeout + s.config.LeavePropagateDelay)
|
||||
}
|
||||
|
||||
s.logger.Printf("[INFO] serf: EventMemberReap (forced): %s %s", member.Name, member.Member.Addr)
|
||||
|
||||
//If we are leaving or left we may be in that list of members
|
||||
if member.Status == StatusLeaving || member.Status == StatusLeft {
|
||||
s.leftMembers = removeOldMember(s.leftMembers, member.Name)
|
||||
}
|
||||
s.eraseNode(member)
|
||||
|
||||
}
|
||||
|
||||
// handleNodeJoinIntent is called when a node broadcasts a
|
||||
// join message to set the lamport time of its join
|
||||
func (s *Serf) handleNodeJoinIntent(joinMsg *messageJoin) bool {
|
||||
|
@ -1082,15 +1174,8 @@ func (s *Serf) handleNodeJoinIntent(joinMsg *messageJoin) bool {
|
|||
|
||||
member, ok := s.members[joinMsg.Node]
|
||||
if !ok {
|
||||
// If we've already seen this message don't rebroadcast
|
||||
if recentIntent(s.recentJoin, joinMsg.Node) != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// We don't know this member so store it in a buffer for now
|
||||
s.recentJoin[s.recentJoinIndex] = nodeIntent{LTime: joinMsg.LTime, Node: joinMsg.Node}
|
||||
s.recentJoinIndex = (s.recentJoinIndex + 1) % len(s.recentJoin)
|
||||
return true
|
||||
// Rebroadcast only if this was an update we hadn't seen before.
|
||||
return upsertIntent(s.recentIntents, joinMsg.Node, messageJoinType, joinMsg.LTime, time.Now)
|
||||
}
|
||||
|
||||
// Check if this time is newer than what we have
|
||||
|
@ -1245,19 +1330,23 @@ func (s *Serf) handleQuery(query *messageQuery) bool {
|
|||
if err := s.memberlist.SendTo(&addr, raw); err != nil {
|
||||
s.logger.Printf("[ERR] serf: failed to send ack: %v", err)
|
||||
}
|
||||
if err := s.relayResponse(query.RelayFactor, addr, &ack); err != nil {
|
||||
s.logger.Printf("[ERR] serf: failed to relay ack: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.config.EventCh != nil {
|
||||
s.config.EventCh <- &Query{
|
||||
LTime: query.LTime,
|
||||
Name: query.Name,
|
||||
Payload: query.Payload,
|
||||
serf: s,
|
||||
id: query.ID,
|
||||
addr: query.Addr,
|
||||
port: query.Port,
|
||||
deadline: time.Now().Add(query.Timeout),
|
||||
LTime: query.LTime,
|
||||
Name: query.Name,
|
||||
Payload: query.Payload,
|
||||
serf: s,
|
||||
id: query.ID,
|
||||
addr: query.Addr,
|
||||
port: query.Port,
|
||||
deadline: time.Now().Add(query.Timeout),
|
||||
relayFactor: query.RelayFactor,
|
||||
}
|
||||
}
|
||||
return rebroadcast
|
||||
|
@ -1290,25 +1379,37 @@ func (s *Serf) handleQueryResponse(resp *messageQueryResponse) {
|
|||
|
||||
// Process each type of response
|
||||
if resp.Ack() {
|
||||
// Exit early if this is a duplicate ack
|
||||
if _, ok := query.acks[resp.From]; ok {
|
||||
metrics.IncrCounter([]string{"serf", "query_duplicate_acks"}, 1)
|
||||
return
|
||||
}
|
||||
|
||||
metrics.IncrCounter([]string{"serf", "query_acks"}, 1)
|
||||
select {
|
||||
case query.ackCh <- resp.From:
|
||||
query.acks[resp.From] = struct{}{}
|
||||
default:
|
||||
s.logger.Printf("[WARN] serf: Failed to delivery query ack, dropping")
|
||||
s.logger.Printf("[WARN] serf: Failed to deliver query ack, dropping")
|
||||
}
|
||||
} else {
|
||||
// Exit early if this is a duplicate response
|
||||
if _, ok := query.responses[resp.From]; ok {
|
||||
metrics.IncrCounter([]string{"serf", "query_duplicate_responses"}, 1)
|
||||
return
|
||||
}
|
||||
|
||||
metrics.IncrCounter([]string{"serf", "query_responses"}, 1)
|
||||
select {
|
||||
case query.respCh <- NodeResponse{From: resp.From, Payload: resp.Payload}:
|
||||
default:
|
||||
s.logger.Printf("[WARN] serf: Failed to delivery query response, dropping")
|
||||
err := query.sendResponse(NodeResponse{From: resp.From, Payload: resp.Payload})
|
||||
if err != nil {
|
||||
s.logger.Printf("[WARN] %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleNodeConflict is invoked when a join detects a conflict over a name.
|
||||
// This means two different nodes (IP/Port) are claiming the same name. Memberlist
|
||||
// will reject the "new" node mapping, but we can still be notified
|
||||
// will reject the "new" node mapping, but we can still be notified.
|
||||
func (s *Serf) handleNodeConflict(existing, other *memberlist.Node) {
|
||||
// Log a basic warning if the node is not us...
|
||||
if existing.Name != s.config.NodeName {
|
||||
|
@ -1361,7 +1462,7 @@ func (s *Serf) resolveNodeConflict() {
|
|||
|
||||
// Update the counters
|
||||
responses++
|
||||
if bytes.Equal(member.Addr, local.Addr) && member.Port == local.Port {
|
||||
if member.Addr.Equal(local.Addr) && member.Port == local.Port {
|
||||
matching++
|
||||
}
|
||||
}
|
||||
|
@ -1382,14 +1483,41 @@ func (s *Serf) resolveNodeConflict() {
|
|||
}
|
||||
}
|
||||
|
||||
// handleReap periodically reaps the list of failed and left members.
|
||||
//eraseNode takes a node completely out of the member list
|
||||
func (s *Serf) eraseNode(m *memberState) {
|
||||
// Delete from members
|
||||
delete(s.members, m.Name)
|
||||
|
||||
// Tell the coordinate client the node has gone away and delete
|
||||
// its cached coordinates.
|
||||
if !s.config.DisableCoordinates {
|
||||
s.coordClient.ForgetNode(m.Name)
|
||||
|
||||
s.coordCacheLock.Lock()
|
||||
delete(s.coordCache, m.Name)
|
||||
s.coordCacheLock.Unlock()
|
||||
}
|
||||
|
||||
// Send an event along
|
||||
if s.config.EventCh != nil {
|
||||
s.config.EventCh <- MemberEvent{
|
||||
Type: EventMemberReap,
|
||||
Members: []Member{m.Member},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleReap periodically reaps the list of failed and left members, as well
|
||||
// as old buffered intents.
|
||||
func (s *Serf) handleReap() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(s.config.ReapInterval):
|
||||
s.memberLock.Lock()
|
||||
s.failedMembers = s.reap(s.failedMembers, s.config.ReconnectTimeout)
|
||||
s.leftMembers = s.reap(s.leftMembers, s.config.TombstoneTimeout)
|
||||
now := time.Now()
|
||||
s.failedMembers = s.reap(s.failedMembers, now, s.config.ReconnectTimeout)
|
||||
s.leftMembers = s.reap(s.leftMembers, now, s.config.TombstoneTimeout)
|
||||
reapIntents(s.recentIntents, now, s.config.RecentIntentTimeout)
|
||||
s.memberLock.Unlock()
|
||||
case <-s.shutdownCh:
|
||||
return
|
||||
|
@ -1413,8 +1541,7 @@ func (s *Serf) handleReconnect() {
|
|||
// reap is called with a list of old members and a timeout, and removes
|
||||
// members that have exceeded the timeout. The members are removed from
|
||||
// both the old list and the members itself. Locking is left to the caller.
|
||||
func (s *Serf) reap(old []*memberState, timeout time.Duration) []*memberState {
|
||||
now := time.Now()
|
||||
func (s *Serf) reap(old []*memberState, now time.Time, timeout time.Duration) []*memberState {
|
||||
n := len(old)
|
||||
for i := 0; i < n; i++ {
|
||||
m := old[i]
|
||||
|
@ -1430,27 +1557,10 @@ func (s *Serf) reap(old []*memberState, timeout time.Duration) []*memberState {
|
|||
n--
|
||||
i--
|
||||
|
||||
// Delete from members
|
||||
delete(s.members, m.Name)
|
||||
|
||||
// Tell the coordinate client the node has gone away and delete
|
||||
// its cached coordinates.
|
||||
if !s.config.DisableCoordinates {
|
||||
s.coordClient.ForgetNode(m.Name)
|
||||
|
||||
s.coordCacheLock.Lock()
|
||||
delete(s.coordCache, m.Name)
|
||||
s.coordCacheLock.Unlock()
|
||||
}
|
||||
|
||||
// Send an event along
|
||||
// Delete from members and send out event
|
||||
s.logger.Printf("[INFO] serf: EventMemberReap: %s", m.Name)
|
||||
if s.config.EventCh != nil {
|
||||
s.config.EventCh <- MemberEvent{
|
||||
Type: EventMemberReap,
|
||||
Members: []Member{m.Member},
|
||||
}
|
||||
}
|
||||
s.eraseNode(m)
|
||||
|
||||
}
|
||||
|
||||
return old
|
||||
|
@ -1485,7 +1595,7 @@ func (s *Serf) reconnect() {
|
|||
}
|
||||
|
||||
// Select a random member to try and join
|
||||
idx := int(rand.Uint32() % uint32(n))
|
||||
idx := rand.Int31n(int32(n))
|
||||
mem := s.failedMembers[idx]
|
||||
s.memberLock.RUnlock()
|
||||
|
||||
|
@ -1497,21 +1607,37 @@ func (s *Serf) reconnect() {
|
|||
s.memberlist.Join([]string{addr.String()})
|
||||
}
|
||||
|
||||
// getQueueMax will get the maximum queue depth, which might be dynamic depending
|
||||
// on how Serf is configured.
|
||||
func (s *Serf) getQueueMax() int {
|
||||
max := s.config.MaxQueueDepth
|
||||
if s.config.MinQueueDepth > 0 {
|
||||
s.memberLock.RLock()
|
||||
max = 2 * len(s.members)
|
||||
s.memberLock.RUnlock()
|
||||
|
||||
if max < s.config.MinQueueDepth {
|
||||
max = s.config.MinQueueDepth
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
// checkQueueDepth periodically checks the size of a queue to see if
|
||||
// it is too large
|
||||
func (s *Serf) checkQueueDepth(name string, queue *memberlist.TransmitLimitedQueue) {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
case <-time.After(s.config.QueueCheckInterval):
|
||||
numq := queue.NumQueued()
|
||||
metrics.AddSample([]string{"serf", "queue", name}, float32(numq))
|
||||
if numq >= s.config.QueueDepthWarning {
|
||||
s.logger.Printf("[WARN] serf: %s queue depth: %d", name, numq)
|
||||
}
|
||||
if numq > s.config.MaxQueueDepth {
|
||||
if max := s.getQueueMax(); numq > max {
|
||||
s.logger.Printf("[WARN] serf: %s queue depth (%d) exceeds limit (%d), dropping messages!",
|
||||
name, numq, s.config.MaxQueueDepth)
|
||||
queue.Prune(s.config.MaxQueueDepth)
|
||||
name, numq, max)
|
||||
queue.Prune(max)
|
||||
}
|
||||
case <-s.shutdownCh:
|
||||
return
|
||||
|
@ -1533,24 +1659,46 @@ func removeOldMember(old []*memberState, name string) []*memberState {
|
|||
return old
|
||||
}
|
||||
|
||||
// recentIntent checks the recent intent buffer for a matching
|
||||
// entry for a given node, and either returns the message or nil
|
||||
func recentIntent(recent []nodeIntent, node string) (intent *nodeIntent) {
|
||||
for i := 0; i < len(recent); i++ {
|
||||
// Break fast if we hit a zero entry
|
||||
if recent[i].LTime == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Check for a node match
|
||||
if recent[i].Node == node {
|
||||
// Take the most recent entry
|
||||
if intent == nil || recent[i].LTime > intent.LTime {
|
||||
intent = &recent[i]
|
||||
}
|
||||
// reapIntents clears out any intents that are older than the timeout. Make sure
|
||||
// the memberLock is held when passing in the Serf instance's recentIntents
|
||||
// member.
|
||||
func reapIntents(intents map[string]nodeIntent, now time.Time, timeout time.Duration) {
|
||||
for node, intent := range intents {
|
||||
if now.Sub(intent.WallTime) > timeout {
|
||||
delete(intents, node)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// upsertIntent will update an existing intent with the supplied Lamport time,
|
||||
// or create a new entry. This will return true if a new entry was added. The
|
||||
// stamper is used to capture the wall clock time for expiring these buffered
|
||||
// intents. Make sure the memberLock is held when passing in the Serf instance's
|
||||
// recentIntents member.
|
||||
func upsertIntent(intents map[string]nodeIntent, node string, itype messageType,
|
||||
ltime LamportTime, stamper func() time.Time) bool {
|
||||
if intent, ok := intents[node]; !ok || ltime > intent.LTime {
|
||||
intents[node] = nodeIntent{
|
||||
Type: itype,
|
||||
WallTime: stamper(),
|
||||
LTime: ltime,
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// recentIntent checks the recent intent buffer for a matching entry for a given
|
||||
// node, and returns the Lamport time, if an intent is present, indicated by the
|
||||
// returned boolean. Make sure the memberLock is held for read when passing in
|
||||
// the Serf instance's recentIntents member.
|
||||
func recentIntent(intents map[string]nodeIntent, node string, itype messageType) (LamportTime, bool) {
|
||||
if intent, ok := intents[node]; ok && intent.Type == itype {
|
||||
return intent.LTime, true
|
||||
}
|
||||
|
||||
return LamportTime(0), false
|
||||
}
|
||||
|
||||
// handleRejoin attempts to reconnect to previously known alive nodes
|
||||
|
@ -1613,10 +1761,18 @@ func (s *Serf) Stats() map[string]string {
|
|||
toString := func(v uint64) string {
|
||||
return strconv.FormatUint(v, 10)
|
||||
}
|
||||
s.memberLock.RLock()
|
||||
members := toString(uint64(len(s.members)))
|
||||
failed := toString(uint64(len(s.failedMembers)))
|
||||
left := toString(uint64(len(s.leftMembers)))
|
||||
health_score := toString(uint64(s.memberlist.GetHealthScore()))
|
||||
|
||||
s.memberLock.RUnlock()
|
||||
stats := map[string]string{
|
||||
"members": toString(uint64(len(s.members))),
|
||||
"failed": toString(uint64(len(s.failedMembers))),
|
||||
"left": toString(uint64(len(s.leftMembers))),
|
||||
"members": members,
|
||||
"failed": failed,
|
||||
"left": left,
|
||||
"health_score": health_score,
|
||||
"member_time": toString(uint64(s.clock.Time())),
|
||||
"event_time": toString(uint64(s.eventClock.Time())),
|
||||
"query_time": toString(uint64(s.queryClock.Time())),
|
||||
|
@ -1625,6 +1781,9 @@ func (s *Serf) Stats() map[string]string {
|
|||
"query_queue": toString(uint64(s.queryBroadcasts.NumQueued())),
|
||||
"encrypted": fmt.Sprintf("%v", s.EncryptionEnabled()),
|
||||
}
|
||||
if !s.config.DisableCoordinates {
|
||||
stats["coordinate_resets"] = toString(uint64(s.coordClient.Stats().Resets))
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
|
|
273
vendor/github.com/hashicorp/serf/serf/snapshot.go
generated
vendored
273
vendor/github.com/hashicorp/serf/serf/snapshot.go
generated
vendored
|
@ -2,7 +2,6 @@ package serf
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
|
@ -13,7 +12,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/serf/coordinate"
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -27,34 +25,59 @@ nodes to re-join, as well as restore our clock values to avoid replaying
|
|||
old events.
|
||||
*/
|
||||
|
||||
const flushInterval = 500 * time.Millisecond
|
||||
const clockUpdateInterval = 500 * time.Millisecond
|
||||
const coordinateUpdateInterval = 60 * time.Second
|
||||
const tmpExt = ".compact"
|
||||
const (
|
||||
// flushInterval is how often we force a flush of the snapshot file
|
||||
flushInterval = 500 * time.Millisecond
|
||||
|
||||
// clockUpdateInterval is how often we fetch the current lamport time of the cluster and write to the snapshot file
|
||||
clockUpdateInterval = 500 * time.Millisecond
|
||||
|
||||
// tmpExt is the extention we use for the temporary file during compaction
|
||||
tmpExt = ".compact"
|
||||
|
||||
// snapshotErrorRecoveryInterval is how often we attempt to recover from
|
||||
// errors writing to the snapshot file.
|
||||
snapshotErrorRecoveryInterval = 30 * time.Second
|
||||
|
||||
// eventChSize is the size of the event buffers between Serf and the
|
||||
// consuming application. If this is exhausted we will block Serf and Memberlist.
|
||||
eventChSize = 2048
|
||||
|
||||
// shutdownFlushTimeout is the time limit to write pending events to the snapshot during a shutdown
|
||||
shutdownFlushTimeout = 250 * time.Millisecond
|
||||
|
||||
// snapshotBytesPerNode is an estimated bytes per node to snapshot
|
||||
snapshotBytesPerNode = 128
|
||||
|
||||
// snapshotCompactionThreshold is the threshold we apply to
|
||||
// the snapshot size estimate (nodes * bytes per node) before compacting.
|
||||
snapshotCompactionThreshold = 2
|
||||
)
|
||||
|
||||
// Snapshotter is responsible for ingesting events and persisting
|
||||
// them to disk, and providing a recovery mechanism at start time.
|
||||
type Snapshotter struct {
|
||||
aliveNodes map[string]string
|
||||
clock *LamportClock
|
||||
coordClient *coordinate.Client
|
||||
fh *os.File
|
||||
buffered *bufio.Writer
|
||||
inCh <-chan Event
|
||||
lastFlush time.Time
|
||||
lastClock LamportTime
|
||||
lastEventClock LamportTime
|
||||
lastQueryClock LamportTime
|
||||
leaveCh chan struct{}
|
||||
leaving bool
|
||||
logger *log.Logger
|
||||
maxSize int64
|
||||
path string
|
||||
offset int64
|
||||
outCh chan<- Event
|
||||
rejoinAfterLeave bool
|
||||
shutdownCh <-chan struct{}
|
||||
waitCh chan struct{}
|
||||
aliveNodes map[string]string
|
||||
clock *LamportClock
|
||||
fh *os.File
|
||||
buffered *bufio.Writer
|
||||
inCh <-chan Event
|
||||
streamCh chan Event
|
||||
lastFlush time.Time
|
||||
lastClock LamportTime
|
||||
lastEventClock LamportTime
|
||||
lastQueryClock LamportTime
|
||||
leaveCh chan struct{}
|
||||
leaving bool
|
||||
logger *log.Logger
|
||||
minCompactSize int64
|
||||
path string
|
||||
offset int64
|
||||
outCh chan<- Event
|
||||
rejoinAfterLeave bool
|
||||
shutdownCh <-chan struct{}
|
||||
waitCh chan struct{}
|
||||
lastAttemptedCompaction time.Time
|
||||
}
|
||||
|
||||
// PreviousNode is used to represent the previously known alive nodes
|
||||
|
@ -74,17 +97,17 @@ func (p PreviousNode) String() string {
|
|||
// Setting rejoinAfterLeave makes leave not clear the state, and can be used
|
||||
// if you intend to rejoin the same cluster after a leave.
|
||||
func NewSnapshotter(path string,
|
||||
maxSize int,
|
||||
minCompactSize int,
|
||||
rejoinAfterLeave bool,
|
||||
logger *log.Logger,
|
||||
clock *LamportClock,
|
||||
coordClient *coordinate.Client,
|
||||
outCh chan<- Event,
|
||||
shutdownCh <-chan struct{}) (chan<- Event, *Snapshotter, error) {
|
||||
inCh := make(chan Event, 1024)
|
||||
inCh := make(chan Event, eventChSize)
|
||||
streamCh := make(chan Event, eventChSize)
|
||||
|
||||
// Try to open the file
|
||||
fh, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0755)
|
||||
fh, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to open snapshot: %v", err)
|
||||
}
|
||||
|
@ -101,16 +124,16 @@ func NewSnapshotter(path string,
|
|||
snap := &Snapshotter{
|
||||
aliveNodes: make(map[string]string),
|
||||
clock: clock,
|
||||
coordClient: coordClient,
|
||||
fh: fh,
|
||||
buffered: bufio.NewWriter(fh),
|
||||
inCh: inCh,
|
||||
streamCh: streamCh,
|
||||
lastClock: 0,
|
||||
lastEventClock: 0,
|
||||
lastQueryClock: 0,
|
||||
leaveCh: make(chan struct{}),
|
||||
logger: logger,
|
||||
maxSize: int64(maxSize),
|
||||
minCompactSize: int64(minCompactSize),
|
||||
path: path,
|
||||
offset: offset,
|
||||
outCh: outCh,
|
||||
|
@ -126,6 +149,7 @@ func NewSnapshotter(path string,
|
|||
}
|
||||
|
||||
// Start handling new commands
|
||||
go snap.teeStream()
|
||||
go snap.stream()
|
||||
return inCh, snap, nil
|
||||
}
|
||||
|
@ -175,13 +199,68 @@ func (s *Snapshotter) Leave() {
|
|||
}
|
||||
}
|
||||
|
||||
// teeStream is a long running routine that is used to copy events
|
||||
// to the output channel and the internal event handler.
|
||||
func (s *Snapshotter) teeStream() {
|
||||
flushEvent := func(e Event) {
|
||||
// Forward to the internal stream, do not block
|
||||
select {
|
||||
case s.streamCh <- e:
|
||||
default:
|
||||
}
|
||||
|
||||
// Forward the event immediately, do not block
|
||||
if s.outCh != nil {
|
||||
select {
|
||||
case s.outCh <- e:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OUTER:
|
||||
for {
|
||||
select {
|
||||
case e := <-s.inCh:
|
||||
flushEvent(e)
|
||||
case <-s.shutdownCh:
|
||||
break OUTER
|
||||
}
|
||||
}
|
||||
|
||||
// Drain any remaining events before exiting
|
||||
for {
|
||||
select {
|
||||
case e := <-s.inCh:
|
||||
flushEvent(e)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stream is a long running routine that is used to handle events
|
||||
func (s *Snapshotter) stream() {
|
||||
clockTicker := time.NewTicker(clockUpdateInterval)
|
||||
defer clockTicker.Stop()
|
||||
|
||||
coordinateTicker := time.NewTicker(coordinateUpdateInterval)
|
||||
defer coordinateTicker.Stop()
|
||||
// flushEvent is used to handle writing out an event
|
||||
flushEvent := func(e Event) {
|
||||
// Stop recording events after a leave is issued
|
||||
if s.leaving {
|
||||
return
|
||||
}
|
||||
switch typed := e.(type) {
|
||||
case MemberEvent:
|
||||
s.processMemberEvent(typed)
|
||||
case UserEvent:
|
||||
s.processUserEvent(typed)
|
||||
case *Query:
|
||||
s.processQuery(typed)
|
||||
default:
|
||||
s.logger.Printf("[ERR] serf: Unknown event to snapshot: %#v", e)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
|
@ -200,34 +279,32 @@ func (s *Snapshotter) stream() {
|
|||
s.logger.Printf("[ERR] serf: failed to sync leave to snapshot: %v", err)
|
||||
}
|
||||
|
||||
case e := <-s.inCh:
|
||||
// Forward the event immediately
|
||||
if s.outCh != nil {
|
||||
s.outCh <- e
|
||||
}
|
||||
|
||||
// Stop recording events after a leave is issued
|
||||
if s.leaving {
|
||||
continue
|
||||
}
|
||||
switch typed := e.(type) {
|
||||
case MemberEvent:
|
||||
s.processMemberEvent(typed)
|
||||
case UserEvent:
|
||||
s.processUserEvent(typed)
|
||||
case *Query:
|
||||
s.processQuery(typed)
|
||||
default:
|
||||
s.logger.Printf("[ERR] serf: Unknown event to snapshot: %#v", e)
|
||||
}
|
||||
case e := <-s.streamCh:
|
||||
flushEvent(e)
|
||||
|
||||
case <-clockTicker.C:
|
||||
s.updateClock()
|
||||
|
||||
case <-coordinateTicker.C:
|
||||
s.updateCoordinate()
|
||||
|
||||
case <-s.shutdownCh:
|
||||
// Setup a timeout
|
||||
flushTimeout := time.After(shutdownFlushTimeout)
|
||||
|
||||
// Snapshot the clock
|
||||
s.updateClock()
|
||||
|
||||
// Clear out the buffers
|
||||
FLUSH:
|
||||
for {
|
||||
select {
|
||||
case e := <-s.streamCh:
|
||||
flushEvent(e)
|
||||
case <-flushTimeout:
|
||||
break FLUSH
|
||||
default:
|
||||
break FLUSH
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.buffered.Flush(); err != nil {
|
||||
s.logger.Printf("[ERR] serf: failed to flush snapshot: %v", err)
|
||||
}
|
||||
|
@ -273,20 +350,6 @@ func (s *Snapshotter) updateClock() {
|
|||
}
|
||||
}
|
||||
|
||||
// updateCoordinate is called periodically to write out the current local
|
||||
// coordinate. It's safe to call this if coordinates aren't enabled (nil
|
||||
// client) and it will be a no-op.
|
||||
func (s *Snapshotter) updateCoordinate() {
|
||||
if s.coordClient != nil {
|
||||
encoded, err := json.Marshal(s.coordClient.GetCoordinate())
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] serf: Failed to encode coordinate: %v", err)
|
||||
} else {
|
||||
s.tryAppend(fmt.Sprintf("coordinate: %s\n", encoded))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processUserEvent is used to handle a single user event
|
||||
func (s *Snapshotter) processUserEvent(e UserEvent) {
|
||||
// Ignore old clocks
|
||||
|
@ -311,6 +374,17 @@ func (s *Snapshotter) processQuery(q *Query) {
|
|||
func (s *Snapshotter) tryAppend(l string) {
|
||||
if err := s.appendLine(l); err != nil {
|
||||
s.logger.Printf("[ERR] serf: Failed to update snapshot: %v", err)
|
||||
now := time.Now()
|
||||
if now.Sub(s.lastAttemptedCompaction) > snapshotErrorRecoveryInterval {
|
||||
s.lastAttemptedCompaction = now
|
||||
s.logger.Printf("[INFO] serf: Attempting compaction to recover from error...")
|
||||
err = s.compact()
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] serf: Compaction failed, will reattempt after %v: %v", snapshotErrorRecoveryInterval, err)
|
||||
} else {
|
||||
s.logger.Printf("[INFO] serf: Finished compaction, successfully recovered from error state")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,12 +408,25 @@ func (s *Snapshotter) appendLine(l string) error {
|
|||
|
||||
// Check if a compaction is necessary
|
||||
s.offset += int64(n)
|
||||
if s.offset > s.maxSize {
|
||||
if s.offset > s.snapshotMaxSize() {
|
||||
return s.compact()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// snapshotMaxSize computes the maximum size and is used to force periodic compaction.
|
||||
func (s *Snapshotter) snapshotMaxSize() int64 {
|
||||
nodes := int64(len(s.aliveNodes))
|
||||
estSize := nodes * snapshotBytesPerNode
|
||||
threshold := estSize * snapshotCompactionThreshold
|
||||
|
||||
// Apply a minimum threshold to avoid frequent compaction
|
||||
if threshold < s.minCompactSize {
|
||||
threshold = s.minCompactSize
|
||||
}
|
||||
return threshold
|
||||
}
|
||||
|
||||
// Compact is used to compact the snapshot once it is too large
|
||||
func (s *Snapshotter) compact() error {
|
||||
defer metrics.MeasureSince([]string{"serf", "snapshot", "compact"}, time.Now())
|
||||
|
@ -391,30 +478,22 @@ func (s *Snapshotter) compact() error {
|
|||
}
|
||||
offset += int64(n)
|
||||
|
||||
// Write out the coordinate.
|
||||
if s.coordClient != nil {
|
||||
encoded, err := json.Marshal(s.coordClient.GetCoordinate())
|
||||
if err != nil {
|
||||
fh.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
line = fmt.Sprintf("coordinate: %s\n", encoded)
|
||||
n, err = buf.WriteString(line)
|
||||
if err != nil {
|
||||
fh.Close()
|
||||
return err
|
||||
}
|
||||
offset += int64(n)
|
||||
}
|
||||
|
||||
// Flush the new snapshot
|
||||
err = buf.Flush()
|
||||
fh.Close()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to flush new snapshot: %v", err)
|
||||
}
|
||||
|
||||
err = fh.Sync()
|
||||
|
||||
if err != nil {
|
||||
fh.Close()
|
||||
return fmt.Errorf("failed to fsync new snapshot: %v", err)
|
||||
}
|
||||
|
||||
fh.Close()
|
||||
|
||||
// We now need to swap the old snapshot file with the new snapshot.
|
||||
// Turns out, Windows won't let us rename the files if we have
|
||||
// open handles to them or if the destination already exists. This
|
||||
|
@ -520,19 +599,7 @@ func (s *Snapshotter) replay() error {
|
|||
s.lastQueryClock = LamportTime(timeInt)
|
||||
|
||||
} else if strings.HasPrefix(line, "coordinate: ") {
|
||||
if s.coordClient == nil {
|
||||
s.logger.Printf("[WARN] serf: Ignoring snapshot coordinates since they are disabled")
|
||||
continue
|
||||
}
|
||||
|
||||
coordStr := strings.TrimPrefix(line, "coordinate: ")
|
||||
var coord coordinate.Coordinate
|
||||
err := json.Unmarshal([]byte(coordStr), &coord)
|
||||
if err != nil {
|
||||
s.logger.Printf("[WARN] serf: Failed to decode coordinate: %v", err)
|
||||
continue
|
||||
}
|
||||
s.coordClient.SetCoordinate(&coord)
|
||||
continue // Ignores any coordinate persistence from old snapshots, serf should re-converge
|
||||
} else if line == "leave" {
|
||||
// Ignore a leave if we plan on re-joining
|
||||
if s.rejoinAfterLeave {
|
||||
|
|
2
vendor/github.com/prometheus/client_golang/prometheus/README.md
generated
vendored
2
vendor/github.com/prometheus/client_golang/prometheus/README.md
generated
vendored
|
@ -1 +1 @@
|
|||
See [](https://godoc.org/github.com/prometheus/client_golang/prometheus).
|
||||
See [](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus).
|
||||
|
|
38
vendor/github.com/prometheus/client_golang/prometheus/build_info_collector.go
generated
vendored
Normal file
38
vendor/github.com/prometheus/client_golang/prometheus/build_info_collector.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2021 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
package prometheus
|
||||
|
||||
import "runtime/debug"
|
||||
|
||||
// NewBuildInfoCollector is the obsolete version of collectors.NewBuildInfoCollector.
|
||||
// See there for documentation.
|
||||
//
|
||||
// Deprecated: Use collectors.NewBuildInfoCollector instead.
|
||||
func NewBuildInfoCollector() Collector {
|
||||
path, version, sum := "unknown", "unknown", "unknown"
|
||||
if bi, ok := debug.ReadBuildInfo(); ok {
|
||||
path = bi.Main.Path
|
||||
version = bi.Main.Version
|
||||
sum = bi.Main.Sum
|
||||
}
|
||||
c := &selfCollector{MustNewConstMetric(
|
||||
NewDesc(
|
||||
"go_build_info",
|
||||
"Build information about the main Go module.",
|
||||
nil, Labels{"path": path, "version": version, "checksum": sum},
|
||||
),
|
||||
GaugeValue, 1)}
|
||||
c.init(c.self)
|
||||
return c
|
||||
}
|
8
vendor/github.com/prometheus/client_golang/prometheus/collector.go
generated
vendored
8
vendor/github.com/prometheus/client_golang/prometheus/collector.go
generated
vendored
|
@ -118,3 +118,11 @@ func (c *selfCollector) Describe(ch chan<- *Desc) {
|
|||
func (c *selfCollector) Collect(ch chan<- Metric) {
|
||||
ch <- c.self
|
||||
}
|
||||
|
||||
// collectorMetric is a metric that is also a collector.
|
||||
// Because of selfCollector, most (if not all) Metrics in
|
||||
// this package are also collectors.
|
||||
type collectorMetric interface {
|
||||
Metric
|
||||
Collector
|
||||
}
|
||||
|
|
28
vendor/github.com/prometheus/client_golang/prometheus/counter.go
generated
vendored
28
vendor/github.com/prometheus/client_golang/prometheus/counter.go
generated
vendored
|
@ -133,10 +133,14 @@ func (c *counter) Inc() {
|
|||
atomic.AddUint64(&c.valInt, 1)
|
||||
}
|
||||
|
||||
func (c *counter) Write(out *dto.Metric) error {
|
||||
func (c *counter) get() float64 {
|
||||
fval := math.Float64frombits(atomic.LoadUint64(&c.valBits))
|
||||
ival := atomic.LoadUint64(&c.valInt)
|
||||
val := fval + float64(ival)
|
||||
return fval + float64(ival)
|
||||
}
|
||||
|
||||
func (c *counter) Write(out *dto.Metric) error {
|
||||
val := c.get()
|
||||
|
||||
var exemplar *dto.Exemplar
|
||||
if e := c.exemplar.Load(); e != nil {
|
||||
|
@ -163,7 +167,7 @@ func (c *counter) updateExemplar(v float64, l Labels) {
|
|||
// (e.g. number of HTTP requests, partitioned by response code and
|
||||
// method). Create instances with NewCounterVec.
|
||||
type CounterVec struct {
|
||||
*metricVec
|
||||
*MetricVec
|
||||
}
|
||||
|
||||
// NewCounterVec creates a new CounterVec based on the provided CounterOpts and
|
||||
|
@ -176,11 +180,11 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
|
|||
opts.ConstLabels,
|
||||
)
|
||||
return &CounterVec{
|
||||
metricVec: newMetricVec(desc, func(lvs ...string) Metric {
|
||||
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||
if len(lvs) != len(desc.variableLabels) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
|
||||
}
|
||||
result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs), now: time.Now}
|
||||
result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: time.Now}
|
||||
result.init(result) // Init self-collection.
|
||||
return result
|
||||
}),
|
||||
|
@ -188,7 +192,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
|
|||
}
|
||||
|
||||
// GetMetricWithLabelValues returns the Counter for the given slice of label
|
||||
// values (same order as the VariableLabels in Desc). If that combination of
|
||||
// values (same order as the variable labels in Desc). If that combination of
|
||||
// label values is accessed for the first time, a new Counter is created.
|
||||
//
|
||||
// It is possible to call this method without using the returned Counter to only
|
||||
|
@ -202,7 +206,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
|
|||
// Counter with the same label values is created later.
|
||||
//
|
||||
// An error is returned if the number of label values is not the same as the
|
||||
// number of VariableLabels in Desc (minus any curried labels).
|
||||
// number of variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// Note that for more than one label value, this method is prone to mistakes
|
||||
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
|
||||
|
@ -211,7 +215,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
|
|||
// with a performance overhead (for creating and processing the Labels map).
|
||||
// See also the GaugeVec example.
|
||||
func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
|
||||
metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
|
||||
metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Counter), err
|
||||
}
|
||||
|
@ -219,19 +223,19 @@ func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
|
|||
}
|
||||
|
||||
// GetMetricWith returns the Counter for the given Labels map (the label names
|
||||
// must match those of the VariableLabels in Desc). If that label map is
|
||||
// must match those of the variable labels in Desc). If that label map is
|
||||
// accessed for the first time, a new Counter is created. Implications of
|
||||
// creating a Counter without using it and keeping the Counter for later use are
|
||||
// the same as for GetMetricWithLabelValues.
|
||||
//
|
||||
// An error is returned if the number and names of the Labels are inconsistent
|
||||
// with those of the VariableLabels in Desc (minus any curried labels).
|
||||
// with those of the variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// This method is used for the same purpose as
|
||||
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
|
||||
// methods.
|
||||
func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
|
||||
metric, err := v.metricVec.getMetricWith(labels)
|
||||
metric, err := v.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Counter), err
|
||||
}
|
||||
|
@ -275,7 +279,7 @@ func (v *CounterVec) With(labels Labels) Counter {
|
|||
// registered with a given registry (usually the uncurried version). The Reset
|
||||
// method deletes all metrics, even if called on a curried vector.
|
||||
func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) {
|
||||
vec, err := v.curryWith(labels)
|
||||
vec, err := v.MetricVec.CurryWith(labels)
|
||||
if vec != nil {
|
||||
return &CounterVec{vec}, err
|
||||
}
|
||||
|
|
3
vendor/github.com/prometheus/client_golang/prometheus/desc.go
generated
vendored
3
vendor/github.com/prometheus/client_golang/prometheus/desc.go
generated
vendored
|
@ -20,6 +20,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/cespare/xxhash/v2"
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -50,7 +51,7 @@ type Desc struct {
|
|||
// constLabelPairs contains precalculated DTO label pairs based on
|
||||
// the constant labels.
|
||||
constLabelPairs []*dto.LabelPair
|
||||
// VariableLabels contains names of labels for which the metric
|
||||
// variableLabels contains names of labels for which the metric
|
||||
// maintains variable values.
|
||||
variableLabels []string
|
||||
// id is a hash of the values of the ConstLabels and fqName. This
|
||||
|
|
39
vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
generated
vendored
39
vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
generated
vendored
|
@ -22,43 +22,10 @@ type expvarCollector struct {
|
|||
exports map[string]*Desc
|
||||
}
|
||||
|
||||
// NewExpvarCollector returns a newly allocated expvar Collector that still has
|
||||
// to be registered with a Prometheus registry.
|
||||
// NewExpvarCollector is the obsolete version of collectors.NewExpvarCollector.
|
||||
// See there for documentation.
|
||||
//
|
||||
// An expvar Collector collects metrics from the expvar interface. It provides a
|
||||
// quick way to expose numeric values that are already exported via expvar as
|
||||
// Prometheus metrics. Note that the data models of expvar and Prometheus are
|
||||
// fundamentally different, and that the expvar Collector is inherently slower
|
||||
// than native Prometheus metrics. Thus, the expvar Collector is probably great
|
||||
// for experiments and prototying, but you should seriously consider a more
|
||||
// direct implementation of Prometheus metrics for monitoring production
|
||||
// systems.
|
||||
//
|
||||
// The exports map has the following meaning:
|
||||
//
|
||||
// The keys in the map correspond to expvar keys, i.e. for every expvar key you
|
||||
// want to export as Prometheus metric, you need an entry in the exports
|
||||
// map. The descriptor mapped to each key describes how to export the expvar
|
||||
// value. It defines the name and the help string of the Prometheus metric
|
||||
// proxying the expvar value. The type will always be Untyped.
|
||||
//
|
||||
// For descriptors without variable labels, the expvar value must be a number or
|
||||
// a bool. The number is then directly exported as the Prometheus sample
|
||||
// value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values
|
||||
// that are not numbers or bools are silently ignored.
|
||||
//
|
||||
// If the descriptor has one variable label, the expvar value must be an expvar
|
||||
// map. The keys in the expvar map become the various values of the one
|
||||
// Prometheus label. The values in the expvar map must be numbers or bools again
|
||||
// as above.
|
||||
//
|
||||
// For descriptors with more than one variable label, the expvar must be a
|
||||
// nested expvar map, i.e. where the values of the topmost map are maps again
|
||||
// etc. until a depth is reached that corresponds to the number of labels. The
|
||||
// leaves of that structure must be numbers or bools as above to serve as the
|
||||
// sample values.
|
||||
//
|
||||
// Anything that does not fit into the scheme above is silently ignored.
|
||||
// Deprecated: Use collectors.NewExpvarCollector instead.
|
||||
func NewExpvarCollector(exports map[string]*Desc) Collector {
|
||||
return &expvarCollector{
|
||||
exports: exports,
|
||||
|
|
20
vendor/github.com/prometheus/client_golang/prometheus/gauge.go
generated
vendored
20
vendor/github.com/prometheus/client_golang/prometheus/gauge.go
generated
vendored
|
@ -132,7 +132,7 @@ func (g *gauge) Write(out *dto.Metric) error {
|
|||
// (e.g. number of operations queued, partitioned by user and operation
|
||||
// type). Create instances with NewGaugeVec.
|
||||
type GaugeVec struct {
|
||||
*metricVec
|
||||
*MetricVec
|
||||
}
|
||||
|
||||
// NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
|
||||
|
@ -145,11 +145,11 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
|
|||
opts.ConstLabels,
|
||||
)
|
||||
return &GaugeVec{
|
||||
metricVec: newMetricVec(desc, func(lvs ...string) Metric {
|
||||
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||
if len(lvs) != len(desc.variableLabels) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
|
||||
}
|
||||
result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)}
|
||||
result := &gauge{desc: desc, labelPairs: MakeLabelPairs(desc, lvs)}
|
||||
result.init(result) // Init self-collection.
|
||||
return result
|
||||
}),
|
||||
|
@ -157,7 +157,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
|
|||
}
|
||||
|
||||
// GetMetricWithLabelValues returns the Gauge for the given slice of label
|
||||
// values (same order as the VariableLabels in Desc). If that combination of
|
||||
// values (same order as the variable labels in Desc). If that combination of
|
||||
// label values is accessed for the first time, a new Gauge is created.
|
||||
//
|
||||
// It is possible to call this method without using the returned Gauge to only
|
||||
|
@ -172,7 +172,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
|
|||
// example.
|
||||
//
|
||||
// An error is returned if the number of label values is not the same as the
|
||||
// number of VariableLabels in Desc (minus any curried labels).
|
||||
// number of variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// Note that for more than one label value, this method is prone to mistakes
|
||||
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
|
||||
|
@ -180,7 +180,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
|
|||
// latter has a much more readable (albeit more verbose) syntax, but it comes
|
||||
// with a performance overhead (for creating and processing the Labels map).
|
||||
func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
|
||||
metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
|
||||
metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Gauge), err
|
||||
}
|
||||
|
@ -188,19 +188,19 @@ func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
|
|||
}
|
||||
|
||||
// GetMetricWith returns the Gauge for the given Labels map (the label names
|
||||
// must match those of the VariableLabels in Desc). If that label map is
|
||||
// must match those of the variable labels in Desc). If that label map is
|
||||
// accessed for the first time, a new Gauge is created. Implications of
|
||||
// creating a Gauge without using it and keeping the Gauge for later use are
|
||||
// the same as for GetMetricWithLabelValues.
|
||||
//
|
||||
// An error is returned if the number and names of the Labels are inconsistent
|
||||
// with those of the VariableLabels in Desc (minus any curried labels).
|
||||
// with those of the variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// This method is used for the same purpose as
|
||||
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
|
||||
// methods.
|
||||
func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
|
||||
metric, err := v.metricVec.getMetricWith(labels)
|
||||
metric, err := v.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Gauge), err
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ func (v *GaugeVec) With(labels Labels) Gauge {
|
|||
// registered with a given registry (usually the uncurried version). The Reset
|
||||
// method deletes all metrics, even if called on a curried vector.
|
||||
func (v *GaugeVec) CurryWith(labels Labels) (*GaugeVec, error) {
|
||||
vec, err := v.curryWith(labels)
|
||||
vec, err := v.MetricVec.CurryWith(labels)
|
||||
if vec != nil {
|
||||
return &GaugeVec{vec}, err
|
||||
}
|
||||
|
|
523
vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
generated
vendored
523
vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
generated
vendored
|
@ -16,53 +16,209 @@ package prometheus
|
|||
import (
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type goCollector struct {
|
||||
func goRuntimeMemStats() memStatsMetrics {
|
||||
return memStatsMetrics{
|
||||
{
|
||||
desc: NewDesc(
|
||||
memstatNamespace("alloc_bytes"),
|
||||
"Number of bytes allocated and still in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("alloc_bytes_total"),
|
||||
"Total number of bytes allocated, even if freed.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("sys_bytes"),
|
||||
"Number of bytes obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("lookups_total"),
|
||||
"Total number of pointer lookups.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mallocs_total"),
|
||||
"Total number of mallocs.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("frees_total"),
|
||||
"Total number of frees.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_alloc_bytes"),
|
||||
"Number of heap bytes allocated and still in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_sys_bytes"),
|
||||
"Number of heap bytes obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_idle_bytes"),
|
||||
"Number of heap bytes waiting to be used.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_inuse_bytes"),
|
||||
"Number of heap bytes that are in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_released_bytes"),
|
||||
"Number of heap bytes released to OS.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_objects"),
|
||||
"Number of allocated objects.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("stack_inuse_bytes"),
|
||||
"Number of bytes in use by the stack allocator.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("stack_sys_bytes"),
|
||||
"Number of bytes obtained from system for stack allocator.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mspan_inuse_bytes"),
|
||||
"Number of bytes in use by mspan structures.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mspan_sys_bytes"),
|
||||
"Number of bytes used for mspan structures obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mcache_inuse_bytes"),
|
||||
"Number of bytes in use by mcache structures.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mcache_sys_bytes"),
|
||||
"Number of bytes used for mcache structures obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("buck_hash_sys_bytes"),
|
||||
"Number of bytes used by the profiling bucket hash table.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("gc_sys_bytes"),
|
||||
"Number of bytes used for garbage collection system metadata.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("other_sys_bytes"),
|
||||
"Number of bytes used for other system allocations.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("next_gc_bytes"),
|
||||
"Number of heap bytes when next garbage collection will take place.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("gc_cpu_fraction"),
|
||||
"The fraction of this program's available CPU time used by the GC since the program started.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
|
||||
valType: GaugeValue,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type baseGoCollector struct {
|
||||
goroutinesDesc *Desc
|
||||
threadsDesc *Desc
|
||||
gcDesc *Desc
|
||||
gcLastTimeDesc *Desc
|
||||
goInfoDesc *Desc
|
||||
|
||||
// ms... are memstats related.
|
||||
msLast *runtime.MemStats // Previously collected memstats.
|
||||
msLastTimestamp time.Time
|
||||
msMtx sync.Mutex // Protects msLast and msLastTimestamp.
|
||||
msMetrics memStatsMetrics
|
||||
msRead func(*runtime.MemStats) // For mocking in tests.
|
||||
msMaxWait time.Duration // Wait time for fresh memstats.
|
||||
msMaxAge time.Duration // Maximum allowed age of old memstats.
|
||||
}
|
||||
|
||||
// NewGoCollector returns a collector that exports metrics about the current Go
|
||||
// process. This includes memory stats. To collect those, runtime.ReadMemStats
|
||||
// is called. This requires to “stop the world”, which usually only happens for
|
||||
// garbage collection (GC). Take the following implications into account when
|
||||
// deciding whether to use the Go collector:
|
||||
//
|
||||
// 1. The performance impact of stopping the world is the more relevant the more
|
||||
// frequently metrics are collected. However, with Go1.9 or later the
|
||||
// stop-the-world time per metrics collection is very short (~25µs) so that the
|
||||
// performance impact will only matter in rare cases. However, with older Go
|
||||
// versions, the stop-the-world duration depends on the heap size and can be
|
||||
// quite significant (~1.7 ms/GiB as per
|
||||
// https://go-review.googlesource.com/c/go/+/34937).
|
||||
//
|
||||
// 2. During an ongoing GC, nothing else can stop the world. Therefore, if the
|
||||
// metrics collection happens to coincide with GC, it will only complete after
|
||||
// GC has finished. Usually, GC is fast enough to not cause problems. However,
|
||||
// with a very large heap, GC might take multiple seconds, which is enough to
|
||||
// cause scrape timeouts in common setups. To avoid this problem, the Go
|
||||
// collector will use the memstats from a previous collection if
|
||||
// runtime.ReadMemStats takes more than 1s. However, if there are no previously
|
||||
// collected memstats, or their collection is more than 5m ago, the collection
|
||||
// will block until runtime.ReadMemStats succeeds. (The problem might be solved
|
||||
// in Go1.13, see https://github.com/golang/go/issues/19812 for the related Go
|
||||
// issue.)
|
||||
func NewGoCollector() Collector {
|
||||
return &goCollector{
|
||||
func newBaseGoCollector() baseGoCollector {
|
||||
return baseGoCollector{
|
||||
goroutinesDesc: NewDesc(
|
||||
"go_goroutines",
|
||||
"Number of goroutines that currently exist.",
|
||||
|
@ -75,243 +231,28 @@ func NewGoCollector() Collector {
|
|||
"go_gc_duration_seconds",
|
||||
"A summary of the pause duration of garbage collection cycles.",
|
||||
nil, nil),
|
||||
gcLastTimeDesc: NewDesc(
|
||||
memstatNamespace("last_gc_time_seconds"),
|
||||
"Number of seconds since 1970 of last garbage collection.",
|
||||
nil, nil),
|
||||
goInfoDesc: NewDesc(
|
||||
"go_info",
|
||||
"Information about the Go environment.",
|
||||
nil, Labels{"version": runtime.Version()}),
|
||||
msLast: &runtime.MemStats{},
|
||||
msRead: runtime.ReadMemStats,
|
||||
msMaxWait: time.Second,
|
||||
msMaxAge: 5 * time.Minute,
|
||||
msMetrics: memStatsMetrics{
|
||||
{
|
||||
desc: NewDesc(
|
||||
memstatNamespace("alloc_bytes"),
|
||||
"Number of bytes allocated and still in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("alloc_bytes_total"),
|
||||
"Total number of bytes allocated, even if freed.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("sys_bytes"),
|
||||
"Number of bytes obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("lookups_total"),
|
||||
"Total number of pointer lookups.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mallocs_total"),
|
||||
"Total number of mallocs.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("frees_total"),
|
||||
"Total number of frees.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_alloc_bytes"),
|
||||
"Number of heap bytes allocated and still in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_sys_bytes"),
|
||||
"Number of heap bytes obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_idle_bytes"),
|
||||
"Number of heap bytes waiting to be used.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_inuse_bytes"),
|
||||
"Number of heap bytes that are in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_released_bytes"),
|
||||
"Number of heap bytes released to OS.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_objects"),
|
||||
"Number of allocated objects.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("stack_inuse_bytes"),
|
||||
"Number of bytes in use by the stack allocator.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("stack_sys_bytes"),
|
||||
"Number of bytes obtained from system for stack allocator.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mspan_inuse_bytes"),
|
||||
"Number of bytes in use by mspan structures.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mspan_sys_bytes"),
|
||||
"Number of bytes used for mspan structures obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mcache_inuse_bytes"),
|
||||
"Number of bytes in use by mcache structures.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mcache_sys_bytes"),
|
||||
"Number of bytes used for mcache structures obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("buck_hash_sys_bytes"),
|
||||
"Number of bytes used by the profiling bucket hash table.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("gc_sys_bytes"),
|
||||
"Number of bytes used for garbage collection system metadata.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("other_sys_bytes"),
|
||||
"Number of bytes used for other system allocations.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("next_gc_bytes"),
|
||||
"Number of heap bytes when next garbage collection will take place.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("last_gc_time_seconds"),
|
||||
"Number of seconds since 1970 of last garbage collection.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) / 1e9 },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("gc_cpu_fraction"),
|
||||
"The fraction of this program's available CPU time used by the GC since the program started.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
|
||||
valType: GaugeValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func memstatNamespace(s string) string {
|
||||
return "go_memstats_" + s
|
||||
}
|
||||
|
||||
// Describe returns all descriptions of the collector.
|
||||
func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||
func (c *baseGoCollector) Describe(ch chan<- *Desc) {
|
||||
ch <- c.goroutinesDesc
|
||||
ch <- c.threadsDesc
|
||||
ch <- c.gcDesc
|
||||
ch <- c.gcLastTimeDesc
|
||||
ch <- c.goInfoDesc
|
||||
for _, i := range c.msMetrics {
|
||||
ch <- i.desc
|
||||
}
|
||||
}
|
||||
|
||||
// Collect returns the current state of all metrics of the collector.
|
||||
func (c *goCollector) Collect(ch chan<- Metric) {
|
||||
var (
|
||||
ms = &runtime.MemStats{}
|
||||
done = make(chan struct{})
|
||||
)
|
||||
// Start reading memstats first as it might take a while.
|
||||
go func() {
|
||||
c.msRead(ms)
|
||||
c.msMtx.Lock()
|
||||
c.msLast = ms
|
||||
c.msLastTimestamp = time.Now()
|
||||
c.msMtx.Unlock()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
func (c *baseGoCollector) Collect(ch chan<- Metric) {
|
||||
ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine()))
|
||||
n, _ := runtime.ThreadCreateProfile(nil)
|
||||
ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n))
|
||||
|
@ -326,71 +267,19 @@ func (c *goCollector) Collect(ch chan<- Metric) {
|
|||
}
|
||||
quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
|
||||
ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles)
|
||||
ch <- MustNewConstMetric(c.gcLastTimeDesc, GaugeValue, float64(stats.LastGC.UnixNano())/1e9)
|
||||
|
||||
ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1)
|
||||
|
||||
timer := time.NewTimer(c.msMaxWait)
|
||||
select {
|
||||
case <-done: // Our own ReadMemStats succeeded in time. Use it.
|
||||
timer.Stop() // Important for high collection frequencies to not pile up timers.
|
||||
c.msCollect(ch, ms)
|
||||
return
|
||||
case <-timer.C: // Time out, use last memstats if possible. Continue below.
|
||||
}
|
||||
c.msMtx.Lock()
|
||||
if time.Since(c.msLastTimestamp) < c.msMaxAge {
|
||||
// Last memstats are recent enough. Collect from them under the lock.
|
||||
c.msCollect(ch, c.msLast)
|
||||
c.msMtx.Unlock()
|
||||
return
|
||||
}
|
||||
// If we are here, the last memstats are too old or don't exist. We have
|
||||
// to wait until our own ReadMemStats finally completes. For that to
|
||||
// happen, we have to release the lock.
|
||||
c.msMtx.Unlock()
|
||||
<-done
|
||||
c.msCollect(ch, ms)
|
||||
}
|
||||
|
||||
func (c *goCollector) msCollect(ch chan<- Metric, ms *runtime.MemStats) {
|
||||
for _, i := range c.msMetrics {
|
||||
ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
|
||||
}
|
||||
func memstatNamespace(s string) string {
|
||||
return "go_memstats_" + s
|
||||
}
|
||||
|
||||
// memStatsMetrics provide description, value, and value type for memstat metrics.
|
||||
// memStatsMetrics provide description, evaluator, runtime/metrics name, and
|
||||
// value type for memstat metrics.
|
||||
type memStatsMetrics []struct {
|
||||
desc *Desc
|
||||
eval func(*runtime.MemStats) float64
|
||||
valType ValueType
|
||||
}
|
||||
|
||||
// NewBuildInfoCollector returns a collector collecting a single metric
|
||||
// "go_build_info" with the constant value 1 and three labels "path", "version",
|
||||
// and "checksum". Their label values contain the main module path, version, and
|
||||
// checksum, respectively. The labels will only have meaningful values if the
|
||||
// binary is built with Go module support and from source code retrieved from
|
||||
// the source repository (rather than the local file system). This is usually
|
||||
// accomplished by building from outside of GOPATH, specifying the full address
|
||||
// of the main package, e.g. "GO111MODULE=on go run
|
||||
// github.com/prometheus/client_golang/examples/random". If built without Go
|
||||
// module support, all label values will be "unknown". If built with Go module
|
||||
// support but using the source code from the local file system, the "path" will
|
||||
// be set appropriately, but "checksum" will be empty and "version" will be
|
||||
// "(devel)".
|
||||
//
|
||||
// This collector uses only the build information for the main module. See
|
||||
// https://github.com/povilasv/prommod for an example of a collector for the
|
||||
// module dependencies.
|
||||
func NewBuildInfoCollector() Collector {
|
||||
path, version, sum := readBuildInfo()
|
||||
c := &selfCollector{MustNewConstMetric(
|
||||
NewDesc(
|
||||
"go_build_info",
|
||||
"Build information about the main Go module.",
|
||||
nil, Labels{"path": path, "version": version, "checksum": sum},
|
||||
),
|
||||
GaugeValue, 1)}
|
||||
c.init(c.self)
|
||||
return c
|
||||
}
|
||||
|
|
107
vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go
generated
vendored
Normal file
107
vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go
generated
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2021 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
//go:build !go1.17
|
||||
// +build !go1.17
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type goCollector struct {
|
||||
base baseGoCollector
|
||||
|
||||
// ms... are memstats related.
|
||||
msLast *runtime.MemStats // Previously collected memstats.
|
||||
msLastTimestamp time.Time
|
||||
msMtx sync.Mutex // Protects msLast and msLastTimestamp.
|
||||
msMetrics memStatsMetrics
|
||||
msRead func(*runtime.MemStats) // For mocking in tests.
|
||||
msMaxWait time.Duration // Wait time for fresh memstats.
|
||||
msMaxAge time.Duration // Maximum allowed age of old memstats.
|
||||
}
|
||||
|
||||
// NewGoCollector is the obsolete version of collectors.NewGoCollector.
|
||||
// See there for documentation.
|
||||
//
|
||||
// Deprecated: Use collectors.NewGoCollector instead.
|
||||
func NewGoCollector() Collector {
|
||||
return &goCollector{
|
||||
base: newBaseGoCollector(),
|
||||
msLast: &runtime.MemStats{},
|
||||
msRead: runtime.ReadMemStats,
|
||||
msMaxWait: time.Second,
|
||||
msMaxAge: 5 * time.Minute,
|
||||
msMetrics: goRuntimeMemStats(),
|
||||
}
|
||||
}
|
||||
|
||||
// Describe returns all descriptions of the collector.
|
||||
func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||
c.base.Describe(ch)
|
||||
for _, i := range c.msMetrics {
|
||||
ch <- i.desc
|
||||
}
|
||||
}
|
||||
|
||||
// Collect returns the current state of all metrics of the collector.
|
||||
func (c *goCollector) Collect(ch chan<- Metric) {
|
||||
var (
|
||||
ms = &runtime.MemStats{}
|
||||
done = make(chan struct{})
|
||||
)
|
||||
// Start reading memstats first as it might take a while.
|
||||
go func() {
|
||||
c.msRead(ms)
|
||||
c.msMtx.Lock()
|
||||
c.msLast = ms
|
||||
c.msLastTimestamp = time.Now()
|
||||
c.msMtx.Unlock()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
// Collect base non-memory metrics.
|
||||
c.base.Collect(ch)
|
||||
|
||||
timer := time.NewTimer(c.msMaxWait)
|
||||
select {
|
||||
case <-done: // Our own ReadMemStats succeeded in time. Use it.
|
||||
timer.Stop() // Important for high collection frequencies to not pile up timers.
|
||||
c.msCollect(ch, ms)
|
||||
return
|
||||
case <-timer.C: // Time out, use last memstats if possible. Continue below.
|
||||
}
|
||||
c.msMtx.Lock()
|
||||
if time.Since(c.msLastTimestamp) < c.msMaxAge {
|
||||
// Last memstats are recent enough. Collect from them under the lock.
|
||||
c.msCollect(ch, c.msLast)
|
||||
c.msMtx.Unlock()
|
||||
return
|
||||
}
|
||||
// If we are here, the last memstats are too old or don't exist. We have
|
||||
// to wait until our own ReadMemStats finally completes. For that to
|
||||
// happen, we have to release the lock.
|
||||
c.msMtx.Unlock()
|
||||
<-done
|
||||
c.msCollect(ch, ms)
|
||||
}
|
||||
|
||||
func (c *goCollector) msCollect(ch chan<- Metric, ms *runtime.MemStats) {
|
||||
for _, i := range c.msMetrics {
|
||||
ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
|
||||
}
|
||||
}
|
408
vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go
generated
vendored
Normal file
408
vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go
generated
vendored
Normal file
|
@ -0,0 +1,408 @@
|
|||
// Copyright 2021 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
//go:build go1.17
|
||||
// +build go1.17
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"math"
|
||||
"runtime"
|
||||
"runtime/metrics"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/client_golang/prometheus/internal"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
type goCollector struct {
|
||||
base baseGoCollector
|
||||
|
||||
// mu protects updates to all fields ensuring a consistent
|
||||
// snapshot is always produced by Collect.
|
||||
mu sync.Mutex
|
||||
|
||||
// rm... fields all pertain to the runtime/metrics package.
|
||||
rmSampleBuf []metrics.Sample
|
||||
rmSampleMap map[string]*metrics.Sample
|
||||
rmMetrics []collectorMetric
|
||||
|
||||
// With Go 1.17, the runtime/metrics package was introduced.
|
||||
// From that point on, metric names produced by the runtime/metrics
|
||||
// package could be generated from runtime/metrics names. However,
|
||||
// these differ from the old names for the same values.
|
||||
//
|
||||
// This field exist to export the same values under the old names
|
||||
// as well.
|
||||
msMetrics memStatsMetrics
|
||||
}
|
||||
|
||||
// NewGoCollector is the obsolete version of collectors.NewGoCollector.
|
||||
// See there for documentation.
|
||||
//
|
||||
// Deprecated: Use collectors.NewGoCollector instead.
|
||||
func NewGoCollector() Collector {
|
||||
descriptions := metrics.All()
|
||||
|
||||
// Collect all histogram samples so that we can get their buckets.
|
||||
// The API guarantees that the buckets are always fixed for the lifetime
|
||||
// of the process.
|
||||
var histograms []metrics.Sample
|
||||
for _, d := range descriptions {
|
||||
if d.Kind == metrics.KindFloat64Histogram {
|
||||
histograms = append(histograms, metrics.Sample{Name: d.Name})
|
||||
}
|
||||
}
|
||||
metrics.Read(histograms)
|
||||
bucketsMap := make(map[string][]float64)
|
||||
for i := range histograms {
|
||||
bucketsMap[histograms[i].Name] = histograms[i].Value.Float64Histogram().Buckets
|
||||
}
|
||||
|
||||
// Generate a Desc and ValueType for each runtime/metrics metric.
|
||||
metricSet := make([]collectorMetric, 0, len(descriptions))
|
||||
sampleBuf := make([]metrics.Sample, 0, len(descriptions))
|
||||
sampleMap := make(map[string]*metrics.Sample, len(descriptions))
|
||||
for i := range descriptions {
|
||||
d := &descriptions[i]
|
||||
namespace, subsystem, name, ok := internal.RuntimeMetricsToProm(d)
|
||||
if !ok {
|
||||
// Just ignore this metric; we can't do anything with it here.
|
||||
// If a user decides to use the latest version of Go, we don't want
|
||||
// to fail here. This condition is tested elsewhere.
|
||||
continue
|
||||
}
|
||||
|
||||
// Set up sample buffer for reading, and a map
|
||||
// for quick lookup of sample values.
|
||||
sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name})
|
||||
sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1]
|
||||
|
||||
var m collectorMetric
|
||||
if d.Kind == metrics.KindFloat64Histogram {
|
||||
_, hasSum := rmExactSumMap[d.Name]
|
||||
unit := d.Name[strings.IndexRune(d.Name, ':')+1:]
|
||||
m = newBatchHistogram(
|
||||
NewDesc(
|
||||
BuildFQName(namespace, subsystem, name),
|
||||
d.Description,
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
internal.RuntimeMetricsBucketsForUnit(bucketsMap[d.Name], unit),
|
||||
hasSum,
|
||||
)
|
||||
} else if d.Cumulative {
|
||||
m = NewCounter(CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: name,
|
||||
Help: d.Description,
|
||||
})
|
||||
} else {
|
||||
m = NewGauge(GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: name,
|
||||
Help: d.Description,
|
||||
})
|
||||
}
|
||||
metricSet = append(metricSet, m)
|
||||
}
|
||||
return &goCollector{
|
||||
base: newBaseGoCollector(),
|
||||
rmSampleBuf: sampleBuf,
|
||||
rmSampleMap: sampleMap,
|
||||
rmMetrics: metricSet,
|
||||
msMetrics: goRuntimeMemStats(),
|
||||
}
|
||||
}
|
||||
|
||||
// Describe returns all descriptions of the collector.
|
||||
func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||
c.base.Describe(ch)
|
||||
for _, i := range c.msMetrics {
|
||||
ch <- i.desc
|
||||
}
|
||||
for _, m := range c.rmMetrics {
|
||||
ch <- m.Desc()
|
||||
}
|
||||
}
|
||||
|
||||
// Collect returns the current state of all metrics of the collector.
|
||||
func (c *goCollector) Collect(ch chan<- Metric) {
|
||||
// Collect base non-memory metrics.
|
||||
c.base.Collect(ch)
|
||||
|
||||
// Collect must be thread-safe, so prevent concurrent use of
|
||||
// rmSampleBuf. Just read into rmSampleBuf but write all the data
|
||||
// we get into our Metrics or MemStats.
|
||||
//
|
||||
// This lock also ensures that the Metrics we send out are all from
|
||||
// the same updates, ensuring their mutual consistency insofar as
|
||||
// is guaranteed by the runtime/metrics package.
|
||||
//
|
||||
// N.B. This locking is heavy-handed, but Collect is expected to be called
|
||||
// relatively infrequently. Also the core operation here, metrics.Read,
|
||||
// is fast (O(tens of microseconds)) so contention should certainly be
|
||||
// low, though channel operations and any allocations may add to that.
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// Populate runtime/metrics sample buffer.
|
||||
metrics.Read(c.rmSampleBuf)
|
||||
|
||||
// Update all our metrics from rmSampleBuf.
|
||||
for i, sample := range c.rmSampleBuf {
|
||||
// N.B. switch on concrete type because it's significantly more efficient
|
||||
// than checking for the Counter and Gauge interface implementations. In
|
||||
// this case, we control all the types here.
|
||||
switch m := c.rmMetrics[i].(type) {
|
||||
case *counter:
|
||||
// Guard against decreases. This should never happen, but a failure
|
||||
// to do so will result in a panic, which is a harsh consequence for
|
||||
// a metrics collection bug.
|
||||
v0, v1 := m.get(), unwrapScalarRMValue(sample.Value)
|
||||
if v1 > v0 {
|
||||
m.Add(unwrapScalarRMValue(sample.Value) - m.get())
|
||||
}
|
||||
m.Collect(ch)
|
||||
case *gauge:
|
||||
m.Set(unwrapScalarRMValue(sample.Value))
|
||||
m.Collect(ch)
|
||||
case *batchHistogram:
|
||||
m.update(sample.Value.Float64Histogram(), c.exactSumFor(sample.Name))
|
||||
m.Collect(ch)
|
||||
default:
|
||||
panic("unexpected metric type")
|
||||
}
|
||||
}
|
||||
// ms is a dummy MemStats that we populate ourselves so that we can
|
||||
// populate the old metrics from it.
|
||||
var ms runtime.MemStats
|
||||
memStatsFromRM(&ms, c.rmSampleMap)
|
||||
for _, i := range c.msMetrics {
|
||||
ch <- MustNewConstMetric(i.desc, i.valType, i.eval(&ms))
|
||||
}
|
||||
}
|
||||
|
||||
// unwrapScalarRMValue unwraps a runtime/metrics value that is assumed
|
||||
// to be scalar and returns the equivalent float64 value. Panics if the
|
||||
// value is not scalar.
|
||||
func unwrapScalarRMValue(v metrics.Value) float64 {
|
||||
switch v.Kind() {
|
||||
case metrics.KindUint64:
|
||||
return float64(v.Uint64())
|
||||
case metrics.KindFloat64:
|
||||
return v.Float64()
|
||||
case metrics.KindBad:
|
||||
// Unsupported metric.
|
||||
//
|
||||
// This should never happen because we always populate our metric
|
||||
// set from the runtime/metrics package.
|
||||
panic("unexpected unsupported metric")
|
||||
default:
|
||||
// Unsupported metric kind.
|
||||
//
|
||||
// This should never happen because we check for this during initialization
|
||||
// and flag and filter metrics whose kinds we don't understand.
|
||||
panic("unexpected unsupported metric kind")
|
||||
}
|
||||
}
|
||||
|
||||
var rmExactSumMap = map[string]string{
|
||||
"/gc/heap/allocs-by-size:bytes": "/gc/heap/allocs:bytes",
|
||||
"/gc/heap/frees-by-size:bytes": "/gc/heap/frees:bytes",
|
||||
}
|
||||
|
||||
// exactSumFor takes a runtime/metrics metric name (that is assumed to
|
||||
// be of kind KindFloat64Histogram) and returns its exact sum and whether
|
||||
// its exact sum exists.
|
||||
//
|
||||
// The runtime/metrics API for histograms doesn't currently expose exact
|
||||
// sums, but some of the other metrics are in fact exact sums of histograms.
|
||||
func (c *goCollector) exactSumFor(rmName string) float64 {
|
||||
sumName, ok := rmExactSumMap[rmName]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
s, ok := c.rmSampleMap[sumName]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
return unwrapScalarRMValue(s.Value)
|
||||
}
|
||||
|
||||
func memStatsFromRM(ms *runtime.MemStats, rm map[string]*metrics.Sample) {
|
||||
lookupOrZero := func(name string) uint64 {
|
||||
if s, ok := rm[name]; ok {
|
||||
return s.Value.Uint64()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Currently, MemStats adds tiny alloc count to both Mallocs AND Frees.
|
||||
// The reason for this is because MemStats couldn't be extended at the time
|
||||
// but there was a desire to have Mallocs at least be a little more representative,
|
||||
// while having Mallocs - Frees still represent a live object count.
|
||||
// Unfortunately, MemStats doesn't actually export a large allocation count,
|
||||
// so it's impossible to pull this number out directly.
|
||||
tinyAllocs := lookupOrZero("/gc/heap/tiny/allocs:objects")
|
||||
ms.Mallocs = lookupOrZero("/gc/heap/allocs:objects") + tinyAllocs
|
||||
ms.Frees = lookupOrZero("/gc/heap/frees:objects") + tinyAllocs
|
||||
|
||||
ms.TotalAlloc = lookupOrZero("/gc/heap/allocs:bytes")
|
||||
ms.Sys = lookupOrZero("/memory/classes/total:bytes")
|
||||
ms.Lookups = 0 // Already always zero.
|
||||
ms.HeapAlloc = lookupOrZero("/memory/classes/heap/objects:bytes")
|
||||
ms.Alloc = ms.HeapAlloc
|
||||
ms.HeapInuse = ms.HeapAlloc + lookupOrZero("/memory/classes/heap/unused:bytes")
|
||||
ms.HeapReleased = lookupOrZero("/memory/classes/heap/released:bytes")
|
||||
ms.HeapIdle = ms.HeapReleased + lookupOrZero("/memory/classes/heap/free:bytes")
|
||||
ms.HeapSys = ms.HeapInuse + ms.HeapIdle
|
||||
ms.HeapObjects = lookupOrZero("/gc/heap/objects:objects")
|
||||
ms.StackInuse = lookupOrZero("/memory/classes/heap/stacks:bytes")
|
||||
ms.StackSys = ms.StackInuse + lookupOrZero("/memory/classes/os-stacks:bytes")
|
||||
ms.MSpanInuse = lookupOrZero("/memory/classes/metadata/mspan/inuse:bytes")
|
||||
ms.MSpanSys = ms.MSpanInuse + lookupOrZero("/memory/classes/metadata/mspan/free:bytes")
|
||||
ms.MCacheInuse = lookupOrZero("/memory/classes/metadata/mcache/inuse:bytes")
|
||||
ms.MCacheSys = ms.MCacheInuse + lookupOrZero("/memory/classes/metadata/mcache/free:bytes")
|
||||
ms.BuckHashSys = lookupOrZero("/memory/classes/profiling/buckets:bytes")
|
||||
ms.GCSys = lookupOrZero("/memory/classes/metadata/other:bytes")
|
||||
ms.OtherSys = lookupOrZero("/memory/classes/other:bytes")
|
||||
ms.NextGC = lookupOrZero("/gc/heap/goal:bytes")
|
||||
|
||||
// N.B. LastGC is omitted because runtime.GCStats already has this.
|
||||
// See https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034
|
||||
// for more details.
|
||||
ms.LastGC = 0
|
||||
|
||||
// N.B. GCCPUFraction is intentionally omitted. This metric is not useful,
|
||||
// and often misleading due to the fact that it's an average over the lifetime
|
||||
// of the process.
|
||||
// See https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034
|
||||
// for more details.
|
||||
ms.GCCPUFraction = 0
|
||||
}
|
||||
|
||||
// batchHistogram is a mutable histogram that is updated
|
||||
// in batches.
|
||||
type batchHistogram struct {
|
||||
selfCollector
|
||||
|
||||
// Static fields updated only once.
|
||||
desc *Desc
|
||||
hasSum bool
|
||||
|
||||
// Because this histogram operates in batches, it just uses a
|
||||
// single mutex for everything. updates are always serialized
|
||||
// but Write calls may operate concurrently with updates.
|
||||
// Contention between these two sources should be rare.
|
||||
mu sync.Mutex
|
||||
buckets []float64 // Inclusive lower bounds, like runtime/metrics.
|
||||
counts []uint64
|
||||
sum float64 // Used if hasSum is true.
|
||||
}
|
||||
|
||||
// newBatchHistogram creates a new batch histogram value with the given
|
||||
// Desc, buckets, and whether or not it has an exact sum available.
|
||||
//
|
||||
// buckets must always be from the runtime/metrics package, following
|
||||
// the same conventions.
|
||||
func newBatchHistogram(desc *Desc, buckets []float64, hasSum bool) *batchHistogram {
|
||||
h := &batchHistogram{
|
||||
desc: desc,
|
||||
buckets: buckets,
|
||||
// Because buckets follows runtime/metrics conventions, there's
|
||||
// 1 more value in the buckets list than there are buckets represented,
|
||||
// because in runtime/metrics, the bucket values represent *boundaries*,
|
||||
// and non-Inf boundaries are inclusive lower bounds for that bucket.
|
||||
counts: make([]uint64, len(buckets)-1),
|
||||
hasSum: hasSum,
|
||||
}
|
||||
h.init(h)
|
||||
return h
|
||||
}
|
||||
|
||||
// update updates the batchHistogram from a runtime/metrics histogram.
|
||||
//
|
||||
// sum must be provided if the batchHistogram was created to have an exact sum.
|
||||
// h.buckets must be a strict subset of his.Buckets.
|
||||
func (h *batchHistogram) update(his *metrics.Float64Histogram, sum float64) {
|
||||
counts, buckets := his.Counts, his.Buckets
|
||||
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
// Clear buckets.
|
||||
for i := range h.counts {
|
||||
h.counts[i] = 0
|
||||
}
|
||||
// Copy and reduce buckets.
|
||||
var j int
|
||||
for i, count := range counts {
|
||||
h.counts[j] += count
|
||||
if buckets[i+1] == h.buckets[j+1] {
|
||||
j++
|
||||
}
|
||||
}
|
||||
if h.hasSum {
|
||||
h.sum = sum
|
||||
}
|
||||
}
|
||||
|
||||
func (h *batchHistogram) Desc() *Desc {
|
||||
return h.desc
|
||||
}
|
||||
|
||||
func (h *batchHistogram) Write(out *dto.Metric) error {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
sum := float64(0)
|
||||
if h.hasSum {
|
||||
sum = h.sum
|
||||
}
|
||||
dtoBuckets := make([]*dto.Bucket, 0, len(h.counts))
|
||||
totalCount := uint64(0)
|
||||
for i, count := range h.counts {
|
||||
totalCount += count
|
||||
if !h.hasSum {
|
||||
// N.B. This computed sum is an underestimate.
|
||||
sum += h.buckets[i] * float64(count)
|
||||
}
|
||||
|
||||
// Skip the +Inf bucket, but only for the bucket list.
|
||||
// It must still count for sum and totalCount.
|
||||
if math.IsInf(h.buckets[i+1], 1) {
|
||||
break
|
||||
}
|
||||
// Float64Histogram's upper bound is exclusive, so make it inclusive
|
||||
// by obtaining the next float64 value down, in order.
|
||||
upperBound := math.Nextafter(h.buckets[i+1], h.buckets[i])
|
||||
dtoBuckets = append(dtoBuckets, &dto.Bucket{
|
||||
CumulativeCount: proto.Uint64(totalCount),
|
||||
UpperBound: proto.Float64(upperBound),
|
||||
})
|
||||
}
|
||||
out.Histogram = &dto.Histogram{
|
||||
Bucket: dtoBuckets,
|
||||
SampleCount: proto.Uint64(totalCount),
|
||||
SampleSum: proto.Float64(sum),
|
||||
}
|
||||
return nil
|
||||
}
|
60
vendor/github.com/prometheus/client_golang/prometheus/histogram.go
generated
vendored
60
vendor/github.com/prometheus/client_golang/prometheus/histogram.go
generated
vendored
|
@ -22,6 +22,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
@ -46,7 +47,12 @@ type Histogram interface {
|
|||
Metric
|
||||
Collector
|
||||
|
||||
// Observe adds a single observation to the histogram.
|
||||
// Observe adds a single observation to the histogram. Observations are
|
||||
// usually positive or zero. Negative observations are accepted but
|
||||
// prevent current versions of Prometheus from properly detecting
|
||||
// counter resets in the sum of observations. See
|
||||
// https://prometheus.io/docs/practices/histograms/#count-and-sum-of-observations
|
||||
// for details.
|
||||
Observe(float64)
|
||||
}
|
||||
|
||||
|
@ -110,6 +116,34 @@ func ExponentialBuckets(start, factor float64, count int) []float64 {
|
|||
return buckets
|
||||
}
|
||||
|
||||
// ExponentialBucketsRange creates 'count' buckets, where the lowest bucket is
|
||||
// 'min' and the highest bucket is 'max'. The final +Inf bucket is not counted
|
||||
// and not included in the returned slice. The returned slice is meant to be
|
||||
// used for the Buckets field of HistogramOpts.
|
||||
//
|
||||
// The function panics if 'count' is 0 or negative, if 'min' is 0 or negative.
|
||||
func ExponentialBucketsRange(min, max float64, count int) []float64 {
|
||||
if count < 1 {
|
||||
panic("ExponentialBucketsRange count needs a positive count")
|
||||
}
|
||||
if min <= 0 {
|
||||
panic("ExponentialBucketsRange min needs to be greater than 0")
|
||||
}
|
||||
|
||||
// Formula for exponential buckets.
|
||||
// max = min*growthFactor^(bucketCount-1)
|
||||
|
||||
// We know max/min and highest bucket. Solve for growthFactor.
|
||||
growthFactor := math.Pow(max/min, 1.0/float64(count-1))
|
||||
|
||||
// Now that we know growthFactor, solve for each bucket.
|
||||
buckets := make([]float64, count)
|
||||
for i := 1; i <= count; i++ {
|
||||
buckets[i-1] = min * math.Pow(growthFactor, float64(i-1))
|
||||
}
|
||||
return buckets
|
||||
}
|
||||
|
||||
// HistogramOpts bundles the options for creating a Histogram metric. It is
|
||||
// mandatory to set Name to a non-empty string. All other fields are optional
|
||||
// and can safely be left at their zero value, although it is strongly
|
||||
|
@ -191,7 +225,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
|||
h := &histogram{
|
||||
desc: desc,
|
||||
upperBounds: opts.Buckets,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||
counts: [2]*histogramCounts{{}, {}},
|
||||
now: time.Now,
|
||||
}
|
||||
|
@ -408,7 +442,7 @@ func (h *histogram) updateExemplar(v float64, bucket int, l Labels) {
|
|||
// (e.g. HTTP request latencies, partitioned by status code and method). Create
|
||||
// instances with NewHistogramVec.
|
||||
type HistogramVec struct {
|
||||
*metricVec
|
||||
*MetricVec
|
||||
}
|
||||
|
||||
// NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and
|
||||
|
@ -421,14 +455,14 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
|
|||
opts.ConstLabels,
|
||||
)
|
||||
return &HistogramVec{
|
||||
metricVec: newMetricVec(desc, func(lvs ...string) Metric {
|
||||
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||
return newHistogram(desc, opts, lvs...)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// GetMetricWithLabelValues returns the Histogram for the given slice of label
|
||||
// values (same order as the VariableLabels in Desc). If that combination of
|
||||
// values (same order as the variable labels in Desc). If that combination of
|
||||
// label values is accessed for the first time, a new Histogram is created.
|
||||
//
|
||||
// It is possible to call this method without using the returned Histogram to only
|
||||
|
@ -443,7 +477,7 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
|
|||
// example.
|
||||
//
|
||||
// An error is returned if the number of label values is not the same as the
|
||||
// number of VariableLabels in Desc (minus any curried labels).
|
||||
// number of variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// Note that for more than one label value, this method is prone to mistakes
|
||||
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
|
||||
|
@ -452,7 +486,7 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
|
|||
// with a performance overhead (for creating and processing the Labels map).
|
||||
// See also the GaugeVec example.
|
||||
func (v *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
|
||||
metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
|
||||
metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Observer), err
|
||||
}
|
||||
|
@ -460,19 +494,19 @@ func (v *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error)
|
|||
}
|
||||
|
||||
// GetMetricWith returns the Histogram for the given Labels map (the label names
|
||||
// must match those of the VariableLabels in Desc). If that label map is
|
||||
// must match those of the variable labels in Desc). If that label map is
|
||||
// accessed for the first time, a new Histogram is created. Implications of
|
||||
// creating a Histogram without using it and keeping the Histogram for later use
|
||||
// are the same as for GetMetricWithLabelValues.
|
||||
//
|
||||
// An error is returned if the number and names of the Labels are inconsistent
|
||||
// with those of the VariableLabels in Desc (minus any curried labels).
|
||||
// with those of the variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// This method is used for the same purpose as
|
||||
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
|
||||
// methods.
|
||||
func (v *HistogramVec) GetMetricWith(labels Labels) (Observer, error) {
|
||||
metric, err := v.metricVec.getMetricWith(labels)
|
||||
metric, err := v.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Observer), err
|
||||
}
|
||||
|
@ -516,7 +550,7 @@ func (v *HistogramVec) With(labels Labels) Observer {
|
|||
// registered with a given registry (usually the uncurried version). The Reset
|
||||
// method deletes all metrics, even if called on a curried vector.
|
||||
func (v *HistogramVec) CurryWith(labels Labels) (ObserverVec, error) {
|
||||
vec, err := v.curryWith(labels)
|
||||
vec, err := v.MetricVec.CurryWith(labels)
|
||||
if vec != nil {
|
||||
return &HistogramVec{vec}, err
|
||||
}
|
||||
|
@ -601,12 +635,12 @@ func NewConstHistogram(
|
|||
count: count,
|
||||
sum: sum,
|
||||
buckets: buckets,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MustNewConstHistogram is a version of NewConstHistogram that panics where
|
||||
// NewConstMetric would have returned an error.
|
||||
// NewConstHistogram would have returned an error.
|
||||
func MustNewConstHistogram(
|
||||
desc *Desc,
|
||||
count uint64,
|
||||
|
|
142
vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go
generated
vendored
Normal file
142
vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go
generated
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
// Copyright 2021 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
//go:build go1.17
|
||||
// +build go1.17
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"math"
|
||||
"path"
|
||||
"runtime/metrics"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// RuntimeMetricsToProm produces a Prometheus metric name from a runtime/metrics
|
||||
// metric description and validates whether the metric is suitable for integration
|
||||
// with Prometheus.
|
||||
//
|
||||
// Returns false if a name could not be produced, or if Prometheus does not understand
|
||||
// the runtime/metrics Kind.
|
||||
//
|
||||
// Note that the main reason a name couldn't be produced is if the runtime/metrics
|
||||
// package exports a name with characters outside the valid Prometheus metric name
|
||||
// character set. This is theoretically possible, but should never happen in practice.
|
||||
// Still, don't rely on it.
|
||||
func RuntimeMetricsToProm(d *metrics.Description) (string, string, string, bool) {
|
||||
namespace := "go"
|
||||
|
||||
comp := strings.SplitN(d.Name, ":", 2)
|
||||
key := comp[0]
|
||||
unit := comp[1]
|
||||
|
||||
// The last path element in the key is the name,
|
||||
// the rest is the subsystem.
|
||||
subsystem := path.Dir(key[1:] /* remove leading / */)
|
||||
name := path.Base(key)
|
||||
|
||||
// subsystem is translated by replacing all / and - with _.
|
||||
subsystem = strings.ReplaceAll(subsystem, "/", "_")
|
||||
subsystem = strings.ReplaceAll(subsystem, "-", "_")
|
||||
|
||||
// unit is translated assuming that the unit contains no
|
||||
// non-ASCII characters.
|
||||
unit = strings.ReplaceAll(unit, "-", "_")
|
||||
unit = strings.ReplaceAll(unit, "*", "_")
|
||||
unit = strings.ReplaceAll(unit, "/", "_per_")
|
||||
|
||||
// name has - replaced with _ and is concatenated with the unit and
|
||||
// other data.
|
||||
name = strings.ReplaceAll(name, "-", "_")
|
||||
name = name + "_" + unit
|
||||
if d.Cumulative {
|
||||
name = name + "_total"
|
||||
}
|
||||
|
||||
valid := model.IsValidMetricName(model.LabelValue(namespace + "_" + subsystem + "_" + name))
|
||||
switch d.Kind {
|
||||
case metrics.KindUint64:
|
||||
case metrics.KindFloat64:
|
||||
case metrics.KindFloat64Histogram:
|
||||
default:
|
||||
valid = false
|
||||
}
|
||||
return namespace, subsystem, name, valid
|
||||
}
|
||||
|
||||
// RuntimeMetricsBucketsForUnit takes a set of buckets obtained for a runtime/metrics histogram
|
||||
// type (so, lower-bound inclusive) and a unit from a runtime/metrics name, and produces
|
||||
// a reduced set of buckets. This function always removes any -Inf bucket as it's represented
|
||||
// as the bottom-most upper-bound inclusive bucket in Prometheus.
|
||||
func RuntimeMetricsBucketsForUnit(buckets []float64, unit string) []float64 {
|
||||
switch unit {
|
||||
case "bytes":
|
||||
// Rebucket as powers of 2.
|
||||
return rebucketExp(buckets, 2)
|
||||
case "seconds":
|
||||
// Rebucket as powers of 10 and then merge all buckets greater
|
||||
// than 1 second into the +Inf bucket.
|
||||
b := rebucketExp(buckets, 10)
|
||||
for i := range b {
|
||||
if b[i] <= 1 {
|
||||
continue
|
||||
}
|
||||
b[i] = math.Inf(1)
|
||||
b = b[:i+1]
|
||||
break
|
||||
}
|
||||
return b
|
||||
}
|
||||
return buckets
|
||||
}
|
||||
|
||||
// rebucketExp takes a list of bucket boundaries (lower bound inclusive) and
|
||||
// downsamples the buckets to those a multiple of base apart. The end result
|
||||
// is a roughly exponential (in many cases, perfectly exponential) bucketing
|
||||
// scheme.
|
||||
func rebucketExp(buckets []float64, base float64) []float64 {
|
||||
bucket := buckets[0]
|
||||
var newBuckets []float64
|
||||
// We may see a -Inf here, in which case, add it and skip it
|
||||
// since we risk producing NaNs otherwise.
|
||||
//
|
||||
// We need to preserve -Inf values to maintain runtime/metrics
|
||||
// conventions. We'll strip it out later.
|
||||
if bucket == math.Inf(-1) {
|
||||
newBuckets = append(newBuckets, bucket)
|
||||
buckets = buckets[1:]
|
||||
bucket = buckets[0]
|
||||
}
|
||||
// From now on, bucket should always have a non-Inf value because
|
||||
// Infs are only ever at the ends of the bucket lists, so
|
||||
// arithmetic operations on it are non-NaN.
|
||||
for i := 1; i < len(buckets); i++ {
|
||||
if bucket >= 0 && buckets[i] < bucket*base {
|
||||
// The next bucket we want to include is at least bucket*base.
|
||||
continue
|
||||
} else if bucket < 0 && buckets[i] < bucket/base {
|
||||
// In this case the bucket we're targeting is negative, and since
|
||||
// we're ascending through buckets here, we need to divide to get
|
||||
// closer to zero exponentially.
|
||||
continue
|
||||
}
|
||||
// The +Inf bucket will always be the last one, and we'll always
|
||||
// end up including it here because bucket
|
||||
newBuckets = append(newBuckets, bucket)
|
||||
bucket = buckets[i]
|
||||
}
|
||||
return append(newBuckets, bucket)
|
||||
}
|
5
vendor/github.com/prometheus/client_golang/prometheus/metric.go
generated
vendored
5
vendor/github.com/prometheus/client_golang/prometheus/metric.go
generated
vendored
|
@ -17,6 +17,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
|
@ -57,7 +58,7 @@ type Metric interface {
|
|||
}
|
||||
|
||||
// Opts bundles the options for creating most Metric types. Each metric
|
||||
// implementation XXX has its own XXXOpts type, but in most cases, it is just be
|
||||
// implementation XXX has its own XXXOpts type, but in most cases, it is just
|
||||
// an alias of this type (which might change when the requirement arises.)
|
||||
//
|
||||
// It is mandatory to set Name to a non-empty string. All other fields are
|
||||
|
@ -88,7 +89,7 @@ type Opts struct {
|
|||
// better covered by target labels set by the scraping Prometheus
|
||||
// server, or by one specific metric (e.g. a build_info or a
|
||||
// machine_role metric). See also
|
||||
// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels
|
||||
// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
|
||||
ConstLabels Labels
|
||||
}
|
||||
|
||||
|
|
33
vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
generated
vendored
33
vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
generated
vendored
|
@ -15,7 +15,11 @@ package prometheus
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type processCollector struct {
|
||||
|
@ -50,16 +54,10 @@ type ProcessCollectorOpts struct {
|
|||
ReportErrors bool
|
||||
}
|
||||
|
||||
// NewProcessCollector returns a collector which exports the current state of
|
||||
// process metrics including CPU, memory and file descriptor usage as well as
|
||||
// the process start time. The detailed behavior is defined by the provided
|
||||
// ProcessCollectorOpts. The zero value of ProcessCollectorOpts creates a
|
||||
// collector for the current process with an empty namespace string and no error
|
||||
// reporting.
|
||||
// NewProcessCollector is the obsolete version of collectors.NewProcessCollector.
|
||||
// See there for documentation.
|
||||
//
|
||||
// The collector only works on operating systems with a Linux-style proc
|
||||
// filesystem and on Microsoft Windows. On other operating systems, it will not
|
||||
// collect any metrics.
|
||||
// Deprecated: Use collectors.NewProcessCollector instead.
|
||||
func NewProcessCollector(opts ProcessCollectorOpts) Collector {
|
||||
ns := ""
|
||||
if len(opts.Namespace) > 0 {
|
||||
|
@ -149,3 +147,20 @@ func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error)
|
|||
}
|
||||
ch <- NewInvalidMetric(desc, err)
|
||||
}
|
||||
|
||||
// NewPidFileFn returns a function that retrieves a pid from the specified file.
|
||||
// It is meant to be used for the PidFn field in ProcessCollectorOpts.
|
||||
func NewPidFileFn(pidFilePath string) func() (int, error) {
|
||||
return func() (int, error) {
|
||||
content, err := ioutil.ReadFile(pidFilePath)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("can't read pid file %q: %+v", pidFilePath, err)
|
||||
}
|
||||
pid, err := strconv.Atoi(strings.TrimSpace(string(content)))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("can't parse pid file %q: %+v", pidFilePath, err)
|
||||
}
|
||||
|
||||
return pid, nil
|
||||
}
|
||||
}
|
||||
|
|
1
vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go
generated
vendored
1
vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go
generated
vendored
|
@ -11,6 +11,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package prometheus
|
||||
|
|
6
vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go
generated
vendored
6
vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go
generated
vendored
|
@ -83,8 +83,7 @@ type readerFromDelegator struct{ *responseWriterDelegator }
|
|||
type pusherDelegator struct{ *responseWriterDelegator }
|
||||
|
||||
func (d closeNotifierDelegator) CloseNotify() <-chan bool {
|
||||
//lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to
|
||||
//remove support from client_golang yet.
|
||||
//nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users.
|
||||
return d.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
func (d flusherDelegator) Flush() {
|
||||
|
@ -348,8 +347,7 @@ func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) deleg
|
|||
}
|
||||
|
||||
id := 0
|
||||
//lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to
|
||||
//remove support from client_golang yet.
|
||||
//nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users.
|
||||
if _, ok := w.(http.CloseNotifier); ok {
|
||||
id += closeNotifier
|
||||
}
|
||||
|
|
10
vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
generated
vendored
10
vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
generated
vendored
|
@ -99,7 +99,7 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
|
|||
inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight)
|
||||
}
|
||||
if opts.Registry != nil {
|
||||
// Initialize all possibilites that can occur below.
|
||||
// Initialize all possibilities that can occur below.
|
||||
errCnt.WithLabelValues("gathering")
|
||||
errCnt.WithLabelValues("encoding")
|
||||
if err := opts.Registry.Register(errCnt); err != nil {
|
||||
|
@ -303,8 +303,12 @@ type Logger interface {
|
|||
// HandlerOpts specifies options how to serve metrics via an http.Handler. The
|
||||
// zero value of HandlerOpts is a reasonable default.
|
||||
type HandlerOpts struct {
|
||||
// ErrorLog specifies an optional logger for errors collecting and
|
||||
// serving metrics. If nil, errors are not logged at all.
|
||||
// ErrorLog specifies an optional Logger for errors collecting and
|
||||
// serving metrics. If nil, errors are not logged at all. Note that the
|
||||
// type of a reported error is often prometheus.MultiError, which
|
||||
// formats into a multi-line error string. If you want to avoid the
|
||||
// latter, create a Logger implementation that detects a
|
||||
// prometheus.MultiError and formats the contained errors into one line.
|
||||
ErrorLog Logger
|
||||
// ErrorHandling defines how errors are handled. Note that errors are
|
||||
// logged regardless of the configured ErrorHandling provided ErrorLog
|
||||
|
|
28
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
generated
vendored
28
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
generated
vendored
|
@ -49,7 +49,10 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
|
|||
// http.RoundTripper to observe the request result with the provided CounterVec.
|
||||
// The CounterVec must have zero, one, or two non-const non-curried labels. For
|
||||
// those, the only allowed label names are "code" and "method". The function
|
||||
// panics otherwise. Partitioning of the CounterVec happens by HTTP status code
|
||||
// panics otherwise. For the "method" label a predefined default label value set
|
||||
// is used to filter given values. Values besides predefined values will count
|
||||
// as `unknown` method.`WithExtraMethods` can be used to add more
|
||||
// methods to the set. Partitioning of the CounterVec happens by HTTP status code
|
||||
// and/or HTTP method if the respective instance label names are present in the
|
||||
// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
|
||||
//
|
||||
|
@ -57,13 +60,18 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
|
|||
// is not incremented.
|
||||
//
|
||||
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
||||
func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc {
|
||||
func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
|
||||
rtOpts := &option{}
|
||||
for _, o := range opts {
|
||||
o(rtOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(counter)
|
||||
|
||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := next.RoundTrip(r)
|
||||
if err == nil {
|
||||
counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
|
||||
counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc()
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
|
@ -73,7 +81,10 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
|
|||
// http.RoundTripper to observe the request duration with the provided
|
||||
// ObserverVec. The ObserverVec must have zero, one, or two non-const
|
||||
// non-curried labels. For those, the only allowed label names are "code" and
|
||||
// "method". The function panics otherwise. The Observe method of the Observer
|
||||
// "method". The function panics otherwise. For the "method" label a predefined
|
||||
// default label value set is used to filter given values. Values besides
|
||||
// predefined values will count as `unknown` method. `WithExtraMethods`
|
||||
// can be used to add more methods to the set. The Observe method of the Observer
|
||||
// in the ObserverVec is called with the request duration in
|
||||
// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
|
||||
// respective instance label names are present in the ObserverVec. For
|
||||
|
@ -85,14 +96,19 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
|
|||
//
|
||||
// Note that this method is only guaranteed to never observe negative durations
|
||||
// if used with Go1.9+.
|
||||
func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc {
|
||||
func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
|
||||
rtOpts := &option{}
|
||||
for _, o := range opts {
|
||||
o(rtOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
|
||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
||||
start := time.Now()
|
||||
resp, err := next.RoundTrip(r)
|
||||
if err == nil {
|
||||
obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
|
||||
obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Observe(time.Since(start).Seconds())
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
|
|
188
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
generated
vendored
188
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
generated
vendored
|
@ -43,14 +43,17 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
|
|||
|
||||
// InstrumentHandlerDuration is a middleware that wraps the provided
|
||||
// http.Handler to observe the request duration with the provided ObserverVec.
|
||||
// The ObserverVec must have zero, one, or two non-const non-curried labels. For
|
||||
// those, the only allowed label names are "code" and "method". The function
|
||||
// panics otherwise. The Observe method of the Observer in the ObserverVec is
|
||||
// called with the request duration in seconds. Partitioning happens by HTTP
|
||||
// status code and/or HTTP method if the respective instance label names are
|
||||
// present in the ObserverVec. For unpartitioned observations, use an
|
||||
// ObserverVec with zero labels. Note that partitioning of Histograms is
|
||||
// expensive and should be used judiciously.
|
||||
// The ObserverVec must have valid metric and label names and must have zero,
|
||||
// one, or two non-const non-curried labels. For those, the only allowed label
|
||||
// names are "code" and "method". The function panics otherwise. For the "method"
|
||||
// label a predefined default label value set is used to filter given values.
|
||||
// Values besides predefined values will count as `unknown` method.
|
||||
//`WithExtraMethods` can be used to add more methods to the set. The Observe
|
||||
// method of the Observer in the ObserverVec is called with the request duration
|
||||
// in seconds. Partitioning happens by HTTP status code and/or HTTP method if
|
||||
// the respective instance label names are present in the ObserverVec. For
|
||||
// unpartitioned observations, use an ObserverVec with zero labels. Note that
|
||||
// partitioning of Histograms is expensive and should be used judiciously.
|
||||
//
|
||||
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
|
||||
//
|
||||
|
@ -58,7 +61,12 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
|
|||
//
|
||||
// Note that this method is only guaranteed to never observe negative durations
|
||||
// if used with Go1.9+.
|
||||
func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
|
||||
func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
|
||||
mwOpts := &option{}
|
||||
for _, o := range opts {
|
||||
o(mwOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
|
||||
if code {
|
||||
|
@ -67,57 +75,70 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
|
|||
d := newDelegator(w, nil)
|
||||
next.ServeHTTP(d, r)
|
||||
|
||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
|
||||
obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
|
||||
})
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
now := time.Now()
|
||||
next.ServeHTTP(w, r)
|
||||
obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds())
|
||||
obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandlerCounter is a middleware that wraps the provided http.Handler
|
||||
// to observe the request result with the provided CounterVec. The CounterVec
|
||||
// must have zero, one, or two non-const non-curried labels. For those, the only
|
||||
// allowed label names are "code" and "method". The function panics
|
||||
// otherwise. Partitioning of the CounterVec happens by HTTP status code and/or
|
||||
// HTTP method if the respective instance label names are present in the
|
||||
// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
|
||||
// to observe the request result with the provided CounterVec. The CounterVec
|
||||
// must have valid metric and label names and must have zero, one, or two
|
||||
// non-const non-curried labels. For those, the only allowed label names are
|
||||
// "code" and "method". The function panics otherwise. For the "method"
|
||||
// label a predefined default label value set is used to filter given values.
|
||||
// Values besides predefined values will count as `unknown` method.
|
||||
// `WithExtraMethods` can be used to add more methods to the set. Partitioning of the
|
||||
// CounterVec happens by HTTP status code and/or HTTP method if the respective
|
||||
// instance label names are present in the CounterVec. For unpartitioned
|
||||
// counting, use a CounterVec with zero labels.
|
||||
//
|
||||
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
|
||||
//
|
||||
// If the wrapped Handler panics, the Counter is not incremented.
|
||||
//
|
||||
// See the example for InstrumentHandlerDuration for example usage.
|
||||
func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc {
|
||||
func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, opts ...Option) http.HandlerFunc {
|
||||
mwOpts := &option{}
|
||||
for _, o := range opts {
|
||||
o(mwOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(counter)
|
||||
|
||||
if code {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
d := newDelegator(w, nil)
|
||||
next.ServeHTTP(d, r)
|
||||
counter.With(labels(code, method, r.Method, d.Status())).Inc()
|
||||
counter.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Inc()
|
||||
})
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r)
|
||||
counter.With(labels(code, method, r.Method, 0)).Inc()
|
||||
counter.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Inc()
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided
|
||||
// http.Handler to observe with the provided ObserverVec the request duration
|
||||
// until the response headers are written. The ObserverVec must have zero, one,
|
||||
// or two non-const non-curried labels. For those, the only allowed label names
|
||||
// are "code" and "method". The function panics otherwise. The Observe method of
|
||||
// the Observer in the ObserverVec is called with the request duration in
|
||||
// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
|
||||
// respective instance label names are present in the ObserverVec. For
|
||||
// unpartitioned observations, use an ObserverVec with zero labels. Note that
|
||||
// partitioning of Histograms is expensive and should be used judiciously.
|
||||
// until the response headers are written. The ObserverVec must have valid
|
||||
// metric and label names and must have zero, one, or two non-const non-curried
|
||||
// labels. For those, the only allowed label names are "code" and "method". The
|
||||
// function panics otherwise. For the "method" label a predefined default label
|
||||
// value set is used to filter given values. Values besides predefined values
|
||||
// will count as `unknown` method.`WithExtraMethods` can be used to add more
|
||||
// methods to the set. The Observe method of the Observer in the
|
||||
// ObserverVec is called with the request duration in seconds. Partitioning
|
||||
// happens by HTTP status code and/or HTTP method if the respective instance
|
||||
// label names are present in the ObserverVec. For unpartitioned observations,
|
||||
// use an ObserverVec with zero labels. Note that partitioning of Histograms is
|
||||
// expensive and should be used judiciously.
|
||||
//
|
||||
// If the wrapped Handler panics before calling WriteHeader, no value is
|
||||
// reported.
|
||||
|
@ -126,35 +147,48 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
|
|||
// if used with Go1.9+.
|
||||
//
|
||||
// See the example for InstrumentHandlerDuration for example usage.
|
||||
func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
|
||||
func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
|
||||
mwOpts := &option{}
|
||||
for _, o := range opts {
|
||||
o(mwOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
now := time.Now()
|
||||
d := newDelegator(w, func(status int) {
|
||||
obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds())
|
||||
obs.With(labels(code, method, r.Method, status, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
|
||||
})
|
||||
next.ServeHTTP(d, r)
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandlerRequestSize is a middleware that wraps the provided
|
||||
// http.Handler to observe the request size with the provided ObserverVec. The
|
||||
// ObserverVec must have zero, one, or two non-const non-curried labels. For
|
||||
// those, the only allowed label names are "code" and "method". The function
|
||||
// panics otherwise. The Observe method of the Observer in the ObserverVec is
|
||||
// called with the request size in bytes. Partitioning happens by HTTP status
|
||||
// code and/or HTTP method if the respective instance label names are present in
|
||||
// the ObserverVec. For unpartitioned observations, use an ObserverVec with zero
|
||||
// labels. Note that partitioning of Histograms is expensive and should be used
|
||||
// judiciously.
|
||||
// http.Handler to observe the request size with the provided ObserverVec. The
|
||||
// ObserverVec must have valid metric and label names and must have zero, one,
|
||||
// or two non-const non-curried labels. For those, the only allowed label names
|
||||
// are "code" and "method". The function panics otherwise. For the "method"
|
||||
// label a predefined default label value set is used to filter given values.
|
||||
// Values besides predefined values will count as `unknown` method.
|
||||
// `WithExtraMethods` can be used to add more methods to the set. The Observe
|
||||
// method of the Observer in the ObserverVec is called with the request size in
|
||||
// bytes. Partitioning happens by HTTP status code and/or HTTP method if the
|
||||
// respective instance label names are present in the ObserverVec. For
|
||||
// unpartitioned observations, use an ObserverVec with zero labels. Note that
|
||||
// partitioning of Histograms is expensive and should be used judiciously.
|
||||
//
|
||||
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
|
||||
//
|
||||
// If the wrapped Handler panics, no values are reported.
|
||||
//
|
||||
// See the example for InstrumentHandlerDuration for example usage.
|
||||
func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
|
||||
func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
|
||||
mwOpts := &option{}
|
||||
for _, o := range opts {
|
||||
o(mwOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
|
||||
if code {
|
||||
|
@ -162,42 +196,56 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
|
|||
d := newDelegator(w, nil)
|
||||
next.ServeHTTP(d, r)
|
||||
size := computeApproximateRequestSize(r)
|
||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
|
||||
obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(size))
|
||||
})
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r)
|
||||
size := computeApproximateRequestSize(r)
|
||||
obs.With(labels(code, method, r.Method, 0)).Observe(float64(size))
|
||||
obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(float64(size))
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandlerResponseSize is a middleware that wraps the provided
|
||||
// http.Handler to observe the response size with the provided ObserverVec. The
|
||||
// ObserverVec must have zero, one, or two non-const non-curried labels. For
|
||||
// those, the only allowed label names are "code" and "method". The function
|
||||
// panics otherwise. The Observe method of the Observer in the ObserverVec is
|
||||
// called with the response size in bytes. Partitioning happens by HTTP status
|
||||
// code and/or HTTP method if the respective instance label names are present in
|
||||
// the ObserverVec. For unpartitioned observations, use an ObserverVec with zero
|
||||
// labels. Note that partitioning of Histograms is expensive and should be used
|
||||
// judiciously.
|
||||
// http.Handler to observe the response size with the provided ObserverVec. The
|
||||
// ObserverVec must have valid metric and label names and must have zero, one,
|
||||
// or two non-const non-curried labels. For those, the only allowed label names
|
||||
// are "code" and "method". The function panics otherwise. For the "method"
|
||||
// label a predefined default label value set is used to filter given values.
|
||||
// Values besides predefined values will count as `unknown` method.
|
||||
// `WithExtraMethods` can be used to add more methods to the set. The Observe
|
||||
// method of the Observer in the ObserverVec is called with the response size in
|
||||
// bytes. Partitioning happens by HTTP status code and/or HTTP method if the
|
||||
// respective instance label names are present in the ObserverVec. For
|
||||
// unpartitioned observations, use an ObserverVec with zero labels. Note that
|
||||
// partitioning of Histograms is expensive and should be used judiciously.
|
||||
//
|
||||
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
|
||||
//
|
||||
// If the wrapped Handler panics, no values are reported.
|
||||
//
|
||||
// See the example for InstrumentHandlerDuration for example usage.
|
||||
func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler {
|
||||
func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.Handler {
|
||||
mwOpts := &option{}
|
||||
for _, o := range opts {
|
||||
o(mwOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
d := newDelegator(w, nil)
|
||||
next.ServeHTTP(d, r)
|
||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
|
||||
obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(d.Written()))
|
||||
})
|
||||
}
|
||||
|
||||
// checkLabels returns whether the provided Collector has a non-const,
|
||||
// non-curried label named "code" and/or "method". It panics if the provided
|
||||
// Collector does not have a Desc or has more than one Desc or its Desc is
|
||||
// invalid. It also panics if the Collector has any non-const, non-curried
|
||||
// labels that are not named "code" or "method".
|
||||
func checkLabels(c prometheus.Collector) (code bool, method bool) {
|
||||
// TODO(beorn7): Remove this hacky way to check for instance labels
|
||||
// once Descriptors can have their dimensionality queried.
|
||||
|
@ -225,6 +273,10 @@ func checkLabels(c prometheus.Collector) (code bool, method bool) {
|
|||
|
||||
close(descc)
|
||||
|
||||
// Make sure the Collector has a valid Desc by registering it with a
|
||||
// temporary registry.
|
||||
prometheus.NewRegistry().MustRegister(c)
|
||||
|
||||
// Create a ConstMetric with the Desc. Since we don't know how many
|
||||
// variable labels there are, try for as long as it needs.
|
||||
for err := errors.New("dummy"); err != nil; lvs = append(lvs, magicString) {
|
||||
|
@ -279,7 +331,7 @@ func isLabelCurried(c prometheus.Collector, label string) bool {
|
|||
// unnecessary allocations on each request.
|
||||
var emptyLabels = prometheus.Labels{}
|
||||
|
||||
func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
|
||||
func labels(code, method bool, reqMethod string, status int, extraMethods ...string) prometheus.Labels {
|
||||
if !(code || method) {
|
||||
return emptyLabels
|
||||
}
|
||||
|
@ -289,7 +341,7 @@ func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
|
|||
labels["code"] = sanitizeCode(status)
|
||||
}
|
||||
if method {
|
||||
labels["method"] = sanitizeMethod(reqMethod)
|
||||
labels["method"] = sanitizeMethod(reqMethod, extraMethods...)
|
||||
}
|
||||
|
||||
return labels
|
||||
|
@ -319,7 +371,12 @@ func computeApproximateRequestSize(r *http.Request) int {
|
|||
return s
|
||||
}
|
||||
|
||||
func sanitizeMethod(m string) string {
|
||||
// If the wrapped http.Handler has a known method, it will be sanitized and returned.
|
||||
// Otherwise, "unknown" will be returned. The known method list can be extended
|
||||
// as needed by using extraMethods parameter.
|
||||
func sanitizeMethod(m string, extraMethods ...string) string {
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for
|
||||
// the methods chosen as default.
|
||||
switch m {
|
||||
case "GET", "get":
|
||||
return "get"
|
||||
|
@ -337,15 +394,25 @@ func sanitizeMethod(m string) string {
|
|||
return "options"
|
||||
case "NOTIFY", "notify":
|
||||
return "notify"
|
||||
case "TRACE", "trace":
|
||||
return "trace"
|
||||
case "PATCH", "patch":
|
||||
return "patch"
|
||||
default:
|
||||
return strings.ToLower(m)
|
||||
for _, method := range extraMethods {
|
||||
if strings.EqualFold(m, method) {
|
||||
return strings.ToLower(m)
|
||||
}
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// If the wrapped http.Handler has not set a status code, i.e. the value is
|
||||
// currently 0, santizeCode will return 200, for consistency with behavior in
|
||||
// currently 0, sanitizeCode will return 200, for consistency with behavior in
|
||||
// the stdlib.
|
||||
func sanitizeCode(s int) string {
|
||||
// See for accepted codes https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||
switch s {
|
||||
case 100:
|
||||
return "100"
|
||||
|
@ -442,6 +509,9 @@ func sanitizeCode(s int) string {
|
|||
return "511"
|
||||
|
||||
default:
|
||||
return strconv.Itoa(s)
|
||||
if s >= 100 && s <= 599 {
|
||||
return strconv.Itoa(s)
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
|
31
vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
generated
vendored
Normal file
31
vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2022 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
package promhttp
|
||||
|
||||
// Option are used to configure a middleware or round tripper..
|
||||
type Option func(*option)
|
||||
|
||||
type option struct {
|
||||
extraMethods []string
|
||||
}
|
||||
|
||||
// WithExtraMethods adds additional HTTP methods to the list of allowed methods.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for the default list.
|
||||
//
|
||||
// See the example for ExampleInstrumentHandlerWithExtraMethods for example usage.
|
||||
func WithExtraMethods(methods ...string) Option {
|
||||
return func(o *option) {
|
||||
o.extraMethods = methods
|
||||
}
|
||||
}
|
3
vendor/github.com/prometheus/client_golang/prometheus/registry.go
generated
vendored
3
vendor/github.com/prometheus/client_golang/prometheus/registry.go
generated
vendored
|
@ -26,6 +26,7 @@ import (
|
|||
"unicode/utf8"
|
||||
|
||||
"github.com/cespare/xxhash/v2"
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
|
||||
|
@ -214,6 +215,8 @@ func (err AlreadyRegisteredError) Error() string {
|
|||
// by a Gatherer to report multiple errors during MetricFamily gathering.
|
||||
type MultiError []error
|
||||
|
||||
// Error formats the contained errors as a bullet point list, preceded by the
|
||||
// total number of errors. Note that this results in a multi-line string.
|
||||
func (errs MultiError) Error() string {
|
||||
if len(errs) == 0 {
|
||||
return ""
|
||||
|
|
38
vendor/github.com/prometheus/client_golang/prometheus/summary.go
generated
vendored
38
vendor/github.com/prometheus/client_golang/prometheus/summary.go
generated
vendored
|
@ -23,6 +23,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/beorn7/perks/quantile"
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
@ -54,7 +55,12 @@ type Summary interface {
|
|||
Metric
|
||||
Collector
|
||||
|
||||
// Observe adds a single observation to the summary.
|
||||
// Observe adds a single observation to the summary. Observations are
|
||||
// usually positive or zero. Negative observations are accepted but
|
||||
// prevent current versions of Prometheus from properly detecting
|
||||
// counter resets in the sum of observations. See
|
||||
// https://prometheus.io/docs/practices/histograms/#count-and-sum-of-observations
|
||||
// for details.
|
||||
Observe(float64)
|
||||
}
|
||||
|
||||
|
@ -109,7 +115,7 @@ type SummaryOpts struct {
|
|||
// better covered by target labels set by the scraping Prometheus
|
||||
// server, or by one specific metric (e.g. a build_info or a
|
||||
// machine_role metric). See also
|
||||
// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels
|
||||
// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
|
||||
ConstLabels Labels
|
||||
|
||||
// Objectives defines the quantile rank estimates with their respective
|
||||
|
@ -120,7 +126,9 @@ type SummaryOpts struct {
|
|||
Objectives map[float64]float64
|
||||
|
||||
// MaxAge defines the duration for which an observation stays relevant
|
||||
// for the summary. Must be positive. The default value is DefMaxAge.
|
||||
// for the summary. Only applies to pre-calculated quantiles, does not
|
||||
// apply to _sum and _count. Must be positive. The default value is
|
||||
// DefMaxAge.
|
||||
MaxAge time.Duration
|
||||
|
||||
// AgeBuckets is the number of buckets used to exclude observations that
|
||||
|
@ -207,7 +215,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
|||
// Use the lock-free implementation of a Summary without objectives.
|
||||
s := &noObjectivesSummary{
|
||||
desc: desc,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||
counts: [2]*summaryCounts{{}, {}},
|
||||
}
|
||||
s.init(s) // Init self-collection.
|
||||
|
@ -220,7 +228,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
|||
objectives: opts.Objectives,
|
||||
sortedObjectives: make([]float64, 0, len(opts.Objectives)),
|
||||
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||
|
||||
hotBuf: make([]float64, 0, opts.BufCap),
|
||||
coldBuf: make([]float64, 0, opts.BufCap),
|
||||
|
@ -512,7 +520,7 @@ func (s quantSort) Less(i, j int) bool {
|
|||
// (e.g. HTTP request latencies, partitioned by status code and method). Create
|
||||
// instances with NewSummaryVec.
|
||||
type SummaryVec struct {
|
||||
*metricVec
|
||||
*MetricVec
|
||||
}
|
||||
|
||||
// NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and
|
||||
|
@ -534,14 +542,14 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
|
|||
opts.ConstLabels,
|
||||
)
|
||||
return &SummaryVec{
|
||||
metricVec: newMetricVec(desc, func(lvs ...string) Metric {
|
||||
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||
return newSummary(desc, opts, lvs...)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// GetMetricWithLabelValues returns the Summary for the given slice of label
|
||||
// values (same order as the VariableLabels in Desc). If that combination of
|
||||
// values (same order as the variable labels in Desc). If that combination of
|
||||
// label values is accessed for the first time, a new Summary is created.
|
||||
//
|
||||
// It is possible to call this method without using the returned Summary to only
|
||||
|
@ -556,7 +564,7 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
|
|||
// example.
|
||||
//
|
||||
// An error is returned if the number of label values is not the same as the
|
||||
// number of VariableLabels in Desc (minus any curried labels).
|
||||
// number of variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// Note that for more than one label value, this method is prone to mistakes
|
||||
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
|
||||
|
@ -565,7 +573,7 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
|
|||
// with a performance overhead (for creating and processing the Labels map).
|
||||
// See also the GaugeVec example.
|
||||
func (v *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
|
||||
metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
|
||||
metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Observer), err
|
||||
}
|
||||
|
@ -573,19 +581,19 @@ func (v *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
|
|||
}
|
||||
|
||||
// GetMetricWith returns the Summary for the given Labels map (the label names
|
||||
// must match those of the VariableLabels in Desc). If that label map is
|
||||
// must match those of the variable labels in Desc). If that label map is
|
||||
// accessed for the first time, a new Summary is created. Implications of
|
||||
// creating a Summary without using it and keeping the Summary for later use are
|
||||
// the same as for GetMetricWithLabelValues.
|
||||
//
|
||||
// An error is returned if the number and names of the Labels are inconsistent
|
||||
// with those of the VariableLabels in Desc (minus any curried labels).
|
||||
// with those of the variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// This method is used for the same purpose as
|
||||
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
|
||||
// methods.
|
||||
func (v *SummaryVec) GetMetricWith(labels Labels) (Observer, error) {
|
||||
metric, err := v.metricVec.getMetricWith(labels)
|
||||
metric, err := v.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Observer), err
|
||||
}
|
||||
|
@ -629,7 +637,7 @@ func (v *SummaryVec) With(labels Labels) Observer {
|
|||
// registered with a given registry (usually the uncurried version). The Reset
|
||||
// method deletes all metrics, even if called on a curried vector.
|
||||
func (v *SummaryVec) CurryWith(labels Labels) (ObserverVec, error) {
|
||||
vec, err := v.curryWith(labels)
|
||||
vec, err := v.MetricVec.CurryWith(labels)
|
||||
if vec != nil {
|
||||
return &SummaryVec{vec}, err
|
||||
}
|
||||
|
@ -715,7 +723,7 @@ func NewConstSummary(
|
|||
count: count,
|
||||
sum: sum,
|
||||
quantiles: quantiles,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
20
vendor/github.com/prometheus/client_golang/prometheus/value.go
generated
vendored
20
vendor/github.com/prometheus/client_golang/prometheus/value.go
generated
vendored
|
@ -19,8 +19,9 @@ import (
|
|||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
@ -62,7 +63,7 @@ func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *val
|
|||
desc: desc,
|
||||
valType: valueType,
|
||||
function: function,
|
||||
labelPairs: makeLabelPairs(desc, nil),
|
||||
labelPairs: MakeLabelPairs(desc, nil),
|
||||
}
|
||||
result.init(result)
|
||||
return result
|
||||
|
@ -94,7 +95,7 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues
|
|||
desc: desc,
|
||||
valType: valueType,
|
||||
val: value,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -144,7 +145,14 @@ func populateMetric(
|
|||
return nil
|
||||
}
|
||||
|
||||
func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
|
||||
// MakeLabelPairs is a helper function to create protobuf LabelPairs from the
|
||||
// variable and constant labels in the provided Desc. The values for the
|
||||
// variable labels are defined by the labelValues slice, which must be in the
|
||||
// same order as the corresponding variable labels in the Desc.
|
||||
//
|
||||
// This function is only needed for custom Metric implementations. See MetricVec
|
||||
// example.
|
||||
func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
|
||||
totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
|
||||
if totalLen == 0 {
|
||||
// Super fast path.
|
||||
|
@ -175,8 +183,8 @@ const ExemplarMaxRunes = 64
|
|||
func newExemplar(value float64, ts time.Time, l Labels) (*dto.Exemplar, error) {
|
||||
e := &dto.Exemplar{}
|
||||
e.Value = proto.Float64(value)
|
||||
tsProto, err := ptypes.TimestampProto(ts)
|
||||
if err != nil {
|
||||
tsProto := timestamppb.New(ts)
|
||||
if err := tsProto.CheckValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.Timestamp = tsProto
|
||||
|
|
112
vendor/github.com/prometheus/client_golang/prometheus/vec.go
generated
vendored
112
vendor/github.com/prometheus/client_golang/prometheus/vec.go
generated
vendored
|
@ -20,12 +20,20 @@ import (
|
|||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// metricVec is a Collector to bundle metrics of the same name that differ in
|
||||
// their label values. metricVec is not used directly (and therefore
|
||||
// unexported). It is used as a building block for implementations of vectors of
|
||||
// a given metric type, like GaugeVec, CounterVec, SummaryVec, and HistogramVec.
|
||||
// It also handles label currying.
|
||||
type metricVec struct {
|
||||
// MetricVec is a Collector to bundle metrics of the same name that differ in
|
||||
// their label values. MetricVec is not used directly but as a building block
|
||||
// for implementations of vectors of a given metric type, like GaugeVec,
|
||||
// CounterVec, SummaryVec, and HistogramVec. It is exported so that it can be
|
||||
// used for custom Metric implementations.
|
||||
//
|
||||
// To create a FooVec for custom Metric Foo, embed a pointer to MetricVec in
|
||||
// FooVec and initialize it with NewMetricVec. Implement wrappers for
|
||||
// GetMetricWithLabelValues and GetMetricWith that return (Foo, error) rather
|
||||
// than (Metric, error). Similarly, create a wrapper for CurryWith that returns
|
||||
// (*FooVec, error) rather than (*MetricVec, error). It is recommended to also
|
||||
// add the convenience methods WithLabelValues, With, and MustCurryWith, which
|
||||
// panic instead of returning errors. See also the MetricVec example.
|
||||
type MetricVec struct {
|
||||
*metricMap
|
||||
|
||||
curry []curriedLabelValue
|
||||
|
@ -35,9 +43,9 @@ type metricVec struct {
|
|||
hashAddByte func(h uint64, b byte) uint64
|
||||
}
|
||||
|
||||
// newMetricVec returns an initialized metricVec.
|
||||
func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec {
|
||||
return &metricVec{
|
||||
// NewMetricVec returns an initialized metricVec.
|
||||
func NewMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec {
|
||||
return &MetricVec{
|
||||
metricMap: &metricMap{
|
||||
metrics: map[uint64][]metricWithLabelValues{},
|
||||
desc: desc,
|
||||
|
@ -63,7 +71,7 @@ func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec {
|
|||
// latter has a much more readable (albeit more verbose) syntax, but it comes
|
||||
// with a performance overhead (for creating and processing the Labels map).
|
||||
// See also the CounterVec example.
|
||||
func (m *metricVec) DeleteLabelValues(lvs ...string) bool {
|
||||
func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
|
||||
h, err := m.hashLabelValues(lvs)
|
||||
if err != nil {
|
||||
return false
|
||||
|
@ -82,7 +90,7 @@ func (m *metricVec) DeleteLabelValues(lvs ...string) bool {
|
|||
//
|
||||
// This method is used for the same purpose as DeleteLabelValues(...string). See
|
||||
// there for pros and cons of the two methods.
|
||||
func (m *metricVec) Delete(labels Labels) bool {
|
||||
func (m *MetricVec) Delete(labels Labels) bool {
|
||||
h, err := m.hashLabels(labels)
|
||||
if err != nil {
|
||||
return false
|
||||
|
@ -95,15 +103,32 @@ func (m *metricVec) Delete(labels Labels) bool {
|
|||
// show up in GoDoc.
|
||||
|
||||
// Describe implements Collector.
|
||||
func (m *metricVec) Describe(ch chan<- *Desc) { m.metricMap.Describe(ch) }
|
||||
func (m *MetricVec) Describe(ch chan<- *Desc) { m.metricMap.Describe(ch) }
|
||||
|
||||
// Collect implements Collector.
|
||||
func (m *metricVec) Collect(ch chan<- Metric) { m.metricMap.Collect(ch) }
|
||||
func (m *MetricVec) Collect(ch chan<- Metric) { m.metricMap.Collect(ch) }
|
||||
|
||||
// Reset deletes all metrics in this vector.
|
||||
func (m *metricVec) Reset() { m.metricMap.Reset() }
|
||||
func (m *MetricVec) Reset() { m.metricMap.Reset() }
|
||||
|
||||
func (m *metricVec) curryWith(labels Labels) (*metricVec, error) {
|
||||
// CurryWith returns a vector curried with the provided labels, i.e. the
|
||||
// returned vector has those labels pre-set for all labeled operations performed
|
||||
// on it. The cardinality of the curried vector is reduced accordingly. The
|
||||
// order of the remaining labels stays the same (just with the curried labels
|
||||
// taken out of the sequence – which is relevant for the
|
||||
// (GetMetric)WithLabelValues methods). It is possible to curry a curried
|
||||
// vector, but only with labels not yet used for currying before.
|
||||
//
|
||||
// The metrics contained in the MetricVec are shared between the curried and
|
||||
// uncurried vectors. They are just accessed differently. Curried and uncurried
|
||||
// vectors behave identically in terms of collection. Only one must be
|
||||
// registered with a given registry (usually the uncurried version). The Reset
|
||||
// method deletes all metrics, even if called on a curried vector.
|
||||
//
|
||||
// Note that CurryWith is usually not called directly but through a wrapper
|
||||
// around MetricVec, implementing a vector for a specific Metric
|
||||
// implementation, for example GaugeVec.
|
||||
func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) {
|
||||
var (
|
||||
newCurry []curriedLabelValue
|
||||
oldCurry = m.curry
|
||||
|
@ -128,7 +153,7 @@ func (m *metricVec) curryWith(labels Labels) (*metricVec, error) {
|
|||
return nil, fmt.Errorf("%d unknown label(s) found during currying", l)
|
||||
}
|
||||
|
||||
return &metricVec{
|
||||
return &MetricVec{
|
||||
metricMap: m.metricMap,
|
||||
curry: newCurry,
|
||||
hashAdd: m.hashAdd,
|
||||
|
@ -136,7 +161,34 @@ func (m *metricVec) curryWith(labels Labels) (*metricVec, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) {
|
||||
// GetMetricWithLabelValues returns the Metric for the given slice of label
|
||||
// values (same order as the variable labels in Desc). If that combination of
|
||||
// label values is accessed for the first time, a new Metric is created (by
|
||||
// calling the newMetric function provided during construction of the
|
||||
// MetricVec).
|
||||
//
|
||||
// It is possible to call this method without using the returned Metric to only
|
||||
// create the new Metric but leave it in its initial state.
|
||||
//
|
||||
// Keeping the Metric for later use is possible (and should be considered if
|
||||
// performance is critical), but keep in mind that Reset, DeleteLabelValues and
|
||||
// Delete can be used to delete the Metric from the MetricVec. In that case, the
|
||||
// Metric will still exist, but it will not be exported anymore, even if a
|
||||
// Metric with the same label values is created later.
|
||||
//
|
||||
// An error is returned if the number of label values is not the same as the
|
||||
// number of variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// Note that for more than one label value, this method is prone to mistakes
|
||||
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
|
||||
// an alternative to avoid that type of mistake. For higher label numbers, the
|
||||
// latter has a much more readable (albeit more verbose) syntax, but it comes
|
||||
// with a performance overhead (for creating and processing the Labels map).
|
||||
//
|
||||
// Note that GetMetricWithLabelValues is usually not called directly but through
|
||||
// a wrapper around MetricVec, implementing a vector for a specific Metric
|
||||
// implementation, for example GaugeVec.
|
||||
func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
|
||||
h, err := m.hashLabelValues(lvs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -145,7 +197,23 @@ func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) {
|
|||
return m.metricMap.getOrCreateMetricWithLabelValues(h, lvs, m.curry), nil
|
||||
}
|
||||
|
||||
func (m *metricVec) getMetricWith(labels Labels) (Metric, error) {
|
||||
// GetMetricWith returns the Metric for the given Labels map (the label names
|
||||
// must match those of the variable labels in Desc). If that label map is
|
||||
// accessed for the first time, a new Metric is created. Implications of
|
||||
// creating a Metric without using it and keeping the Metric for later use
|
||||
// are the same as for GetMetricWithLabelValues.
|
||||
//
|
||||
// An error is returned if the number and names of the Labels are inconsistent
|
||||
// with those of the variable labels in Desc (minus any curried labels).
|
||||
//
|
||||
// This method is used for the same purpose as
|
||||
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
|
||||
// methods.
|
||||
//
|
||||
// Note that GetMetricWith is usually not called directly but through a wrapper
|
||||
// around MetricVec, implementing a vector for a specific Metric implementation,
|
||||
// for example GaugeVec.
|
||||
func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
|
||||
h, err := m.hashLabels(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -154,7 +222,7 @@ func (m *metricVec) getMetricWith(labels Labels) (Metric, error) {
|
|||
return m.metricMap.getOrCreateMetricWithLabels(h, labels, m.curry), nil
|
||||
}
|
||||
|
||||
func (m *metricVec) hashLabelValues(vals []string) (uint64, error) {
|
||||
func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
|
||||
if err := validateLabelValues(vals, len(m.desc.variableLabels)-len(m.curry)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -177,7 +245,7 @@ func (m *metricVec) hashLabelValues(vals []string) (uint64, error) {
|
|||
return h, nil
|
||||
}
|
||||
|
||||
func (m *metricVec) hashLabels(labels Labels) (uint64, error) {
|
||||
func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
|
||||
if err := validateValuesInLabels(labels, len(m.desc.variableLabels)-len(m.curry)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -276,7 +344,9 @@ func (m *metricMap) deleteByHashWithLabelValues(
|
|||
}
|
||||
|
||||
if len(metrics) > 1 {
|
||||
old := metrics
|
||||
m.metrics[h] = append(metrics[:i], metrics[i+1:]...)
|
||||
old[len(old)-1] = metricWithLabelValues{}
|
||||
} else {
|
||||
delete(m.metrics, h)
|
||||
}
|
||||
|
@ -302,7 +372,9 @@ func (m *metricMap) deleteByHashWithLabels(
|
|||
}
|
||||
|
||||
if len(metrics) > 1 {
|
||||
old := metrics
|
||||
m.metrics[h] = append(metrics[:i], metrics[i+1:]...)
|
||||
old[len(old)-1] = metricWithLabelValues{}
|
||||
} else {
|
||||
delete(m.metrics, h)
|
||||
}
|
||||
|
|
18
vendor/github.com/prometheus/client_golang/prometheus/wrap.go
generated
vendored
18
vendor/github.com/prometheus/client_golang/prometheus/wrap.go
generated
vendored
|
@ -17,6 +17,7 @@ import (
|
|||
"fmt"
|
||||
"sort"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
@ -27,10 +28,13 @@ import (
|
|||
// registered with the wrapped Registerer in a modified way. The modified
|
||||
// Collector adds the provided Labels to all Metrics it collects (as
|
||||
// ConstLabels). The Metrics collected by the unmodified Collector must not
|
||||
// duplicate any of those labels.
|
||||
// duplicate any of those labels. Wrapping a nil value is valid, resulting
|
||||
// in a no-op Registerer.
|
||||
//
|
||||
// WrapRegistererWith provides a way to add fixed labels to a subset of
|
||||
// Collectors. It should not be used to add fixed labels to all metrics exposed.
|
||||
// Collectors. It should not be used to add fixed labels to all metrics
|
||||
// exposed. See also
|
||||
// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
|
||||
//
|
||||
// Conflicts between Collectors registered through the original Registerer with
|
||||
// Collectors registered through the wrapping Registerer will still be
|
||||
|
@ -50,6 +54,7 @@ func WrapRegistererWith(labels Labels, reg Registerer) Registerer {
|
|||
// Registerer. Collectors registered with the returned Registerer will be
|
||||
// registered with the wrapped Registerer in a modified way. The modified
|
||||
// Collector adds the provided prefix to the name of all Metrics it collects.
|
||||
// Wrapping a nil value is valid, resulting in a no-op Registerer.
|
||||
//
|
||||
// WrapRegistererWithPrefix is useful to have one place to prefix all metrics of
|
||||
// a sub-system. To make this work, register metrics of the sub-system with the
|
||||
|
@ -80,6 +85,9 @@ type wrappingRegisterer struct {
|
|||
}
|
||||
|
||||
func (r *wrappingRegisterer) Register(c Collector) error {
|
||||
if r.wrappedRegisterer == nil {
|
||||
return nil
|
||||
}
|
||||
return r.wrappedRegisterer.Register(&wrappingCollector{
|
||||
wrappedCollector: c,
|
||||
prefix: r.prefix,
|
||||
|
@ -88,6 +96,9 @@ func (r *wrappingRegisterer) Register(c Collector) error {
|
|||
}
|
||||
|
||||
func (r *wrappingRegisterer) MustRegister(cs ...Collector) {
|
||||
if r.wrappedRegisterer == nil {
|
||||
return
|
||||
}
|
||||
for _, c := range cs {
|
||||
if err := r.Register(c); err != nil {
|
||||
panic(err)
|
||||
|
@ -96,6 +107,9 @@ func (r *wrappingRegisterer) MustRegister(cs ...Collector) {
|
|||
}
|
||||
|
||||
func (r *wrappingRegisterer) Unregister(c Collector) bool {
|
||||
if r.wrappedRegisterer == nil {
|
||||
return false
|
||||
}
|
||||
return r.wrappedRegisterer.Unregister(&wrappingCollector{
|
||||
wrappedCollector: c,
|
||||
prefix: r.prefix,
|
||||
|
|
3
vendor/github.com/prometheus/procfs/CODE_OF_CONDUCT.md
generated
vendored
Normal file
3
vendor/github.com/prometheus/procfs/CODE_OF_CONDUCT.md
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
## Prometheus Community Code of Conduct
|
||||
|
||||
Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
2
vendor/github.com/prometheus/procfs/Makefile
generated
vendored
2
vendor/github.com/prometheus/procfs/Makefile
generated
vendored
|
@ -18,6 +18,8 @@ include Makefile.common
|
|||
./ttar -C $(dir $*) -x -f $*.ttar
|
||||
touch $@
|
||||
|
||||
fixtures: fixtures/.unpacked
|
||||
|
||||
update_fixtures:
|
||||
rm -vf fixtures/.unpacked
|
||||
./ttar -c -f fixtures.ttar fixtures/
|
||||
|
|
28
vendor/github.com/prometheus/procfs/Makefile.common
generated
vendored
28
vendor/github.com/prometheus/procfs/Makefile.common
generated
vendored
|
@ -78,12 +78,12 @@ ifneq ($(shell which gotestsum),)
|
|||
endif
|
||||
endif
|
||||
|
||||
PROMU_VERSION ?= 0.5.0
|
||||
PROMU_VERSION ?= 0.12.0
|
||||
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
|
||||
|
||||
GOLANGCI_LINT :=
|
||||
GOLANGCI_LINT_OPTS ?=
|
||||
GOLANGCI_LINT_VERSION ?= v1.18.0
|
||||
GOLANGCI_LINT_VERSION ?= v1.39.0
|
||||
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
|
||||
# windows isn't included here because of the path separator being different.
|
||||
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
|
||||
|
@ -118,7 +118,7 @@ endif
|
|||
%: common-% ;
|
||||
|
||||
.PHONY: common-all
|
||||
common-all: precheck style check_license lint unused build test
|
||||
common-all: precheck style check_license lint yamllint unused build test
|
||||
|
||||
.PHONY: common-style
|
||||
common-style:
|
||||
|
@ -150,6 +150,17 @@ else
|
|||
$(GO) get $(GOOPTS) -t ./...
|
||||
endif
|
||||
|
||||
.PHONY: update-go-deps
|
||||
update-go-deps:
|
||||
@echo ">> updating Go dependencies"
|
||||
@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
|
||||
$(GO) get $$m; \
|
||||
done
|
||||
GO111MODULE=$(GO111MODULE) $(GO) mod tidy
|
||||
ifneq (,$(wildcard vendor))
|
||||
GO111MODULE=$(GO111MODULE) $(GO) mod vendor
|
||||
endif
|
||||
|
||||
.PHONY: common-test-short
|
||||
common-test-short: $(GOTEST_DIR)
|
||||
@echo ">> running short tests"
|
||||
|
@ -187,6 +198,15 @@ else
|
|||
endif
|
||||
endif
|
||||
|
||||
.PHONY: common-yamllint
|
||||
common-yamllint:
|
||||
@echo ">> running yamllint on all YAML files in the repository"
|
||||
ifeq (, $(shell which yamllint))
|
||||
@echo "yamllint not installed so skipping"
|
||||
else
|
||||
yamllint .
|
||||
endif
|
||||
|
||||
# For backward-compatibility.
|
||||
.PHONY: common-staticcheck
|
||||
common-staticcheck: lint
|
||||
|
@ -234,10 +254,12 @@ common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
|
|||
$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
|
||||
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
|
||||
|
||||
DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION)))
|
||||
.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
|
||||
common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
|
||||
$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
|
||||
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
|
||||
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"
|
||||
|
||||
.PHONY: common-docker-manifest
|
||||
common-docker-manifest:
|
||||
|
|
4
vendor/github.com/prometheus/procfs/README.md
generated
vendored
4
vendor/github.com/prometheus/procfs/README.md
generated
vendored
|
@ -6,8 +6,8 @@ metrics from the pseudo-filesystems /proc and /sys.
|
|||
*WARNING*: This package is a work in progress. Its API may still break in
|
||||
backwards-incompatible ways without warnings. Use it at your own risk.
|
||||
|
||||
[](https://godoc.org/github.com/prometheus/procfs)
|
||||
[](https://travis-ci.org/prometheus/procfs)
|
||||
[](https://pkg.go.dev/github.com/prometheus/procfs)
|
||||
[](https://circleci.com/gh/prometheus/procfs/tree/master)
|
||||
[](https://goreportcard.com/report/github.com/prometheus/procfs)
|
||||
|
||||
## Usage
|
||||
|
|
6
vendor/github.com/prometheus/procfs/SECURITY.md
generated
vendored
Normal file
6
vendor/github.com/prometheus/procfs/SECURITY.md
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Reporting a security issue
|
||||
|
||||
The Prometheus security policy, including how to report vulnerabilities, can be
|
||||
found here:
|
||||
|
||||
https://prometheus.io/docs/operating/security/
|
4
vendor/github.com/prometheus/procfs/arp.go
generated
vendored
4
vendor/github.com/prometheus/procfs/arp.go
generated
vendored
|
@ -36,7 +36,7 @@ type ARPEntry struct {
|
|||
func (fs FS) GatherARPEntries() ([]ARPEntry, error) {
|
||||
data, err := ioutil.ReadFile(fs.proc.Path("net/arp"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading arp %s: %s", fs.proc.Path("net/arp"), err)
|
||||
return nil, fmt.Errorf("error reading arp %q: %w", fs.proc.Path("net/arp"), err)
|
||||
}
|
||||
|
||||
return parseARPEntries(data)
|
||||
|
@ -59,7 +59,7 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) {
|
|||
} else if width == expectedDataWidth {
|
||||
entry, err := parseARPEntry(columns)
|
||||
if err != nil {
|
||||
return []ARPEntry{}, fmt.Errorf("failed to parse ARP entry: %s", err)
|
||||
return []ARPEntry{}, fmt.Errorf("failed to parse ARP entry: %w", err)
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
} else {
|
||||
|
|
2
vendor/github.com/prometheus/procfs/buddyinfo.go
generated
vendored
2
vendor/github.com/prometheus/procfs/buddyinfo.go
generated
vendored
|
@ -74,7 +74,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
|
|||
for i := 0; i < arraySize; i++ {
|
||||
sizes[i], err = strconv.ParseFloat(parts[i+4], 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid value in buddyinfo: %s", err)
|
||||
return nil, fmt.Errorf("invalid value in buddyinfo: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2019 The Prometheus Authors
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// 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
|
||||
|
@ -11,19 +11,20 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build go1.12
|
||||
package procfs
|
||||
|
||||
package prometheus
|
||||
import (
|
||||
"strings"
|
||||
|
||||
import "runtime/debug"
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
)
|
||||
|
||||
// readBuildInfo is a wrapper around debug.ReadBuildInfo for Go 1.12+.
|
||||
func readBuildInfo() (path, version, sum string) {
|
||||
path, version, sum = "unknown", "unknown", "unknown"
|
||||
if bi, ok := debug.ReadBuildInfo(); ok {
|
||||
path = bi.Main.Path
|
||||
version = bi.Main.Version
|
||||
sum = bi.Main.Sum
|
||||
// CmdLine returns the command line of the kernel.
|
||||
func (fs FS) CmdLine() ([]string, error) {
|
||||
data, err := util.ReadFileNoStat(fs.proc.Path("cmdline"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
|
||||
return strings.Fields(string(data)), nil
|
||||
}
|
326
vendor/github.com/prometheus/procfs/cpuinfo.go
generated
vendored
326
vendor/github.com/prometheus/procfs/cpuinfo.go
generated
vendored
|
@ -11,11 +11,16 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build linux
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -52,6 +57,11 @@ type CPUInfo struct {
|
|||
PowerManagement string
|
||||
}
|
||||
|
||||
var (
|
||||
cpuinfoClockRegexp = regexp.MustCompile(`([\d.]+)`)
|
||||
cpuinfoS390XProcessorRegexp = regexp.MustCompile(`^processor\s+(\d+):.*`)
|
||||
)
|
||||
|
||||
// CPUInfo returns information about current system CPUs.
|
||||
// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
|
||||
func (fs FS) CPUInfo() ([]CPUInfo, error) {
|
||||
|
@ -62,14 +72,26 @@ func (fs FS) CPUInfo() ([]CPUInfo, error) {
|
|||
return parseCPUInfo(data)
|
||||
}
|
||||
|
||||
// parseCPUInfo parses data from /proc/cpuinfo
|
||||
func parseCPUInfo(info []byte) ([]CPUInfo, error) {
|
||||
cpuinfo := []CPUInfo{}
|
||||
i := -1
|
||||
func parseCPUInfoX86(info []byte) ([]CPUInfo, error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(info))
|
||||
|
||||
// find the first "processor" line
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
firstcpu := CPUInfo{Processor: uint(v)}
|
||||
cpuinfo := []CPUInfo{firstcpu}
|
||||
i := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.TrimSpace(line) == "" {
|
||||
if !strings.Contains(line, ":") {
|
||||
continue
|
||||
}
|
||||
field := strings.SplitN(line, ": ", 2)
|
||||
|
@ -82,7 +104,7 @@ func parseCPUInfo(info []byte) ([]CPUInfo, error) {
|
|||
return nil, err
|
||||
}
|
||||
cpuinfo[i].Processor = uint(v)
|
||||
case "vendor_id":
|
||||
case "vendor", "vendor_id":
|
||||
cpuinfo[i].VendorID = field[1]
|
||||
case "cpu family":
|
||||
cpuinfo[i].CPUFamily = field[1]
|
||||
|
@ -163,5 +185,297 @@ func parseCPUInfo(info []byte) ([]CPUInfo, error) {
|
|||
}
|
||||
}
|
||||
return cpuinfo, nil
|
||||
}
|
||||
|
||||
func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(info))
|
||||
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
match, _ := regexp.MatchString("^[Pp]rocessor", firstLine)
|
||||
if !match || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
cpuinfo := []CPUInfo{}
|
||||
featuresLine := ""
|
||||
commonCPUInfo := CPUInfo{}
|
||||
i := 0
|
||||
if strings.TrimSpace(field[0]) == "Processor" {
|
||||
commonCPUInfo = CPUInfo{ModelName: field[1]}
|
||||
i = -1
|
||||
} else {
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
firstcpu := CPUInfo{Processor: uint(v)}
|
||||
cpuinfo = []CPUInfo{firstcpu}
|
||||
}
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.Contains(line, ":") {
|
||||
continue
|
||||
}
|
||||
field := strings.SplitN(line, ": ", 2)
|
||||
switch strings.TrimSpace(field[0]) {
|
||||
case "processor":
|
||||
cpuinfo = append(cpuinfo, commonCPUInfo) // start of the next processor
|
||||
i++
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuinfo[i].Processor = uint(v)
|
||||
case "BogoMIPS":
|
||||
if i == -1 {
|
||||
cpuinfo = append(cpuinfo, commonCPUInfo) // There is only one processor
|
||||
i++
|
||||
cpuinfo[i].Processor = 0
|
||||
}
|
||||
v, err := strconv.ParseFloat(field[1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuinfo[i].BogoMips = v
|
||||
case "Features":
|
||||
featuresLine = line
|
||||
case "model name":
|
||||
cpuinfo[i].ModelName = field[1]
|
||||
}
|
||||
}
|
||||
fields := strings.SplitN(featuresLine, ": ", 2)
|
||||
for i := range cpuinfo {
|
||||
cpuinfo[i].Flags = strings.Fields(fields[1])
|
||||
}
|
||||
return cpuinfo, nil
|
||||
|
||||
}
|
||||
|
||||
func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(info))
|
||||
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "vendor_id") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
cpuinfo := []CPUInfo{}
|
||||
commonCPUInfo := CPUInfo{VendorID: field[1]}
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.Contains(line, ":") {
|
||||
continue
|
||||
}
|
||||
field := strings.SplitN(line, ": ", 2)
|
||||
switch strings.TrimSpace(field[0]) {
|
||||
case "bogomips per cpu":
|
||||
v, err := strconv.ParseFloat(field[1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commonCPUInfo.BogoMips = v
|
||||
case "features":
|
||||
commonCPUInfo.Flags = strings.Fields(field[1])
|
||||
}
|
||||
if strings.HasPrefix(line, "processor") {
|
||||
match := cpuinfoS390XProcessorRegexp.FindStringSubmatch(line)
|
||||
if len(match) < 2 {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
}
|
||||
cpu := commonCPUInfo
|
||||
v, err := strconv.ParseUint(match[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpu.Processor = uint(v)
|
||||
cpuinfo = append(cpuinfo, cpu)
|
||||
}
|
||||
if strings.HasPrefix(line, "cpu number") {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
i := 0
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.Contains(line, ":") {
|
||||
continue
|
||||
}
|
||||
field := strings.SplitN(line, ": ", 2)
|
||||
switch strings.TrimSpace(field[0]) {
|
||||
case "cpu number":
|
||||
i++
|
||||
case "cpu MHz dynamic":
|
||||
clock := cpuinfoClockRegexp.FindString(strings.TrimSpace(field[1]))
|
||||
v, err := strconv.ParseFloat(clock, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuinfo[i].CPUMHz = v
|
||||
case "physical id":
|
||||
cpuinfo[i].PhysicalID = field[1]
|
||||
case "core id":
|
||||
cpuinfo[i].CoreID = field[1]
|
||||
case "cpu cores":
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuinfo[i].CPUCores = uint(v)
|
||||
case "siblings":
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuinfo[i].Siblings = uint(v)
|
||||
}
|
||||
}
|
||||
|
||||
return cpuinfo, nil
|
||||
}
|
||||
|
||||
func parseCPUInfoMips(info []byte) ([]CPUInfo, error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(info))
|
||||
|
||||
// find the first "processor" line
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "system type") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
cpuinfo := []CPUInfo{}
|
||||
systemType := field[1]
|
||||
|
||||
i := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.Contains(line, ":") {
|
||||
continue
|
||||
}
|
||||
field := strings.SplitN(line, ": ", 2)
|
||||
switch strings.TrimSpace(field[0]) {
|
||||
case "processor":
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i = int(v)
|
||||
cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
|
||||
cpuinfo[i].Processor = uint(v)
|
||||
cpuinfo[i].VendorID = systemType
|
||||
case "cpu model":
|
||||
cpuinfo[i].ModelName = field[1]
|
||||
case "BogoMIPS":
|
||||
v, err := strconv.ParseFloat(field[1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuinfo[i].BogoMips = v
|
||||
}
|
||||
}
|
||||
return cpuinfo, nil
|
||||
}
|
||||
|
||||
func parseCPUInfoPPC(info []byte) ([]CPUInfo, error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(info))
|
||||
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
firstcpu := CPUInfo{Processor: uint(v)}
|
||||
cpuinfo := []CPUInfo{firstcpu}
|
||||
i := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.Contains(line, ":") {
|
||||
continue
|
||||
}
|
||||
field := strings.SplitN(line, ": ", 2)
|
||||
switch strings.TrimSpace(field[0]) {
|
||||
case "processor":
|
||||
cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
|
||||
i++
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuinfo[i].Processor = uint(v)
|
||||
case "cpu":
|
||||
cpuinfo[i].VendorID = field[1]
|
||||
case "clock":
|
||||
clock := cpuinfoClockRegexp.FindString(strings.TrimSpace(field[1]))
|
||||
v, err := strconv.ParseFloat(clock, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuinfo[i].CPUMHz = v
|
||||
}
|
||||
}
|
||||
return cpuinfo, nil
|
||||
}
|
||||
|
||||
func parseCPUInfoRISCV(info []byte) ([]CPUInfo, error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(info))
|
||||
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
firstcpu := CPUInfo{Processor: uint(v)}
|
||||
cpuinfo := []CPUInfo{firstcpu}
|
||||
i := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.Contains(line, ":") {
|
||||
continue
|
||||
}
|
||||
field := strings.SplitN(line, ": ", 2)
|
||||
switch strings.TrimSpace(field[0]) {
|
||||
case "processor":
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i = int(v)
|
||||
cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
|
||||
cpuinfo[i].Processor = uint(v)
|
||||
case "hart":
|
||||
cpuinfo[i].CoreID = field[1]
|
||||
case "isa":
|
||||
cpuinfo[i].ModelName = field[1]
|
||||
}
|
||||
}
|
||||
return cpuinfo, nil
|
||||
}
|
||||
|
||||
func parseCPUInfoDummy(_ []byte) ([]CPUInfo, error) { // nolint:unused,deadcode
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
// firstNonEmptyLine advances the scanner to the first non-empty line
|
||||
// and returns the contents of that line
|
||||
func firstNonEmptyLine(scanner *bufio.Scanner) string {
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.TrimSpace(line) != "" {
|
||||
return line
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2019 The Prometheus Authors
|
||||
// Copyright 2020 The Prometheus Authors
|
||||
// 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
|
||||
|
@ -11,12 +11,9 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !go1.12
|
||||
// +build linux
|
||||
// +build arm arm64
|
||||
|
||||
package prometheus
|
||||
package procfs
|
||||
|
||||
// readBuildInfo is a wrapper around debug.ReadBuildInfo for Go versions before
|
||||
// 1.12. Remove this whole file once the minimum supported Go version is 1.12.
|
||||
func readBuildInfo() (path, version, sum string) {
|
||||
return "unknown", "unknown", "unknown"
|
||||
}
|
||||
var parseCPUInfo = parseCPUInfoARM
|
19
vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go
generated
vendored
Normal file
19
vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build linux
|
||||
// +build mips mipsle mips64 mips64le
|
||||
|
||||
package procfs
|
||||
|
||||
var parseCPUInfo = parseCPUInfoMips
|
19
vendor/github.com/prometheus/procfs/cpuinfo_others.go
generated
vendored
Normal file
19
vendor/github.com/prometheus/procfs/cpuinfo_others.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build linux
|
||||
// +build !386,!amd64,!arm,!arm64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!riscv64,!s390x
|
||||
|
||||
package procfs
|
||||
|
||||
var parseCPUInfo = parseCPUInfoDummy
|
19
vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go
generated
vendored
Normal file
19
vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build linux
|
||||
// +build ppc64 ppc64le
|
||||
|
||||
package procfs
|
||||
|
||||
var parseCPUInfo = parseCPUInfoPPC
|
19
vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go
generated
vendored
Normal file
19
vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build linux
|
||||
// +build riscv riscv64
|
||||
|
||||
package procfs
|
||||
|
||||
var parseCPUInfo = parseCPUInfoRISCV
|
18
vendor/github.com/prometheus/procfs/cpuinfo_s390x.go
generated
vendored
Normal file
18
vendor/github.com/prometheus/procfs/cpuinfo_s390x.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build linux
|
||||
|
||||
package procfs
|
||||
|
||||
var parseCPUInfo = parseCPUInfoS390X
|
19
vendor/github.com/prometheus/procfs/cpuinfo_x86.go
generated
vendored
Normal file
19
vendor/github.com/prometheus/procfs/cpuinfo_x86.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build linux
|
||||
// +build 386 amd64
|
||||
|
||||
package procfs
|
||||
|
||||
var parseCPUInfo = parseCPUInfoX86
|
4
vendor/github.com/prometheus/procfs/crypto.go
generated
vendored
4
vendor/github.com/prometheus/procfs/crypto.go
generated
vendored
|
@ -55,12 +55,12 @@ func (fs FS) Crypto() ([]Crypto, error) {
|
|||
path := fs.proc.Path("crypto")
|
||||
b, err := util.ReadFileNoStat(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading crypto %s: %s", path, err)
|
||||
return nil, fmt.Errorf("error reading crypto %q: %w", path, err)
|
||||
}
|
||||
|
||||
crypto, err := parseCrypto(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing crypto %s: %s", path, err)
|
||||
return nil, fmt.Errorf("error parsing crypto %q: %w", path, err)
|
||||
}
|
||||
|
||||
return crypto, nil
|
||||
|
|
2
vendor/github.com/prometheus/procfs/doc.go
generated
vendored
2
vendor/github.com/prometheus/procfs/doc.go
generated
vendored
|
@ -31,7 +31,7 @@
|
|||
// log.Fatalf("could not get process: %s", err)
|
||||
// }
|
||||
//
|
||||
// stat, err := p.NewStat()
|
||||
// stat, err := p.Stat()
|
||||
// if err != nil {
|
||||
// log.Fatalf("could not get process stat: %s", err)
|
||||
// }
|
||||
|
|
2306
vendor/github.com/prometheus/procfs/fixtures.ttar
generated
vendored
2306
vendor/github.com/prometheus/procfs/fixtures.ttar
generated
vendored
File diff suppressed because it is too large
Load diff
422
vendor/github.com/prometheus/procfs/fscache.go
generated
vendored
Normal file
422
vendor/github.com/prometheus/procfs/fscache.go
generated
vendored
Normal file
|
@ -0,0 +1,422 @@
|
|||
// Copyright 2019 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
)
|
||||
|
||||
// Fscacheinfo represents fscache statistics.
|
||||
type Fscacheinfo struct {
|
||||
// Number of index cookies allocated
|
||||
IndexCookiesAllocated uint64
|
||||
// data storage cookies allocated
|
||||
DataStorageCookiesAllocated uint64
|
||||
// Number of special cookies allocated
|
||||
SpecialCookiesAllocated uint64
|
||||
// Number of objects allocated
|
||||
ObjectsAllocated uint64
|
||||
// Number of object allocation failures
|
||||
ObjectAllocationsFailure uint64
|
||||
// Number of objects that reached the available state
|
||||
ObjectsAvailable uint64
|
||||
// Number of objects that reached the dead state
|
||||
ObjectsDead uint64
|
||||
// Number of objects that didn't have a coherency check
|
||||
ObjectsWithoutCoherencyCheck uint64
|
||||
// Number of objects that passed a coherency check
|
||||
ObjectsWithCoherencyCheck uint64
|
||||
// Number of objects that needed a coherency data update
|
||||
ObjectsNeedCoherencyCheckUpdate uint64
|
||||
// Number of objects that were declared obsolete
|
||||
ObjectsDeclaredObsolete uint64
|
||||
// Number of pages marked as being cached
|
||||
PagesMarkedAsBeingCached uint64
|
||||
// Number of uncache page requests seen
|
||||
UncachePagesRequestSeen uint64
|
||||
// Number of acquire cookie requests seen
|
||||
AcquireCookiesRequestSeen uint64
|
||||
// Number of acq reqs given a NULL parent
|
||||
AcquireRequestsWithNullParent uint64
|
||||
// Number of acq reqs rejected due to no cache available
|
||||
AcquireRequestsRejectedNoCacheAvailable uint64
|
||||
// Number of acq reqs succeeded
|
||||
AcquireRequestsSucceeded uint64
|
||||
// Number of acq reqs rejected due to error
|
||||
AcquireRequestsRejectedDueToError uint64
|
||||
// Number of acq reqs failed on ENOMEM
|
||||
AcquireRequestsFailedDueToEnomem uint64
|
||||
// Number of lookup calls made on cache backends
|
||||
LookupsNumber uint64
|
||||
// Number of negative lookups made
|
||||
LookupsNegative uint64
|
||||
// Number of positive lookups made
|
||||
LookupsPositive uint64
|
||||
// Number of objects created by lookup
|
||||
ObjectsCreatedByLookup uint64
|
||||
// Number of lookups timed out and requeued
|
||||
LookupsTimedOutAndRequed uint64
|
||||
InvalidationsNumber uint64
|
||||
InvalidationsRunning uint64
|
||||
// Number of update cookie requests seen
|
||||
UpdateCookieRequestSeen uint64
|
||||
// Number of upd reqs given a NULL parent
|
||||
UpdateRequestsWithNullParent uint64
|
||||
// Number of upd reqs granted CPU time
|
||||
UpdateRequestsRunning uint64
|
||||
// Number of relinquish cookie requests seen
|
||||
RelinquishCookiesRequestSeen uint64
|
||||
// Number of rlq reqs given a NULL parent
|
||||
RelinquishCookiesWithNullParent uint64
|
||||
// Number of rlq reqs waited on completion of creation
|
||||
RelinquishRequestsWaitingCompleteCreation uint64
|
||||
// Relinqs rtr
|
||||
RelinquishRetries uint64
|
||||
// Number of attribute changed requests seen
|
||||
AttributeChangedRequestsSeen uint64
|
||||
// Number of attr changed requests queued
|
||||
AttributeChangedRequestsQueued uint64
|
||||
// Number of attr changed rejected -ENOBUFS
|
||||
AttributeChangedRejectDueToEnobufs uint64
|
||||
// Number of attr changed failed -ENOMEM
|
||||
AttributeChangedFailedDueToEnomem uint64
|
||||
// Number of attr changed ops given CPU time
|
||||
AttributeChangedOps uint64
|
||||
// Number of allocation requests seen
|
||||
AllocationRequestsSeen uint64
|
||||
// Number of successful alloc reqs
|
||||
AllocationOkRequests uint64
|
||||
// Number of alloc reqs that waited on lookup completion
|
||||
AllocationWaitingOnLookup uint64
|
||||
// Number of alloc reqs rejected -ENOBUFS
|
||||
AllocationsRejectedDueToEnobufs uint64
|
||||
// Number of alloc reqs aborted -ERESTARTSYS
|
||||
AllocationsAbortedDueToErestartsys uint64
|
||||
// Number of alloc reqs submitted
|
||||
AllocationOperationsSubmitted uint64
|
||||
// Number of alloc reqs waited for CPU time
|
||||
AllocationsWaitedForCPU uint64
|
||||
// Number of alloc reqs aborted due to object death
|
||||
AllocationsAbortedDueToObjectDeath uint64
|
||||
// Number of retrieval (read) requests seen
|
||||
RetrievalsReadRequests uint64
|
||||
// Number of successful retr reqs
|
||||
RetrievalsOk uint64
|
||||
// Number of retr reqs that waited on lookup completion
|
||||
RetrievalsWaitingLookupCompletion uint64
|
||||
// Number of retr reqs returned -ENODATA
|
||||
RetrievalsReturnedEnodata uint64
|
||||
// Number of retr reqs rejected -ENOBUFS
|
||||
RetrievalsRejectedDueToEnobufs uint64
|
||||
// Number of retr reqs aborted -ERESTARTSYS
|
||||
RetrievalsAbortedDueToErestartsys uint64
|
||||
// Number of retr reqs failed -ENOMEM
|
||||
RetrievalsFailedDueToEnomem uint64
|
||||
// Number of retr reqs submitted
|
||||
RetrievalsRequests uint64
|
||||
// Number of retr reqs waited for CPU time
|
||||
RetrievalsWaitingCPU uint64
|
||||
// Number of retr reqs aborted due to object death
|
||||
RetrievalsAbortedDueToObjectDeath uint64
|
||||
// Number of storage (write) requests seen
|
||||
StoreWriteRequests uint64
|
||||
// Number of successful store reqs
|
||||
StoreSuccessfulRequests uint64
|
||||
// Number of store reqs on a page already pending storage
|
||||
StoreRequestsOnPendingStorage uint64
|
||||
// Number of store reqs rejected -ENOBUFS
|
||||
StoreRequestsRejectedDueToEnobufs uint64
|
||||
// Number of store reqs failed -ENOMEM
|
||||
StoreRequestsFailedDueToEnomem uint64
|
||||
// Number of store reqs submitted
|
||||
StoreRequestsSubmitted uint64
|
||||
// Number of store reqs granted CPU time
|
||||
StoreRequestsRunning uint64
|
||||
// Number of pages given store req processing time
|
||||
StorePagesWithRequestsProcessing uint64
|
||||
// Number of store reqs deleted from tracking tree
|
||||
StoreRequestsDeleted uint64
|
||||
// Number of store reqs over store limit
|
||||
StoreRequestsOverStoreLimit uint64
|
||||
// Number of release reqs against pages with no pending store
|
||||
ReleaseRequestsAgainstPagesWithNoPendingStorage uint64
|
||||
// Number of release reqs against pages stored by time lock granted
|
||||
ReleaseRequestsAgainstPagesStoredByTimeLockGranted uint64
|
||||
// Number of release reqs ignored due to in-progress store
|
||||
ReleaseRequestsIgnoredDueToInProgressStore uint64
|
||||
// Number of page stores cancelled due to release req
|
||||
PageStoresCancelledByReleaseRequests uint64
|
||||
VmscanWaiting uint64
|
||||
// Number of times async ops added to pending queues
|
||||
OpsPending uint64
|
||||
// Number of times async ops given CPU time
|
||||
OpsRunning uint64
|
||||
// Number of times async ops queued for processing
|
||||
OpsEnqueued uint64
|
||||
// Number of async ops cancelled
|
||||
OpsCancelled uint64
|
||||
// Number of async ops rejected due to object lookup/create failure
|
||||
OpsRejected uint64
|
||||
// Number of async ops initialised
|
||||
OpsInitialised uint64
|
||||
// Number of async ops queued for deferred release
|
||||
OpsDeferred uint64
|
||||
// Number of async ops released (should equal ini=N when idle)
|
||||
OpsReleased uint64
|
||||
// Number of deferred-release async ops garbage collected
|
||||
OpsGarbageCollected uint64
|
||||
// Number of in-progress alloc_object() cache ops
|
||||
CacheopAllocationsinProgress uint64
|
||||
// Number of in-progress lookup_object() cache ops
|
||||
CacheopLookupObjectInProgress uint64
|
||||
// Number of in-progress lookup_complete() cache ops
|
||||
CacheopLookupCompleteInPorgress uint64
|
||||
// Number of in-progress grab_object() cache ops
|
||||
CacheopGrabObjectInProgress uint64
|
||||
CacheopInvalidations uint64
|
||||
// Number of in-progress update_object() cache ops
|
||||
CacheopUpdateObjectInProgress uint64
|
||||
// Number of in-progress drop_object() cache ops
|
||||
CacheopDropObjectInProgress uint64
|
||||
// Number of in-progress put_object() cache ops
|
||||
CacheopPutObjectInProgress uint64
|
||||
// Number of in-progress attr_changed() cache ops
|
||||
CacheopAttributeChangeInProgress uint64
|
||||
// Number of in-progress sync_cache() cache ops
|
||||
CacheopSyncCacheInProgress uint64
|
||||
// Number of in-progress read_or_alloc_page() cache ops
|
||||
CacheopReadOrAllocPageInProgress uint64
|
||||
// Number of in-progress read_or_alloc_pages() cache ops
|
||||
CacheopReadOrAllocPagesInProgress uint64
|
||||
// Number of in-progress allocate_page() cache ops
|
||||
CacheopAllocatePageInProgress uint64
|
||||
// Number of in-progress allocate_pages() cache ops
|
||||
CacheopAllocatePagesInProgress uint64
|
||||
// Number of in-progress write_page() cache ops
|
||||
CacheopWritePagesInProgress uint64
|
||||
// Number of in-progress uncache_page() cache ops
|
||||
CacheopUncachePagesInProgress uint64
|
||||
// Number of in-progress dissociate_pages() cache ops
|
||||
CacheopDissociatePagesInProgress uint64
|
||||
// Number of object lookups/creations rejected due to lack of space
|
||||
CacheevLookupsAndCreationsRejectedLackSpace uint64
|
||||
// Number of stale objects deleted
|
||||
CacheevStaleObjectsDeleted uint64
|
||||
// Number of objects retired when relinquished
|
||||
CacheevRetiredWhenReliquished uint64
|
||||
// Number of objects culled
|
||||
CacheevObjectsCulled uint64
|
||||
}
|
||||
|
||||
// Fscacheinfo returns information about current fscache statistics.
|
||||
// See https://www.kernel.org/doc/Documentation/filesystems/caching/fscache.txt
|
||||
func (fs FS) Fscacheinfo() (Fscacheinfo, error) {
|
||||
b, err := util.ReadFileNoStat(fs.proc.Path("fs/fscache/stats"))
|
||||
if err != nil {
|
||||
return Fscacheinfo{}, err
|
||||
}
|
||||
|
||||
m, err := parseFscacheinfo(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return Fscacheinfo{}, fmt.Errorf("failed to parse Fscacheinfo: %w", err)
|
||||
}
|
||||
|
||||
return *m, nil
|
||||
}
|
||||
|
||||
func setFSCacheFields(fields []string, setFields ...*uint64) error {
|
||||
var err error
|
||||
if len(fields) < len(setFields) {
|
||||
return fmt.Errorf("Insufficient number of fields, expected %v, got %v", len(setFields), len(fields))
|
||||
}
|
||||
|
||||
for i := range setFields {
|
||||
*setFields[i], err = strconv.ParseUint(strings.Split(fields[i], "=")[1], 0, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseFscacheinfo(r io.Reader) (*Fscacheinfo, error) {
|
||||
var m Fscacheinfo
|
||||
s := bufio.NewScanner(r)
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
if len(fields) < 2 {
|
||||
return nil, fmt.Errorf("malformed Fscacheinfo line: %q", s.Text())
|
||||
}
|
||||
|
||||
switch fields[0] {
|
||||
case "Cookies:":
|
||||
err := setFSCacheFields(fields[1:], &m.IndexCookiesAllocated, &m.DataStorageCookiesAllocated,
|
||||
&m.SpecialCookiesAllocated)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Objects:":
|
||||
err := setFSCacheFields(fields[1:], &m.ObjectsAllocated, &m.ObjectAllocationsFailure,
|
||||
&m.ObjectsAvailable, &m.ObjectsDead)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "ChkAux":
|
||||
err := setFSCacheFields(fields[2:], &m.ObjectsWithoutCoherencyCheck, &m.ObjectsWithCoherencyCheck,
|
||||
&m.ObjectsNeedCoherencyCheckUpdate, &m.ObjectsDeclaredObsolete)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Pages":
|
||||
err := setFSCacheFields(fields[2:], &m.PagesMarkedAsBeingCached, &m.UncachePagesRequestSeen)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Acquire:":
|
||||
err := setFSCacheFields(fields[1:], &m.AcquireCookiesRequestSeen, &m.AcquireRequestsWithNullParent,
|
||||
&m.AcquireRequestsRejectedNoCacheAvailable, &m.AcquireRequestsSucceeded, &m.AcquireRequestsRejectedDueToError,
|
||||
&m.AcquireRequestsFailedDueToEnomem)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Lookups:":
|
||||
err := setFSCacheFields(fields[1:], &m.LookupsNumber, &m.LookupsNegative, &m.LookupsPositive,
|
||||
&m.ObjectsCreatedByLookup, &m.LookupsTimedOutAndRequed)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Invals":
|
||||
err := setFSCacheFields(fields[2:], &m.InvalidationsNumber, &m.InvalidationsRunning)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Updates:":
|
||||
err := setFSCacheFields(fields[1:], &m.UpdateCookieRequestSeen, &m.UpdateRequestsWithNullParent,
|
||||
&m.UpdateRequestsRunning)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Relinqs:":
|
||||
err := setFSCacheFields(fields[1:], &m.RelinquishCookiesRequestSeen, &m.RelinquishCookiesWithNullParent,
|
||||
&m.RelinquishRequestsWaitingCompleteCreation, &m.RelinquishRetries)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "AttrChg:":
|
||||
err := setFSCacheFields(fields[1:], &m.AttributeChangedRequestsSeen, &m.AttributeChangedRequestsQueued,
|
||||
&m.AttributeChangedRejectDueToEnobufs, &m.AttributeChangedFailedDueToEnomem, &m.AttributeChangedOps)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Allocs":
|
||||
if strings.Split(fields[2], "=")[0] == "n" {
|
||||
err := setFSCacheFields(fields[2:], &m.AllocationRequestsSeen, &m.AllocationOkRequests,
|
||||
&m.AllocationWaitingOnLookup, &m.AllocationsRejectedDueToEnobufs, &m.AllocationsAbortedDueToErestartsys)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
} else {
|
||||
err := setFSCacheFields(fields[2:], &m.AllocationOperationsSubmitted, &m.AllocationsWaitedForCPU,
|
||||
&m.AllocationsAbortedDueToObjectDeath)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
}
|
||||
case "Retrvls:":
|
||||
if strings.Split(fields[1], "=")[0] == "n" {
|
||||
err := setFSCacheFields(fields[1:], &m.RetrievalsReadRequests, &m.RetrievalsOk, &m.RetrievalsWaitingLookupCompletion,
|
||||
&m.RetrievalsReturnedEnodata, &m.RetrievalsRejectedDueToEnobufs, &m.RetrievalsAbortedDueToErestartsys,
|
||||
&m.RetrievalsFailedDueToEnomem)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
} else {
|
||||
err := setFSCacheFields(fields[1:], &m.RetrievalsRequests, &m.RetrievalsWaitingCPU, &m.RetrievalsAbortedDueToObjectDeath)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
}
|
||||
case "Stores":
|
||||
if strings.Split(fields[2], "=")[0] == "n" {
|
||||
err := setFSCacheFields(fields[2:], &m.StoreWriteRequests, &m.StoreSuccessfulRequests,
|
||||
&m.StoreRequestsOnPendingStorage, &m.StoreRequestsRejectedDueToEnobufs, &m.StoreRequestsFailedDueToEnomem)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
} else {
|
||||
err := setFSCacheFields(fields[2:], &m.StoreRequestsSubmitted, &m.StoreRequestsRunning,
|
||||
&m.StorePagesWithRequestsProcessing, &m.StoreRequestsDeleted, &m.StoreRequestsOverStoreLimit)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
}
|
||||
case "VmScan":
|
||||
err := setFSCacheFields(fields[2:], &m.ReleaseRequestsAgainstPagesWithNoPendingStorage,
|
||||
&m.ReleaseRequestsAgainstPagesStoredByTimeLockGranted, &m.ReleaseRequestsIgnoredDueToInProgressStore,
|
||||
&m.PageStoresCancelledByReleaseRequests, &m.VmscanWaiting)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
case "Ops":
|
||||
if strings.Split(fields[2], "=")[0] == "pend" {
|
||||
err := setFSCacheFields(fields[2:], &m.OpsPending, &m.OpsRunning, &m.OpsEnqueued, &m.OpsCancelled, &m.OpsRejected)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
} else {
|
||||
err := setFSCacheFields(fields[2:], &m.OpsInitialised, &m.OpsDeferred, &m.OpsReleased, &m.OpsGarbageCollected)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
}
|
||||
case "CacheOp:":
|
||||
if strings.Split(fields[1], "=")[0] == "alo" {
|
||||
err := setFSCacheFields(fields[1:], &m.CacheopAllocationsinProgress, &m.CacheopLookupObjectInProgress,
|
||||
&m.CacheopLookupCompleteInPorgress, &m.CacheopGrabObjectInProgress)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
} else if strings.Split(fields[1], "=")[0] == "inv" {
|
||||
err := setFSCacheFields(fields[1:], &m.CacheopInvalidations, &m.CacheopUpdateObjectInProgress,
|
||||
&m.CacheopDropObjectInProgress, &m.CacheopPutObjectInProgress, &m.CacheopAttributeChangeInProgress,
|
||||
&m.CacheopSyncCacheInProgress)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
} else {
|
||||
err := setFSCacheFields(fields[1:], &m.CacheopReadOrAllocPageInProgress, &m.CacheopReadOrAllocPagesInProgress,
|
||||
&m.CacheopAllocatePageInProgress, &m.CacheopAllocatePagesInProgress, &m.CacheopWritePagesInProgress,
|
||||
&m.CacheopUncachePagesInProgress, &m.CacheopDissociatePagesInProgress)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
}
|
||||
case "CacheEv:":
|
||||
err := setFSCacheFields(fields[1:], &m.CacheevLookupsAndCreationsRejectedLackSpace, &m.CacheevStaleObjectsDeleted,
|
||||
&m.CacheevRetiredWhenReliquished, &m.CacheevObjectsCulled)
|
||||
if err != nil {
|
||||
return &m, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
4
vendor/github.com/prometheus/procfs/internal/fs/fs.go
generated
vendored
4
vendor/github.com/prometheus/procfs/internal/fs/fs.go
generated
vendored
|
@ -39,10 +39,10 @@ type FS string
|
|||
func NewFS(mountPoint string) (FS, error) {
|
||||
info, err := os.Stat(mountPoint)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not read %s: %s", mountPoint, err)
|
||||
return "", fmt.Errorf("could not read %q: %w", mountPoint, err)
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return "", fmt.Errorf("mount point %s is not a directory", mountPoint)
|
||||
return "", fmt.Errorf("mount point %q is not a directory", mountPoint)
|
||||
}
|
||||
|
||||
return FS(mountPoint), nil
|
||||
|
|
9
vendor/github.com/prometheus/procfs/internal/util/parse.go
generated
vendored
9
vendor/github.com/prometheus/procfs/internal/util/parse.go
generated
vendored
|
@ -73,6 +73,15 @@ func ReadUintFromFile(path string) (uint64, error) {
|
|||
return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
|
||||
}
|
||||
|
||||
// ReadIntFromFile reads a file and attempts to parse a int64 from it.
|
||||
func ReadIntFromFile(path string) (int64, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64)
|
||||
}
|
||||
|
||||
// ParseBool parses a string into a boolean pointer.
|
||||
func ParseBool(b string) *bool {
|
||||
var truth bool
|
||||
|
|
62
vendor/github.com/prometheus/procfs/kernel_random.go
generated
vendored
Normal file
62
vendor/github.com/prometheus/procfs/kernel_random.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
)
|
||||
|
||||
// KernelRandom contains information about to the kernel's random number generator.
|
||||
type KernelRandom struct {
|
||||
// EntropyAvaliable gives the available entropy, in bits.
|
||||
EntropyAvaliable *uint64
|
||||
// PoolSize gives the size of the entropy pool, in bits.
|
||||
PoolSize *uint64
|
||||
// URandomMinReseedSeconds is the number of seconds after which the DRNG will be reseeded.
|
||||
URandomMinReseedSeconds *uint64
|
||||
// WriteWakeupThreshold the number of bits of entropy below which we wake up processes
|
||||
// that do a select(2) or poll(2) for write access to /dev/random.
|
||||
WriteWakeupThreshold *uint64
|
||||
// ReadWakeupThreshold is the number of bits of entropy required for waking up processes that sleep
|
||||
// waiting for entropy from /dev/random.
|
||||
ReadWakeupThreshold *uint64
|
||||
}
|
||||
|
||||
// KernelRandom returns values from /proc/sys/kernel/random.
|
||||
func (fs FS) KernelRandom() (KernelRandom, error) {
|
||||
random := KernelRandom{}
|
||||
|
||||
for file, p := range map[string]**uint64{
|
||||
"entropy_avail": &random.EntropyAvaliable,
|
||||
"poolsize": &random.PoolSize,
|
||||
"urandom_min_reseed_secs": &random.URandomMinReseedSeconds,
|
||||
"write_wakeup_threshold": &random.WriteWakeupThreshold,
|
||||
"read_wakeup_threshold": &random.ReadWakeupThreshold,
|
||||
} {
|
||||
val, err := util.ReadUintFromFile(fs.proc.Path("sys", "kernel", "random", file))
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return random, err
|
||||
}
|
||||
*p = &val
|
||||
}
|
||||
|
||||
return random, nil
|
||||
}
|
4
vendor/github.com/prometheus/procfs/loadavg.go
generated
vendored
4
vendor/github.com/prometheus/procfs/loadavg.go
generated
vendored
|
@ -44,14 +44,14 @@ func parseLoad(loadavgBytes []byte) (*LoadAvg, error) {
|
|||
loads := make([]float64, 3)
|
||||
parts := strings.Fields(string(loadavgBytes))
|
||||
if len(parts) < 3 {
|
||||
return nil, fmt.Errorf("malformed loadavg line: too few fields in loadavg string: %s", string(loadavgBytes))
|
||||
return nil, fmt.Errorf("malformed loadavg line: too few fields in loadavg string: %q", string(loadavgBytes))
|
||||
}
|
||||
|
||||
var err error
|
||||
for i, load := range parts[0:3] {
|
||||
loads[i], err = strconv.ParseFloat(load, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse load '%s': %s", load, err)
|
||||
return nil, fmt.Errorf("could not parse load %q: %w", load, err)
|
||||
}
|
||||
}
|
||||
return &LoadAvg{
|
||||
|
|
138
vendor/github.com/prometheus/procfs/mdstat.go
generated
vendored
138
vendor/github.com/prometheus/procfs/mdstat.go
generated
vendored
|
@ -22,8 +22,12 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
statusLineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`)
|
||||
recoveryLineRE = regexp.MustCompile(`\((\d+)/\d+\)`)
|
||||
statusLineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[([U_]+)\]`)
|
||||
recoveryLineBlocksRE = regexp.MustCompile(`\((\d+)/\d+\)`)
|
||||
recoveryLinePctRE = regexp.MustCompile(`= (.+)%`)
|
||||
recoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`)
|
||||
recoveryLineSpeedRE = regexp.MustCompile(`speed=(.+)[A-Z]`)
|
||||
componentDeviceRE = regexp.MustCompile(`(.*)\[\d+\]`)
|
||||
)
|
||||
|
||||
// MDStat holds info parsed from /proc/mdstat.
|
||||
|
@ -38,12 +42,22 @@ type MDStat struct {
|
|||
DisksTotal int64
|
||||
// Number of failed disks.
|
||||
DisksFailed int64
|
||||
// Number of "down" disks. (the _ indicator in the status line)
|
||||
DisksDown int64
|
||||
// Spare disks in the device.
|
||||
DisksSpare int64
|
||||
// Number of blocks the device holds.
|
||||
BlocksTotal int64
|
||||
// Number of blocks on the device that are in sync.
|
||||
BlocksSynced int64
|
||||
// progress percentage of current sync
|
||||
BlocksSyncedPct float64
|
||||
// estimated finishing time for current sync (in minutes)
|
||||
BlocksSyncedFinishTime float64
|
||||
// current sync speed (in Kilobytes/sec)
|
||||
BlocksSyncedSpeed float64
|
||||
// Name of md component devices
|
||||
Devices []string
|
||||
}
|
||||
|
||||
// MDStat parses an mdstat-file (/proc/mdstat) and returns a slice of
|
||||
|
@ -52,11 +66,11 @@ type MDStat struct {
|
|||
func (fs FS) MDStat() ([]MDStat, error) {
|
||||
data, err := ioutil.ReadFile(fs.proc.Path("mdstat"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing mdstat %s: %s", fs.proc.Path("mdstat"), err)
|
||||
return nil, err
|
||||
}
|
||||
mdstat, err := parseMDStat(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing mdstat %s: %s", fs.proc.Path("mdstat"), err)
|
||||
return nil, fmt.Errorf("error parsing mdstat %q: %w", fs.proc.Path("mdstat"), err)
|
||||
}
|
||||
return mdstat, nil
|
||||
}
|
||||
|
@ -82,19 +96,16 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
|||
state := deviceFields[2] // active or inactive
|
||||
|
||||
if len(lines) <= i+3 {
|
||||
return nil, fmt.Errorf(
|
||||
"error parsing %s: too few lines for md device",
|
||||
mdName,
|
||||
)
|
||||
return nil, fmt.Errorf("error parsing %q: too few lines for md device", mdName)
|
||||
}
|
||||
|
||||
// Failed disks have the suffix (F) & Spare disks have the suffix (S).
|
||||
fail := int64(strings.Count(line, "(F)"))
|
||||
spare := int64(strings.Count(line, "(S)"))
|
||||
active, total, size, err := evalStatusLine(lines[i], lines[i+1])
|
||||
active, total, down, size, err := evalStatusLine(lines[i], lines[i+1])
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing md device lines: %s", err)
|
||||
return nil, fmt.Errorf("error parsing md device lines: %w", err)
|
||||
}
|
||||
|
||||
syncLineIdx := i + 2
|
||||
|
@ -105,13 +116,19 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
|||
// If device is syncing at the moment, get the number of currently
|
||||
// synced bytes, otherwise that number equals the size of the device.
|
||||
syncedBlocks := size
|
||||
speed := float64(0)
|
||||
finish := float64(0)
|
||||
pct := float64(0)
|
||||
recovering := strings.Contains(lines[syncLineIdx], "recovery")
|
||||
resyncing := strings.Contains(lines[syncLineIdx], "resync")
|
||||
checking := strings.Contains(lines[syncLineIdx], "check")
|
||||
|
||||
// Append recovery and resyncing state info.
|
||||
if recovering || resyncing {
|
||||
if recovering || resyncing || checking {
|
||||
if recovering {
|
||||
state = "recovering"
|
||||
} else if checking {
|
||||
state = "checking"
|
||||
} else {
|
||||
state = "resyncing"
|
||||
}
|
||||
|
@ -121,74 +138,125 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
|||
strings.Contains(lines[syncLineIdx], "DELAYED") {
|
||||
syncedBlocks = 0
|
||||
} else {
|
||||
syncedBlocks, err = evalRecoveryLine(lines[syncLineIdx])
|
||||
syncedBlocks, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing sync line in md device %s: %s", mdName, err)
|
||||
return nil, fmt.Errorf("error parsing sync line in md device %q: %w", mdName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mdStats = append(mdStats, MDStat{
|
||||
Name: mdName,
|
||||
ActivityState: state,
|
||||
DisksActive: active,
|
||||
DisksFailed: fail,
|
||||
DisksSpare: spare,
|
||||
DisksTotal: total,
|
||||
BlocksTotal: size,
|
||||
BlocksSynced: syncedBlocks,
|
||||
Name: mdName,
|
||||
ActivityState: state,
|
||||
DisksActive: active,
|
||||
DisksFailed: fail,
|
||||
DisksDown: down,
|
||||
DisksSpare: spare,
|
||||
DisksTotal: total,
|
||||
BlocksTotal: size,
|
||||
BlocksSynced: syncedBlocks,
|
||||
BlocksSyncedPct: pct,
|
||||
BlocksSyncedFinishTime: finish,
|
||||
BlocksSyncedSpeed: speed,
|
||||
Devices: evalComponentDevices(deviceFields),
|
||||
})
|
||||
}
|
||||
|
||||
return mdStats, nil
|
||||
}
|
||||
|
||||
func evalStatusLine(deviceLine, statusLine string) (active, total, size int64, err error) {
|
||||
func evalStatusLine(deviceLine, statusLine string) (active, total, down, size int64, err error) {
|
||||
|
||||
sizeStr := strings.Fields(statusLine)[0]
|
||||
size, err = strconv.ParseInt(sizeStr, 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
|
||||
return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err)
|
||||
}
|
||||
|
||||
if strings.Contains(deviceLine, "raid0") || strings.Contains(deviceLine, "linear") {
|
||||
// In the device deviceLine, only disks have a number associated with them in [].
|
||||
total = int64(strings.Count(deviceLine, "["))
|
||||
return total, total, size, nil
|
||||
return total, total, 0, size, nil
|
||||
}
|
||||
|
||||
if strings.Contains(deviceLine, "inactive") {
|
||||
return 0, 0, size, nil
|
||||
return 0, 0, 0, size, nil
|
||||
}
|
||||
|
||||
matches := statusLineRE.FindStringSubmatch(statusLine)
|
||||
if len(matches) != 4 {
|
||||
return 0, 0, 0, fmt.Errorf("couldn't find all the substring matches: %s", statusLine)
|
||||
if len(matches) != 5 {
|
||||
return 0, 0, 0, 0, fmt.Errorf("couldn't find all the substring matches: %s", statusLine)
|
||||
}
|
||||
|
||||
total, err = strconv.ParseInt(matches[2], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
|
||||
return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err)
|
||||
}
|
||||
|
||||
active, err = strconv.ParseInt(matches[3], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
|
||||
return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err)
|
||||
}
|
||||
down = int64(strings.Count(matches[4], "_"))
|
||||
|
||||
return active, total, size, nil
|
||||
return active, total, down, size, nil
|
||||
}
|
||||
|
||||
func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, err error) {
|
||||
matches := recoveryLineRE.FindStringSubmatch(recoveryLine)
|
||||
func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, pct float64, finish float64, speed float64, err error) {
|
||||
matches := recoveryLineBlocksRE.FindStringSubmatch(recoveryLine)
|
||||
if len(matches) != 2 {
|
||||
return 0, fmt.Errorf("unexpected recoveryLine: %s", recoveryLine)
|
||||
return 0, 0, 0, 0, fmt.Errorf("unexpected recoveryLine: %s", recoveryLine)
|
||||
}
|
||||
|
||||
syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s in recoveryLine: %s", err, recoveryLine)
|
||||
return 0, 0, 0, 0, fmt.Errorf("error parsing int from recoveryLine %q: %w", recoveryLine, err)
|
||||
}
|
||||
|
||||
return syncedBlocks, nil
|
||||
// Get percentage complete
|
||||
matches = recoveryLinePctRE.FindStringSubmatch(recoveryLine)
|
||||
if len(matches) != 2 {
|
||||
return syncedBlocks, 0, 0, 0, fmt.Errorf("unexpected recoveryLine matching percentage: %s", recoveryLine)
|
||||
}
|
||||
pct, err = strconv.ParseFloat(strings.TrimSpace(matches[1]), 64)
|
||||
if err != nil {
|
||||
return syncedBlocks, 0, 0, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err)
|
||||
}
|
||||
|
||||
// Get time expected left to complete
|
||||
matches = recoveryLineFinishRE.FindStringSubmatch(recoveryLine)
|
||||
if len(matches) != 2 {
|
||||
return syncedBlocks, pct, 0, 0, fmt.Errorf("unexpected recoveryLine matching est. finish time: %s", recoveryLine)
|
||||
}
|
||||
finish, err = strconv.ParseFloat(matches[1], 64)
|
||||
if err != nil {
|
||||
return syncedBlocks, pct, 0, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err)
|
||||
}
|
||||
|
||||
// Get recovery speed
|
||||
matches = recoveryLineSpeedRE.FindStringSubmatch(recoveryLine)
|
||||
if len(matches) != 2 {
|
||||
return syncedBlocks, pct, finish, 0, fmt.Errorf("unexpected recoveryLine matching speed: %s", recoveryLine)
|
||||
}
|
||||
speed, err = strconv.ParseFloat(matches[1], 64)
|
||||
if err != nil {
|
||||
return syncedBlocks, pct, finish, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err)
|
||||
}
|
||||
|
||||
return syncedBlocks, pct, finish, speed, nil
|
||||
}
|
||||
|
||||
func evalComponentDevices(deviceFields []string) []string {
|
||||
mdComponentDevices := make([]string, 0)
|
||||
if len(deviceFields) > 3 {
|
||||
for _, field := range deviceFields[4:] {
|
||||
match := componentDeviceRE.FindStringSubmatch(field)
|
||||
if match == nil {
|
||||
continue
|
||||
}
|
||||
mdComponentDevices = append(mdComponentDevices, match[1])
|
||||
}
|
||||
}
|
||||
|
||||
return mdComponentDevices
|
||||
}
|
||||
|
|
194
vendor/github.com/prometheus/procfs/meminfo.go
generated
vendored
194
vendor/github.com/prometheus/procfs/meminfo.go
generated
vendored
|
@ -28,9 +28,9 @@ import (
|
|||
type Meminfo struct {
|
||||
// Total usable ram (i.e. physical ram minus a few reserved
|
||||
// bits and the kernel binary code)
|
||||
MemTotal uint64
|
||||
MemTotal *uint64
|
||||
// The sum of LowFree+HighFree
|
||||
MemFree uint64
|
||||
MemFree *uint64
|
||||
// An estimate of how much memory is available for starting
|
||||
// new applications, without swapping. Calculated from
|
||||
// MemFree, SReclaimable, the size of the file LRU lists, and
|
||||
|
@ -39,59 +39,59 @@ type Meminfo struct {
|
|||
// well, and that not all reclaimable slab will be
|
||||
// reclaimable, due to items being in use. The impact of those
|
||||
// factors will vary from system to system.
|
||||
MemAvailable uint64
|
||||
MemAvailable *uint64
|
||||
// Relatively temporary storage for raw disk blocks shouldn't
|
||||
// get tremendously large (20MB or so)
|
||||
Buffers uint64
|
||||
Cached uint64
|
||||
Buffers *uint64
|
||||
Cached *uint64
|
||||
// Memory that once was swapped out, is swapped back in but
|
||||
// still also is in the swapfile (if memory is needed it
|
||||
// doesn't need to be swapped out AGAIN because it is already
|
||||
// in the swapfile. This saves I/O)
|
||||
SwapCached uint64
|
||||
SwapCached *uint64
|
||||
// Memory that has been used more recently and usually not
|
||||
// reclaimed unless absolutely necessary.
|
||||
Active uint64
|
||||
Active *uint64
|
||||
// Memory which has been less recently used. It is more
|
||||
// eligible to be reclaimed for other purposes
|
||||
Inactive uint64
|
||||
ActiveAnon uint64
|
||||
InactiveAnon uint64
|
||||
ActiveFile uint64
|
||||
InactiveFile uint64
|
||||
Unevictable uint64
|
||||
Mlocked uint64
|
||||
Inactive *uint64
|
||||
ActiveAnon *uint64
|
||||
InactiveAnon *uint64
|
||||
ActiveFile *uint64
|
||||
InactiveFile *uint64
|
||||
Unevictable *uint64
|
||||
Mlocked *uint64
|
||||
// total amount of swap space available
|
||||
SwapTotal uint64
|
||||
SwapTotal *uint64
|
||||
// Memory which has been evicted from RAM, and is temporarily
|
||||
// on the disk
|
||||
SwapFree uint64
|
||||
SwapFree *uint64
|
||||
// Memory which is waiting to get written back to the disk
|
||||
Dirty uint64
|
||||
Dirty *uint64
|
||||
// Memory which is actively being written back to the disk
|
||||
Writeback uint64
|
||||
Writeback *uint64
|
||||
// Non-file backed pages mapped into userspace page tables
|
||||
AnonPages uint64
|
||||
AnonPages *uint64
|
||||
// files which have been mapped, such as libraries
|
||||
Mapped uint64
|
||||
Shmem uint64
|
||||
Mapped *uint64
|
||||
Shmem *uint64
|
||||
// in-kernel data structures cache
|
||||
Slab uint64
|
||||
Slab *uint64
|
||||
// Part of Slab, that might be reclaimed, such as caches
|
||||
SReclaimable uint64
|
||||
SReclaimable *uint64
|
||||
// Part of Slab, that cannot be reclaimed on memory pressure
|
||||
SUnreclaim uint64
|
||||
KernelStack uint64
|
||||
SUnreclaim *uint64
|
||||
KernelStack *uint64
|
||||
// amount of memory dedicated to the lowest level of page
|
||||
// tables.
|
||||
PageTables uint64
|
||||
PageTables *uint64
|
||||
// NFS pages sent to the server, but not yet committed to
|
||||
// stable storage
|
||||
NFSUnstable uint64
|
||||
NFSUnstable *uint64
|
||||
// Memory used for block device "bounce buffers"
|
||||
Bounce uint64
|
||||
Bounce *uint64
|
||||
// Memory used by FUSE for temporary writeback buffers
|
||||
WritebackTmp uint64
|
||||
WritebackTmp *uint64
|
||||
// Based on the overcommit ratio ('vm.overcommit_ratio'),
|
||||
// this is the total amount of memory currently available to
|
||||
// be allocated on the system. This limit is only adhered to
|
||||
|
@ -105,7 +105,7 @@ type Meminfo struct {
|
|||
// yield a CommitLimit of 7.3G.
|
||||
// For more details, see the memory overcommit documentation
|
||||
// in vm/overcommit-accounting.
|
||||
CommitLimit uint64
|
||||
CommitLimit *uint64
|
||||
// The amount of memory presently allocated on the system.
|
||||
// The committed memory is a sum of all of the memory which
|
||||
// has been allocated by processes, even if it has not been
|
||||
|
@ -119,27 +119,27 @@ type Meminfo struct {
|
|||
// This is useful if one needs to guarantee that processes will
|
||||
// not fail due to lack of memory once that memory has been
|
||||
// successfully allocated.
|
||||
CommittedAS uint64
|
||||
CommittedAS *uint64
|
||||
// total size of vmalloc memory area
|
||||
VmallocTotal uint64
|
||||
VmallocTotal *uint64
|
||||
// amount of vmalloc area which is used
|
||||
VmallocUsed uint64
|
||||
VmallocUsed *uint64
|
||||
// largest contiguous block of vmalloc area which is free
|
||||
VmallocChunk uint64
|
||||
HardwareCorrupted uint64
|
||||
AnonHugePages uint64
|
||||
ShmemHugePages uint64
|
||||
ShmemPmdMapped uint64
|
||||
CmaTotal uint64
|
||||
CmaFree uint64
|
||||
HugePagesTotal uint64
|
||||
HugePagesFree uint64
|
||||
HugePagesRsvd uint64
|
||||
HugePagesSurp uint64
|
||||
Hugepagesize uint64
|
||||
DirectMap4k uint64
|
||||
DirectMap2M uint64
|
||||
DirectMap1G uint64
|
||||
VmallocChunk *uint64
|
||||
HardwareCorrupted *uint64
|
||||
AnonHugePages *uint64
|
||||
ShmemHugePages *uint64
|
||||
ShmemPmdMapped *uint64
|
||||
CmaTotal *uint64
|
||||
CmaFree *uint64
|
||||
HugePagesTotal *uint64
|
||||
HugePagesFree *uint64
|
||||
HugePagesRsvd *uint64
|
||||
HugePagesSurp *uint64
|
||||
Hugepagesize *uint64
|
||||
DirectMap4k *uint64
|
||||
DirectMap2M *uint64
|
||||
DirectMap1G *uint64
|
||||
}
|
||||
|
||||
// Meminfo returns an information about current kernel/system memory statistics.
|
||||
|
@ -152,7 +152,7 @@ func (fs FS) Meminfo() (Meminfo, error) {
|
|||
|
||||
m, err := parseMemInfo(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return Meminfo{}, fmt.Errorf("failed to parse meminfo: %v", err)
|
||||
return Meminfo{}, fmt.Errorf("failed to parse meminfo: %w", err)
|
||||
}
|
||||
|
||||
return *m, nil
|
||||
|
@ -175,101 +175,101 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) {
|
|||
|
||||
switch fields[0] {
|
||||
case "MemTotal:":
|
||||
m.MemTotal = v
|
||||
m.MemTotal = &v
|
||||
case "MemFree:":
|
||||
m.MemFree = v
|
||||
m.MemFree = &v
|
||||
case "MemAvailable:":
|
||||
m.MemAvailable = v
|
||||
m.MemAvailable = &v
|
||||
case "Buffers:":
|
||||
m.Buffers = v
|
||||
m.Buffers = &v
|
||||
case "Cached:":
|
||||
m.Cached = v
|
||||
m.Cached = &v
|
||||
case "SwapCached:":
|
||||
m.SwapCached = v
|
||||
m.SwapCached = &v
|
||||
case "Active:":
|
||||
m.Active = v
|
||||
m.Active = &v
|
||||
case "Inactive:":
|
||||
m.Inactive = v
|
||||
m.Inactive = &v
|
||||
case "Active(anon):":
|
||||
m.ActiveAnon = v
|
||||
m.ActiveAnon = &v
|
||||
case "Inactive(anon):":
|
||||
m.InactiveAnon = v
|
||||
m.InactiveAnon = &v
|
||||
case "Active(file):":
|
||||
m.ActiveFile = v
|
||||
m.ActiveFile = &v
|
||||
case "Inactive(file):":
|
||||
m.InactiveFile = v
|
||||
m.InactiveFile = &v
|
||||
case "Unevictable:":
|
||||
m.Unevictable = v
|
||||
m.Unevictable = &v
|
||||
case "Mlocked:":
|
||||
m.Mlocked = v
|
||||
m.Mlocked = &v
|
||||
case "SwapTotal:":
|
||||
m.SwapTotal = v
|
||||
m.SwapTotal = &v
|
||||
case "SwapFree:":
|
||||
m.SwapFree = v
|
||||
m.SwapFree = &v
|
||||
case "Dirty:":
|
||||
m.Dirty = v
|
||||
m.Dirty = &v
|
||||
case "Writeback:":
|
||||
m.Writeback = v
|
||||
m.Writeback = &v
|
||||
case "AnonPages:":
|
||||
m.AnonPages = v
|
||||
m.AnonPages = &v
|
||||
case "Mapped:":
|
||||
m.Mapped = v
|
||||
m.Mapped = &v
|
||||
case "Shmem:":
|
||||
m.Shmem = v
|
||||
m.Shmem = &v
|
||||
case "Slab:":
|
||||
m.Slab = v
|
||||
m.Slab = &v
|
||||
case "SReclaimable:":
|
||||
m.SReclaimable = v
|
||||
m.SReclaimable = &v
|
||||
case "SUnreclaim:":
|
||||
m.SUnreclaim = v
|
||||
m.SUnreclaim = &v
|
||||
case "KernelStack:":
|
||||
m.KernelStack = v
|
||||
m.KernelStack = &v
|
||||
case "PageTables:":
|
||||
m.PageTables = v
|
||||
m.PageTables = &v
|
||||
case "NFS_Unstable:":
|
||||
m.NFSUnstable = v
|
||||
m.NFSUnstable = &v
|
||||
case "Bounce:":
|
||||
m.Bounce = v
|
||||
m.Bounce = &v
|
||||
case "WritebackTmp:":
|
||||
m.WritebackTmp = v
|
||||
m.WritebackTmp = &v
|
||||
case "CommitLimit:":
|
||||
m.CommitLimit = v
|
||||
m.CommitLimit = &v
|
||||
case "Committed_AS:":
|
||||
m.CommittedAS = v
|
||||
m.CommittedAS = &v
|
||||
case "VmallocTotal:":
|
||||
m.VmallocTotal = v
|
||||
m.VmallocTotal = &v
|
||||
case "VmallocUsed:":
|
||||
m.VmallocUsed = v
|
||||
m.VmallocUsed = &v
|
||||
case "VmallocChunk:":
|
||||
m.VmallocChunk = v
|
||||
m.VmallocChunk = &v
|
||||
case "HardwareCorrupted:":
|
||||
m.HardwareCorrupted = v
|
||||
m.HardwareCorrupted = &v
|
||||
case "AnonHugePages:":
|
||||
m.AnonHugePages = v
|
||||
m.AnonHugePages = &v
|
||||
case "ShmemHugePages:":
|
||||
m.ShmemHugePages = v
|
||||
m.ShmemHugePages = &v
|
||||
case "ShmemPmdMapped:":
|
||||
m.ShmemPmdMapped = v
|
||||
m.ShmemPmdMapped = &v
|
||||
case "CmaTotal:":
|
||||
m.CmaTotal = v
|
||||
m.CmaTotal = &v
|
||||
case "CmaFree:":
|
||||
m.CmaFree = v
|
||||
m.CmaFree = &v
|
||||
case "HugePages_Total:":
|
||||
m.HugePagesTotal = v
|
||||
m.HugePagesTotal = &v
|
||||
case "HugePages_Free:":
|
||||
m.HugePagesFree = v
|
||||
m.HugePagesFree = &v
|
||||
case "HugePages_Rsvd:":
|
||||
m.HugePagesRsvd = v
|
||||
m.HugePagesRsvd = &v
|
||||
case "HugePages_Surp:":
|
||||
m.HugePagesSurp = v
|
||||
m.HugePagesSurp = &v
|
||||
case "Hugepagesize:":
|
||||
m.Hugepagesize = v
|
||||
m.Hugepagesize = &v
|
||||
case "DirectMap4k:":
|
||||
m.DirectMap4k = v
|
||||
m.DirectMap4k = &v
|
||||
case "DirectMap2M:":
|
||||
m.DirectMap2M = v
|
||||
m.DirectMap2M = &v
|
||||
case "DirectMap1G:":
|
||||
m.DirectMap1G = v
|
||||
m.DirectMap1G = &v
|
||||
}
|
||||
}
|
||||
|
||||
|
|
8
vendor/github.com/prometheus/procfs/mountinfo.go
generated
vendored
8
vendor/github.com/prometheus/procfs/mountinfo.go
generated
vendored
|
@ -77,7 +77,7 @@ func parseMountInfoString(mountString string) (*MountInfo, error) {
|
|||
|
||||
mountInfo := strings.Split(mountString, " ")
|
||||
mountInfoLength := len(mountInfo)
|
||||
if mountInfoLength < 11 {
|
||||
if mountInfoLength < 10 {
|
||||
return nil, fmt.Errorf("couldn't find enough fields in mount string: %s", mountString)
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ func mountOptionsParseOptionalFields(o []string) (map[string]string, error) {
|
|||
return optionalFields, nil
|
||||
}
|
||||
|
||||
// Parses the mount options, superblock options.
|
||||
// mountOptionsParser parses the mount options, superblock options.
|
||||
func mountOptionsParser(mountOptions string) map[string]string {
|
||||
opts := make(map[string]string)
|
||||
options := strings.Split(mountOptions, ",")
|
||||
|
@ -161,7 +161,7 @@ func mountOptionsParser(mountOptions string) map[string]string {
|
|||
return opts
|
||||
}
|
||||
|
||||
// Retrieves mountinfo information from `/proc/self/mountinfo`.
|
||||
// GetMounts retrieves mountinfo information from `/proc/self/mountinfo`.
|
||||
func GetMounts() ([]*MountInfo, error) {
|
||||
data, err := util.ReadFileNoStat("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
|
@ -170,7 +170,7 @@ func GetMounts() ([]*MountInfo, error) {
|
|||
return parseMountInfo(data)
|
||||
}
|
||||
|
||||
// Retrieves mountinfo information from a processes' `/proc/<pid>/mountinfo`.
|
||||
// GetProcMounts retrieves mountinfo information from a processes' `/proc/<pid>/mountinfo`.
|
||||
func GetProcMounts(pid int) ([]*MountInfo, error) {
|
||||
data, err := util.ReadFileNoStat(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||
if err != nil {
|
||||
|
|
35
vendor/github.com/prometheus/procfs/mountstats.go
generated
vendored
35
vendor/github.com/prometheus/procfs/mountstats.go
generated
vendored
|
@ -186,6 +186,8 @@ type NFSOperationStats struct {
|
|||
CumulativeTotalResponseMilliseconds uint64
|
||||
// Duration from when a request was enqueued to when it was completely handled.
|
||||
CumulativeTotalRequestMilliseconds uint64
|
||||
// The count of operations that complete with tk_status < 0. These statuses usually indicate error conditions.
|
||||
Errors uint64
|
||||
}
|
||||
|
||||
// A NFSTransportStats contains statistics for the NFS mount RPC requests and
|
||||
|
@ -336,12 +338,12 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
|
|||
if len(ss) == 0 {
|
||||
break
|
||||
}
|
||||
if len(ss) < 2 {
|
||||
return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
|
||||
}
|
||||
|
||||
switch ss[0] {
|
||||
case fieldOpts:
|
||||
if len(ss) < 2 {
|
||||
return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
|
||||
}
|
||||
if stats.Opts == nil {
|
||||
stats.Opts = map[string]string{}
|
||||
}
|
||||
|
@ -354,6 +356,9 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
|
|||
}
|
||||
}
|
||||
case fieldAge:
|
||||
if len(ss) < 2 {
|
||||
return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
|
||||
}
|
||||
// Age integer is in seconds
|
||||
d, err := time.ParseDuration(ss[1] + "s")
|
||||
if err != nil {
|
||||
|
@ -362,6 +367,9 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
|
|||
|
||||
stats.Age = d
|
||||
case fieldBytes:
|
||||
if len(ss) < 2 {
|
||||
return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
|
||||
}
|
||||
bstats, err := parseNFSBytesStats(ss[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -369,6 +377,9 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
|
|||
|
||||
stats.Bytes = *bstats
|
||||
case fieldEvents:
|
||||
if len(ss) < 2 {
|
||||
return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
|
||||
}
|
||||
estats, err := parseNFSEventsStats(ss[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -494,8 +505,8 @@ func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) {
|
|||
// line is reached.
|
||||
func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
|
||||
const (
|
||||
// Number of expected fields in each per-operation statistics set
|
||||
numFields = 9
|
||||
// Minimum number of expected fields in each per-operation statistics set
|
||||
minFields = 9
|
||||
)
|
||||
|
||||
var ops []NFSOperationStats
|
||||
|
@ -508,12 +519,12 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
|
|||
break
|
||||
}
|
||||
|
||||
if len(ss) != numFields {
|
||||
if len(ss) < minFields {
|
||||
return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss)
|
||||
}
|
||||
|
||||
// Skip string operation name for integers
|
||||
ns := make([]uint64, 0, numFields-1)
|
||||
ns := make([]uint64, 0, minFields-1)
|
||||
for _, st := range ss[1:] {
|
||||
n, err := strconv.ParseUint(st, 10, 64)
|
||||
if err != nil {
|
||||
|
@ -523,7 +534,7 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
|
|||
ns = append(ns, n)
|
||||
}
|
||||
|
||||
ops = append(ops, NFSOperationStats{
|
||||
opStats := NFSOperationStats{
|
||||
Operation: strings.TrimSuffix(ss[0], ":"),
|
||||
Requests: ns[0],
|
||||
Transmissions: ns[1],
|
||||
|
@ -533,7 +544,13 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
|
|||
CumulativeQueueMilliseconds: ns[5],
|
||||
CumulativeTotalResponseMilliseconds: ns[6],
|
||||
CumulativeTotalRequestMilliseconds: ns[7],
|
||||
})
|
||||
}
|
||||
|
||||
if len(ns) > 8 {
|
||||
opStats.Errors = ns[8]
|
||||
}
|
||||
|
||||
ops = append(ops, opStats)
|
||||
}
|
||||
|
||||
return ops, s.Err()
|
||||
|
|
6
vendor/github.com/prometheus/procfs/net_conntrackstat.go
generated
vendored
6
vendor/github.com/prometheus/procfs/net_conntrackstat.go
generated
vendored
|
@ -38,7 +38,7 @@ type ConntrackStatEntry struct {
|
|||
SearchRestart uint64
|
||||
}
|
||||
|
||||
// Retrieves netfilter's conntrack statistics, split by CPU cores
|
||||
// ConntrackStat retrieves netfilter's conntrack statistics, split by CPU cores
|
||||
func (fs FS) ConntrackStat() ([]ConntrackStatEntry, error) {
|
||||
return readConntrackStat(fs.proc.Path("net", "stat", "nf_conntrack"))
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func readConntrackStat(path string) ([]ConntrackStatEntry, error) {
|
|||
|
||||
stat, err := parseConntrackStat(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read conntrack stats from %q: %v", path, err)
|
||||
return nil, fmt.Errorf("failed to read conntrack stats from %q: %w", path, err)
|
||||
}
|
||||
|
||||
return stat, nil
|
||||
|
@ -147,7 +147,7 @@ func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) {
|
|||
func parseConntrackStatField(field string) (uint64, error) {
|
||||
val, err := strconv.ParseUint(field, 16, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("couldn't parse \"%s\" field: %s", field, err)
|
||||
return 0, fmt.Errorf("couldn't parse %q field: %w", field, err)
|
||||
}
|
||||
return val, err
|
||||
}
|
||||
|
|
226
vendor/github.com/prometheus/procfs/net_ip_socket.go
generated
vendored
Normal file
226
vendor/github.com/prometheus/procfs/net_ip_socket.go
generated
vendored
Normal file
|
@ -0,0 +1,226 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// readLimit is used by io.LimitReader while reading the content of the
|
||||
// /proc/net/udp{,6} files. The number of lines inside such a file is dynamic
|
||||
// as each line represents a single used socket.
|
||||
// In theory, the number of available sockets is 65535 (2^16 - 1) per IP.
|
||||
// With e.g. 150 Byte per line and the maximum number of 65535,
|
||||
// the reader needs to handle 150 Byte * 65535 =~ 10 MB for a single IP.
|
||||
readLimit = 4294967296 // Byte -> 4 GiB
|
||||
)
|
||||
|
||||
// this contains generic data structures for both udp and tcp sockets
|
||||
type (
|
||||
// NetIPSocket represents the contents of /proc/net/{t,u}dp{,6} file without the header.
|
||||
NetIPSocket []*netIPSocketLine
|
||||
|
||||
// NetIPSocketSummary provides already computed values like the total queue lengths or
|
||||
// the total number of used sockets. In contrast to NetIPSocket it does not collect
|
||||
// the parsed lines into a slice.
|
||||
NetIPSocketSummary struct {
|
||||
// TxQueueLength shows the total queue length of all parsed tx_queue lengths.
|
||||
TxQueueLength uint64
|
||||
// RxQueueLength shows the total queue length of all parsed rx_queue lengths.
|
||||
RxQueueLength uint64
|
||||
// UsedSockets shows the total number of parsed lines representing the
|
||||
// number of used sockets.
|
||||
UsedSockets uint64
|
||||
}
|
||||
|
||||
// netIPSocketLine represents the fields parsed from a single line
|
||||
// in /proc/net/{t,u}dp{,6}. Fields which are not used by IPSocket are skipped.
|
||||
// For the proc file format details, see https://linux.die.net/man/5/proc.
|
||||
netIPSocketLine struct {
|
||||
Sl uint64
|
||||
LocalAddr net.IP
|
||||
LocalPort uint64
|
||||
RemAddr net.IP
|
||||
RemPort uint64
|
||||
St uint64
|
||||
TxQueue uint64
|
||||
RxQueue uint64
|
||||
UID uint64
|
||||
Inode uint64
|
||||
}
|
||||
)
|
||||
|
||||
func newNetIPSocket(file string) (NetIPSocket, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var netIPSocket NetIPSocket
|
||||
|
||||
lr := io.LimitReader(f, readLimit)
|
||||
s := bufio.NewScanner(lr)
|
||||
s.Scan() // skip first line with headers
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
line, err := parseNetIPSocketLine(fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netIPSocket = append(netIPSocket, line)
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return netIPSocket, nil
|
||||
}
|
||||
|
||||
// newNetIPSocketSummary creates a new NetIPSocket{,6} from the contents of the given file.
|
||||
func newNetIPSocketSummary(file string) (*NetIPSocketSummary, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var netIPSocketSummary NetIPSocketSummary
|
||||
|
||||
lr := io.LimitReader(f, readLimit)
|
||||
s := bufio.NewScanner(lr)
|
||||
s.Scan() // skip first line with headers
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
line, err := parseNetIPSocketLine(fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netIPSocketSummary.TxQueueLength += line.TxQueue
|
||||
netIPSocketSummary.RxQueueLength += line.RxQueue
|
||||
netIPSocketSummary.UsedSockets++
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &netIPSocketSummary, nil
|
||||
}
|
||||
|
||||
// the /proc/net/{t,u}dp{,6} files are network byte order for ipv4 and for ipv6 the address is four words consisting of four bytes each. In each of those four words the four bytes are written in reverse order.
|
||||
|
||||
func parseIP(hexIP string) (net.IP, error) {
|
||||
var byteIP []byte
|
||||
byteIP, err := hex.DecodeString(hexIP)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse address field in socket line %q", hexIP)
|
||||
}
|
||||
switch len(byteIP) {
|
||||
case 4:
|
||||
return net.IP{byteIP[3], byteIP[2], byteIP[1], byteIP[0]}, nil
|
||||
case 16:
|
||||
i := net.IP{
|
||||
byteIP[3], byteIP[2], byteIP[1], byteIP[0],
|
||||
byteIP[7], byteIP[6], byteIP[5], byteIP[4],
|
||||
byteIP[11], byteIP[10], byteIP[9], byteIP[8],
|
||||
byteIP[15], byteIP[14], byteIP[13], byteIP[12],
|
||||
}
|
||||
return i, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unable to parse IP %s", hexIP)
|
||||
}
|
||||
}
|
||||
|
||||
// parseNetIPSocketLine parses a single line, represented by a list of fields.
|
||||
func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
|
||||
line := &netIPSocketLine{}
|
||||
if len(fields) < 10 {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse net socket line as it has less then 10 columns %q",
|
||||
strings.Join(fields, " "),
|
||||
)
|
||||
}
|
||||
var err error // parse error
|
||||
|
||||
// sl
|
||||
s := strings.Split(fields[0], ":")
|
||||
if len(s) != 2 {
|
||||
return nil, fmt.Errorf("cannot parse sl field in socket line %q", fields[0])
|
||||
}
|
||||
|
||||
if line.Sl, err = strconv.ParseUint(s[0], 0, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse sl value in socket line: %w", err)
|
||||
}
|
||||
// local_address
|
||||
l := strings.Split(fields[1], ":")
|
||||
if len(l) != 2 {
|
||||
return nil, fmt.Errorf("cannot parse local_address field in socket line %q", fields[1])
|
||||
}
|
||||
if line.LocalAddr, err = parseIP(l[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if line.LocalPort, err = strconv.ParseUint(l[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse local_address port value in socket line: %w", err)
|
||||
}
|
||||
|
||||
// remote_address
|
||||
r := strings.Split(fields[2], ":")
|
||||
if len(r) != 2 {
|
||||
return nil, fmt.Errorf("cannot parse rem_address field in socket line %q", fields[1])
|
||||
}
|
||||
if line.RemAddr, err = parseIP(r[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if line.RemPort, err = strconv.ParseUint(r[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse rem_address port value in socket line: %w", err)
|
||||
}
|
||||
|
||||
// st
|
||||
if line.St, err = strconv.ParseUint(fields[3], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse st value in socket line: %w", err)
|
||||
}
|
||||
|
||||
// tx_queue and rx_queue
|
||||
q := strings.Split(fields[4], ":")
|
||||
if len(q) != 2 {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse tx/rx queues in socket line as it has a missing colon %q",
|
||||
fields[4],
|
||||
)
|
||||
}
|
||||
if line.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse tx_queue value in socket line: %w", err)
|
||||
}
|
||||
if line.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse rx_queue value in socket line: %w", err)
|
||||
}
|
||||
|
||||
// uid
|
||||
if line.UID, err = strconv.ParseUint(fields[7], 0, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse uid value in socket line: %w", err)
|
||||
}
|
||||
|
||||
// inode
|
||||
if line.Inode, err = strconv.ParseUint(fields[9], 0, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse inode value in socket line: %w", err)
|
||||
}
|
||||
|
||||
return line, nil
|
||||
}
|
180
vendor/github.com/prometheus/procfs/net_protocols.go
generated
vendored
Normal file
180
vendor/github.com/prometheus/procfs/net_protocols.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
)
|
||||
|
||||
// NetProtocolStats stores the contents from /proc/net/protocols
|
||||
type NetProtocolStats map[string]NetProtocolStatLine
|
||||
|
||||
// NetProtocolStatLine contains a single line parsed from /proc/net/protocols. We
|
||||
// only care about the first six columns as the rest are not likely to change
|
||||
// and only serve to provide a set of capabilities for each protocol.
|
||||
type NetProtocolStatLine struct {
|
||||
Name string // 0 The name of the protocol
|
||||
Size uint64 // 1 The size, in bytes, of a given protocol structure. e.g. sizeof(struct tcp_sock) or sizeof(struct unix_sock)
|
||||
Sockets int64 // 2 Number of sockets in use by this protocol
|
||||
Memory int64 // 3 Number of 4KB pages allocated by all sockets of this protocol
|
||||
Pressure int // 4 This is either yes, no, or NI (not implemented). For the sake of simplicity we treat NI as not experiencing memory pressure.
|
||||
MaxHeader uint64 // 5 Protocol specific max header size
|
||||
Slab bool // 6 Indicates whether or not memory is allocated from the SLAB
|
||||
ModuleName string // 7 The name of the module that implemented this protocol or "kernel" if not from a module
|
||||
Capabilities NetProtocolCapabilities
|
||||
}
|
||||
|
||||
// NetProtocolCapabilities contains a list of capabilities for each protocol
|
||||
type NetProtocolCapabilities struct {
|
||||
Close bool // 8
|
||||
Connect bool // 9
|
||||
Disconnect bool // 10
|
||||
Accept bool // 11
|
||||
IoCtl bool // 12
|
||||
Init bool // 13
|
||||
Destroy bool // 14
|
||||
Shutdown bool // 15
|
||||
SetSockOpt bool // 16
|
||||
GetSockOpt bool // 17
|
||||
SendMsg bool // 18
|
||||
RecvMsg bool // 19
|
||||
SendPage bool // 20
|
||||
Bind bool // 21
|
||||
BacklogRcv bool // 22
|
||||
Hash bool // 23
|
||||
UnHash bool // 24
|
||||
GetPort bool // 25
|
||||
EnterMemoryPressure bool // 26
|
||||
}
|
||||
|
||||
// NetProtocols reads stats from /proc/net/protocols and returns a map of
|
||||
// PortocolStatLine entries. As of this writing no official Linux Documentation
|
||||
// exists, however the source is fairly self-explanatory and the format seems
|
||||
// stable since its introduction in 2.6.12-rc2
|
||||
// Linux 2.6.12-rc2 - https://elixir.bootlin.com/linux/v2.6.12-rc2/source/net/core/sock.c#L1452
|
||||
// Linux 5.10 - https://elixir.bootlin.com/linux/v5.10.4/source/net/core/sock.c#L3586
|
||||
func (fs FS) NetProtocols() (NetProtocolStats, error) {
|
||||
data, err := util.ReadFileNoStat(fs.proc.Path("net/protocols"))
|
||||
if err != nil {
|
||||
return NetProtocolStats{}, err
|
||||
}
|
||||
return parseNetProtocols(bufio.NewScanner(bytes.NewReader(data)))
|
||||
}
|
||||
|
||||
func parseNetProtocols(s *bufio.Scanner) (NetProtocolStats, error) {
|
||||
nps := NetProtocolStats{}
|
||||
|
||||
// Skip the header line
|
||||
s.Scan()
|
||||
|
||||
for s.Scan() {
|
||||
line, err := nps.parseLine(s.Text())
|
||||
if err != nil {
|
||||
return NetProtocolStats{}, err
|
||||
}
|
||||
|
||||
nps[line.Name] = *line
|
||||
}
|
||||
return nps, nil
|
||||
}
|
||||
|
||||
func (ps NetProtocolStats) parseLine(rawLine string) (*NetProtocolStatLine, error) {
|
||||
line := &NetProtocolStatLine{Capabilities: NetProtocolCapabilities{}}
|
||||
var err error
|
||||
const enabled = "yes"
|
||||
const disabled = "no"
|
||||
|
||||
fields := strings.Fields(rawLine)
|
||||
line.Name = fields[0]
|
||||
line.Size, err = strconv.ParseUint(fields[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
line.Sockets, err = strconv.ParseInt(fields[2], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
line.Memory, err = strconv.ParseInt(fields[3], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fields[4] == enabled {
|
||||
line.Pressure = 1
|
||||
} else if fields[4] == disabled {
|
||||
line.Pressure = 0
|
||||
} else {
|
||||
line.Pressure = -1
|
||||
}
|
||||
line.MaxHeader, err = strconv.ParseUint(fields[5], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fields[6] == enabled {
|
||||
line.Slab = true
|
||||
} else if fields[6] == disabled {
|
||||
line.Slab = false
|
||||
} else {
|
||||
return nil, fmt.Errorf("unable to parse capability for protocol: %s", line.Name)
|
||||
}
|
||||
line.ModuleName = fields[7]
|
||||
|
||||
err = line.Capabilities.parseCapabilities(fields[8:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func (pc *NetProtocolCapabilities) parseCapabilities(capabilities []string) error {
|
||||
// The capabilities are all bools so we can loop over to map them
|
||||
capabilityFields := [...]*bool{
|
||||
&pc.Close,
|
||||
&pc.Connect,
|
||||
&pc.Disconnect,
|
||||
&pc.Accept,
|
||||
&pc.IoCtl,
|
||||
&pc.Init,
|
||||
&pc.Destroy,
|
||||
&pc.Shutdown,
|
||||
&pc.SetSockOpt,
|
||||
&pc.GetSockOpt,
|
||||
&pc.SendMsg,
|
||||
&pc.RecvMsg,
|
||||
&pc.SendPage,
|
||||
&pc.Bind,
|
||||
&pc.BacklogRcv,
|
||||
&pc.Hash,
|
||||
&pc.UnHash,
|
||||
&pc.GetPort,
|
||||
&pc.EnterMemoryPressure,
|
||||
}
|
||||
|
||||
for i := 0; i < len(capabilities); i++ {
|
||||
if capabilities[i] == "y" {
|
||||
*capabilityFields[i] = true
|
||||
} else if capabilities[i] == "n" {
|
||||
*capabilityFields[i] = false
|
||||
} else {
|
||||
return fmt.Errorf("unable to parse capability block for protocol: position %d", i)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
4
vendor/github.com/prometheus/procfs/net_sockstat.go
generated
vendored
4
vendor/github.com/prometheus/procfs/net_sockstat.go
generated
vendored
|
@ -70,7 +70,7 @@ func readSockstat(name string) (*NetSockstat, error) {
|
|||
|
||||
stat, err := parseSockstat(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read sockstats from %q: %v", name, err)
|
||||
return nil, fmt.Errorf("failed to read sockstats from %q: %w", name, err)
|
||||
}
|
||||
|
||||
return stat, nil
|
||||
|
@ -90,7 +90,7 @@ func parseSockstat(r io.Reader) (*NetSockstat, error) {
|
|||
// The remaining fields are key/value pairs.
|
||||
kvs, err := parseSockstatKVs(fields[1:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing sockstat key/value pairs from %q: %v", s.Text(), err)
|
||||
return nil, fmt.Errorf("error parsing sockstat key/value pairs from %q: %w", s.Text(), err)
|
||||
}
|
||||
|
||||
// The first field is the protocol. We must trim its colon suffix.
|
||||
|
|
2
vendor/github.com/prometheus/procfs/net_softnet.go
generated
vendored
2
vendor/github.com/prometheus/procfs/net_softnet.go
generated
vendored
|
@ -51,7 +51,7 @@ func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) {
|
|||
|
||||
entries, err := parseSoftnet(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse /proc/net/softnet_stat: %v", err)
|
||||
return nil, fmt.Errorf("failed to parse /proc/net/softnet_stat: %w", err)
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
|
|
64
vendor/github.com/prometheus/procfs/net_tcp.go
generated
vendored
Normal file
64
vendor/github.com/prometheus/procfs/net_tcp.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
package procfs
|
||||
|
||||
type (
|
||||
// NetTCP represents the contents of /proc/net/tcp{,6} file without the header.
|
||||
NetTCP []*netIPSocketLine
|
||||
|
||||
// NetTCPSummary provides already computed values like the total queue lengths or
|
||||
// the total number of used sockets. In contrast to NetTCP it does not collect
|
||||
// the parsed lines into a slice.
|
||||
NetTCPSummary NetIPSocketSummary
|
||||
)
|
||||
|
||||
// NetTCP returns the IPv4 kernel/networking statistics for TCP datagrams
|
||||
// read from /proc/net/tcp.
|
||||
func (fs FS) NetTCP() (NetTCP, error) {
|
||||
return newNetTCP(fs.proc.Path("net/tcp"))
|
||||
}
|
||||
|
||||
// NetTCP6 returns the IPv6 kernel/networking statistics for TCP datagrams
|
||||
// read from /proc/net/tcp6.
|
||||
func (fs FS) NetTCP6() (NetTCP, error) {
|
||||
return newNetTCP(fs.proc.Path("net/tcp6"))
|
||||
}
|
||||
|
||||
// NetTCPSummary returns already computed statistics like the total queue lengths
|
||||
// for TCP datagrams read from /proc/net/tcp.
|
||||
func (fs FS) NetTCPSummary() (*NetTCPSummary, error) {
|
||||
return newNetTCPSummary(fs.proc.Path("net/tcp"))
|
||||
}
|
||||
|
||||
// NetTCP6Summary returns already computed statistics like the total queue lengths
|
||||
// for TCP datagrams read from /proc/net/tcp6.
|
||||
func (fs FS) NetTCP6Summary() (*NetTCPSummary, error) {
|
||||
return newNetTCPSummary(fs.proc.Path("net/tcp6"))
|
||||
}
|
||||
|
||||
// newNetTCP creates a new NetTCP{,6} from the contents of the given file.
|
||||
func newNetTCP(file string) (NetTCP, error) {
|
||||
n, err := newNetIPSocket(file)
|
||||
n1 := NetTCP(n)
|
||||
return n1, err
|
||||
}
|
||||
|
||||
func newNetTCPSummary(file string) (*NetTCPSummary, error) {
|
||||
n, err := newNetIPSocketSummary(file)
|
||||
if n == nil {
|
||||
return nil, err
|
||||
}
|
||||
n1 := NetTCPSummary(*n)
|
||||
return &n1, err
|
||||
}
|
183
vendor/github.com/prometheus/procfs/net_udp.go
generated
vendored
183
vendor/github.com/prometheus/procfs/net_udp.go
generated
vendored
|
@ -13,58 +13,14 @@
|
|||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// readLimit is used by io.LimitReader while reading the content of the
|
||||
// /proc/net/udp{,6} files. The number of lines inside such a file is dynamic
|
||||
// as each line represents a single used socket.
|
||||
// In theory, the number of available sockets is 65535 (2^16 - 1) per IP.
|
||||
// With e.g. 150 Byte per line and the maximum number of 65535,
|
||||
// the reader needs to handle 150 Byte * 65535 =~ 10 MB for a single IP.
|
||||
readLimit = 4294967296 // Byte -> 4 GiB
|
||||
)
|
||||
|
||||
type (
|
||||
// NetUDP represents the contents of /proc/net/udp{,6} file without the header.
|
||||
NetUDP []*netUDPLine
|
||||
NetUDP []*netIPSocketLine
|
||||
|
||||
// NetUDPSummary provides already computed values like the total queue lengths or
|
||||
// the total number of used sockets. In contrast to NetUDP it does not collect
|
||||
// the parsed lines into a slice.
|
||||
NetUDPSummary struct {
|
||||
// TxQueueLength shows the total queue length of all parsed tx_queue lengths.
|
||||
TxQueueLength uint64
|
||||
// RxQueueLength shows the total queue length of all parsed rx_queue lengths.
|
||||
RxQueueLength uint64
|
||||
// UsedSockets shows the total number of parsed lines representing the
|
||||
// number of used sockets.
|
||||
UsedSockets uint64
|
||||
}
|
||||
|
||||
// netUDPLine represents the fields parsed from a single line
|
||||
// in /proc/net/udp{,6}. Fields which are not used by UDP are skipped.
|
||||
// For the proc file format details, see https://linux.die.net/man/5/proc.
|
||||
netUDPLine struct {
|
||||
Sl uint64
|
||||
LocalAddr net.IP
|
||||
LocalPort uint64
|
||||
RemAddr net.IP
|
||||
RemPort uint64
|
||||
St uint64
|
||||
TxQueue uint64
|
||||
RxQueue uint64
|
||||
UID uint64
|
||||
}
|
||||
NetUDPSummary NetIPSocketSummary
|
||||
)
|
||||
|
||||
// NetUDP returns the IPv4 kernel/networking statistics for UDP datagrams
|
||||
|
@ -93,137 +49,16 @@ func (fs FS) NetUDP6Summary() (*NetUDPSummary, error) {
|
|||
|
||||
// newNetUDP creates a new NetUDP{,6} from the contents of the given file.
|
||||
func newNetUDP(file string) (NetUDP, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
netUDP := NetUDP{}
|
||||
|
||||
lr := io.LimitReader(f, readLimit)
|
||||
s := bufio.NewScanner(lr)
|
||||
s.Scan() // skip first line with headers
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
line, err := parseNetUDPLine(fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netUDP = append(netUDP, line)
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return netUDP, nil
|
||||
n, err := newNetIPSocket(file)
|
||||
n1 := NetUDP(n)
|
||||
return n1, err
|
||||
}
|
||||
|
||||
// newNetUDPSummary creates a new NetUDP{,6} from the contents of the given file.
|
||||
func newNetUDPSummary(file string) (*NetUDPSummary, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
n, err := newNetIPSocketSummary(file)
|
||||
if n == nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
netUDPSummary := &NetUDPSummary{}
|
||||
|
||||
lr := io.LimitReader(f, readLimit)
|
||||
s := bufio.NewScanner(lr)
|
||||
s.Scan() // skip first line with headers
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
line, err := parseNetUDPLine(fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netUDPSummary.TxQueueLength += line.TxQueue
|
||||
netUDPSummary.RxQueueLength += line.RxQueue
|
||||
netUDPSummary.UsedSockets++
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return netUDPSummary, nil
|
||||
}
|
||||
|
||||
// parseNetUDPLine parses a single line, represented by a list of fields.
|
||||
func parseNetUDPLine(fields []string) (*netUDPLine, error) {
|
||||
line := &netUDPLine{}
|
||||
if len(fields) < 8 {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse net udp socket line as it has less then 8 columns: %s",
|
||||
strings.Join(fields, " "),
|
||||
)
|
||||
}
|
||||
var err error // parse error
|
||||
|
||||
// sl
|
||||
s := strings.Split(fields[0], ":")
|
||||
if len(s) != 2 {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse sl field in udp socket line: %s", fields[0])
|
||||
}
|
||||
|
||||
if line.Sl, err = strconv.ParseUint(s[0], 0, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse sl value in udp socket line: %s", err)
|
||||
}
|
||||
// local_address
|
||||
l := strings.Split(fields[1], ":")
|
||||
if len(l) != 2 {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse local_address field in udp socket line: %s", fields[1])
|
||||
}
|
||||
if line.LocalAddr, err = hex.DecodeString(l[0]); err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse local_address value in udp socket line: %s", err)
|
||||
}
|
||||
if line.LocalPort, err = strconv.ParseUint(l[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse local_address port value in udp socket line: %s", err)
|
||||
}
|
||||
|
||||
// remote_address
|
||||
r := strings.Split(fields[2], ":")
|
||||
if len(r) != 2 {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse rem_address field in udp socket line: %s", fields[1])
|
||||
}
|
||||
if line.RemAddr, err = hex.DecodeString(r[0]); err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse rem_address value in udp socket line: %s", err)
|
||||
}
|
||||
if line.RemPort, err = strconv.ParseUint(r[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse rem_address port value in udp socket line: %s", err)
|
||||
}
|
||||
|
||||
// st
|
||||
if line.St, err = strconv.ParseUint(fields[3], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse st value in udp socket line: %s", err)
|
||||
}
|
||||
|
||||
// tx_queue and rx_queue
|
||||
q := strings.Split(fields[4], ":")
|
||||
if len(q) != 2 {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse tx/rx queues in udp socket line as it has a missing colon: %s",
|
||||
fields[4],
|
||||
)
|
||||
}
|
||||
if line.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse tx_queue value in udp socket line: %s", err)
|
||||
}
|
||||
if line.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse rx_queue value in udp socket line: %s", err)
|
||||
}
|
||||
|
||||
// uid
|
||||
if line.UID, err = strconv.ParseUint(fields[7], 0, 64); err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot parse uid value in udp socket line: %s", err)
|
||||
}
|
||||
|
||||
return line, nil
|
||||
n1 := NetUDPSummary(*n)
|
||||
return &n1, err
|
||||
}
|
||||
|
|
14
vendor/github.com/prometheus/procfs/net_unix.go
generated
vendored
14
vendor/github.com/prometheus/procfs/net_unix.go
generated
vendored
|
@ -108,14 +108,14 @@ func parseNetUNIX(r io.Reader) (*NetUNIX, error) {
|
|||
line := s.Text()
|
||||
item, err := nu.parseLine(line, hasInode, minFields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse /proc/net/unix data %q: %v", line, err)
|
||||
return nil, fmt.Errorf("failed to parse /proc/net/unix data %q: %w", line, err)
|
||||
}
|
||||
|
||||
nu.Rows = append(nu.Rows, item)
|
||||
}
|
||||
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, fmt.Errorf("failed to scan /proc/net/unix data: %v", err)
|
||||
return nil, fmt.Errorf("failed to scan /proc/net/unix data: %w", err)
|
||||
}
|
||||
|
||||
return &nu, nil
|
||||
|
@ -136,29 +136,29 @@ func (u *NetUNIX) parseLine(line string, hasInode bool, min int) (*NetUNIXLine,
|
|||
|
||||
users, err := u.parseUsers(fields[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse ref count(%s): %v", fields[1], err)
|
||||
return nil, fmt.Errorf("failed to parse ref count %q: %w", fields[1], err)
|
||||
}
|
||||
|
||||
flags, err := u.parseFlags(fields[3])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse flags(%s): %v", fields[3], err)
|
||||
return nil, fmt.Errorf("failed to parse flags %q: %w", fields[3], err)
|
||||
}
|
||||
|
||||
typ, err := u.parseType(fields[4])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse type(%s): %v", fields[4], err)
|
||||
return nil, fmt.Errorf("failed to parse type %q: %w", fields[4], err)
|
||||
}
|
||||
|
||||
state, err := u.parseState(fields[5])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse state(%s): %v", fields[5], err)
|
||||
return nil, fmt.Errorf("failed to parse state %q: %w", fields[5], err)
|
||||
}
|
||||
|
||||
var inode uint64
|
||||
if hasInode {
|
||||
inode, err = u.parseInode(fields[6])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse inode(%s): %v", fields[6], err)
|
||||
return nil, fmt.Errorf("failed to parse inode %q: %w", fields[6], err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
68
vendor/github.com/prometheus/procfs/netstat.go
generated
vendored
Normal file
68
vendor/github.com/prometheus/procfs/netstat.go
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NetStat contains statistics for all the counters from one file
|
||||
type NetStat struct {
|
||||
Filename string
|
||||
Stats map[string][]uint64
|
||||
}
|
||||
|
||||
// NetStat retrieves stats from /proc/net/stat/
|
||||
func (fs FS) NetStat() ([]NetStat, error) {
|
||||
statFiles, err := filepath.Glob(fs.proc.Path("net/stat/*"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var netStatsTotal []NetStat
|
||||
|
||||
for _, filePath := range statFiles {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
netStatFile := NetStat{
|
||||
Filename: filepath.Base(filePath),
|
||||
Stats: make(map[string][]uint64),
|
||||
}
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Scan()
|
||||
// First string is always a header for stats
|
||||
var headers []string
|
||||
headers = append(headers, strings.Fields(scanner.Text())...)
|
||||
|
||||
// Other strings represent per-CPU counters
|
||||
for scanner.Scan() {
|
||||
for num, counter := range strings.Fields(scanner.Text()) {
|
||||
value, err := strconv.ParseUint(counter, 16, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netStatFile.Stats[headers[num]] = append(netStatFile.Stats[headers[num]], value)
|
||||
}
|
||||
}
|
||||
netStatsTotal = append(netStatsTotal, netStatFile)
|
||||
}
|
||||
return netStatsTotal, nil
|
||||
}
|
27
vendor/github.com/prometheus/procfs/proc.go
generated
vendored
27
vendor/github.com/prometheus/procfs/proc.go
generated
vendored
|
@ -105,7 +105,7 @@ func (fs FS) AllProcs() (Procs, error) {
|
|||
|
||||
names, err := d.Readdirnames(-1)
|
||||
if err != nil {
|
||||
return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err)
|
||||
return Procs{}, fmt.Errorf("could not read %q: %w", d.Name(), err)
|
||||
}
|
||||
|
||||
p := Procs{}
|
||||
|
@ -134,6 +134,27 @@ func (p Proc) CmdLine() ([]string, error) {
|
|||
return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
|
||||
}
|
||||
|
||||
// Wchan returns the wchan (wait channel) of a process.
|
||||
func (p Proc) Wchan() (string, error) {
|
||||
f, err := os.Open(p.path("wchan"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
wchan := string(data)
|
||||
if wchan == "" || wchan == "0" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return wchan, nil
|
||||
}
|
||||
|
||||
// Comm returns the command name of a process.
|
||||
func (p Proc) Comm() (string, error) {
|
||||
data, err := util.ReadFileNoStat(p.path("comm"))
|
||||
|
@ -185,7 +206,7 @@ func (p Proc) FileDescriptors() ([]uintptr, error) {
|
|||
for i, n := range names {
|
||||
fd, err := strconv.ParseInt(n, 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
|
||||
return nil, fmt.Errorf("could not parse fd %q: %w", n, err)
|
||||
}
|
||||
fds[i] = uintptr(fd)
|
||||
}
|
||||
|
@ -257,7 +278,7 @@ func (p Proc) fileDescriptors() ([]string, error) {
|
|||
|
||||
names, err := d.Readdirnames(-1)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
|
||||
return nil, fmt.Errorf("could not read %q: %w", d.Name(), err)
|
||||
}
|
||||
|
||||
return names, nil
|
||||
|
|
98
vendor/github.com/prometheus/procfs/proc_cgroup.go
generated
vendored
Normal file
98
vendor/github.com/prometheus/procfs/proc_cgroup.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2020 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
)
|
||||
|
||||
// Cgroup models one line from /proc/[pid]/cgroup. Each Cgroup struct describes the the placement of a PID inside a
|
||||
// specific control hierarchy. The kernel has two cgroup APIs, v1 and v2. v1 has one hierarchy per available resource
|
||||
// controller, while v2 has one unified hierarchy shared by all controllers. Regardless of v1 or v2, all hierarchies
|
||||
// contain all running processes, so the question answerable with a Cgroup struct is 'where is this process in
|
||||
// this hierarchy' (where==what path on the specific cgroupfs). By prefixing this path with the mount point of
|
||||
// *this specific* hierarchy, you can locate the relevant pseudo-files needed to read/set the data for this PID
|
||||
// in this hierarchy
|
||||
//
|
||||
// Also see http://man7.org/linux/man-pages/man7/cgroups.7.html
|
||||
type Cgroup struct {
|
||||
// HierarchyID that can be matched to a named hierarchy using /proc/cgroups. Cgroups V2 only has one
|
||||
// hierarchy, so HierarchyID is always 0. For cgroups v1 this is a unique ID number
|
||||
HierarchyID int
|
||||
// Controllers using this hierarchy of processes. Controllers are also known as subsystems. For
|
||||
// Cgroups V2 this may be empty, as all active controllers use the same hierarchy
|
||||
Controllers []string
|
||||
// Path of this control group, relative to the mount point of the cgroupfs representing this specific
|
||||
// hierarchy
|
||||
Path string
|
||||
}
|
||||
|
||||
// parseCgroupString parses each line of the /proc/[pid]/cgroup file
|
||||
// Line format is hierarchyID:[controller1,controller2]:path
|
||||
func parseCgroupString(cgroupStr string) (*Cgroup, error) {
|
||||
var err error
|
||||
|
||||
fields := strings.SplitN(cgroupStr, ":", 3)
|
||||
if len(fields) < 3 {
|
||||
return nil, fmt.Errorf("at least 3 fields required, found %d fields in cgroup string: %s", len(fields), cgroupStr)
|
||||
}
|
||||
|
||||
cgroup := &Cgroup{
|
||||
Path: fields[2],
|
||||
Controllers: nil,
|
||||
}
|
||||
cgroup.HierarchyID, err = strconv.Atoi(fields[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse hierarchy ID")
|
||||
}
|
||||
if fields[1] != "" {
|
||||
ssNames := strings.Split(fields[1], ",")
|
||||
cgroup.Controllers = append(cgroup.Controllers, ssNames...)
|
||||
}
|
||||
return cgroup, nil
|
||||
}
|
||||
|
||||
// parseCgroups reads each line of the /proc/[pid]/cgroup file
|
||||
func parseCgroups(data []byte) ([]Cgroup, error) {
|
||||
var cgroups []Cgroup
|
||||
scanner := bufio.NewScanner(bytes.NewReader(data))
|
||||
for scanner.Scan() {
|
||||
mountString := scanner.Text()
|
||||
parsedMounts, err := parseCgroupString(mountString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cgroups = append(cgroups, *parsedMounts)
|
||||
}
|
||||
|
||||
err := scanner.Err()
|
||||
return cgroups, err
|
||||
}
|
||||
|
||||
// Cgroups reads from /proc/<pid>/cgroups and returns a []*Cgroup struct locating this PID in each process
|
||||
// control hierarchy running on this system. On every system (v1 and v2), all hierarchies contain all processes,
|
||||
// so the len of the returned struct is equal to the number of active hierarchies on this system
|
||||
func (p Proc) Cgroups() ([]Cgroup, error) {
|
||||
data, err := util.ReadFileNoStat(p.path("cgroup"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parseCgroups(data)
|
||||
}
|
6
vendor/github.com/prometheus/procfs/proc_fdinfo.go
generated
vendored
6
vendor/github.com/prometheus/procfs/proc_fdinfo.go
generated
vendored
|
@ -16,7 +16,7 @@ package procfs
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
|
@ -41,7 +41,7 @@ type ProcFDInfo struct {
|
|||
Flags string
|
||||
// Mount point ID
|
||||
MntID string
|
||||
// List of inotify lines (structed) in the fdinfo file (kernel 3.8+ only)
|
||||
// List of inotify lines (structured) in the fdinfo file (kernel 3.8+ only)
|
||||
InotifyInfos []InotifyInfo
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ func parseInotifyInfo(line string) (*InotifyInfo, error) {
|
|||
}
|
||||
return i, nil
|
||||
}
|
||||
return nil, errors.New("invalid inode entry: " + line)
|
||||
return nil, fmt.Errorf("invalid inode entry: %q", line)
|
||||
}
|
||||
|
||||
// ProcFDInfos represents a list of ProcFDInfo structs.
|
||||
|
|
87
vendor/github.com/prometheus/procfs/proc_limits.go
generated
vendored
87
vendor/github.com/prometheus/procfs/proc_limits.go
generated
vendored
|
@ -26,55 +26,55 @@ import (
|
|||
// http://man7.org/linux/man-pages/man2/getrlimit.2.html.
|
||||
type ProcLimits struct {
|
||||
// CPU time limit in seconds.
|
||||
CPUTime int64
|
||||
CPUTime uint64
|
||||
// Maximum size of files that the process may create.
|
||||
FileSize int64
|
||||
FileSize uint64
|
||||
// Maximum size of the process's data segment (initialized data,
|
||||
// uninitialized data, and heap).
|
||||
DataSize int64
|
||||
DataSize uint64
|
||||
// Maximum size of the process stack in bytes.
|
||||
StackSize int64
|
||||
StackSize uint64
|
||||
// Maximum size of a core file.
|
||||
CoreFileSize int64
|
||||
CoreFileSize uint64
|
||||
// Limit of the process's resident set in pages.
|
||||
ResidentSet int64
|
||||
ResidentSet uint64
|
||||
// Maximum number of processes that can be created for the real user ID of
|
||||
// the calling process.
|
||||
Processes int64
|
||||
Processes uint64
|
||||
// Value one greater than the maximum file descriptor number that can be
|
||||
// opened by this process.
|
||||
OpenFiles int64
|
||||
OpenFiles uint64
|
||||
// Maximum number of bytes of memory that may be locked into RAM.
|
||||
LockedMemory int64
|
||||
LockedMemory uint64
|
||||
// Maximum size of the process's virtual memory address space in bytes.
|
||||
AddressSpace int64
|
||||
AddressSpace uint64
|
||||
// Limit on the combined number of flock(2) locks and fcntl(2) leases that
|
||||
// this process may establish.
|
||||
FileLocks int64
|
||||
FileLocks uint64
|
||||
// Limit of signals that may be queued for the real user ID of the calling
|
||||
// process.
|
||||
PendingSignals int64
|
||||
PendingSignals uint64
|
||||
// Limit on the number of bytes that can be allocated for POSIX message
|
||||
// queues for the real user ID of the calling process.
|
||||
MsqqueueSize int64
|
||||
MsqqueueSize uint64
|
||||
// Limit of the nice priority set using setpriority(2) or nice(2).
|
||||
NicePriority int64
|
||||
NicePriority uint64
|
||||
// Limit of the real-time priority set using sched_setscheduler(2) or
|
||||
// sched_setparam(2).
|
||||
RealtimePriority int64
|
||||
RealtimePriority uint64
|
||||
// Limit (in microseconds) on the amount of CPU time that a process
|
||||
// scheduled under a real-time scheduling policy may consume without making
|
||||
// a blocking system call.
|
||||
RealtimeTimeout int64
|
||||
RealtimeTimeout uint64
|
||||
}
|
||||
|
||||
const (
|
||||
limitsFields = 3
|
||||
limitsFields = 4
|
||||
limitsUnlimited = "unlimited"
|
||||
)
|
||||
|
||||
var (
|
||||
limitsDelimiter = regexp.MustCompile(" +")
|
||||
limitsMatch = regexp.MustCompile(`(Max \w+\s{0,1}?\w*\s{0,1}\w*)\s{2,}(\w+)\s+(\w+)`)
|
||||
)
|
||||
|
||||
// NewLimits returns the current soft limits of the process.
|
||||
|
@ -96,46 +96,49 @@ func (p Proc) Limits() (ProcLimits, error) {
|
|||
l = ProcLimits{}
|
||||
s = bufio.NewScanner(f)
|
||||
)
|
||||
|
||||
s.Scan() // Skip limits header
|
||||
|
||||
for s.Scan() {
|
||||
fields := limitsDelimiter.Split(s.Text(), limitsFields)
|
||||
//fields := limitsMatch.Split(s.Text(), limitsFields)
|
||||
fields := limitsMatch.FindStringSubmatch(s.Text())
|
||||
if len(fields) != limitsFields {
|
||||
return ProcLimits{}, fmt.Errorf(
|
||||
"couldn't parse %s line %s", f.Name(), s.Text())
|
||||
return ProcLimits{}, fmt.Errorf("couldn't parse %q line %q", f.Name(), s.Text())
|
||||
}
|
||||
|
||||
switch fields[0] {
|
||||
switch fields[1] {
|
||||
case "Max cpu time":
|
||||
l.CPUTime, err = parseInt(fields[1])
|
||||
l.CPUTime, err = parseUint(fields[2])
|
||||
case "Max file size":
|
||||
l.FileSize, err = parseInt(fields[1])
|
||||
l.FileSize, err = parseUint(fields[2])
|
||||
case "Max data size":
|
||||
l.DataSize, err = parseInt(fields[1])
|
||||
l.DataSize, err = parseUint(fields[2])
|
||||
case "Max stack size":
|
||||
l.StackSize, err = parseInt(fields[1])
|
||||
l.StackSize, err = parseUint(fields[2])
|
||||
case "Max core file size":
|
||||
l.CoreFileSize, err = parseInt(fields[1])
|
||||
l.CoreFileSize, err = parseUint(fields[2])
|
||||
case "Max resident set":
|
||||
l.ResidentSet, err = parseInt(fields[1])
|
||||
l.ResidentSet, err = parseUint(fields[2])
|
||||
case "Max processes":
|
||||
l.Processes, err = parseInt(fields[1])
|
||||
l.Processes, err = parseUint(fields[2])
|
||||
case "Max open files":
|
||||
l.OpenFiles, err = parseInt(fields[1])
|
||||
l.OpenFiles, err = parseUint(fields[2])
|
||||
case "Max locked memory":
|
||||
l.LockedMemory, err = parseInt(fields[1])
|
||||
l.LockedMemory, err = parseUint(fields[2])
|
||||
case "Max address space":
|
||||
l.AddressSpace, err = parseInt(fields[1])
|
||||
l.AddressSpace, err = parseUint(fields[2])
|
||||
case "Max file locks":
|
||||
l.FileLocks, err = parseInt(fields[1])
|
||||
l.FileLocks, err = parseUint(fields[2])
|
||||
case "Max pending signals":
|
||||
l.PendingSignals, err = parseInt(fields[1])
|
||||
l.PendingSignals, err = parseUint(fields[2])
|
||||
case "Max msgqueue size":
|
||||
l.MsqqueueSize, err = parseInt(fields[1])
|
||||
l.MsqqueueSize, err = parseUint(fields[2])
|
||||
case "Max nice priority":
|
||||
l.NicePriority, err = parseInt(fields[1])
|
||||
l.NicePriority, err = parseUint(fields[2])
|
||||
case "Max realtime priority":
|
||||
l.RealtimePriority, err = parseInt(fields[1])
|
||||
l.RealtimePriority, err = parseUint(fields[2])
|
||||
case "Max realtime timeout":
|
||||
l.RealtimeTimeout, err = parseInt(fields[1])
|
||||
l.RealtimeTimeout, err = parseUint(fields[2])
|
||||
}
|
||||
if err != nil {
|
||||
return ProcLimits{}, err
|
||||
|
@ -145,13 +148,13 @@ func (p Proc) Limits() (ProcLimits, error) {
|
|||
return l, s.Err()
|
||||
}
|
||||
|
||||
func parseInt(s string) (int64, error) {
|
||||
func parseUint(s string) (uint64, error) {
|
||||
if s == limitsUnlimited {
|
||||
return -1, nil
|
||||
return 18446744073709551615, nil
|
||||
}
|
||||
i, err := strconv.ParseInt(s, 10, 64)
|
||||
i, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("couldn't parse value %s: %s", s, err)
|
||||
return 0, fmt.Errorf("couldn't parse value %q: %w", s, err)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue