chore(go.mod): Update operator dependencies (#1840)
* chore(go.mod) Update operator dependencies Signed-off-by: Anatolii Bazko <abazko@redhat.com>pull/1827/head
parent
a5433b0678
commit
726dc03a5d
1048
DEPENDENCIES.md
1048
DEPENDENCIES.md
File diff suppressed because it is too large
Load Diff
32
go.mod
32
go.mod
|
|
@ -29,7 +29,7 @@ require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||||
|
|
@ -44,7 +44,7 @@ require (
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/uuid v1.1.2 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.13 // indirect
|
github.com/imdario/mergo v0.3.13 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.6 // indirect
|
github.com/mailru/easyjson v0.7.6 // indirect
|
||||||
|
|
@ -63,16 +63,15 @@ require (
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
|
golang.org/x/oauth2 v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.15.0 // indirect
|
golang.org/x/sys v0.15.0 // indirect
|
||||||
golang.org/x/term v0.15.0 // indirect
|
golang.org/x/term v0.15.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect
|
google.golang.org/grpc v1.58.3 // indirect
|
||||||
google.golang.org/grpc v1.49.0 // indirect
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|
@ -93,7 +92,8 @@ require (
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||||
golang.org/x/mod v0.12.0 // indirect
|
golang.org/x/mod v0.12.0 // indirect
|
||||||
golang.org/x/tools v0.13.0 // indirect
|
golang.org/x/tools v0.13.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
|
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -148,7 +148,7 @@ replace (
|
||||||
github.com/bugsnag/bugsnag-go => github.com/bugsnag/bugsnag-go v1.5.3
|
github.com/bugsnag/bugsnag-go => github.com/bugsnag/bugsnag-go v1.5.3
|
||||||
github.com/bugsnag/panicwrap => github.com/bugsnag/panicwrap v1.2.0
|
github.com/bugsnag/panicwrap => github.com/bugsnag/panicwrap v1.2.0
|
||||||
github.com/census-instrumentation/opencensus-proto => github.com/census-instrumentation/opencensus-proto v0.2.1
|
github.com/census-instrumentation/opencensus-proto => github.com/census-instrumentation/opencensus-proto v0.2.1
|
||||||
github.com/cespare/xxhash/v2 => github.com/cespare/xxhash/v2 v2.1.0
|
github.com/cespare/xxhash/v2 => github.com/cespare/xxhash/v2 v2.2.0
|
||||||
github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
|
github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
|
||||||
github.com/chzyer/logex => github.com/chzyer/logex v1.1.10
|
github.com/chzyer/logex => github.com/chzyer/logex v1.1.10
|
||||||
github.com/chzyer/readline => github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
github.com/chzyer/readline => github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
||||||
|
|
@ -252,7 +252,7 @@ replace (
|
||||||
github.com/google/martian => github.com/google/martian v0.0.0-20180813215018-c223d6f7955e
|
github.com/google/martian => github.com/google/martian v0.0.0-20180813215018-c223d6f7955e
|
||||||
github.com/google/pprof => github.com/google/pprof v0.0.0-20180921154107-7dadf64105bb
|
github.com/google/pprof => github.com/google/pprof v0.0.0-20180921154107-7dadf64105bb
|
||||||
github.com/google/renameio => github.com/google/renameio v0.1.0
|
github.com/google/renameio => github.com/google/renameio v0.1.0
|
||||||
github.com/google/uuid => github.com/google/uuid v1.1.2
|
github.com/google/uuid => github.com/google/uuid v1.3.0
|
||||||
github.com/googleapis/gax-go/v2 => github.com/googleapis/gax-go/v2 v2.0.5
|
github.com/googleapis/gax-go/v2 => github.com/googleapis/gax-go/v2 v2.0.5
|
||||||
github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.4.2
|
github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.4.2
|
||||||
github.com/gopherjs/gopherjs => github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00
|
github.com/gopherjs/gopherjs => github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00
|
||||||
|
|
@ -384,8 +384,8 @@ replace (
|
||||||
github.com/pmezard/go-difflib => github.com/pmezard/go-difflib v1.0.0
|
github.com/pmezard/go-difflib => github.com/pmezard/go-difflib v1.0.0
|
||||||
github.com/posener/complete => github.com/posener/complete v1.1.1
|
github.com/posener/complete => github.com/posener/complete v1.1.1
|
||||||
github.com/pquerna/cachecontrol => github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021
|
github.com/pquerna/cachecontrol => github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021
|
||||||
github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.14.0
|
||||||
github.com/prometheus/client_model => github.com/prometheus/client_model v0.2.0
|
github.com/prometheus/client_model => github.com/prometheus/client_model v0.3.0
|
||||||
github.com/prometheus/common => github.com/prometheus/common v0.26.0
|
github.com/prometheus/common => github.com/prometheus/common v0.26.0
|
||||||
github.com/prometheus/procfs => github.com/prometheus/procfs v0.6.0
|
github.com/prometheus/procfs => github.com/prometheus/procfs v0.6.0
|
||||||
github.com/redhat-cop/operator-utils => github.com/redhat-cop/operator-utils v1.1.4
|
github.com/redhat-cop/operator-utils => github.com/redhat-cop/operator-utils v1.1.4
|
||||||
|
|
@ -445,14 +445,14 @@ replace (
|
||||||
go.uber.org/zap => go.uber.org/zap v1.18.1
|
go.uber.org/zap => go.uber.org/zap v1.18.1
|
||||||
golang.org/x/crypto => golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
golang.org/x/crypto => golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||||
golang.org/x/exp => golang.org/x/exp v0.0.0-20190426190305-956cc1757749
|
golang.org/x/exp => golang.org/x/exp v0.0.0-20190426190305-956cc1757749
|
||||||
|
golang.org/x/oauth2 => golang.org/x/oauth2 v0.10.0
|
||||||
gomodules.xyz/jsonpatch/v2 => gomodules.xyz/jsonpatch/v2 v2.0.1
|
gomodules.xyz/jsonpatch/v2 => gomodules.xyz/jsonpatch/v2 v2.0.1
|
||||||
google.golang.org/api => google.golang.org/api v0.20.0
|
google.golang.org/api => google.golang.org/api v0.20.0
|
||||||
google.golang.org/appengine => google.golang.org/appengine v1.6.5
|
google.golang.org/appengine => google.golang.org/appengine v1.6.5
|
||||||
google.golang.org/cloud => cloud.google.com/go v0.0.0-20200305180117-a6b88cf34a49
|
google.golang.org/cloud => cloud.google.com/go v0.0.0-20200305180117-a6b88cf34a49
|
||||||
google.golang.org/genproto => google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5
|
google.golang.org/genproto/googleapis/rpc => google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
|
||||||
google.golang.org/grpc => google.golang.org/grpc v1.27.0
|
google.golang.org/grpc => google.golang.org/grpc v1.58.3
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc => google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e
|
google.golang.org/protobuf => google.golang.org/protobuf v1.34.1
|
||||||
google.golang.org/protobuf => google.golang.org/protobuf v1.25.0
|
|
||||||
gopkg.in/airbrake/gobrake.v2 => gopkg.in/airbrake/gobrake.v2 v2.0.9
|
gopkg.in/airbrake/gobrake.v2 => gopkg.in/airbrake/gobrake.v2 v2.0.9
|
||||||
gopkg.in/alecthomas/kingpin.v2 => gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
gopkg.in/alecthomas/kingpin.v2 => gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||||
gopkg.in/check.v1 => gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789
|
gopkg.in/check.v1 => gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789
|
||||||
|
|
@ -472,7 +472,7 @@ replace (
|
||||||
gopkg.in/tomb.v1 => gopkg.in/tomb.v1 v1.0.0-20161208151619-d5d1b5820637
|
gopkg.in/tomb.v1 => gopkg.in/tomb.v1 v1.0.0-20161208151619-d5d1b5820637
|
||||||
gopkg.in/tomb.v2 => gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
|
gopkg.in/tomb.v2 => gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
|
||||||
gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.4.0
|
||||||
gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
|
||||||
grpc-ecosystem/grpc-health-probe => grpc-ecosystem/grpc-health-probe v0.3.2
|
grpc-ecosystem/grpc-health-probe => grpc-ecosystem/grpc-health-probe v0.3.2
|
||||||
helm.sh/helm/v3 => helm.sh/helm/v3 v3.0.0-20200422233323-0a9a9a88e8af
|
helm.sh/helm/v3 => helm.sh/helm/v3 v3.0.0-20200422233323-0a9a9a88e8af
|
||||||
honnef.co/go/tools => honnef.co/go/tools v0.0.0-20200822191040-81508471876c
|
honnef.co/go/tools => honnef.co/go/tools v0.0.0-20200822191040-81508471876c
|
||||||
|
|
|
||||||
790
go.sum
790
go.sum
|
|
@ -1,11 +1,620 @@
|
||||||
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
|
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
|
||||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||||
|
cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4=
|
||||||
|
cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw=
|
||||||
|
cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E=
|
||||||
|
cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68=
|
||||||
|
cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o=
|
||||||
|
cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE=
|
||||||
|
cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM=
|
||||||
|
cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ=
|
||||||
|
cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps=
|
||||||
|
cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo=
|
||||||
|
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
|
||||||
|
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
|
||||||
|
cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg=
|
||||||
|
cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ=
|
||||||
|
cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k=
|
||||||
|
cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw=
|
||||||
|
cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA=
|
||||||
|
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
|
||||||
|
cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
|
||||||
|
cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE=
|
||||||
|
cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE=
|
||||||
|
cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo=
|
||||||
|
cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk=
|
||||||
|
cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc=
|
||||||
|
cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8=
|
||||||
|
cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA=
|
||||||
|
cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc=
|
||||||
|
cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04=
|
||||||
|
cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8=
|
||||||
|
cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs=
|
||||||
|
cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY=
|
||||||
|
cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM=
|
||||||
|
cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc=
|
||||||
|
cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw=
|
||||||
|
cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU=
|
||||||
|
cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI=
|
||||||
|
cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8=
|
||||||
|
cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno=
|
||||||
|
cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak=
|
||||||
|
cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84=
|
||||||
|
cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A=
|
||||||
|
cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E=
|
||||||
|
cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY=
|
||||||
|
cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=
|
||||||
|
cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=
|
||||||
|
cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k=
|
||||||
|
cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg=
|
||||||
|
cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=
|
||||||
|
cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=
|
||||||
|
cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0=
|
||||||
|
cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc=
|
||||||
|
cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ=
|
||||||
|
cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI=
|
||||||
|
cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08=
|
||||||
|
cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E=
|
||||||
|
cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=
|
||||||
|
cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=
|
||||||
|
cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=
|
||||||
|
cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ=
|
||||||
|
cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY=
|
||||||
|
cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo=
|
||||||
|
cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg=
|
||||||
|
cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw=
|
||||||
|
cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ=
|
||||||
|
cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=
|
||||||
|
cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=
|
||||||
|
cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=
|
||||||
|
cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=
|
||||||
|
cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=
|
||||||
|
cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=
|
||||||
|
cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0=
|
||||||
|
cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
|
||||||
|
cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
|
||||||
|
cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8=
|
||||||
|
cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM=
|
||||||
|
cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU=
|
||||||
|
cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE=
|
||||||
|
cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc=
|
||||||
|
cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI=
|
||||||
|
cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss=
|
||||||
|
cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE=
|
||||||
|
cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE=
|
||||||
|
cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g=
|
||||||
|
cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4=
|
||||||
|
cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8=
|
||||||
|
cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM=
|
||||||
|
cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU=
|
||||||
|
cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4=
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
|
cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
|
||||||
|
cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
|
||||||
|
cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI=
|
||||||
|
cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y=
|
||||||
|
cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss=
|
||||||
|
cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc=
|
||||||
|
cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA=
|
||||||
|
cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=
|
||||||
|
cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=
|
||||||
|
cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0=
|
||||||
|
cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk=
|
||||||
|
cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q=
|
||||||
|
cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U=
|
||||||
|
cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg=
|
||||||
|
cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590=
|
||||||
|
cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8=
|
||||||
|
cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI=
|
||||||
|
cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk=
|
||||||
|
cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk=
|
||||||
|
cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE=
|
||||||
|
cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU=
|
||||||
|
cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc=
|
||||||
|
cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U=
|
||||||
|
cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA=
|
||||||
|
cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg=
|
||||||
|
cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s=
|
||||||
|
cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU=
|
||||||
|
cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM=
|
||||||
|
cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk=
|
||||||
|
cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA=
|
||||||
|
cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI=
|
||||||
|
cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=
|
||||||
|
cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=
|
||||||
|
cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4=
|
||||||
|
cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI=
|
||||||
|
cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y=
|
||||||
|
cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs=
|
||||||
|
cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM=
|
||||||
|
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||||
|
cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
|
||||||
|
cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
|
||||||
|
cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
|
||||||
|
cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE=
|
||||||
|
cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=
|
||||||
|
cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
|
||||||
|
cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=
|
||||||
|
cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI=
|
||||||
|
cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||||
|
cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||||
|
cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
|
||||||
|
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||||
|
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||||
|
cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
|
||||||
|
cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
|
||||||
|
cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w=
|
||||||
|
cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM=
|
||||||
|
cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg=
|
||||||
|
cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo=
|
||||||
|
cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4=
|
||||||
|
cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM=
|
||||||
|
cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA=
|
||||||
|
cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4=
|
||||||
|
cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
|
||||||
|
cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
|
||||||
|
cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI=
|
||||||
|
cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s=
|
||||||
|
cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0=
|
||||||
|
cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=
|
||||||
|
cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=
|
||||||
|
cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE=
|
||||||
|
cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM=
|
||||||
|
cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0=
|
||||||
|
cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8=
|
||||||
|
cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4=
|
||||||
|
cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=
|
||||||
|
cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=
|
||||||
|
cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE=
|
||||||
|
cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw=
|
||||||
|
cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=
|
||||||
|
cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=
|
||||||
|
cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0=
|
||||||
|
cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA=
|
||||||
|
cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE=
|
||||||
|
cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M=
|
||||||
|
cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38=
|
||||||
|
cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w=
|
||||||
|
cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8=
|
||||||
|
cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI=
|
||||||
|
cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=
|
||||||
|
cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=
|
||||||
|
cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM=
|
||||||
|
cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY=
|
||||||
|
cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA=
|
||||||
|
cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A=
|
||||||
|
cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ=
|
||||||
|
cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs=
|
||||||
|
cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE=
|
||||||
|
cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s=
|
||||||
|
cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI=
|
||||||
|
cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4=
|
||||||
|
cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=
|
||||||
|
cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=
|
||||||
|
cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c=
|
||||||
|
cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8=
|
||||||
cloud.google.com/go/datastore v1.2.0/go.mod h1:FKd9dFEjRui5757lkOJ7z/eKtL74o5hsbY0o6Z0ozz8=
|
cloud.google.com/go/datastore v1.2.0/go.mod h1:FKd9dFEjRui5757lkOJ7z/eKtL74o5hsbY0o6Z0ozz8=
|
||||||
|
cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
|
||||||
|
cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
|
||||||
|
cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g=
|
||||||
|
cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4=
|
||||||
|
cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs=
|
||||||
|
cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww=
|
||||||
|
cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q=
|
||||||
|
cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c=
|
||||||
|
cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s=
|
||||||
|
cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI=
|
||||||
|
cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ=
|
||||||
|
cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g=
|
||||||
|
cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=
|
||||||
|
cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=
|
||||||
|
cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=
|
||||||
|
cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek=
|
||||||
|
cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0=
|
||||||
|
cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM=
|
||||||
|
cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4=
|
||||||
|
cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE=
|
||||||
|
cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4=
|
||||||
|
cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM=
|
||||||
|
cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q=
|
||||||
|
cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4=
|
||||||
|
cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI=
|
||||||
|
cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=
|
||||||
|
cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=
|
||||||
|
cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k=
|
||||||
|
cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4=
|
||||||
|
cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM=
|
||||||
|
cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs=
|
||||||
|
cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E=
|
||||||
|
cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=
|
||||||
|
cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
|
||||||
|
cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE=
|
||||||
|
cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE=
|
||||||
|
cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
|
||||||
|
cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
|
||||||
|
cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc=
|
||||||
|
cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY=
|
||||||
|
cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk=
|
||||||
|
cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU=
|
||||||
|
cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI=
|
||||||
|
cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8=
|
||||||
|
cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M=
|
||||||
|
cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4=
|
||||||
|
cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc=
|
||||||
|
cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw=
|
||||||
|
cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw=
|
||||||
|
cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY=
|
||||||
|
cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI=
|
||||||
|
cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w=
|
||||||
|
cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI=
|
||||||
|
cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs=
|
||||||
|
cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg=
|
||||||
|
cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4=
|
||||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||||
|
cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
|
||||||
|
cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
|
||||||
|
cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY=
|
||||||
|
cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08=
|
||||||
|
cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw=
|
||||||
|
cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA=
|
||||||
|
cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c=
|
||||||
|
cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE=
|
||||||
|
cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=
|
||||||
|
cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=
|
||||||
|
cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w=
|
||||||
|
cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM=
|
||||||
|
cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0=
|
||||||
|
cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s=
|
||||||
|
cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60=
|
||||||
|
cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo=
|
||||||
|
cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg=
|
||||||
|
cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=
|
||||||
|
cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=
|
||||||
|
cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw=
|
||||||
|
cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw=
|
||||||
|
cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=
|
||||||
|
cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
|
||||||
|
cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E=
|
||||||
|
cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw=
|
||||||
|
cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY=
|
||||||
|
cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA=
|
||||||
|
cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI=
|
||||||
|
cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y=
|
||||||
|
cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw=
|
||||||
|
cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
|
||||||
|
cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8=
|
||||||
|
cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM=
|
||||||
|
cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o=
|
||||||
|
cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo=
|
||||||
|
cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY=
|
||||||
|
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||||
|
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
|
||||||
|
cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc=
|
||||||
|
cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
|
||||||
|
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
|
||||||
|
cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY=
|
||||||
|
cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY=
|
||||||
|
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
|
||||||
|
cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8=
|
||||||
|
cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk=
|
||||||
|
cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
|
||||||
|
cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc=
|
||||||
|
cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A=
|
||||||
|
cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk=
|
||||||
|
cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo=
|
||||||
|
cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74=
|
||||||
|
cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ=
|
||||||
|
cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM=
|
||||||
|
cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY=
|
||||||
|
cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4=
|
||||||
|
cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw=
|
||||||
|
cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs=
|
||||||
|
cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g=
|
||||||
|
cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o=
|
||||||
|
cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE=
|
||||||
|
cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk=
|
||||||
|
cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg=
|
||||||
|
cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0=
|
||||||
|
cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w=
|
||||||
|
cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24=
|
||||||
|
cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI=
|
||||||
|
cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM=
|
||||||
|
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
|
||||||
|
cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
|
||||||
|
cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE=
|
||||||
|
cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8=
|
||||||
|
cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY=
|
||||||
|
cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0=
|
||||||
|
cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
|
||||||
|
cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=
|
||||||
|
cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo=
|
||||||
|
cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc=
|
||||||
|
cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw=
|
||||||
|
cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M=
|
||||||
|
cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE=
|
||||||
|
cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc=
|
||||||
|
cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
|
||||||
|
cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ=
|
||||||
|
cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc=
|
||||||
|
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
|
||||||
|
cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE=
|
||||||
|
cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM=
|
||||||
|
cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA=
|
||||||
|
cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak=
|
||||||
|
cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI=
|
||||||
|
cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw=
|
||||||
|
cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY=
|
||||||
|
cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
|
||||||
|
cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
|
||||||
|
cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I=
|
||||||
|
cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig=
|
||||||
|
cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=
|
||||||
|
cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=
|
||||||
|
cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA=
|
||||||
|
cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY=
|
||||||
|
cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM=
|
||||||
|
cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA=
|
||||||
|
cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=
|
||||||
|
cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=
|
||||||
|
cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8=
|
||||||
|
cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI=
|
||||||
|
cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo=
|
||||||
|
cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA=
|
||||||
|
cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk=
|
||||||
|
cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4=
|
||||||
|
cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w=
|
||||||
|
cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw=
|
||||||
|
cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM=
|
||||||
|
cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
|
||||||
|
cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
|
||||||
|
cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM=
|
||||||
|
cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8=
|
||||||
|
cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E=
|
||||||
|
cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM=
|
||||||
|
cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E=
|
||||||
|
cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8=
|
||||||
|
cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4=
|
||||||
|
cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY=
|
||||||
|
cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0=
|
||||||
|
cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=
|
||||||
|
cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=
|
||||||
|
cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k=
|
||||||
|
cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU=
|
||||||
|
cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ=
|
||||||
|
cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=
|
||||||
|
cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=
|
||||||
|
cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA=
|
||||||
|
cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0=
|
||||||
|
cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE=
|
||||||
|
cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ=
|
||||||
|
cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8=
|
||||||
|
cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4=
|
||||||
|
cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs=
|
||||||
|
cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI=
|
||||||
|
cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk=
|
||||||
|
cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA=
|
||||||
|
cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk=
|
||||||
|
cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ=
|
||||||
|
cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8=
|
||||||
|
cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE=
|
||||||
|
cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc=
|
||||||
|
cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc=
|
||||||
|
cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M=
|
||||||
|
cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE=
|
||||||
|
cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=
|
||||||
|
cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=
|
||||||
|
cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo=
|
||||||
|
cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw=
|
||||||
|
cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw=
|
||||||
|
cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc=
|
||||||
|
cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE=
|
||||||
|
cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=
|
||||||
|
cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=
|
||||||
|
cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70=
|
||||||
|
cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo=
|
||||||
|
cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs=
|
||||||
|
cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs=
|
||||||
|
cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=
|
||||||
|
cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=
|
||||||
|
cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk=
|
||||||
|
cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I=
|
||||||
|
cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg=
|
||||||
|
cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE=
|
||||||
|
cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw=
|
||||||
|
cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc=
|
||||||
|
cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0=
|
||||||
|
cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=
|
||||||
|
cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=
|
||||||
|
cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg=
|
||||||
|
cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs=
|
||||||
|
cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA=
|
||||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
|
cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg=
|
||||||
|
cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k=
|
||||||
|
cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM=
|
||||||
|
cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0=
|
||||||
|
cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
|
||||||
|
cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
|
||||||
|
cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
|
||||||
|
cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo=
|
||||||
|
cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE=
|
||||||
|
cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U=
|
||||||
|
cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA=
|
||||||
|
cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c=
|
||||||
|
cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU=
|
||||||
|
cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=
|
||||||
|
cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=
|
||||||
|
cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac=
|
||||||
|
cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE=
|
||||||
|
cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=
|
||||||
|
cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=
|
||||||
|
cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs=
|
||||||
|
cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70=
|
||||||
|
cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ=
|
||||||
|
cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA=
|
||||||
|
cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=
|
||||||
|
cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=
|
||||||
|
cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA=
|
||||||
|
cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM=
|
||||||
|
cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ=
|
||||||
|
cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg=
|
||||||
|
cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA=
|
||||||
|
cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0=
|
||||||
|
cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots=
|
||||||
|
cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo=
|
||||||
|
cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI=
|
||||||
|
cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8=
|
||||||
|
cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU=
|
||||||
|
cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg=
|
||||||
|
cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA=
|
||||||
|
cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw=
|
||||||
|
cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=
|
||||||
|
cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=
|
||||||
|
cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc=
|
||||||
|
cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y=
|
||||||
|
cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14=
|
||||||
|
cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE=
|
||||||
|
cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do=
|
||||||
|
cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo=
|
||||||
|
cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM=
|
||||||
|
cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg=
|
||||||
|
cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=
|
||||||
|
cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=
|
||||||
|
cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk=
|
||||||
|
cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44=
|
||||||
|
cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc=
|
||||||
|
cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc=
|
||||||
|
cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo=
|
||||||
|
cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
|
||||||
|
cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4=
|
||||||
|
cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4=
|
||||||
|
cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU=
|
||||||
|
cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw=
|
||||||
|
cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=
|
||||||
|
cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=
|
||||||
|
cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=
|
||||||
|
cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q=
|
||||||
|
cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA=
|
||||||
|
cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8=
|
||||||
|
cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0=
|
||||||
|
cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA=
|
||||||
|
cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=
|
||||||
|
cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=
|
||||||
|
cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk=
|
||||||
|
cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk=
|
||||||
|
cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0=
|
||||||
|
cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag=
|
||||||
|
cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ=
|
||||||
|
cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU=
|
||||||
|
cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s=
|
||||||
|
cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc=
|
||||||
|
cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk=
|
||||||
|
cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=
|
||||||
|
cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=
|
||||||
|
cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4=
|
||||||
|
cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U=
|
||||||
|
cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY=
|
||||||
|
cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s=
|
||||||
|
cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ=
|
||||||
|
cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco=
|
||||||
|
cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo=
|
||||||
|
cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc=
|
||||||
|
cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4=
|
||||||
|
cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E=
|
||||||
|
cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU=
|
||||||
|
cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec=
|
||||||
|
cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA=
|
||||||
|
cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4=
|
||||||
|
cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw=
|
||||||
|
cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A=
|
||||||
|
cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g=
|
||||||
cloud.google.com/go/spanner v1.2.0/go.mod h1:LfwGAsK42Yz8IeLsd/oagGFBqTXt3xVWtm8/KD2vrEI=
|
cloud.google.com/go/spanner v1.2.0/go.mod h1:LfwGAsK42Yz8IeLsd/oagGFBqTXt3xVWtm8/KD2vrEI=
|
||||||
|
cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
|
||||||
|
cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
|
||||||
|
cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0=
|
||||||
|
cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco=
|
||||||
|
cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0=
|
||||||
|
cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI=
|
||||||
|
cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo=
|
||||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
|
cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w=
|
||||||
|
cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I=
|
||||||
|
cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4=
|
||||||
|
cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw=
|
||||||
|
cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA=
|
||||||
|
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
|
||||||
|
cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
|
||||||
|
cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM=
|
||||||
|
cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA=
|
||||||
|
cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c=
|
||||||
|
cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24=
|
||||||
|
cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8=
|
||||||
|
cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4=
|
||||||
|
cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc=
|
||||||
|
cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk=
|
||||||
|
cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ=
|
||||||
|
cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg=
|
||||||
|
cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM=
|
||||||
|
cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E=
|
||||||
|
cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28=
|
||||||
|
cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y=
|
||||||
|
cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA=
|
||||||
|
cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk=
|
||||||
|
cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk=
|
||||||
|
cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs=
|
||||||
|
cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg=
|
||||||
|
cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=
|
||||||
|
cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=
|
||||||
|
cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs=
|
||||||
|
cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk=
|
||||||
|
cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw=
|
||||||
|
cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk=
|
||||||
|
cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ=
|
||||||
|
cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ=
|
||||||
|
cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU=
|
||||||
|
cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
|
||||||
|
cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=
|
||||||
|
cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M=
|
||||||
|
cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU=
|
||||||
|
cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU=
|
||||||
|
cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo=
|
||||||
|
cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=
|
||||||
|
cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=
|
||||||
|
cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=
|
||||||
|
cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY=
|
||||||
|
cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E=
|
||||||
|
cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY=
|
||||||
|
cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0=
|
||||||
|
cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU=
|
||||||
|
cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE=
|
||||||
|
cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g=
|
||||||
|
cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc=
|
||||||
|
cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY=
|
||||||
|
cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro=
|
||||||
|
cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208=
|
||||||
|
cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8=
|
||||||
|
cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY=
|
||||||
|
cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0=
|
||||||
|
cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w=
|
||||||
|
cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8=
|
||||||
|
cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes=
|
||||||
|
cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs=
|
||||||
|
cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=
|
||||||
|
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
|
||||||
|
cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc=
|
||||||
|
cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A=
|
||||||
|
cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg=
|
||||||
|
cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc=
|
||||||
|
cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo=
|
||||||
|
cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ=
|
||||||
|
cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng=
|
||||||
|
cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg=
|
||||||
|
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
|
||||||
|
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
|
||||||
|
cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M=
|
||||||
|
cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA=
|
||||||
|
cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw=
|
||||||
|
cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
github.com/Azure/go-autorest v0.0.0-20200908233159-fafe600ec8bd/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/Azure/go-autorest v0.0.0-20200908233159-fafe600ec8bd/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
|
|
@ -63,13 +672,14 @@ github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqR
|
||||||
github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA=
|
github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA=
|
||||||
github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
||||||
github.com/che-incubator/kubernetes-image-puller-operator v0.0.0-20210929175054-0128446f5af7 h1:E18RJWMhzdbW5C27h4/TgTD5n5I+r43EO+8YJ9/fqRU=
|
github.com/che-incubator/kubernetes-image-puller-operator v0.0.0-20210929175054-0128446f5af7 h1:E18RJWMhzdbW5C27h4/TgTD5n5I+r43EO+8YJ9/fqRU=
|
||||||
github.com/che-incubator/kubernetes-image-puller-operator v0.0.0-20210929175054-0128446f5af7/go.mod h1:2x0FwJwxUaaKmAHF5+DIq27BmL2d0mkwWOQiXYHmQQM=
|
github.com/che-incubator/kubernetes-image-puller-operator v0.0.0-20210929175054-0128446f5af7/go.mod h1:2x0FwJwxUaaKmAHF5+DIq27BmL2d0mkwWOQiXYHmQQM=
|
||||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||||
github.com/cncf/udpa/go v0.0.0-20200327203949-e8cd3a4bb307/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20200327203949-e8cd3a4bb307/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
|
|
@ -195,11 +805,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-migrate/migrate/v4 v4.10.0 h1:76R6UL3BGnDTpYeittMtfpaNvGBH5zMZatO/fCzIjWo=
|
github.com/golang-migrate/migrate/v4 v4.10.0 h1:76R6UL3BGnDTpYeittMtfpaNvGBH5zMZatO/fCzIjWo=
|
||||||
github.com/golang-migrate/migrate/v4 v4.10.0/go.mod h1:Llx0NRzBKs/zbR/Pc0huEpJA2195sJVkGU5dCyjQ678=
|
github.com/golang-migrate/migrate/v4 v4.10.0/go.mod h1:Llx0NRzBKs/zbR/Pc0huEpJA2195sJVkGU5dCyjQ678=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
|
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
|
||||||
|
|
@ -223,8 +831,15 @@ github.com/google/martian v0.0.0-20180813215018-c223d6f7955e/go.mod h1:9I4somxYT
|
||||||
github.com/google/pprof v0.0.0-20180921154107-7dadf64105bb h1:+A9aN/lFi+7+d3iTfMIy1sLWAJ1YQe5jfZVgSPhk53I=
|
github.com/google/pprof v0.0.0-20180921154107-7dadf64105bb h1:+A9aN/lFi+7+d3iTfMIy1sLWAJ1YQe5jfZVgSPhk53I=
|
||||||
github.com/google/pprof v0.0.0-20180921154107-7dadf64105bb/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20180921154107-7dadf64105bb/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
||||||
|
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/gnostic v0.4.2/go.mod h1:P0d+GwDcJO8XvMi7aihGGl/CkivFa9JX/V/FfjyYzI0=
|
github.com/googleapis/gnostic v0.4.2/go.mod h1:P0d+GwDcJO8XvMi7aihGGl/CkivFa9JX/V/FfjyYzI0=
|
||||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||||
|
|
@ -392,10 +1007,10 @@ 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/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/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/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||||
|
|
@ -469,6 +1084,7 @@ go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/exp v0.0.0-20190426190305-956cc1757749/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190426190305-956cc1757749/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
|
@ -481,6 +1097,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
|
@ -490,7 +1108,7 @@ golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73r
|
||||||
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/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-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-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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
|
@ -515,26 +1133,37 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
|
golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
|
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
|
||||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
|
@ -579,18 +1208,33 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/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-20210615035016-665e8c7367d1/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
|
@ -599,7 +1243,16 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
|
@ -614,6 +1267,7 @@ golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
|
@ -642,25 +1296,101 @@ golang.org/x/tools v0.0.0-20200609164405-eb789aa7ce50/go.mod h1:EkVYQZoAsY45+roY
|
||||||
golang.org/x/tools v0.0.0-20200612220849-54c614fe050c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200612220849-54c614fe050c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||||
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
|
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
|
||||||
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
|
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
|
||||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5 h1:YejJbGvoWsTXHab4OKNrzk27Dr7s4lPLnewbHue1+gM=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200128133413-58ce757ed39b/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200612171551-7676ae05be11/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200701001935-0939c5918c31/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
|
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
|
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
|
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
|
google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||||
|
google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||||
|
google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||||
|
google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||||
|
google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=
|
||||||
|
google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
|
||||||
|
google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=
|
||||||
|
google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
|
||||||
|
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
|
||||||
|
google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
|
||||||
|
google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
|
||||||
|
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo=
|
||||||
|
google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||||
|
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||||
|
google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||||
|
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
|
||||||
|
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=
|
||||||
|
google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
|
||||||
|
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||||
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||||
|
google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
|
||||||
|
google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
|
||||||
|
google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
|
||||||
|
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||||
|
google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY=
|
||||||
|
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
|
||||||
|
google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
|
||||||
|
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y=
|
||||||
|
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
||||||
|
google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ=
|
||||||
|
google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789 h1:NMiUjDZiD6qDVeBOzpImftxXzQHCp2Y2QLdmaqU9MRk=
|
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789 h1:NMiUjDZiD6qDVeBOzpImftxXzQHCp2Y2QLdmaqU9MRk=
|
||||||
|
|
@ -683,8 +1413,8 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76
|
||||||
gopkg.in/tomb.v1 v1.0.0-20161208151619-d5d1b5820637/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20161208151619-d5d1b5820637/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
language: go
|
|
||||||
go:
|
|
||||||
- "1.x"
|
|
||||||
- master
|
|
||||||
env:
|
|
||||||
- TAGS=""
|
|
||||||
- TAGS="-tags purego"
|
|
||||||
script: go test $TAGS -v ./...
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
# xxhash
|
# xxhash
|
||||||
|
|
||||||
[](https://godoc.org/github.com/cespare/xxhash)
|
[](https://pkg.go.dev/github.com/cespare/xxhash/v2)
|
||||||
[](https://travis-ci.org/cespare/xxhash)
|
[](https://github.com/cespare/xxhash/actions/workflows/test.yml)
|
||||||
|
|
||||||
xxhash is a Go implementation of the 64-bit
|
xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
|
||||||
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
|
||||||
high-quality hashing algorithm that is much faster than anything in the Go
|
high-quality hashing algorithm that is much faster than anything in the Go
|
||||||
standard library.
|
standard library.
|
||||||
|
|
||||||
|
|
@ -25,31 +24,49 @@ func (*Digest) WriteString(string) (int, error)
|
||||||
func (*Digest) Sum64() uint64
|
func (*Digest) Sum64() uint64
|
||||||
```
|
```
|
||||||
|
|
||||||
This implementation provides a fast pure-Go implementation and an even faster
|
The package is written with optimized pure Go and also contains even faster
|
||||||
assembly implementation for amd64.
|
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
|
||||||
|
opts into using the Go code even on those architectures.
|
||||||
|
|
||||||
|
[xxHash]: http://cyan4973.github.io/xxHash/
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
This package is in a module and the latest code is in version 2 of the module.
|
||||||
|
You need a version of Go with at least "minimal module compatibility" to use
|
||||||
|
github.com/cespare/xxhash/v2:
|
||||||
|
|
||||||
|
* 1.9.7+ for Go 1.9
|
||||||
|
* 1.10.3+ for Go 1.10
|
||||||
|
* Go 1.11 or later
|
||||||
|
|
||||||
|
I recommend using the latest release of Go.
|
||||||
|
|
||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
Here are some quick benchmarks comparing the pure-Go and assembly
|
Here are some quick benchmarks comparing the pure-Go and assembly
|
||||||
implementations of Sum64.
|
implementations of Sum64.
|
||||||
|
|
||||||
| input size | purego | asm |
|
| input size | purego | asm |
|
||||||
| --- | --- | --- |
|
| ---------- | --------- | --------- |
|
||||||
| 5 B | 979.66 MB/s | 1291.17 MB/s |
|
| 4 B | 1.3 GB/s | 1.2 GB/s |
|
||||||
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
|
| 16 B | 2.9 GB/s | 3.5 GB/s |
|
||||||
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
|
| 100 B | 6.9 GB/s | 8.1 GB/s |
|
||||||
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
|
| 4 KB | 11.7 GB/s | 16.7 GB/s |
|
||||||
|
| 10 MB | 12.0 GB/s | 17.3 GB/s |
|
||||||
|
|
||||||
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
|
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
|
||||||
the following commands under Go 1.11.2:
|
CPU using the following commands under Go 1.19.2:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
|
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||||
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||||
```
|
```
|
||||||
|
|
||||||
## Projects using this package
|
## Projects using this package
|
||||||
|
|
||||||
- [InfluxDB](https://github.com/influxdata/influxdb)
|
- [InfluxDB](https://github.com/influxdata/influxdb)
|
||||||
- [Prometheus](https://github.com/prometheus/prometheus)
|
- [Prometheus](https://github.com/prometheus/prometheus)
|
||||||
|
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||||
- [FreeCache](https://github.com/coocood/freecache)
|
- [FreeCache](https://github.com/coocood/freecache)
|
||||||
|
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -eu -o pipefail
|
||||||
|
|
||||||
|
# Small convenience script for running the tests with various combinations of
|
||||||
|
# arch/tags. This assumes we're running on amd64 and have qemu available.
|
||||||
|
|
||||||
|
go test ./...
|
||||||
|
go test -tags purego ./...
|
||||||
|
GOARCH=arm64 go test
|
||||||
|
GOARCH=arm64 go test -tags purego
|
||||||
|
|
@ -16,19 +16,11 @@ const (
|
||||||
prime5 uint64 = 2870177450012600261
|
prime5 uint64 = 2870177450012600261
|
||||||
)
|
)
|
||||||
|
|
||||||
// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
|
// Store the primes in an array as well.
|
||||||
// possible in the Go code is worth a small (but measurable) performance boost
|
//
|
||||||
// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
|
// The consts are used when possible in Go code to avoid MOVs but we need a
|
||||||
// convenience in the Go code in a few places where we need to intentionally
|
// contiguous array of the assembly code.
|
||||||
// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
|
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
|
||||||
// result overflows a uint64).
|
|
||||||
var (
|
|
||||||
prime1v = prime1
|
|
||||||
prime2v = prime2
|
|
||||||
prime3v = prime3
|
|
||||||
prime4v = prime4
|
|
||||||
prime5v = prime5
|
|
||||||
)
|
|
||||||
|
|
||||||
// Digest implements hash.Hash64.
|
// Digest implements hash.Hash64.
|
||||||
type Digest struct {
|
type Digest struct {
|
||||||
|
|
@ -50,10 +42,10 @@ func New() *Digest {
|
||||||
|
|
||||||
// Reset clears the Digest's state so that it can be reused.
|
// Reset clears the Digest's state so that it can be reused.
|
||||||
func (d *Digest) Reset() {
|
func (d *Digest) Reset() {
|
||||||
d.v1 = prime1v + prime2
|
d.v1 = primes[0] + prime2
|
||||||
d.v2 = prime2
|
d.v2 = prime2
|
||||||
d.v3 = 0
|
d.v3 = 0
|
||||||
d.v4 = -prime1v
|
d.v4 = -primes[0]
|
||||||
d.total = 0
|
d.total = 0
|
||||||
d.n = 0
|
d.n = 0
|
||||||
}
|
}
|
||||||
|
|
@ -69,21 +61,23 @@ func (d *Digest) Write(b []byte) (n int, err error) {
|
||||||
n = len(b)
|
n = len(b)
|
||||||
d.total += uint64(n)
|
d.total += uint64(n)
|
||||||
|
|
||||||
|
memleft := d.mem[d.n&(len(d.mem)-1):]
|
||||||
|
|
||||||
if d.n+n < 32 {
|
if d.n+n < 32 {
|
||||||
// This new data doesn't even fill the current block.
|
// This new data doesn't even fill the current block.
|
||||||
copy(d.mem[d.n:], b)
|
copy(memleft, b)
|
||||||
d.n += n
|
d.n += n
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.n > 0 {
|
if d.n > 0 {
|
||||||
// Finish off the partial block.
|
// Finish off the partial block.
|
||||||
copy(d.mem[d.n:], b)
|
c := copy(memleft, b)
|
||||||
d.v1 = round(d.v1, u64(d.mem[0:8]))
|
d.v1 = round(d.v1, u64(d.mem[0:8]))
|
||||||
d.v2 = round(d.v2, u64(d.mem[8:16]))
|
d.v2 = round(d.v2, u64(d.mem[8:16]))
|
||||||
d.v3 = round(d.v3, u64(d.mem[16:24]))
|
d.v3 = round(d.v3, u64(d.mem[16:24]))
|
||||||
d.v4 = round(d.v4, u64(d.mem[24:32]))
|
d.v4 = round(d.v4, u64(d.mem[24:32]))
|
||||||
b = b[32-d.n:]
|
b = b[c:]
|
||||||
d.n = 0
|
d.n = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,21 +127,20 @@ func (d *Digest) Sum64() uint64 {
|
||||||
|
|
||||||
h += d.total
|
h += d.total
|
||||||
|
|
||||||
i, end := 0, d.n
|
b := d.mem[:d.n&(len(d.mem)-1)]
|
||||||
for ; i+8 <= end; i += 8 {
|
for ; len(b) >= 8; b = b[8:] {
|
||||||
k1 := round(0, u64(d.mem[i:i+8]))
|
k1 := round(0, u64(b[:8]))
|
||||||
h ^= k1
|
h ^= k1
|
||||||
h = rol27(h)*prime1 + prime4
|
h = rol27(h)*prime1 + prime4
|
||||||
}
|
}
|
||||||
if i+4 <= end {
|
if len(b) >= 4 {
|
||||||
h ^= uint64(u32(d.mem[i:i+4])) * prime1
|
h ^= uint64(u32(b[:4])) * prime1
|
||||||
h = rol23(h)*prime2 + prime3
|
h = rol23(h)*prime2 + prime3
|
||||||
i += 4
|
b = b[4:]
|
||||||
}
|
}
|
||||||
for i < end {
|
for ; len(b) > 0; b = b[1:] {
|
||||||
h ^= uint64(d.mem[i]) * prime5
|
h ^= uint64(b[0]) * prime5
|
||||||
h = rol11(h) * prime1
|
h = rol11(h) * prime1
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h ^= h >> 33
|
h ^= h >> 33
|
||||||
|
|
@ -193,7 +186,6 @@ func (d *Digest) UnmarshalBinary(b []byte) error {
|
||||||
b, d.v4 = consumeUint64(b)
|
b, d.v4 = consumeUint64(b)
|
||||||
b, d.total = consumeUint64(b)
|
b, d.total = consumeUint64(b)
|
||||||
copy(d.mem[:], b)
|
copy(d.mem[:], b)
|
||||||
b = b[len(d.mem):]
|
|
||||||
d.n = int(d.total % uint64(len(d.mem)))
|
d.n = int(d.total % uint64(len(d.mem)))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,215 +1,209 @@
|
||||||
|
//go:build !appengine && gc && !purego
|
||||||
// +build !appengine
|
// +build !appengine
|
||||||
// +build gc
|
// +build gc
|
||||||
// +build !purego
|
// +build !purego
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// Register allocation:
|
// Registers:
|
||||||
// AX h
|
#define h AX
|
||||||
// CX pointer to advance through b
|
#define d AX
|
||||||
// DX n
|
#define p SI // pointer to advance through b
|
||||||
// BX loop end
|
#define n DX
|
||||||
// R8 v1, k1
|
#define end BX // loop end
|
||||||
// R9 v2
|
#define v1 R8
|
||||||
// R10 v3
|
#define v2 R9
|
||||||
// R11 v4
|
#define v3 R10
|
||||||
// R12 tmp
|
#define v4 R11
|
||||||
// R13 prime1v
|
#define x R12
|
||||||
// R14 prime2v
|
#define prime1 R13
|
||||||
// R15 prime4v
|
#define prime2 R14
|
||||||
|
#define prime4 DI
|
||||||
|
|
||||||
// round reads from and advances the buffer pointer in CX.
|
#define round(acc, x) \
|
||||||
// It assumes that R13 has prime1v and R14 has prime2v.
|
IMULQ prime2, x \
|
||||||
#define round(r) \
|
ADDQ x, acc \
|
||||||
MOVQ (CX), R12 \
|
ROLQ $31, acc \
|
||||||
ADDQ $8, CX \
|
IMULQ prime1, acc
|
||||||
IMULQ R14, R12 \
|
|
||||||
ADDQ R12, r \
|
|
||||||
ROLQ $31, r \
|
|
||||||
IMULQ R13, r
|
|
||||||
|
|
||||||
// mergeRound applies a merge round on the two registers acc and val.
|
// round0 performs the operation x = round(0, x).
|
||||||
// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v.
|
#define round0(x) \
|
||||||
#define mergeRound(acc, val) \
|
IMULQ prime2, x \
|
||||||
IMULQ R14, val \
|
ROLQ $31, x \
|
||||||
ROLQ $31, val \
|
IMULQ prime1, x
|
||||||
IMULQ R13, val \
|
|
||||||
XORQ val, acc \
|
// mergeRound applies a merge round on the two registers acc and x.
|
||||||
IMULQ R13, acc \
|
// It assumes that prime1, prime2, and prime4 have been loaded.
|
||||||
ADDQ R15, acc
|
#define mergeRound(acc, x) \
|
||||||
|
round0(x) \
|
||||||
|
XORQ x, acc \
|
||||||
|
IMULQ prime1, acc \
|
||||||
|
ADDQ prime4, acc
|
||||||
|
|
||||||
|
// blockLoop processes as many 32-byte blocks as possible,
|
||||||
|
// updating v1, v2, v3, and v4. It assumes that there is at least one block
|
||||||
|
// to process.
|
||||||
|
#define blockLoop() \
|
||||||
|
loop: \
|
||||||
|
MOVQ +0(p), x \
|
||||||
|
round(v1, x) \
|
||||||
|
MOVQ +8(p), x \
|
||||||
|
round(v2, x) \
|
||||||
|
MOVQ +16(p), x \
|
||||||
|
round(v3, x) \
|
||||||
|
MOVQ +24(p), x \
|
||||||
|
round(v4, x) \
|
||||||
|
ADDQ $32, p \
|
||||||
|
CMPQ p, end \
|
||||||
|
JLE loop
|
||||||
|
|
||||||
// func Sum64(b []byte) uint64
|
// func Sum64(b []byte) uint64
|
||||||
TEXT ·Sum64(SB), NOSPLIT, $0-32
|
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
|
||||||
// Load fixed primes.
|
// Load fixed primes.
|
||||||
MOVQ ·prime1v(SB), R13
|
MOVQ ·primes+0(SB), prime1
|
||||||
MOVQ ·prime2v(SB), R14
|
MOVQ ·primes+8(SB), prime2
|
||||||
MOVQ ·prime4v(SB), R15
|
MOVQ ·primes+24(SB), prime4
|
||||||
|
|
||||||
// Load slice.
|
// Load slice.
|
||||||
MOVQ b_base+0(FP), CX
|
MOVQ b_base+0(FP), p
|
||||||
MOVQ b_len+8(FP), DX
|
MOVQ b_len+8(FP), n
|
||||||
LEAQ (CX)(DX*1), BX
|
LEAQ (p)(n*1), end
|
||||||
|
|
||||||
// The first loop limit will be len(b)-32.
|
// The first loop limit will be len(b)-32.
|
||||||
SUBQ $32, BX
|
SUBQ $32, end
|
||||||
|
|
||||||
// Check whether we have at least one block.
|
// Check whether we have at least one block.
|
||||||
CMPQ DX, $32
|
CMPQ n, $32
|
||||||
JLT noBlocks
|
JLT noBlocks
|
||||||
|
|
||||||
// Set up initial state (v1, v2, v3, v4).
|
// Set up initial state (v1, v2, v3, v4).
|
||||||
MOVQ R13, R8
|
MOVQ prime1, v1
|
||||||
ADDQ R14, R8
|
ADDQ prime2, v1
|
||||||
MOVQ R14, R9
|
MOVQ prime2, v2
|
||||||
XORQ R10, R10
|
XORQ v3, v3
|
||||||
XORQ R11, R11
|
XORQ v4, v4
|
||||||
SUBQ R13, R11
|
SUBQ prime1, v4
|
||||||
|
|
||||||
// Loop until CX > BX.
|
blockLoop()
|
||||||
blockLoop:
|
|
||||||
round(R8)
|
|
||||||
round(R9)
|
|
||||||
round(R10)
|
|
||||||
round(R11)
|
|
||||||
|
|
||||||
CMPQ CX, BX
|
MOVQ v1, h
|
||||||
JLE blockLoop
|
ROLQ $1, h
|
||||||
|
MOVQ v2, x
|
||||||
|
ROLQ $7, x
|
||||||
|
ADDQ x, h
|
||||||
|
MOVQ v3, x
|
||||||
|
ROLQ $12, x
|
||||||
|
ADDQ x, h
|
||||||
|
MOVQ v4, x
|
||||||
|
ROLQ $18, x
|
||||||
|
ADDQ x, h
|
||||||
|
|
||||||
MOVQ R8, AX
|
mergeRound(h, v1)
|
||||||
ROLQ $1, AX
|
mergeRound(h, v2)
|
||||||
MOVQ R9, R12
|
mergeRound(h, v3)
|
||||||
ROLQ $7, R12
|
mergeRound(h, v4)
|
||||||
ADDQ R12, AX
|
|
||||||
MOVQ R10, R12
|
|
||||||
ROLQ $12, R12
|
|
||||||
ADDQ R12, AX
|
|
||||||
MOVQ R11, R12
|
|
||||||
ROLQ $18, R12
|
|
||||||
ADDQ R12, AX
|
|
||||||
|
|
||||||
mergeRound(AX, R8)
|
|
||||||
mergeRound(AX, R9)
|
|
||||||
mergeRound(AX, R10)
|
|
||||||
mergeRound(AX, R11)
|
|
||||||
|
|
||||||
JMP afterBlocks
|
JMP afterBlocks
|
||||||
|
|
||||||
noBlocks:
|
noBlocks:
|
||||||
MOVQ ·prime5v(SB), AX
|
MOVQ ·primes+32(SB), h
|
||||||
|
|
||||||
afterBlocks:
|
afterBlocks:
|
||||||
ADDQ DX, AX
|
ADDQ n, h
|
||||||
|
|
||||||
// Right now BX has len(b)-32, and we want to loop until CX > len(b)-8.
|
ADDQ $24, end
|
||||||
ADDQ $24, BX
|
CMPQ p, end
|
||||||
|
JG try4
|
||||||
|
|
||||||
CMPQ CX, BX
|
loop8:
|
||||||
JG fourByte
|
MOVQ (p), x
|
||||||
|
ADDQ $8, p
|
||||||
|
round0(x)
|
||||||
|
XORQ x, h
|
||||||
|
ROLQ $27, h
|
||||||
|
IMULQ prime1, h
|
||||||
|
ADDQ prime4, h
|
||||||
|
|
||||||
wordLoop:
|
CMPQ p, end
|
||||||
// Calculate k1.
|
JLE loop8
|
||||||
MOVQ (CX), R8
|
|
||||||
ADDQ $8, CX
|
|
||||||
IMULQ R14, R8
|
|
||||||
ROLQ $31, R8
|
|
||||||
IMULQ R13, R8
|
|
||||||
|
|
||||||
XORQ R8, AX
|
try4:
|
||||||
ROLQ $27, AX
|
ADDQ $4, end
|
||||||
IMULQ R13, AX
|
CMPQ p, end
|
||||||
ADDQ R15, AX
|
JG try1
|
||||||
|
|
||||||
CMPQ CX, BX
|
MOVL (p), x
|
||||||
JLE wordLoop
|
ADDQ $4, p
|
||||||
|
IMULQ prime1, x
|
||||||
|
XORQ x, h
|
||||||
|
|
||||||
fourByte:
|
ROLQ $23, h
|
||||||
ADDQ $4, BX
|
IMULQ prime2, h
|
||||||
CMPQ CX, BX
|
ADDQ ·primes+16(SB), h
|
||||||
JG singles
|
|
||||||
|
|
||||||
MOVL (CX), R8
|
try1:
|
||||||
ADDQ $4, CX
|
ADDQ $4, end
|
||||||
IMULQ R13, R8
|
CMPQ p, end
|
||||||
XORQ R8, AX
|
|
||||||
|
|
||||||
ROLQ $23, AX
|
|
||||||
IMULQ R14, AX
|
|
||||||
ADDQ ·prime3v(SB), AX
|
|
||||||
|
|
||||||
singles:
|
|
||||||
ADDQ $4, BX
|
|
||||||
CMPQ CX, BX
|
|
||||||
JGE finalize
|
JGE finalize
|
||||||
|
|
||||||
singlesLoop:
|
loop1:
|
||||||
MOVBQZX (CX), R12
|
MOVBQZX (p), x
|
||||||
ADDQ $1, CX
|
ADDQ $1, p
|
||||||
IMULQ ·prime5v(SB), R12
|
IMULQ ·primes+32(SB), x
|
||||||
XORQ R12, AX
|
XORQ x, h
|
||||||
|
ROLQ $11, h
|
||||||
|
IMULQ prime1, h
|
||||||
|
|
||||||
ROLQ $11, AX
|
CMPQ p, end
|
||||||
IMULQ R13, AX
|
JL loop1
|
||||||
|
|
||||||
CMPQ CX, BX
|
|
||||||
JL singlesLoop
|
|
||||||
|
|
||||||
finalize:
|
finalize:
|
||||||
MOVQ AX, R12
|
MOVQ h, x
|
||||||
SHRQ $33, R12
|
SHRQ $33, x
|
||||||
XORQ R12, AX
|
XORQ x, h
|
||||||
IMULQ R14, AX
|
IMULQ prime2, h
|
||||||
MOVQ AX, R12
|
MOVQ h, x
|
||||||
SHRQ $29, R12
|
SHRQ $29, x
|
||||||
XORQ R12, AX
|
XORQ x, h
|
||||||
IMULQ ·prime3v(SB), AX
|
IMULQ ·primes+16(SB), h
|
||||||
MOVQ AX, R12
|
MOVQ h, x
|
||||||
SHRQ $32, R12
|
SHRQ $32, x
|
||||||
XORQ R12, AX
|
XORQ x, h
|
||||||
|
|
||||||
MOVQ AX, ret+24(FP)
|
MOVQ h, ret+24(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// writeBlocks uses the same registers as above except that it uses AX to store
|
|
||||||
// the d pointer.
|
|
||||||
|
|
||||||
// func writeBlocks(d *Digest, b []byte) int
|
// func writeBlocks(d *Digest, b []byte) int
|
||||||
TEXT ·writeBlocks(SB), NOSPLIT, $0-40
|
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||||
// Load fixed primes needed for round.
|
// Load fixed primes needed for round.
|
||||||
MOVQ ·prime1v(SB), R13
|
MOVQ ·primes+0(SB), prime1
|
||||||
MOVQ ·prime2v(SB), R14
|
MOVQ ·primes+8(SB), prime2
|
||||||
|
|
||||||
// Load slice.
|
// Load slice.
|
||||||
MOVQ b_base+8(FP), CX
|
MOVQ b_base+8(FP), p
|
||||||
MOVQ b_len+16(FP), DX
|
MOVQ b_len+16(FP), n
|
||||||
LEAQ (CX)(DX*1), BX
|
LEAQ (p)(n*1), end
|
||||||
SUBQ $32, BX
|
SUBQ $32, end
|
||||||
|
|
||||||
// Load vN from d.
|
// Load vN from d.
|
||||||
MOVQ d+0(FP), AX
|
MOVQ s+0(FP), d
|
||||||
MOVQ 0(AX), R8 // v1
|
MOVQ 0(d), v1
|
||||||
MOVQ 8(AX), R9 // v2
|
MOVQ 8(d), v2
|
||||||
MOVQ 16(AX), R10 // v3
|
MOVQ 16(d), v3
|
||||||
MOVQ 24(AX), R11 // v4
|
MOVQ 24(d), v4
|
||||||
|
|
||||||
// We don't need to check the loop condition here; this function is
|
// We don't need to check the loop condition here; this function is
|
||||||
// always called with at least one block of data to process.
|
// always called with at least one block of data to process.
|
||||||
blockLoop:
|
blockLoop()
|
||||||
round(R8)
|
|
||||||
round(R9)
|
|
||||||
round(R10)
|
|
||||||
round(R11)
|
|
||||||
|
|
||||||
CMPQ CX, BX
|
|
||||||
JLE blockLoop
|
|
||||||
|
|
||||||
// Copy vN back to d.
|
// Copy vN back to d.
|
||||||
MOVQ R8, 0(AX)
|
MOVQ v1, 0(d)
|
||||||
MOVQ R9, 8(AX)
|
MOVQ v2, 8(d)
|
||||||
MOVQ R10, 16(AX)
|
MOVQ v3, 16(d)
|
||||||
MOVQ R11, 24(AX)
|
MOVQ v4, 24(d)
|
||||||
|
|
||||||
// The number of bytes written is CX minus the old base pointer.
|
// The number of bytes written is p minus the old base pointer.
|
||||||
SUBQ b_base+8(FP), CX
|
SUBQ b_base+8(FP), p
|
||||||
MOVQ CX, ret+32(FP)
|
MOVQ p, ret+32(FP)
|
||||||
|
|
||||||
RET
|
RET
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,183 @@
|
||||||
|
//go:build !appengine && gc && !purego
|
||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !purego
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// Registers:
|
||||||
|
#define digest R1
|
||||||
|
#define h R2 // return value
|
||||||
|
#define p R3 // input pointer
|
||||||
|
#define n R4 // input length
|
||||||
|
#define nblocks R5 // n / 32
|
||||||
|
#define prime1 R7
|
||||||
|
#define prime2 R8
|
||||||
|
#define prime3 R9
|
||||||
|
#define prime4 R10
|
||||||
|
#define prime5 R11
|
||||||
|
#define v1 R12
|
||||||
|
#define v2 R13
|
||||||
|
#define v3 R14
|
||||||
|
#define v4 R15
|
||||||
|
#define x1 R20
|
||||||
|
#define x2 R21
|
||||||
|
#define x3 R22
|
||||||
|
#define x4 R23
|
||||||
|
|
||||||
|
#define round(acc, x) \
|
||||||
|
MADD prime2, acc, x, acc \
|
||||||
|
ROR $64-31, acc \
|
||||||
|
MUL prime1, acc
|
||||||
|
|
||||||
|
// round0 performs the operation x = round(0, x).
|
||||||
|
#define round0(x) \
|
||||||
|
MUL prime2, x \
|
||||||
|
ROR $64-31, x \
|
||||||
|
MUL prime1, x
|
||||||
|
|
||||||
|
#define mergeRound(acc, x) \
|
||||||
|
round0(x) \
|
||||||
|
EOR x, acc \
|
||||||
|
MADD acc, prime4, prime1, acc
|
||||||
|
|
||||||
|
// blockLoop processes as many 32-byte blocks as possible,
|
||||||
|
// updating v1, v2, v3, and v4. It assumes that n >= 32.
|
||||||
|
#define blockLoop() \
|
||||||
|
LSR $5, n, nblocks \
|
||||||
|
PCALIGN $16 \
|
||||||
|
loop: \
|
||||||
|
LDP.P 16(p), (x1, x2) \
|
||||||
|
LDP.P 16(p), (x3, x4) \
|
||||||
|
round(v1, x1) \
|
||||||
|
round(v2, x2) \
|
||||||
|
round(v3, x3) \
|
||||||
|
round(v4, x4) \
|
||||||
|
SUB $1, nblocks \
|
||||||
|
CBNZ nblocks, loop
|
||||||
|
|
||||||
|
// func Sum64(b []byte) uint64
|
||||||
|
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
|
||||||
|
LDP b_base+0(FP), (p, n)
|
||||||
|
|
||||||
|
LDP ·primes+0(SB), (prime1, prime2)
|
||||||
|
LDP ·primes+16(SB), (prime3, prime4)
|
||||||
|
MOVD ·primes+32(SB), prime5
|
||||||
|
|
||||||
|
CMP $32, n
|
||||||
|
CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
|
||||||
|
BLT afterLoop
|
||||||
|
|
||||||
|
ADD prime1, prime2, v1
|
||||||
|
MOVD prime2, v2
|
||||||
|
MOVD $0, v3
|
||||||
|
NEG prime1, v4
|
||||||
|
|
||||||
|
blockLoop()
|
||||||
|
|
||||||
|
ROR $64-1, v1, x1
|
||||||
|
ROR $64-7, v2, x2
|
||||||
|
ADD x1, x2
|
||||||
|
ROR $64-12, v3, x3
|
||||||
|
ROR $64-18, v4, x4
|
||||||
|
ADD x3, x4
|
||||||
|
ADD x2, x4, h
|
||||||
|
|
||||||
|
mergeRound(h, v1)
|
||||||
|
mergeRound(h, v2)
|
||||||
|
mergeRound(h, v3)
|
||||||
|
mergeRound(h, v4)
|
||||||
|
|
||||||
|
afterLoop:
|
||||||
|
ADD n, h
|
||||||
|
|
||||||
|
TBZ $4, n, try8
|
||||||
|
LDP.P 16(p), (x1, x2)
|
||||||
|
|
||||||
|
round0(x1)
|
||||||
|
|
||||||
|
// NOTE: here and below, sequencing the EOR after the ROR (using a
|
||||||
|
// rotated register) is worth a small but measurable speedup for small
|
||||||
|
// inputs.
|
||||||
|
ROR $64-27, h
|
||||||
|
EOR x1 @> 64-27, h, h
|
||||||
|
MADD h, prime4, prime1, h
|
||||||
|
|
||||||
|
round0(x2)
|
||||||
|
ROR $64-27, h
|
||||||
|
EOR x2 @> 64-27, h, h
|
||||||
|
MADD h, prime4, prime1, h
|
||||||
|
|
||||||
|
try8:
|
||||||
|
TBZ $3, n, try4
|
||||||
|
MOVD.P 8(p), x1
|
||||||
|
|
||||||
|
round0(x1)
|
||||||
|
ROR $64-27, h
|
||||||
|
EOR x1 @> 64-27, h, h
|
||||||
|
MADD h, prime4, prime1, h
|
||||||
|
|
||||||
|
try4:
|
||||||
|
TBZ $2, n, try2
|
||||||
|
MOVWU.P 4(p), x2
|
||||||
|
|
||||||
|
MUL prime1, x2
|
||||||
|
ROR $64-23, h
|
||||||
|
EOR x2 @> 64-23, h, h
|
||||||
|
MADD h, prime3, prime2, h
|
||||||
|
|
||||||
|
try2:
|
||||||
|
TBZ $1, n, try1
|
||||||
|
MOVHU.P 2(p), x3
|
||||||
|
AND $255, x3, x1
|
||||||
|
LSR $8, x3, x2
|
||||||
|
|
||||||
|
MUL prime5, x1
|
||||||
|
ROR $64-11, h
|
||||||
|
EOR x1 @> 64-11, h, h
|
||||||
|
MUL prime1, h
|
||||||
|
|
||||||
|
MUL prime5, x2
|
||||||
|
ROR $64-11, h
|
||||||
|
EOR x2 @> 64-11, h, h
|
||||||
|
MUL prime1, h
|
||||||
|
|
||||||
|
try1:
|
||||||
|
TBZ $0, n, finalize
|
||||||
|
MOVBU (p), x4
|
||||||
|
|
||||||
|
MUL prime5, x4
|
||||||
|
ROR $64-11, h
|
||||||
|
EOR x4 @> 64-11, h, h
|
||||||
|
MUL prime1, h
|
||||||
|
|
||||||
|
finalize:
|
||||||
|
EOR h >> 33, h
|
||||||
|
MUL prime2, h
|
||||||
|
EOR h >> 29, h
|
||||||
|
MUL prime3, h
|
||||||
|
EOR h >> 32, h
|
||||||
|
|
||||||
|
MOVD h, ret+24(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func writeBlocks(d *Digest, b []byte) int
|
||||||
|
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||||
|
LDP ·primes+0(SB), (prime1, prime2)
|
||||||
|
|
||||||
|
// Load state. Assume v[1-4] are stored contiguously.
|
||||||
|
MOVD d+0(FP), digest
|
||||||
|
LDP 0(digest), (v1, v2)
|
||||||
|
LDP 16(digest), (v3, v4)
|
||||||
|
|
||||||
|
LDP b_base+8(FP), (p, n)
|
||||||
|
|
||||||
|
blockLoop()
|
||||||
|
|
||||||
|
// Store updated state.
|
||||||
|
STP (v1, v2), 0(digest)
|
||||||
|
STP (v3, v4), 16(digest)
|
||||||
|
|
||||||
|
BIC $31, n
|
||||||
|
MOVD n, ret+32(FP)
|
||||||
|
RET
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//go:build (amd64 || arm64) && !appengine && gc && !purego
|
||||||
|
// +build amd64 arm64
|
||||||
// +build !appengine
|
// +build !appengine
|
||||||
// +build gc
|
// +build gc
|
||||||
// +build !purego
|
// +build !purego
|
||||||
|
|
@ -10,4 +12,4 @@ package xxhash
|
||||||
func Sum64(b []byte) uint64
|
func Sum64(b []byte) uint64
|
||||||
|
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func writeBlocks(*Digest, []byte) int
|
func writeBlocks(d *Digest, b []byte) int
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
// +build !amd64 appengine !gc purego
|
//go:build (!amd64 && !arm64) || appengine || !gc || purego
|
||||||
|
// +build !amd64,!arm64 appengine !gc purego
|
||||||
|
|
||||||
package xxhash
|
package xxhash
|
||||||
|
|
||||||
|
|
@ -14,10 +15,10 @@ func Sum64(b []byte) uint64 {
|
||||||
var h uint64
|
var h uint64
|
||||||
|
|
||||||
if n >= 32 {
|
if n >= 32 {
|
||||||
v1 := prime1v + prime2
|
v1 := primes[0] + prime2
|
||||||
v2 := prime2
|
v2 := prime2
|
||||||
v3 := uint64(0)
|
v3 := uint64(0)
|
||||||
v4 := -prime1v
|
v4 := -primes[0]
|
||||||
for len(b) >= 32 {
|
for len(b) >= 32 {
|
||||||
v1 = round(v1, u64(b[0:8:len(b)]))
|
v1 = round(v1, u64(b[0:8:len(b)]))
|
||||||
v2 = round(v2, u64(b[8:16:len(b)]))
|
v2 = round(v2, u64(b[8:16:len(b)]))
|
||||||
|
|
@ -36,19 +37,18 @@ func Sum64(b []byte) uint64 {
|
||||||
|
|
||||||
h += uint64(n)
|
h += uint64(n)
|
||||||
|
|
||||||
i, end := 0, len(b)
|
for ; len(b) >= 8; b = b[8:] {
|
||||||
for ; i+8 <= end; i += 8 {
|
k1 := round(0, u64(b[:8]))
|
||||||
k1 := round(0, u64(b[i:i+8:len(b)]))
|
|
||||||
h ^= k1
|
h ^= k1
|
||||||
h = rol27(h)*prime1 + prime4
|
h = rol27(h)*prime1 + prime4
|
||||||
}
|
}
|
||||||
if i+4 <= end {
|
if len(b) >= 4 {
|
||||||
h ^= uint64(u32(b[i:i+4:len(b)])) * prime1
|
h ^= uint64(u32(b[:4])) * prime1
|
||||||
h = rol23(h)*prime2 + prime3
|
h = rol23(h)*prime2 + prime3
|
||||||
i += 4
|
b = b[4:]
|
||||||
}
|
}
|
||||||
for ; i < end; i++ {
|
for ; len(b) > 0; b = b[1:] {
|
||||||
h ^= uint64(b[i]) * prime5
|
h ^= uint64(b[0]) * prime5
|
||||||
h = rol11(h) * prime1
|
h = rol11(h) * prime1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build appengine
|
||||||
// +build appengine
|
// +build appengine
|
||||||
|
|
||||||
// This file contains the safe implementations of otherwise unsafe-using code.
|
// This file contains the safe implementations of otherwise unsafe-using code.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build !appengine
|
||||||
// +build !appengine
|
// +build !appengine
|
||||||
|
|
||||||
// This file encapsulates usage of unsafe.
|
// This file encapsulates usage of unsafe.
|
||||||
|
|
@ -6,41 +7,52 @@
|
||||||
package xxhash
|
package xxhash
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Notes:
|
|
||||||
//
|
|
||||||
// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ
|
|
||||||
// for some discussion about these unsafe conversions.
|
|
||||||
//
|
|
||||||
// In the future it's possible that compiler optimizations will make these
|
// In the future it's possible that compiler optimizations will make these
|
||||||
// unsafe operations unnecessary: https://golang.org/issue/2205.
|
// XxxString functions unnecessary by realizing that calls such as
|
||||||
|
// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205.
|
||||||
|
// If that happens, even if we keep these functions they can be replaced with
|
||||||
|
// the trivial safe code.
|
||||||
|
|
||||||
|
// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:
|
||||||
//
|
//
|
||||||
// Both of these wrapper functions still incur function call overhead since they
|
// var b []byte
|
||||||
// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write
|
// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||||
// for strings to squeeze out a bit more speed. Mid-stack inlining should
|
// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||||
// eventually fix this.
|
// bh.Len = len(s)
|
||||||
|
// bh.Cap = len(s)
|
||||||
|
//
|
||||||
|
// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough
|
||||||
|
// weight to this sequence of expressions that any function that uses it will
|
||||||
|
// not be inlined. Instead, the functions below use a different unsafe
|
||||||
|
// conversion designed to minimize the inliner weight and allow both to be
|
||||||
|
// inlined. There is also a test (TestInlining) which verifies that these are
|
||||||
|
// inlined.
|
||||||
|
//
|
||||||
|
// See https://github.com/golang/go/issues/42739 for discussion.
|
||||||
|
|
||||||
// Sum64String computes the 64-bit xxHash digest of s.
|
// Sum64String computes the 64-bit xxHash digest of s.
|
||||||
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
||||||
func Sum64String(s string) uint64 {
|
func Sum64String(s string) uint64 {
|
||||||
var b []byte
|
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
|
||||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
|
||||||
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
|
||||||
bh.Len = len(s)
|
|
||||||
bh.Cap = len(s)
|
|
||||||
return Sum64(b)
|
return Sum64(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteString adds more data to d. It always returns len(s), nil.
|
// WriteString adds more data to d. It always returns len(s), nil.
|
||||||
// It may be faster than Write([]byte(s)) by avoiding a copy.
|
// It may be faster than Write([]byte(s)) by avoiding a copy.
|
||||||
func (d *Digest) WriteString(s string) (n int, err error) {
|
func (d *Digest) WriteString(s string) (n int, err error) {
|
||||||
var b []byte
|
d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
|
||||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
// d.Write always returns len(s), nil.
|
||||||
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
// Ignoring the return output and returning these fixed values buys a
|
||||||
bh.Len = len(s)
|
// savings of 6 in the inliner's cost model.
|
||||||
bh.Cap = len(s)
|
return len(s), nil
|
||||||
return d.Write(b)
|
}
|
||||||
|
|
||||||
|
// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout
|
||||||
|
// of the first two words is the same as the layout of a string.
|
||||||
|
type sliceHeader struct {
|
||||||
|
s string
|
||||||
|
cap int
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,514 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package jsonpb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
protoV2 "google.golang.org/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"google.golang.org/protobuf/reflect/protoregistry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const wrapJSONUnmarshalV2 = false
|
||||||
|
|
||||||
|
// UnmarshalNext unmarshals the next JSON object from d into m.
|
||||||
|
func UnmarshalNext(d *json.Decoder, m proto.Message) error {
|
||||||
|
return new(Unmarshaler).UnmarshalNext(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals a JSON object from r into m.
|
||||||
|
func Unmarshal(r io.Reader, m proto.Message) error {
|
||||||
|
return new(Unmarshaler).Unmarshal(r, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalString unmarshals a JSON object from s into m.
|
||||||
|
func UnmarshalString(s string, m proto.Message) error {
|
||||||
|
return new(Unmarshaler).Unmarshal(strings.NewReader(s), m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshaler is a configurable object for converting from a JSON
|
||||||
|
// representation to a protocol buffer object.
|
||||||
|
type Unmarshaler struct {
|
||||||
|
// AllowUnknownFields specifies whether to allow messages to contain
|
||||||
|
// unknown JSON fields, as opposed to failing to unmarshal.
|
||||||
|
AllowUnknownFields bool
|
||||||
|
|
||||||
|
// AnyResolver is used to resolve the google.protobuf.Any well-known type.
|
||||||
|
// If unset, the global registry is used by default.
|
||||||
|
AnyResolver AnyResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONPBUnmarshaler is implemented by protobuf messages that customize the way
|
||||||
|
// they are unmarshaled from JSON. Messages that implement this should also
|
||||||
|
// implement JSONPBMarshaler so that the custom format can be produced.
|
||||||
|
//
|
||||||
|
// The JSON unmarshaling must follow the JSON to proto specification:
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||||
|
//
|
||||||
|
// Deprecated: Custom types should implement protobuf reflection instead.
|
||||||
|
type JSONPBUnmarshaler interface {
|
||||||
|
UnmarshalJSONPB(*Unmarshaler, []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals a JSON object from r into m.
|
||||||
|
func (u *Unmarshaler) Unmarshal(r io.Reader, m proto.Message) error {
|
||||||
|
return u.UnmarshalNext(json.NewDecoder(r), m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalNext unmarshals the next JSON object from d into m.
|
||||||
|
func (u *Unmarshaler) UnmarshalNext(d *json.Decoder, m proto.Message) error {
|
||||||
|
if m == nil {
|
||||||
|
return errors.New("invalid nil message")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the next JSON object from the stream.
|
||||||
|
raw := json.RawMessage{}
|
||||||
|
if err := d.Decode(&raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for custom unmarshalers first since they may not properly
|
||||||
|
// implement protobuf reflection that the logic below relies on.
|
||||||
|
if jsu, ok := m.(JSONPBUnmarshaler); ok {
|
||||||
|
return jsu.UnmarshalJSONPB(u, raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
mr := proto.MessageReflect(m)
|
||||||
|
|
||||||
|
// NOTE: For historical reasons, a top-level null is treated as a noop.
|
||||||
|
// This is incorrect, but kept for compatibility.
|
||||||
|
if string(raw) == "null" && mr.Descriptor().FullName() != "google.protobuf.Value" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if wrapJSONUnmarshalV2 {
|
||||||
|
// NOTE: If input message is non-empty, we need to preserve merge semantics
|
||||||
|
// of the old jsonpb implementation. These semantics are not supported by
|
||||||
|
// the protobuf JSON specification.
|
||||||
|
isEmpty := true
|
||||||
|
mr.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool {
|
||||||
|
isEmpty = false // at least one iteration implies non-empty
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if !isEmpty {
|
||||||
|
// Perform unmarshaling into a newly allocated, empty message.
|
||||||
|
mr = mr.New()
|
||||||
|
|
||||||
|
// Use a defer to copy all unmarshaled fields into the original message.
|
||||||
|
dst := proto.MessageReflect(m)
|
||||||
|
defer mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
||||||
|
dst.Set(fd, v)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal using the v2 JSON unmarshaler.
|
||||||
|
opts := protojson.UnmarshalOptions{
|
||||||
|
DiscardUnknown: u.AllowUnknownFields,
|
||||||
|
}
|
||||||
|
if u.AnyResolver != nil {
|
||||||
|
opts.Resolver = anyResolver{u.AnyResolver}
|
||||||
|
}
|
||||||
|
return opts.Unmarshal(raw, mr.Interface())
|
||||||
|
} else {
|
||||||
|
if err := u.unmarshalMessage(mr, raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return protoV2.CheckInitialized(mr.Interface())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error {
|
||||||
|
md := m.Descriptor()
|
||||||
|
fds := md.Fields()
|
||||||
|
|
||||||
|
if string(in) == "null" && md.FullName() != "google.protobuf.Value" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if jsu, ok := proto.MessageV1(m.Interface()).(JSONPBUnmarshaler); ok {
|
||||||
|
return jsu.UnmarshalJSONPB(u, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch wellKnownType(md.FullName()) {
|
||||||
|
case "Any":
|
||||||
|
var jsonObject map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonObject); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawTypeURL, ok := jsonObject["@type"]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("Any JSON doesn't have '@type'")
|
||||||
|
}
|
||||||
|
typeURL, err := unquoteString(string(rawTypeURL))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't unmarshal Any's '@type': %q", rawTypeURL)
|
||||||
|
}
|
||||||
|
m.Set(fds.ByNumber(1), protoreflect.ValueOfString(typeURL))
|
||||||
|
|
||||||
|
var m2 protoreflect.Message
|
||||||
|
if u.AnyResolver != nil {
|
||||||
|
mi, err := u.AnyResolver.Resolve(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m2 = proto.MessageReflect(mi)
|
||||||
|
} else {
|
||||||
|
mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
if err == protoregistry.NotFound {
|
||||||
|
return fmt.Errorf("could not resolve Any message type: %v", typeURL)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m2 = mt.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
if wellKnownType(m2.Descriptor().FullName()) != "" {
|
||||||
|
rawValue, ok := jsonObject["value"]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("Any JSON doesn't have 'value'")
|
||||||
|
}
|
||||||
|
if err := u.unmarshalMessage(m2, rawValue); err != nil {
|
||||||
|
return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete(jsonObject, "@type")
|
||||||
|
rawJSON, err := json.Marshal(jsonObject)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", err)
|
||||||
|
}
|
||||||
|
if err = u.unmarshalMessage(m2, rawJSON); err != nil {
|
||||||
|
return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rawWire, err := protoV2.Marshal(m2.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't marshal proto %v into Any.Value: %v", typeURL, err)
|
||||||
|
}
|
||||||
|
m.Set(fds.ByNumber(2), protoreflect.ValueOfBytes(rawWire))
|
||||||
|
return nil
|
||||||
|
case "BoolValue", "BytesValue", "StringValue",
|
||||||
|
"Int32Value", "UInt32Value", "FloatValue",
|
||||||
|
"Int64Value", "UInt64Value", "DoubleValue":
|
||||||
|
fd := fds.ByNumber(1)
|
||||||
|
v, err := u.unmarshalValue(m.NewField(fd), in, fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Set(fd, v)
|
||||||
|
return nil
|
||||||
|
case "Duration":
|
||||||
|
v, err := unquoteString(string(in))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d, err := time.ParseDuration(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("bad Duration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sec := d.Nanoseconds() / 1e9
|
||||||
|
nsec := d.Nanoseconds() % 1e9
|
||||||
|
m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec)))
|
||||||
|
m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec)))
|
||||||
|
return nil
|
||||||
|
case "Timestamp":
|
||||||
|
v, err := unquoteString(string(in))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t, err := time.Parse(time.RFC3339Nano, v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("bad Timestamp: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sec := t.Unix()
|
||||||
|
nsec := t.Nanosecond()
|
||||||
|
m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec)))
|
||||||
|
m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec)))
|
||||||
|
return nil
|
||||||
|
case "Value":
|
||||||
|
switch {
|
||||||
|
case string(in) == "null":
|
||||||
|
m.Set(fds.ByNumber(1), protoreflect.ValueOfEnum(0))
|
||||||
|
case string(in) == "true":
|
||||||
|
m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(true))
|
||||||
|
case string(in) == "false":
|
||||||
|
m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(false))
|
||||||
|
case hasPrefixAndSuffix('"', in, '"'):
|
||||||
|
s, err := unquoteString(string(in))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unrecognized type for Value %q", in)
|
||||||
|
}
|
||||||
|
m.Set(fds.ByNumber(3), protoreflect.ValueOfString(s))
|
||||||
|
case hasPrefixAndSuffix('[', in, ']'):
|
||||||
|
v := m.Mutable(fds.ByNumber(6))
|
||||||
|
return u.unmarshalMessage(v.Message(), in)
|
||||||
|
case hasPrefixAndSuffix('{', in, '}'):
|
||||||
|
v := m.Mutable(fds.ByNumber(5))
|
||||||
|
return u.unmarshalMessage(v.Message(), in)
|
||||||
|
default:
|
||||||
|
f, err := strconv.ParseFloat(string(in), 0)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unrecognized type for Value %q", in)
|
||||||
|
}
|
||||||
|
m.Set(fds.ByNumber(2), protoreflect.ValueOfFloat64(f))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case "ListValue":
|
||||||
|
var jsonArray []json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonArray); err != nil {
|
||||||
|
return fmt.Errorf("bad ListValue: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lv := m.Mutable(fds.ByNumber(1)).List()
|
||||||
|
for _, raw := range jsonArray {
|
||||||
|
ve := lv.NewElement()
|
||||||
|
if err := u.unmarshalMessage(ve.Message(), raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
lv.Append(ve)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case "Struct":
|
||||||
|
var jsonObject map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonObject); err != nil {
|
||||||
|
return fmt.Errorf("bad StructValue: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mv := m.Mutable(fds.ByNumber(1)).Map()
|
||||||
|
for key, raw := range jsonObject {
|
||||||
|
kv := protoreflect.ValueOf(key).MapKey()
|
||||||
|
vv := mv.NewValue()
|
||||||
|
if err := u.unmarshalMessage(vv.Message(), raw); err != nil {
|
||||||
|
return fmt.Errorf("bad value in StructValue for key %q: %v", key, err)
|
||||||
|
}
|
||||||
|
mv.Set(kv, vv)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonObject map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonObject); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle known fields.
|
||||||
|
for i := 0; i < fds.Len(); i++ {
|
||||||
|
fd := fds.Get(i)
|
||||||
|
if fd.IsWeak() && fd.Message().IsPlaceholder() {
|
||||||
|
continue // weak reference is not linked in
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for any raw JSON value associated with this field.
|
||||||
|
var raw json.RawMessage
|
||||||
|
name := string(fd.Name())
|
||||||
|
if fd.Kind() == protoreflect.GroupKind {
|
||||||
|
name = string(fd.Message().Name())
|
||||||
|
}
|
||||||
|
if v, ok := jsonObject[name]; ok {
|
||||||
|
delete(jsonObject, name)
|
||||||
|
raw = v
|
||||||
|
}
|
||||||
|
name = string(fd.JSONName())
|
||||||
|
if v, ok := jsonObject[name]; ok {
|
||||||
|
delete(jsonObject, name)
|
||||||
|
raw = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal the field value.
|
||||||
|
if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v, err := u.unmarshalValue(m.NewField(fd), raw, fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Set(fd, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle extension fields.
|
||||||
|
for name, raw := range jsonObject {
|
||||||
|
if !strings.HasPrefix(name, "[") || !strings.HasSuffix(name, "]") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the extension field by name.
|
||||||
|
xname := protoreflect.FullName(name[len("[") : len(name)-len("]")])
|
||||||
|
xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
|
||||||
|
if xt == nil && isMessageSet(md) {
|
||||||
|
xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
|
||||||
|
}
|
||||||
|
if xt == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(jsonObject, name)
|
||||||
|
fd := xt.TypeDescriptor()
|
||||||
|
if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
|
||||||
|
return fmt.Errorf("extension field %q does not extend message %q", xname, m.Descriptor().FullName())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal the field value.
|
||||||
|
if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v, err := u.unmarshalValue(m.NewField(fd), raw, fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Set(fd, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !u.AllowUnknownFields && len(jsonObject) > 0 {
|
||||||
|
for name := range jsonObject {
|
||||||
|
return fmt.Errorf("unknown field %q in %v", name, md.FullName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSingularWellKnownValue(fd protoreflect.FieldDescriptor) bool {
|
||||||
|
if md := fd.Message(); md != nil {
|
||||||
|
return md.FullName() == "google.protobuf.Value" && fd.Cardinality() != protoreflect.Repeated
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unmarshaler) unmarshalValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
|
||||||
|
switch {
|
||||||
|
case fd.IsList():
|
||||||
|
var jsonArray []json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonArray); err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
lv := v.List()
|
||||||
|
for _, raw := range jsonArray {
|
||||||
|
ve, err := u.unmarshalSingularValue(lv.NewElement(), raw, fd)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
lv.Append(ve)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case fd.IsMap():
|
||||||
|
var jsonObject map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonObject); err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
kfd := fd.MapKey()
|
||||||
|
vfd := fd.MapValue()
|
||||||
|
mv := v.Map()
|
||||||
|
for key, raw := range jsonObject {
|
||||||
|
var kv protoreflect.MapKey
|
||||||
|
if kfd.Kind() == protoreflect.StringKind {
|
||||||
|
kv = protoreflect.ValueOf(key).MapKey()
|
||||||
|
} else {
|
||||||
|
v, err := u.unmarshalSingularValue(kfd.Default(), []byte(key), kfd)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
kv = v.MapKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
vv, err := u.unmarshalSingularValue(mv.NewValue(), raw, vfd)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
mv.Set(kv, vv)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
default:
|
||||||
|
return u.unmarshalSingularValue(v, in, fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var nonFinite = map[string]float64{
|
||||||
|
`"NaN"`: math.NaN(),
|
||||||
|
`"Infinity"`: math.Inf(+1),
|
||||||
|
`"-Infinity"`: math.Inf(-1),
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unmarshaler) unmarshalSingularValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
|
||||||
|
switch fd.Kind() {
|
||||||
|
case protoreflect.BoolKind:
|
||||||
|
return unmarshalValue(in, new(bool))
|
||||||
|
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
|
||||||
|
return unmarshalValue(trimQuote(in), new(int32))
|
||||||
|
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
|
||||||
|
return unmarshalValue(trimQuote(in), new(int64))
|
||||||
|
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
|
||||||
|
return unmarshalValue(trimQuote(in), new(uint32))
|
||||||
|
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
|
||||||
|
return unmarshalValue(trimQuote(in), new(uint64))
|
||||||
|
case protoreflect.FloatKind:
|
||||||
|
if f, ok := nonFinite[string(in)]; ok {
|
||||||
|
return protoreflect.ValueOfFloat32(float32(f)), nil
|
||||||
|
}
|
||||||
|
return unmarshalValue(trimQuote(in), new(float32))
|
||||||
|
case protoreflect.DoubleKind:
|
||||||
|
if f, ok := nonFinite[string(in)]; ok {
|
||||||
|
return protoreflect.ValueOfFloat64(float64(f)), nil
|
||||||
|
}
|
||||||
|
return unmarshalValue(trimQuote(in), new(float64))
|
||||||
|
case protoreflect.StringKind:
|
||||||
|
return unmarshalValue(in, new(string))
|
||||||
|
case protoreflect.BytesKind:
|
||||||
|
return unmarshalValue(in, new([]byte))
|
||||||
|
case protoreflect.EnumKind:
|
||||||
|
if hasPrefixAndSuffix('"', in, '"') {
|
||||||
|
vd := fd.Enum().Values().ByName(protoreflect.Name(trimQuote(in)))
|
||||||
|
if vd == nil {
|
||||||
|
return v, fmt.Errorf("unknown value %q for enum %s", in, fd.Enum().FullName())
|
||||||
|
}
|
||||||
|
return protoreflect.ValueOfEnum(vd.Number()), nil
|
||||||
|
}
|
||||||
|
return unmarshalValue(in, new(protoreflect.EnumNumber))
|
||||||
|
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||||
|
err := u.unmarshalMessage(v.Message(), in)
|
||||||
|
return v, err
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalValue(in []byte, v interface{}) (protoreflect.Value, error) {
|
||||||
|
err := json.Unmarshal(in, v)
|
||||||
|
return protoreflect.ValueOf(reflect.ValueOf(v).Elem().Interface()), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func unquoteString(in string) (out string, err error) {
|
||||||
|
err = json.Unmarshal([]byte(in), &out)
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasPrefixAndSuffix(prefix byte, in []byte, suffix byte) bool {
|
||||||
|
if len(in) >= 2 && in[0] == prefix && in[len(in)-1] == suffix {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// trimQuote is like unquoteString but simply strips surrounding quotes.
|
||||||
|
// This is incorrect, but is behavior done by the legacy implementation.
|
||||||
|
func trimQuote(in []byte) []byte {
|
||||||
|
if len(in) >= 2 && in[0] == '"' && in[len(in)-1] == '"' {
|
||||||
|
in = in[1 : len(in)-1]
|
||||||
|
}
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,559 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package jsonpb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
protoV2 "google.golang.org/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"google.golang.org/protobuf/reflect/protoregistry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const wrapJSONMarshalV2 = false
|
||||||
|
|
||||||
|
// Marshaler is a configurable object for marshaling protocol buffer messages
|
||||||
|
// to the specified JSON representation.
|
||||||
|
type Marshaler struct {
|
||||||
|
// OrigName specifies whether to use the original protobuf name for fields.
|
||||||
|
OrigName bool
|
||||||
|
|
||||||
|
// EnumsAsInts specifies whether to render enum values as integers,
|
||||||
|
// as opposed to string values.
|
||||||
|
EnumsAsInts bool
|
||||||
|
|
||||||
|
// EmitDefaults specifies whether to render fields with zero values.
|
||||||
|
EmitDefaults bool
|
||||||
|
|
||||||
|
// Indent controls whether the output is compact or not.
|
||||||
|
// If empty, the output is compact JSON. Otherwise, every JSON object
|
||||||
|
// entry and JSON array value will be on its own line.
|
||||||
|
// Each line will be preceded by repeated copies of Indent, where the
|
||||||
|
// number of copies is the current indentation depth.
|
||||||
|
Indent string
|
||||||
|
|
||||||
|
// AnyResolver is used to resolve the google.protobuf.Any well-known type.
|
||||||
|
// If unset, the global registry is used by default.
|
||||||
|
AnyResolver AnyResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONPBMarshaler is implemented by protobuf messages that customize the
|
||||||
|
// way they are marshaled to JSON. Messages that implement this should also
|
||||||
|
// implement JSONPBUnmarshaler so that the custom format can be parsed.
|
||||||
|
//
|
||||||
|
// The JSON marshaling must follow the proto to JSON specification:
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||||
|
//
|
||||||
|
// Deprecated: Custom types should implement protobuf reflection instead.
|
||||||
|
type JSONPBMarshaler interface {
|
||||||
|
MarshalJSONPB(*Marshaler) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal serializes a protobuf message as JSON into w.
|
||||||
|
func (jm *Marshaler) Marshal(w io.Writer, m proto.Message) error {
|
||||||
|
b, err := jm.marshal(m)
|
||||||
|
if len(b) > 0 {
|
||||||
|
if _, err := w.Write(b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalToString serializes a protobuf message as JSON in string form.
|
||||||
|
func (jm *Marshaler) MarshalToString(m proto.Message) (string, error) {
|
||||||
|
b, err := jm.marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jm *Marshaler) marshal(m proto.Message) ([]byte, error) {
|
||||||
|
v := reflect.ValueOf(m)
|
||||||
|
if m == nil || (v.Kind() == reflect.Ptr && v.IsNil()) {
|
||||||
|
return nil, errors.New("Marshal called with nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for custom marshalers first since they may not properly
|
||||||
|
// implement protobuf reflection that the logic below relies on.
|
||||||
|
if jsm, ok := m.(JSONPBMarshaler); ok {
|
||||||
|
return jsm.MarshalJSONPB(jm)
|
||||||
|
}
|
||||||
|
|
||||||
|
if wrapJSONMarshalV2 {
|
||||||
|
opts := protojson.MarshalOptions{
|
||||||
|
UseProtoNames: jm.OrigName,
|
||||||
|
UseEnumNumbers: jm.EnumsAsInts,
|
||||||
|
EmitUnpopulated: jm.EmitDefaults,
|
||||||
|
Indent: jm.Indent,
|
||||||
|
}
|
||||||
|
if jm.AnyResolver != nil {
|
||||||
|
opts.Resolver = anyResolver{jm.AnyResolver}
|
||||||
|
}
|
||||||
|
return opts.Marshal(proto.MessageReflect(m).Interface())
|
||||||
|
} else {
|
||||||
|
// Check for unpopulated required fields first.
|
||||||
|
m2 := proto.MessageReflect(m)
|
||||||
|
if err := protoV2.CheckInitialized(m2.Interface()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := jsonWriter{Marshaler: jm}
|
||||||
|
err := w.marshalMessage(m2, "", "")
|
||||||
|
return w.buf, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonWriter struct {
|
||||||
|
*Marshaler
|
||||||
|
buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) write(s string) {
|
||||||
|
w.buf = append(w.buf, s...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalMessage(m protoreflect.Message, indent, typeURL string) error {
|
||||||
|
if jsm, ok := proto.MessageV1(m.Interface()).(JSONPBMarshaler); ok {
|
||||||
|
b, err := jsm.MarshalJSONPB(w.Marshaler)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if typeURL != "" {
|
||||||
|
// we are marshaling this object to an Any type
|
||||||
|
var js map[string]*json.RawMessage
|
||||||
|
if err = json.Unmarshal(b, &js); err != nil {
|
||||||
|
return fmt.Errorf("type %T produced invalid JSON: %v", m.Interface(), err)
|
||||||
|
}
|
||||||
|
turl, err := json.Marshal(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err)
|
||||||
|
}
|
||||||
|
js["@type"] = (*json.RawMessage)(&turl)
|
||||||
|
if b, err = json.Marshal(js); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.write(string(b))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
md := m.Descriptor()
|
||||||
|
fds := md.Fields()
|
||||||
|
|
||||||
|
// Handle well-known types.
|
||||||
|
const secondInNanos = int64(time.Second / time.Nanosecond)
|
||||||
|
switch wellKnownType(md.FullName()) {
|
||||||
|
case "Any":
|
||||||
|
return w.marshalAny(m, indent)
|
||||||
|
case "BoolValue", "BytesValue", "StringValue",
|
||||||
|
"Int32Value", "UInt32Value", "FloatValue",
|
||||||
|
"Int64Value", "UInt64Value", "DoubleValue":
|
||||||
|
fd := fds.ByNumber(1)
|
||||||
|
return w.marshalValue(fd, m.Get(fd), indent)
|
||||||
|
case "Duration":
|
||||||
|
const maxSecondsInDuration = 315576000000
|
||||||
|
// "Generated output always contains 0, 3, 6, or 9 fractional digits,
|
||||||
|
// depending on required precision."
|
||||||
|
s := m.Get(fds.ByNumber(1)).Int()
|
||||||
|
ns := m.Get(fds.ByNumber(2)).Int()
|
||||||
|
if s < -maxSecondsInDuration || s > maxSecondsInDuration {
|
||||||
|
return fmt.Errorf("seconds out of range %v", s)
|
||||||
|
}
|
||||||
|
if ns <= -secondInNanos || ns >= secondInNanos {
|
||||||
|
return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos)
|
||||||
|
}
|
||||||
|
if (s > 0 && ns < 0) || (s < 0 && ns > 0) {
|
||||||
|
return errors.New("signs of seconds and nanos do not match")
|
||||||
|
}
|
||||||
|
var sign string
|
||||||
|
if s < 0 || ns < 0 {
|
||||||
|
sign, s, ns = "-", -1*s, -1*ns
|
||||||
|
}
|
||||||
|
x := fmt.Sprintf("%s%d.%09d", sign, s, ns)
|
||||||
|
x = strings.TrimSuffix(x, "000")
|
||||||
|
x = strings.TrimSuffix(x, "000")
|
||||||
|
x = strings.TrimSuffix(x, ".000")
|
||||||
|
w.write(fmt.Sprintf(`"%vs"`, x))
|
||||||
|
return nil
|
||||||
|
case "Timestamp":
|
||||||
|
// "RFC 3339, where generated output will always be Z-normalized
|
||||||
|
// and uses 0, 3, 6 or 9 fractional digits."
|
||||||
|
s := m.Get(fds.ByNumber(1)).Int()
|
||||||
|
ns := m.Get(fds.ByNumber(2)).Int()
|
||||||
|
if ns < 0 || ns >= secondInNanos {
|
||||||
|
return fmt.Errorf("ns out of range [0, %v)", secondInNanos)
|
||||||
|
}
|
||||||
|
t := time.Unix(s, ns).UTC()
|
||||||
|
// time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
|
||||||
|
x := t.Format("2006-01-02T15:04:05.000000000")
|
||||||
|
x = strings.TrimSuffix(x, "000")
|
||||||
|
x = strings.TrimSuffix(x, "000")
|
||||||
|
x = strings.TrimSuffix(x, ".000")
|
||||||
|
w.write(fmt.Sprintf(`"%vZ"`, x))
|
||||||
|
return nil
|
||||||
|
case "Value":
|
||||||
|
// JSON value; which is a null, number, string, bool, object, or array.
|
||||||
|
od := md.Oneofs().Get(0)
|
||||||
|
fd := m.WhichOneof(od)
|
||||||
|
if fd == nil {
|
||||||
|
return errors.New("nil Value")
|
||||||
|
}
|
||||||
|
return w.marshalValue(fd, m.Get(fd), indent)
|
||||||
|
case "Struct", "ListValue":
|
||||||
|
// JSON object or array.
|
||||||
|
fd := fds.ByNumber(1)
|
||||||
|
return w.marshalValue(fd, m.Get(fd), indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.write("{")
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
firstField := true
|
||||||
|
if typeURL != "" {
|
||||||
|
if err := w.marshalTypeURL(indent, typeURL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
firstField = false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < fds.Len(); {
|
||||||
|
fd := fds.Get(i)
|
||||||
|
if od := fd.ContainingOneof(); od != nil {
|
||||||
|
fd = m.WhichOneof(od)
|
||||||
|
i += od.Fields().Len()
|
||||||
|
if fd == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
v := m.Get(fd)
|
||||||
|
|
||||||
|
if !m.Has(fd) {
|
||||||
|
if !w.EmitDefaults || fd.ContainingOneof() != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fd.Cardinality() != protoreflect.Repeated && (fd.Message() != nil || fd.Syntax() == protoreflect.Proto2) {
|
||||||
|
v = protoreflect.Value{} // use "null" for singular messages or proto2 scalars
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !firstField {
|
||||||
|
w.writeComma()
|
||||||
|
}
|
||||||
|
if err := w.marshalField(fd, v, indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
firstField = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle proto2 extensions.
|
||||||
|
if md.ExtensionRanges().Len() > 0 {
|
||||||
|
// Collect a sorted list of all extension descriptor and values.
|
||||||
|
type ext struct {
|
||||||
|
desc protoreflect.FieldDescriptor
|
||||||
|
val protoreflect.Value
|
||||||
|
}
|
||||||
|
var exts []ext
|
||||||
|
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
||||||
|
if fd.IsExtension() {
|
||||||
|
exts = append(exts, ext{fd, v})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
sort.Slice(exts, func(i, j int) bool {
|
||||||
|
return exts[i].desc.Number() < exts[j].desc.Number()
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, ext := range exts {
|
||||||
|
if !firstField {
|
||||||
|
w.writeComma()
|
||||||
|
}
|
||||||
|
if err := w.marshalField(ext.desc, ext.val, indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
firstField = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
}
|
||||||
|
w.write("}")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) writeComma() {
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(",\n")
|
||||||
|
} else {
|
||||||
|
w.write(",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalAny(m protoreflect.Message, indent string) error {
|
||||||
|
// "If the Any contains a value that has a special JSON mapping,
|
||||||
|
// it will be converted as follows: {"@type": xxx, "value": yyy}.
|
||||||
|
// Otherwise, the value will be converted into a JSON object,
|
||||||
|
// and the "@type" field will be inserted to indicate the actual data type."
|
||||||
|
md := m.Descriptor()
|
||||||
|
typeURL := m.Get(md.Fields().ByNumber(1)).String()
|
||||||
|
rawVal := m.Get(md.Fields().ByNumber(2)).Bytes()
|
||||||
|
|
||||||
|
var m2 protoreflect.Message
|
||||||
|
if w.AnyResolver != nil {
|
||||||
|
mi, err := w.AnyResolver.Resolve(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m2 = proto.MessageReflect(mi)
|
||||||
|
} else {
|
||||||
|
mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m2 = mt.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := protoV2.Unmarshal(rawVal, m2.Interface()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if wellKnownType(m2.Descriptor().FullName()) == "" {
|
||||||
|
return w.marshalMessage(m2, indent, typeURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.write("{")
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
}
|
||||||
|
if err := w.marshalTypeURL(indent, typeURL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.writeComma()
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
w.write(`"value": `)
|
||||||
|
} else {
|
||||||
|
w.write(`"value":`)
|
||||||
|
}
|
||||||
|
if err := w.marshalMessage(m2, indent+w.Indent, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
}
|
||||||
|
w.write("}")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalTypeURL(indent, typeURL string) error {
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
w.write(`"@type":`)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(" ")
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.write(string(b))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshalField writes field description and value to the Writer.
|
||||||
|
func (w *jsonWriter) marshalField(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
w.write(`"`)
|
||||||
|
switch {
|
||||||
|
case fd.IsExtension():
|
||||||
|
// For message set, use the fname of the message as the extension name.
|
||||||
|
name := string(fd.FullName())
|
||||||
|
if isMessageSet(fd.ContainingMessage()) {
|
||||||
|
name = strings.TrimSuffix(name, ".message_set_extension")
|
||||||
|
}
|
||||||
|
|
||||||
|
w.write("[" + name + "]")
|
||||||
|
case w.OrigName:
|
||||||
|
name := string(fd.Name())
|
||||||
|
if fd.Kind() == protoreflect.GroupKind {
|
||||||
|
name = string(fd.Message().Name())
|
||||||
|
}
|
||||||
|
w.write(name)
|
||||||
|
default:
|
||||||
|
w.write(string(fd.JSONName()))
|
||||||
|
}
|
||||||
|
w.write(`":`)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(" ")
|
||||||
|
}
|
||||||
|
return w.marshalValue(fd, v, indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
|
||||||
|
switch {
|
||||||
|
case fd.IsList():
|
||||||
|
w.write("[")
|
||||||
|
comma := ""
|
||||||
|
lv := v.List()
|
||||||
|
for i := 0; i < lv.Len(); i++ {
|
||||||
|
w.write(comma)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
if err := w.marshalSingularValue(fd, lv.Get(i), indent+w.Indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
comma = ","
|
||||||
|
}
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
w.write("]")
|
||||||
|
return nil
|
||||||
|
case fd.IsMap():
|
||||||
|
kfd := fd.MapKey()
|
||||||
|
vfd := fd.MapValue()
|
||||||
|
mv := v.Map()
|
||||||
|
|
||||||
|
// Collect a sorted list of all map keys and values.
|
||||||
|
type entry struct{ key, val protoreflect.Value }
|
||||||
|
var entries []entry
|
||||||
|
mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
|
||||||
|
entries = append(entries, entry{k.Value(), v})
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
sort.Slice(entries, func(i, j int) bool {
|
||||||
|
switch kfd.Kind() {
|
||||||
|
case protoreflect.BoolKind:
|
||||||
|
return !entries[i].key.Bool() && entries[j].key.Bool()
|
||||||
|
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
|
||||||
|
return entries[i].key.Int() < entries[j].key.Int()
|
||||||
|
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
|
||||||
|
return entries[i].key.Uint() < entries[j].key.Uint()
|
||||||
|
case protoreflect.StringKind:
|
||||||
|
return entries[i].key.String() < entries[j].key.String()
|
||||||
|
default:
|
||||||
|
panic("invalid kind")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
w.write(`{`)
|
||||||
|
comma := ""
|
||||||
|
for _, entry := range entries {
|
||||||
|
w.write(comma)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := fmt.Sprint(entry.key.Interface())
|
||||||
|
b, err := json.Marshal(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.write(string(b))
|
||||||
|
|
||||||
|
w.write(`:`)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(` `)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.marshalSingularValue(vfd, entry.val, indent+w.Indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
comma = ","
|
||||||
|
}
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
w.write(`}`)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return w.marshalSingularValue(fd, v, indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalSingularValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
|
||||||
|
switch {
|
||||||
|
case !v.IsValid():
|
||||||
|
w.write("null")
|
||||||
|
return nil
|
||||||
|
case fd.Message() != nil:
|
||||||
|
return w.marshalMessage(v.Message(), indent+w.Indent, "")
|
||||||
|
case fd.Enum() != nil:
|
||||||
|
if fd.Enum().FullName() == "google.protobuf.NullValue" {
|
||||||
|
w.write("null")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vd := fd.Enum().Values().ByNumber(v.Enum())
|
||||||
|
if vd == nil || w.EnumsAsInts {
|
||||||
|
w.write(strconv.Itoa(int(v.Enum())))
|
||||||
|
} else {
|
||||||
|
w.write(`"` + string(vd.Name()) + `"`)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
switch v.Interface().(type) {
|
||||||
|
case float32, float64:
|
||||||
|
switch {
|
||||||
|
case math.IsInf(v.Float(), +1):
|
||||||
|
w.write(`"Infinity"`)
|
||||||
|
return nil
|
||||||
|
case math.IsInf(v.Float(), -1):
|
||||||
|
w.write(`"-Infinity"`)
|
||||||
|
return nil
|
||||||
|
case math.IsNaN(v.Float()):
|
||||||
|
w.write(`"NaN"`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case int64, uint64:
|
||||||
|
w.write(fmt.Sprintf(`"%d"`, v.Interface()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(v.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.write(string(b))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package jsonpb provides functionality to marshal and unmarshal between a
|
||||||
|
// protocol buffer message and JSON. It follows the specification at
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/proto3#json.
|
||||||
|
//
|
||||||
|
// Do not rely on the default behavior of the standard encoding/json package
|
||||||
|
// when called on generated message types as it does not operate correctly.
|
||||||
|
//
|
||||||
|
// Deprecated: Use the "google.golang.org/protobuf/encoding/protojson"
|
||||||
|
// package instead.
|
||||||
|
package jsonpb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"google.golang.org/protobuf/reflect/protoregistry"
|
||||||
|
"google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnyResolver takes a type URL, present in an Any message,
|
||||||
|
// and resolves it into an instance of the associated message.
|
||||||
|
type AnyResolver interface {
|
||||||
|
Resolve(typeURL string) (proto.Message, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type anyResolver struct{ AnyResolver }
|
||||||
|
|
||||||
|
func (r anyResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {
|
||||||
|
return r.FindMessageByURL(string(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r anyResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) {
|
||||||
|
m, err := r.Resolve(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return protoimpl.X.MessageTypeOf(m), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r anyResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
|
||||||
|
return protoregistry.GlobalTypes.FindExtensionByName(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r anyResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
|
||||||
|
return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wellKnownType(s protoreflect.FullName) string {
|
||||||
|
if s.Parent() == "google.protobuf" {
|
||||||
|
switch s.Name() {
|
||||||
|
case "Empty", "Any",
|
||||||
|
"BoolValue", "BytesValue", "StringValue",
|
||||||
|
"Int32Value", "UInt32Value", "FloatValue",
|
||||||
|
"Int64Value", "UInt64Value", "DoubleValue",
|
||||||
|
"Duration", "Timestamp",
|
||||||
|
"NullValue", "Struct", "Value", "ListValue":
|
||||||
|
return string(s.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMessageSet(md protoreflect.MessageDescriptor) bool {
|
||||||
|
ms, ok := md.(interface{ IsMessageSet() bool })
|
||||||
|
return ok && ms.IsMessageSet()
|
||||||
|
}
|
||||||
|
|
@ -26,8 +26,8 @@ var (
|
||||||
// NewMD5 and NewSHA1.
|
// NewMD5 and NewSHA1.
|
||||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||||
h.Reset()
|
h.Reset()
|
||||||
h.Write(space[:])
|
h.Write(space[:]) //nolint:errcheck
|
||||||
h.Write(data)
|
h.Write(data) //nolint:errcheck
|
||||||
s := h.Sum(nil)
|
s := h.Sum(nil)
|
||||||
var uuid UUID
|
var uuid UUID
|
||||||
copy(uuid[:], s)
|
copy(uuid[:], s)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
// Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var jsonNull = []byte("null")
|
||||||
|
|
||||||
|
// NullUUID represents a UUID that may be null.
|
||||||
|
// NullUUID implements the SQL driver.Scanner interface so
|
||||||
|
// it can be used as a scan destination:
|
||||||
|
//
|
||||||
|
// var u uuid.NullUUID
|
||||||
|
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
|
||||||
|
// ...
|
||||||
|
// if u.Valid {
|
||||||
|
// // use u.UUID
|
||||||
|
// } else {
|
||||||
|
// // NULL value
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type NullUUID struct {
|
||||||
|
UUID UUID
|
||||||
|
Valid bool // Valid is true if UUID is not NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the SQL driver.Scanner interface.
|
||||||
|
func (nu *NullUUID) Scan(value interface{}) error {
|
||||||
|
if value == nil {
|
||||||
|
nu.UUID, nu.Valid = Nil, false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := nu.UUID.Scan(value)
|
||||||
|
if err != nil {
|
||||||
|
nu.Valid = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (nu NullUUID) Value() (driver.Value, error) {
|
||||||
|
if !nu.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// Delegate to UUID Value function
|
||||||
|
return nu.UUID.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
|
func (nu NullUUID) MarshalBinary() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return nu.UUID[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalBinary(data []byte) error {
|
||||||
|
if len(data) != 16 {
|
||||||
|
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||||
|
}
|
||||||
|
copy(nu.UUID[:], data)
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
|
func (nu NullUUID) MarshalText() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return nu.UUID.MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonNull, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalText(data []byte) error {
|
||||||
|
id, err := ParseBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
nu.Valid = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nu.UUID = id
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (nu NullUUID) MarshalJSON() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return json.Marshal(nu.UUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonNull, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalJSON(data []byte) error {
|
||||||
|
if bytes.Equal(data, jsonNull) {
|
||||||
|
*nu = NullUUID{}
|
||||||
|
return nil // valid null UUID
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(data, &nu.UUID)
|
||||||
|
nu.Valid = err == nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
|
// Scan implements sql.Scanner so UUIDs can be read from databases transparently.
|
||||||
// Currently, database types that map to string and []byte are supported. Please
|
// Currently, database types that map to string and []byte are supported. Please
|
||||||
// consult database-specific driver documentation for matching types.
|
// consult database-specific driver documentation for matching types.
|
||||||
func (uuid *UUID) Scan(src interface{}) error {
|
func (uuid *UUID) Scan(src interface{}) error {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||||
|
|
@ -33,7 +34,27 @@ const (
|
||||||
Future // Reserved for future definition.
|
Future // Reserved for future definition.
|
||||||
)
|
)
|
||||||
|
|
||||||
var rander = rand.Reader // random function
|
const randPoolSize = 16 * 16
|
||||||
|
|
||||||
|
var (
|
||||||
|
rander = rand.Reader // random function
|
||||||
|
poolEnabled = false
|
||||||
|
poolMu sync.Mutex
|
||||||
|
poolPos = randPoolSize // protected with poolMu
|
||||||
|
pool [randPoolSize]byte // protected with poolMu
|
||||||
|
)
|
||||||
|
|
||||||
|
type invalidLengthError struct{ len int }
|
||||||
|
|
||||||
|
func (err invalidLengthError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid UUID length: %d", err.len)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInvalidLengthError is matcher function for custom error invalidLengthError
|
||||||
|
func IsInvalidLengthError(err error) bool {
|
||||||
|
_, ok := err.(invalidLengthError)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
||||||
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||||
|
|
@ -68,7 +89,7 @@ func Parse(s string) (UUID, error) {
|
||||||
}
|
}
|
||||||
return uuid, nil
|
return uuid, nil
|
||||||
default:
|
default:
|
||||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
return uuid, invalidLengthError{len(s)}
|
||||||
}
|
}
|
||||||
// s is now at least 36 bytes long
|
// s is now at least 36 bytes long
|
||||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
|
@ -112,7 +133,7 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||||
}
|
}
|
||||||
return uuid, nil
|
return uuid, nil
|
||||||
default:
|
default:
|
||||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
return uuid, invalidLengthError{len(b)}
|
||||||
}
|
}
|
||||||
// s is now at least 36 bytes long
|
// s is now at least 36 bytes long
|
||||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
|
@ -243,3 +264,31 @@ func SetRand(r io.Reader) {
|
||||||
}
|
}
|
||||||
rander = r
|
rander = r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnableRandPool enables internal randomness pool used for Random
|
||||||
|
// (Version 4) UUID generation. The pool contains random bytes read from
|
||||||
|
// the random number generator on demand in batches. Enabling the pool
|
||||||
|
// may improve the UUID generation throughput significantly.
|
||||||
|
//
|
||||||
|
// Since the pool is stored on the Go heap, this feature may be a bad fit
|
||||||
|
// for security sensitive applications.
|
||||||
|
//
|
||||||
|
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||||
|
// only be called when there is no possibility that New or any other
|
||||||
|
// UUID Version 4 generation function will be called concurrently.
|
||||||
|
func EnableRandPool() {
|
||||||
|
poolEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableRandPool disables the randomness pool if it was previously
|
||||||
|
// enabled with EnableRandPool.
|
||||||
|
//
|
||||||
|
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||||
|
// only be called when there is no possibility that New or any other
|
||||||
|
// UUID Version 4 generation function will be called concurrently.
|
||||||
|
func DisableRandPool() {
|
||||||
|
poolEnabled = false
|
||||||
|
defer poolMu.Unlock()
|
||||||
|
poolMu.Lock()
|
||||||
|
poolPos = randPoolSize
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,21 @@ func New() UUID {
|
||||||
return Must(NewRandom())
|
return Must(NewRandom())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewString creates a new random UUID and returns it as a string or panics.
|
||||||
|
// NewString is equivalent to the expression
|
||||||
|
//
|
||||||
|
// uuid.New().String()
|
||||||
|
func NewString() string {
|
||||||
|
return Must(NewRandom()).String()
|
||||||
|
}
|
||||||
|
|
||||||
// NewRandom returns a Random (Version 4) UUID.
|
// NewRandom returns a Random (Version 4) UUID.
|
||||||
//
|
//
|
||||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||||
// package.
|
// package.
|
||||||
//
|
//
|
||||||
|
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||||
|
//
|
||||||
// A note about uniqueness derived from the UUID Wikipedia entry:
|
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||||
//
|
//
|
||||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||||
|
|
@ -27,7 +37,10 @@ func New() UUID {
|
||||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||||
// year and having one duplicate.
|
// year and having one duplicate.
|
||||||
func NewRandom() (UUID, error) {
|
func NewRandom() (UUID, error) {
|
||||||
return NewRandomFromReader(rander)
|
if !poolEnabled {
|
||||||
|
return NewRandomFromReader(rander)
|
||||||
|
}
|
||||||
|
return newRandomFromPool()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
|
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
|
||||||
|
|
@ -41,3 +54,23 @@ func NewRandomFromReader(r io.Reader) (UUID, error) {
|
||||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||||
return uuid, nil
|
return uuid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newRandomFromPool() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
poolMu.Lock()
|
||||||
|
if poolPos == randPoolSize {
|
||||||
|
_, err := io.ReadFull(rander, pool[:])
|
||||||
|
if err != nil {
|
||||||
|
poolMu.Unlock()
|
||||||
|
return Nil, err
|
||||||
|
}
|
||||||
|
poolPos = 0
|
||||||
|
}
|
||||||
|
copy(uuid[:], pool[poolPos:(poolPos+16)])
|
||||||
|
poolPos += 16
|
||||||
|
poolMu.Unlock()
|
||||||
|
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -69,9 +69,9 @@ type Collector interface {
|
||||||
// If a Collector collects the same metrics throughout its lifetime, its
|
// If a Collector collects the same metrics throughout its lifetime, its
|
||||||
// Describe method can simply be implemented as:
|
// Describe method can simply be implemented as:
|
||||||
//
|
//
|
||||||
// func (c customCollector) Describe(ch chan<- *Desc) {
|
// func (c customCollector) Describe(ch chan<- *Desc) {
|
||||||
// DescribeByCollect(c, ch)
|
// DescribeByCollect(c, ch)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// However, this will not work if the metrics collected change dynamically over
|
// However, this will not work if the metrics collected change dynamically over
|
||||||
// the lifetime of the Collector in a way that their combined set of descriptors
|
// the lifetime of the Collector in a way that their combined set of descriptors
|
||||||
|
|
@ -118,3 +118,11 @@ func (c *selfCollector) Describe(ch chan<- *Desc) {
|
||||||
func (c *selfCollector) Collect(ch chan<- Metric) {
|
func (c *selfCollector) Collect(ch chan<- Metric) {
|
||||||
ch <- c.self
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
24
vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go
generated
vendored
24
vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go
generated
vendored
|
|
@ -14,3 +14,27 @@
|
||||||
// Package collectors provides implementations of prometheus.Collector to
|
// Package collectors provides implementations of prometheus.Collector to
|
||||||
// conveniently collect process and Go-related metrics.
|
// conveniently collect process and Go-related metrics.
|
||||||
package collectors
|
package collectors
|
||||||
|
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
// 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() prometheus.Collector {
|
||||||
|
//nolint:staticcheck // Ignore SA1019 until v2.
|
||||||
|
return prometheus.NewBuildInfoCollector()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ func (c *dbStatsCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||||
ch <- c.waitDuration
|
ch <- c.waitDuration
|
||||||
ch <- c.maxIdleClosed
|
ch <- c.maxIdleClosed
|
||||||
ch <- c.maxLifetimeClosed
|
ch <- c.maxLifetimeClosed
|
||||||
c.describeNewInGo115(ch)
|
ch <- c.maxIdleTimeClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect implements Collector.
|
// Collect implements Collector.
|
||||||
|
|
@ -115,5 +115,5 @@ func (c *dbStatsCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
ch <- prometheus.MustNewConstMetric(c.waitDuration, prometheus.CounterValue, stats.WaitDuration.Seconds())
|
ch <- prometheus.MustNewConstMetric(c.waitDuration, prometheus.CounterValue, stats.WaitDuration.Seconds())
|
||||||
ch <- prometheus.MustNewConstMetric(c.maxIdleClosed, prometheus.CounterValue, float64(stats.MaxIdleClosed))
|
ch <- prometheus.MustNewConstMetric(c.maxIdleClosed, prometheus.CounterValue, float64(stats.MaxIdleClosed))
|
||||||
ch <- prometheus.MustNewConstMetric(c.maxLifetimeClosed, prometheus.CounterValue, float64(stats.MaxLifetimeClosed))
|
ch <- prometheus.MustNewConstMetric(c.maxLifetimeClosed, prometheus.CounterValue, float64(stats.MaxLifetimeClosed))
|
||||||
c.collectNewInGo115(ch, stats)
|
ch <- prometheus.MustNewConstMetric(c.maxIdleTimeClosed, prometheus.CounterValue, float64(stats.MaxIdleTimeClosed))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//go:build !go1.17
|
||||||
|
// +build !go1.17
|
||||||
|
|
||||||
package collectors
|
package collectors
|
||||||
|
|
||||||
import "github.com/prometheus/client_golang/prometheus"
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
@ -42,28 +45,5 @@ import "github.com/prometheus/client_golang/prometheus"
|
||||||
// NOTE: The problem is solved in Go 1.15, see
|
// NOTE: The problem is solved in Go 1.15, see
|
||||||
// https://github.com/golang/go/issues/19812 for the related Go issue.
|
// https://github.com/golang/go/issues/19812 for the related Go issue.
|
||||||
func NewGoCollector() prometheus.Collector {
|
func NewGoCollector() prometheus.Collector {
|
||||||
//nolint:staticcheck // Ignore SA1019 until v2.
|
|
||||||
return prometheus.NewGoCollector()
|
return prometheus.NewGoCollector()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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() prometheus.Collector {
|
|
||||||
//nolint:staticcheck // Ignore SA1019 until v2.
|
|
||||||
return prometheus.NewBuildInfoCollector()
|
|
||||||
}
|
|
||||||
160
vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go
generated
vendored
Normal file
160
vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go
generated
vendored
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
// 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 collectors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// MetricsAll allows all the metrics to be collected from Go runtime.
|
||||||
|
MetricsAll = GoRuntimeMetricsRule{regexp.MustCompile("/.*")}
|
||||||
|
// MetricsGC allows only GC metrics to be collected from Go runtime.
|
||||||
|
// e.g. go_gc_cycles_automatic_gc_cycles_total
|
||||||
|
MetricsGC = GoRuntimeMetricsRule{regexp.MustCompile(`^/gc/.*`)}
|
||||||
|
// MetricsMemory allows only memory metrics to be collected from Go runtime.
|
||||||
|
// e.g. go_memory_classes_heap_free_bytes
|
||||||
|
MetricsMemory = GoRuntimeMetricsRule{regexp.MustCompile(`^/memory/.*`)}
|
||||||
|
// MetricsScheduler allows only scheduler metrics to be collected from Go runtime.
|
||||||
|
// e.g. go_sched_goroutines_goroutines
|
||||||
|
MetricsScheduler = GoRuntimeMetricsRule{regexp.MustCompile(`^/sched/.*`)}
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithGoCollectorMemStatsMetricsDisabled disables metrics that is gathered in runtime.MemStats structure such as:
|
||||||
|
//
|
||||||
|
// go_memstats_alloc_bytes
|
||||||
|
// go_memstats_alloc_bytes_total
|
||||||
|
// go_memstats_sys_bytes
|
||||||
|
// go_memstats_lookups_total
|
||||||
|
// go_memstats_mallocs_total
|
||||||
|
// go_memstats_frees_total
|
||||||
|
// go_memstats_heap_alloc_bytes
|
||||||
|
// go_memstats_heap_sys_bytes
|
||||||
|
// go_memstats_heap_idle_bytes
|
||||||
|
// go_memstats_heap_inuse_bytes
|
||||||
|
// go_memstats_heap_released_bytes
|
||||||
|
// go_memstats_heap_objects
|
||||||
|
// go_memstats_stack_inuse_bytes
|
||||||
|
// go_memstats_stack_sys_bytes
|
||||||
|
// go_memstats_mspan_inuse_bytes
|
||||||
|
// go_memstats_mspan_sys_bytes
|
||||||
|
// go_memstats_mcache_inuse_bytes
|
||||||
|
// go_memstats_mcache_sys_bytes
|
||||||
|
// go_memstats_buck_hash_sys_bytes
|
||||||
|
// go_memstats_gc_sys_bytes
|
||||||
|
// go_memstats_other_sys_bytes
|
||||||
|
// go_memstats_next_gc_bytes
|
||||||
|
//
|
||||||
|
// so the metrics known from pre client_golang v1.12.0,
|
||||||
|
//
|
||||||
|
// NOTE(bwplotka): The above represents runtime.MemStats statistics, but they are
|
||||||
|
// actually implemented using new runtime/metrics package. (except skipped go_memstats_gc_cpu_fraction
|
||||||
|
// -- see https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034 for explanation).
|
||||||
|
//
|
||||||
|
// Some users might want to disable this on collector level (although you can use scrape relabelling on Prometheus),
|
||||||
|
// because similar metrics can be now obtained using WithGoCollectorRuntimeMetrics. Note that the semantics of new
|
||||||
|
// metrics might be different, plus the names can be change over time with different Go version.
|
||||||
|
//
|
||||||
|
// NOTE(bwplotka): Changing metric names can be tedious at times as the alerts, recording rules and dashboards have to be adjusted.
|
||||||
|
// The old metrics are also very useful, with many guides and books written about how to interpret them.
|
||||||
|
//
|
||||||
|
// As a result our recommendation would be to stick with MemStats like metrics and enable other runtime/metrics if you are interested
|
||||||
|
// in advanced insights Go provides. See ExampleGoCollector_WithAdvancedGoMetrics.
|
||||||
|
func WithGoCollectorMemStatsMetricsDisabled() func(options *internal.GoCollectorOptions) {
|
||||||
|
return func(o *internal.GoCollectorOptions) {
|
||||||
|
o.DisableMemStatsLikeMetrics = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoRuntimeMetricsRule allow enabling and configuring particular group of runtime/metrics.
|
||||||
|
// TODO(bwplotka): Consider adding ability to adjust buckets.
|
||||||
|
type GoRuntimeMetricsRule struct {
|
||||||
|
// Matcher represents RE2 expression will match the runtime/metrics from https://golang.bg/src/runtime/metrics/description.go
|
||||||
|
// Use `regexp.MustCompile` or `regexp.Compile` to create this field.
|
||||||
|
Matcher *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGoCollectorRuntimeMetrics allows enabling and configuring particular group of runtime/metrics.
|
||||||
|
// See the list of metrics https://golang.bg/src/runtime/metrics/description.go (pick the Go version you use there!).
|
||||||
|
// You can use this option in repeated manner, which will add new rules. The order of rules is important, the last rule
|
||||||
|
// that matches particular metrics is applied.
|
||||||
|
func WithGoCollectorRuntimeMetrics(rules ...GoRuntimeMetricsRule) func(options *internal.GoCollectorOptions) {
|
||||||
|
rs := make([]internal.GoCollectorRule, len(rules))
|
||||||
|
for i, r := range rules {
|
||||||
|
rs[i] = internal.GoCollectorRule{
|
||||||
|
Matcher: r.Matcher,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(o *internal.GoCollectorOptions) {
|
||||||
|
o.RuntimeMetricRules = append(o.RuntimeMetricRules, rs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithoutGoCollectorRuntimeMetrics allows disabling group of runtime/metrics that you might have added in WithGoCollectorRuntimeMetrics.
|
||||||
|
// It behaves similarly to WithGoCollectorRuntimeMetrics just with deny-list semantics.
|
||||||
|
func WithoutGoCollectorRuntimeMetrics(matchers ...*regexp.Regexp) func(options *internal.GoCollectorOptions) {
|
||||||
|
rs := make([]internal.GoCollectorRule, len(matchers))
|
||||||
|
for i, m := range matchers {
|
||||||
|
rs[i] = internal.GoCollectorRule{
|
||||||
|
Matcher: m,
|
||||||
|
Deny: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(o *internal.GoCollectorOptions) {
|
||||||
|
o.RuntimeMetricRules = append(o.RuntimeMetricRules, rs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoCollectionOption represents Go collection option flag.
|
||||||
|
// Deprecated.
|
||||||
|
type GoCollectionOption uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// GoRuntimeMemStatsCollection represents the metrics represented by runtime.MemStats structure.
|
||||||
|
// Deprecated. Use WithGoCollectorMemStatsMetricsDisabled() function to disable those metrics in the collector.
|
||||||
|
GoRuntimeMemStatsCollection GoCollectionOption = 1 << iota
|
||||||
|
// GoRuntimeMetricsCollection is the new set of metrics represented by runtime/metrics package.
|
||||||
|
// Deprecated. Use WithGoCollectorRuntimeMetrics(GoRuntimeMetricsRule{Matcher: regexp.MustCompile("/.*")})
|
||||||
|
// function to enable those metrics in the collector.
|
||||||
|
GoRuntimeMetricsCollection
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithGoCollections allows enabling different collections for Go collector on top of base metrics.
|
||||||
|
// Deprecated. Use WithGoCollectorRuntimeMetrics() and WithGoCollectorMemStatsMetricsDisabled() instead to control metrics.
|
||||||
|
func WithGoCollections(flags GoCollectionOption) func(options *internal.GoCollectorOptions) {
|
||||||
|
return func(options *internal.GoCollectorOptions) {
|
||||||
|
if flags&GoRuntimeMemStatsCollection == 0 {
|
||||||
|
WithGoCollectorMemStatsMetricsDisabled()(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags&GoRuntimeMetricsCollection != 0 {
|
||||||
|
WithGoCollectorRuntimeMetrics(GoRuntimeMetricsRule{Matcher: regexp.MustCompile("/.*")})(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGoCollector returns a collector that exports metrics about the current Go
|
||||||
|
// process using debug.GCStats (base metrics) and runtime/metrics (both in MemStats style and new ones).
|
||||||
|
func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) prometheus.Collector {
|
||||||
|
//nolint:staticcheck // Ignore SA1019 until v2.
|
||||||
|
return prometheus.NewGoCollector(opts...)
|
||||||
|
}
|
||||||
|
|
@ -51,7 +51,7 @@ type Counter interface {
|
||||||
// will lead to a valid (label-less) exemplar. But if Labels is nil, the current
|
// will lead to a valid (label-less) exemplar. But if Labels is nil, the current
|
||||||
// exemplar is left in place. AddWithExemplar panics if the value is < 0, if any
|
// exemplar is left in place. AddWithExemplar panics if the value is < 0, if any
|
||||||
// of the provided labels are invalid, or if the provided labels contain more
|
// of the provided labels are invalid, or if the provided labels contain more
|
||||||
// than 64 runes in total.
|
// than 128 runes in total.
|
||||||
type ExemplarAdder interface {
|
type ExemplarAdder interface {
|
||||||
AddWithExemplar(value float64, exemplar Labels)
|
AddWithExemplar(value float64, exemplar Labels)
|
||||||
}
|
}
|
||||||
|
|
@ -133,15 +133,20 @@ func (c *counter) Inc() {
|
||||||
atomic.AddUint64(&c.valInt, 1)
|
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))
|
fval := math.Float64frombits(atomic.LoadUint64(&c.valBits))
|
||||||
ival := atomic.LoadUint64(&c.valInt)
|
ival := atomic.LoadUint64(&c.valInt)
|
||||||
val := fval + float64(ival)
|
return fval + float64(ival)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) Write(out *dto.Metric) error {
|
||||||
|
// Read the Exemplar first and the value second. This is to avoid a race condition
|
||||||
|
// where users see an exemplar for a not-yet-existing observation.
|
||||||
var exemplar *dto.Exemplar
|
var exemplar *dto.Exemplar
|
||||||
if e := c.exemplar.Load(); e != nil {
|
if e := c.exemplar.Load(); e != nil {
|
||||||
exemplar = e.(*dto.Exemplar)
|
exemplar = e.(*dto.Exemplar)
|
||||||
}
|
}
|
||||||
|
val := c.get()
|
||||||
|
|
||||||
return populateMetric(CounterValue, val, c.labelPairs, exemplar, out)
|
return populateMetric(CounterValue, val, c.labelPairs, exemplar, out)
|
||||||
}
|
}
|
||||||
|
|
@ -241,7 +246,8 @@ func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
|
||||||
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||||
// GetMetricWithLabelValues would have returned an error. Not returning an
|
// GetMetricWithLabelValues would have returned an error. Not returning an
|
||||||
// error allows shortcuts like
|
// error allows shortcuts like
|
||||||
// myVec.WithLabelValues("404", "GET").Add(42)
|
//
|
||||||
|
// myVec.WithLabelValues("404", "GET").Add(42)
|
||||||
func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
|
func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
|
||||||
c, err := v.GetMetricWithLabelValues(lvs...)
|
c, err := v.GetMetricWithLabelValues(lvs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -252,7 +258,8 @@ func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
|
||||||
|
|
||||||
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
||||||
// returned an error. Not returning an error allows shortcuts like
|
// returned an error. Not returning an error allows shortcuts like
|
||||||
// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
|
//
|
||||||
|
// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
|
||||||
func (v *CounterVec) With(labels Labels) Counter {
|
func (v *CounterVec) With(labels Labels) Counter {
|
||||||
c, err := v.GetMetricWith(labels)
|
c, err := v.GetMetricWith(labels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cespare/xxhash/v2"
|
"github.com/cespare/xxhash/v2"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus/internal"
|
||||||
|
|
||||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
|
|
@ -154,7 +157,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
|
||||||
Value: proto.String(v),
|
Value: proto.String(v),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sort.Sort(labelPairSorter(d.constLabelPairs))
|
sort.Sort(internal.LabelPairSorter(d.constLabelPairs))
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,55 +21,66 @@
|
||||||
// All exported functions and methods are safe to be used concurrently unless
|
// All exported functions and methods are safe to be used concurrently unless
|
||||||
// specified otherwise.
|
// specified otherwise.
|
||||||
//
|
//
|
||||||
// A Basic Example
|
// # A Basic Example
|
||||||
//
|
//
|
||||||
// As a starting point, a very basic usage example:
|
// As a starting point, a very basic usage example:
|
||||||
//
|
//
|
||||||
// package main
|
// package main
|
||||||
//
|
//
|
||||||
// import (
|
// import (
|
||||||
// "log"
|
// "log"
|
||||||
// "net/http"
|
// "net/http"
|
||||||
//
|
//
|
||||||
// "github.com/prometheus/client_golang/prometheus"
|
// "github.com/prometheus/client_golang/prometheus"
|
||||||
// "github.com/prometheus/client_golang/prometheus/promhttp"
|
// "github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
// var (
|
// type metrics struct {
|
||||||
// cpuTemp = prometheus.NewGauge(prometheus.GaugeOpts{
|
// cpuTemp prometheus.Gauge
|
||||||
// Name: "cpu_temperature_celsius",
|
// hdFailures *prometheus.CounterVec
|
||||||
// Help: "Current temperature of the CPU.",
|
// }
|
||||||
// })
|
|
||||||
// hdFailures = prometheus.NewCounterVec(
|
|
||||||
// prometheus.CounterOpts{
|
|
||||||
// Name: "hd_errors_total",
|
|
||||||
// Help: "Number of hard-disk errors.",
|
|
||||||
// },
|
|
||||||
// []string{"device"},
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
//
|
//
|
||||||
// func init() {
|
// func NewMetrics(reg prometheus.Registerer) *metrics {
|
||||||
// // Metrics have to be registered to be exposed:
|
// m := &metrics{
|
||||||
// prometheus.MustRegister(cpuTemp)
|
// cpuTemp: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
// prometheus.MustRegister(hdFailures)
|
// Name: "cpu_temperature_celsius",
|
||||||
// }
|
// Help: "Current temperature of the CPU.",
|
||||||
|
// }),
|
||||||
|
// hdFailures: prometheus.NewCounterVec(
|
||||||
|
// prometheus.CounterOpts{
|
||||||
|
// Name: "hd_errors_total",
|
||||||
|
// Help: "Number of hard-disk errors.",
|
||||||
|
// },
|
||||||
|
// []string{"device"},
|
||||||
|
// ),
|
||||||
|
// }
|
||||||
|
// reg.MustRegister(m.cpuTemp)
|
||||||
|
// reg.MustRegister(m.hdFailures)
|
||||||
|
// return m
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// func main() {
|
// func main() {
|
||||||
// cpuTemp.Set(65.3)
|
// // Create a non-global registry.
|
||||||
// hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc()
|
// reg := prometheus.NewRegistry()
|
||||||
//
|
//
|
||||||
// // The Handler function provides a default handler to expose metrics
|
// // Create new metrics and register them using the custom registry.
|
||||||
// // via an HTTP server. "/metrics" is the usual endpoint for that.
|
// m := NewMetrics(reg)
|
||||||
// http.Handle("/metrics", promhttp.Handler())
|
// // Set values for the new created metrics.
|
||||||
// log.Fatal(http.ListenAndServe(":8080", nil))
|
// m.cpuTemp.Set(65.3)
|
||||||
// }
|
// m.hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc()
|
||||||
//
|
//
|
||||||
|
// // Expose metrics and custom registry via an HTTP server
|
||||||
|
// // using the HandleFor function. "/metrics" is the usual endpoint for that.
|
||||||
|
// http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}))
|
||||||
|
// log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// This is a complete program that exports two metrics, a Gauge and a Counter,
|
// This is a complete program that exports two metrics, a Gauge and a Counter,
|
||||||
// the latter with a label attached to turn it into a (one-dimensional) vector.
|
// the latter with a label attached to turn it into a (one-dimensional) vector.
|
||||||
|
// It register the metrics using a custom registry and exposes them via an HTTP server
|
||||||
|
// on the /metrics endpoint.
|
||||||
//
|
//
|
||||||
// Metrics
|
// # Metrics
|
||||||
//
|
//
|
||||||
// The number of exported identifiers in this package might appear a bit
|
// The number of exported identifiers in this package might appear a bit
|
||||||
// overwhelming. However, in addition to the basic plumbing shown in the example
|
// overwhelming. However, in addition to the basic plumbing shown in the example
|
||||||
|
|
@ -100,7 +111,7 @@
|
||||||
// To create instances of Metrics and their vector versions, you need a suitable
|
// To create instances of Metrics and their vector versions, you need a suitable
|
||||||
// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, or HistogramOpts.
|
// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, or HistogramOpts.
|
||||||
//
|
//
|
||||||
// Custom Collectors and constant Metrics
|
// # Custom Collectors and constant Metrics
|
||||||
//
|
//
|
||||||
// While you could create your own implementations of Metric, most likely you
|
// While you could create your own implementations of Metric, most likely you
|
||||||
// will only ever implement the Collector interface on your own. At a first
|
// will only ever implement the Collector interface on your own. At a first
|
||||||
|
|
@ -141,7 +152,7 @@
|
||||||
// a metric, GaugeFunc, CounterFunc, or UntypedFunc might be interesting
|
// a metric, GaugeFunc, CounterFunc, or UntypedFunc might be interesting
|
||||||
// shortcuts.
|
// shortcuts.
|
||||||
//
|
//
|
||||||
// Advanced Uses of the Registry
|
// # Advanced Uses of the Registry
|
||||||
//
|
//
|
||||||
// While MustRegister is the by far most common way of registering a Collector,
|
// While MustRegister is the by far most common way of registering a Collector,
|
||||||
// sometimes you might want to handle the errors the registration might cause.
|
// sometimes you might want to handle the errors the registration might cause.
|
||||||
|
|
@ -176,23 +187,23 @@
|
||||||
// NewProcessCollector). With a custom registry, you are in control and decide
|
// NewProcessCollector). With a custom registry, you are in control and decide
|
||||||
// yourself about the Collectors to register.
|
// yourself about the Collectors to register.
|
||||||
//
|
//
|
||||||
// HTTP Exposition
|
// # HTTP Exposition
|
||||||
//
|
//
|
||||||
// The Registry implements the Gatherer interface. The caller of the Gather
|
// The Registry implements the Gatherer interface. The caller of the Gather
|
||||||
// method can then expose the gathered metrics in some way. Usually, the metrics
|
// method can then expose the gathered metrics in some way. Usually, the metrics
|
||||||
// are served via HTTP on the /metrics endpoint. That's happening in the example
|
// are served via HTTP on the /metrics endpoint. That's happening in the example
|
||||||
// above. The tools to expose metrics via HTTP are in the promhttp sub-package.
|
// above. The tools to expose metrics via HTTP are in the promhttp sub-package.
|
||||||
//
|
//
|
||||||
// Pushing to the Pushgateway
|
// # Pushing to the Pushgateway
|
||||||
//
|
//
|
||||||
// Function for pushing to the Pushgateway can be found in the push sub-package.
|
// Function for pushing to the Pushgateway can be found in the push sub-package.
|
||||||
//
|
//
|
||||||
// Graphite Bridge
|
// # Graphite Bridge
|
||||||
//
|
//
|
||||||
// Functions and examples to push metrics from a Gatherer to Graphite can be
|
// Functions and examples to push metrics from a Gatherer to Graphite can be
|
||||||
// found in the graphite sub-package.
|
// found in the graphite sub-package.
|
||||||
//
|
//
|
||||||
// Other Means of Exposition
|
// # Other Means of Exposition
|
||||||
//
|
//
|
||||||
// More ways of exposing metrics can easily be added by following the approaches
|
// More ways of exposing metrics can easily be added by following the approaches
|
||||||
// of the existing implementations.
|
// of the existing implementations.
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,8 @@ func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
|
||||||
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||||
// GetMetricWithLabelValues would have returned an error. Not returning an
|
// GetMetricWithLabelValues would have returned an error. Not returning an
|
||||||
// error allows shortcuts like
|
// error allows shortcuts like
|
||||||
// myVec.WithLabelValues("404", "GET").Add(42)
|
//
|
||||||
|
// myVec.WithLabelValues("404", "GET").Add(42)
|
||||||
func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge {
|
func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge {
|
||||||
g, err := v.GetMetricWithLabelValues(lvs...)
|
g, err := v.GetMetricWithLabelValues(lvs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -221,7 +222,8 @@ func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge {
|
||||||
|
|
||||||
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
||||||
// returned an error. Not returning an error allows shortcuts like
|
// returned an error. Not returning an error allows shortcuts like
|
||||||
// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
|
//
|
||||||
|
// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
|
||||||
func (v *GaugeVec) With(labels Labels) Gauge {
|
func (v *GaugeVec) With(labels Labels) Gauge {
|
||||||
g, err := v.GetMetricWith(labels)
|
g, err := v.GetMetricWith(labels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2021 The Prometheus Authors
|
// Copyright 2015 The Prometheus Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
|
@ -11,16 +11,16 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build !go1.15
|
//go:build !js || wasm
|
||||||
|
// +build !js wasm
|
||||||
|
|
||||||
package collectors
|
package prometheus
|
||||||
|
|
||||||
import (
|
import "os"
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
func getPIDFn() func() (int, error) {
|
||||||
)
|
pid := os.Getpid()
|
||||||
|
return func() (int, error) {
|
||||||
func (c *dbStatsCollector) describeNewInGo115(ch chan<- *prometheus.Desc) {}
|
return pid, nil
|
||||||
|
}
|
||||||
func (c *dbStatsCollector) collectNewInGo115(ch chan<- prometheus.Metric, stats sql.DBStats) {}
|
}
|
||||||
23
vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go
generated
vendored
Normal file
23
vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2015 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 js && !wasm
|
||||||
|
// +build js,!wasm
|
||||||
|
|
||||||
|
package prometheus
|
||||||
|
|
||||||
|
func getPIDFn() func() (int, error) {
|
||||||
|
return func() (int, error) {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,32 +16,205 @@ package prometheus
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type goCollector struct {
|
// goRuntimeMemStats provides the metrics initially provided by runtime.ReadMemStats.
|
||||||
|
// From Go 1.17 those similar (and better) statistics are provided by runtime/metrics, so
|
||||||
|
// while eval closure works on runtime.MemStats, the struct from Go 1.17+ is
|
||||||
|
// populated using runtime/metrics.
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type baseGoCollector struct {
|
||||||
goroutinesDesc *Desc
|
goroutinesDesc *Desc
|
||||||
threadsDesc *Desc
|
threadsDesc *Desc
|
||||||
gcDesc *Desc
|
gcDesc *Desc
|
||||||
|
gcLastTimeDesc *Desc
|
||||||
goInfoDesc *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 is the obsolete version of collectors.NewGoCollector.
|
func newBaseGoCollector() baseGoCollector {
|
||||||
// See there for documentation.
|
return baseGoCollector{
|
||||||
//
|
|
||||||
// Deprecated: Use collectors.NewGoCollector instead.
|
|
||||||
func NewGoCollector() Collector {
|
|
||||||
return &goCollector{
|
|
||||||
goroutinesDesc: NewDesc(
|
goroutinesDesc: NewDesc(
|
||||||
"go_goroutines",
|
"go_goroutines",
|
||||||
"Number of goroutines that currently exist.",
|
"Number of goroutines that currently exist.",
|
||||||
|
|
@ -54,246 +227,32 @@ func NewGoCollector() Collector {
|
||||||
"go_gc_duration_seconds",
|
"go_gc_duration_seconds",
|
||||||
"A summary of the pause duration of garbage collection cycles.",
|
"A summary of the pause duration of garbage collection cycles.",
|
||||||
nil, nil),
|
nil, nil),
|
||||||
|
gcLastTimeDesc: NewDesc(
|
||||||
|
"go_memstats_last_gc_time_seconds",
|
||||||
|
"Number of seconds since 1970 of last garbage collection.",
|
||||||
|
nil, nil),
|
||||||
goInfoDesc: NewDesc(
|
goInfoDesc: NewDesc(
|
||||||
"go_info",
|
"go_info",
|
||||||
"Information about the Go environment.",
|
"Information about the Go environment.",
|
||||||
nil, Labels{"version": runtime.Version()}),
|
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.
|
// 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.goroutinesDesc
|
||||||
ch <- c.threadsDesc
|
ch <- c.threadsDesc
|
||||||
ch <- c.gcDesc
|
ch <- c.gcDesc
|
||||||
|
ch <- c.gcLastTimeDesc
|
||||||
ch <- c.goInfoDesc
|
ch <- c.goInfoDesc
|
||||||
for _, i := range c.msMetrics {
|
|
||||||
ch <- i.desc
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect returns the current state of all metrics of the collector.
|
// Collect returns the current state of all metrics of the collector.
|
||||||
func (c *goCollector) Collect(ch chan<- Metric) {
|
func (c *baseGoCollector) 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)
|
|
||||||
}()
|
|
||||||
|
|
||||||
ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine()))
|
ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine()))
|
||||||
n, _ := runtime.ThreadCreateProfile(nil)
|
|
||||||
ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n))
|
n := getRuntimeNumThreads()
|
||||||
|
ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, n)
|
||||||
|
|
||||||
var stats debug.GCStats
|
var stats debug.GCStats
|
||||||
stats.PauseQuantiles = make([]time.Duration, 5)
|
stats.PauseQuantiles = make([]time.Duration, 5)
|
||||||
|
|
@ -305,63 +264,18 @@ func (c *goCollector) Collect(ch chan<- Metric) {
|
||||||
}
|
}
|
||||||
quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
|
quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
|
||||||
ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles)
|
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)
|
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) {
|
func memstatNamespace(s string) string {
|
||||||
for _, i := range c.msMetrics {
|
return "go_memstats_" + s
|
||||||
ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
type memStatsMetrics []struct {
|
||||||
desc *Desc
|
desc *Desc
|
||||||
eval func(*runtime.MemStats) float64
|
eval func(*runtime.MemStats) float64
|
||||||
valType ValueType
|
valType ValueType
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
122
vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go
generated
vendored
Normal file
122
vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go
generated
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
// 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 {
|
||||||
|
msMetrics := goRuntimeMemStats()
|
||||||
|
msMetrics = append(msMetrics, struct {
|
||||||
|
desc *Desc
|
||||||
|
eval func(*runtime.MemStats) float64
|
||||||
|
valType ValueType
|
||||||
|
}{
|
||||||
|
// This metric is omitted in Go1.17+, see https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
return &goCollector{
|
||||||
|
base: newBaseGoCollector(),
|
||||||
|
msLast: &runtime.MemStats{},
|
||||||
|
msRead: runtime.ReadMemStats,
|
||||||
|
msMaxWait: time.Second,
|
||||||
|
msMaxAge: 5 * time.Minute,
|
||||||
|
msMetrics: msMetrics,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
568
vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go
generated
vendored
Normal file
568
vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go
generated
vendored
Normal file
|
|
@ -0,0 +1,568 @@
|
||||||
|
// 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"
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// constants for strings referenced more than once.
|
||||||
|
goGCHeapTinyAllocsObjects = "/gc/heap/tiny/allocs:objects"
|
||||||
|
goGCHeapAllocsObjects = "/gc/heap/allocs:objects"
|
||||||
|
goGCHeapFreesObjects = "/gc/heap/frees:objects"
|
||||||
|
goGCHeapFreesBytes = "/gc/heap/frees:bytes"
|
||||||
|
goGCHeapAllocsBytes = "/gc/heap/allocs:bytes"
|
||||||
|
goGCHeapObjects = "/gc/heap/objects:objects"
|
||||||
|
goGCHeapGoalBytes = "/gc/heap/goal:bytes"
|
||||||
|
goMemoryClassesTotalBytes = "/memory/classes/total:bytes"
|
||||||
|
goMemoryClassesHeapObjectsBytes = "/memory/classes/heap/objects:bytes"
|
||||||
|
goMemoryClassesHeapUnusedBytes = "/memory/classes/heap/unused:bytes"
|
||||||
|
goMemoryClassesHeapReleasedBytes = "/memory/classes/heap/released:bytes"
|
||||||
|
goMemoryClassesHeapFreeBytes = "/memory/classes/heap/free:bytes"
|
||||||
|
goMemoryClassesHeapStacksBytes = "/memory/classes/heap/stacks:bytes"
|
||||||
|
goMemoryClassesOSStacksBytes = "/memory/classes/os-stacks:bytes"
|
||||||
|
goMemoryClassesMetadataMSpanInuseBytes = "/memory/classes/metadata/mspan/inuse:bytes"
|
||||||
|
goMemoryClassesMetadataMSPanFreeBytes = "/memory/classes/metadata/mspan/free:bytes"
|
||||||
|
goMemoryClassesMetadataMCacheInuseBytes = "/memory/classes/metadata/mcache/inuse:bytes"
|
||||||
|
goMemoryClassesMetadataMCacheFreeBytes = "/memory/classes/metadata/mcache/free:bytes"
|
||||||
|
goMemoryClassesProfilingBucketsBytes = "/memory/classes/profiling/buckets:bytes"
|
||||||
|
goMemoryClassesMetadataOtherBytes = "/memory/classes/metadata/other:bytes"
|
||||||
|
goMemoryClassesOtherBytes = "/memory/classes/other:bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// rmNamesForMemStatsMetrics represents runtime/metrics names required to populate goRuntimeMemStats from like logic.
|
||||||
|
var rmNamesForMemStatsMetrics = []string{
|
||||||
|
goGCHeapTinyAllocsObjects,
|
||||||
|
goGCHeapAllocsObjects,
|
||||||
|
goGCHeapFreesObjects,
|
||||||
|
goGCHeapAllocsBytes,
|
||||||
|
goGCHeapObjects,
|
||||||
|
goGCHeapGoalBytes,
|
||||||
|
goMemoryClassesTotalBytes,
|
||||||
|
goMemoryClassesHeapObjectsBytes,
|
||||||
|
goMemoryClassesHeapUnusedBytes,
|
||||||
|
goMemoryClassesHeapReleasedBytes,
|
||||||
|
goMemoryClassesHeapFreeBytes,
|
||||||
|
goMemoryClassesHeapStacksBytes,
|
||||||
|
goMemoryClassesOSStacksBytes,
|
||||||
|
goMemoryClassesMetadataMSpanInuseBytes,
|
||||||
|
goMemoryClassesMetadataMSPanFreeBytes,
|
||||||
|
goMemoryClassesMetadataMCacheInuseBytes,
|
||||||
|
goMemoryClassesMetadataMCacheFreeBytes,
|
||||||
|
goMemoryClassesProfilingBucketsBytes,
|
||||||
|
goMemoryClassesMetadataOtherBytes,
|
||||||
|
goMemoryClassesOtherBytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
func bestEffortLookupRM(lookup []string) []metrics.Description {
|
||||||
|
ret := make([]metrics.Description, 0, len(lookup))
|
||||||
|
for _, rm := range metrics.All() {
|
||||||
|
for _, m := range lookup {
|
||||||
|
if m == rm.Name {
|
||||||
|
ret = append(ret, rm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
type goCollector struct {
|
||||||
|
base baseGoCollector
|
||||||
|
|
||||||
|
// mu protects updates to all fields ensuring a consistent
|
||||||
|
// snapshot is always produced by Collect.
|
||||||
|
mu sync.Mutex
|
||||||
|
|
||||||
|
// Contains all samples that has to retrieved from runtime/metrics (not all of them will be exposed).
|
||||||
|
sampleBuf []metrics.Sample
|
||||||
|
// sampleMap allows lookup for MemStats metrics and runtime/metrics histograms for exact sums.
|
||||||
|
sampleMap map[string]*metrics.Sample
|
||||||
|
|
||||||
|
// rmExposedMetrics represents all runtime/metrics package metrics
|
||||||
|
// that were configured to be exposed.
|
||||||
|
rmExposedMetrics []collectorMetric
|
||||||
|
rmExactSumMapForHist map[string]string
|
||||||
|
|
||||||
|
// 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 exists to export the same values under the old names
|
||||||
|
// as well.
|
||||||
|
msMetrics memStatsMetrics
|
||||||
|
msMetricsEnabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type rmMetricDesc struct {
|
||||||
|
metrics.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchRuntimeMetricsRules(rules []internal.GoCollectorRule) []rmMetricDesc {
|
||||||
|
var descs []rmMetricDesc
|
||||||
|
for _, d := range metrics.All() {
|
||||||
|
var (
|
||||||
|
deny = true
|
||||||
|
desc rmMetricDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, r := range rules {
|
||||||
|
if !r.Matcher.MatchString(d.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
deny = r.Deny
|
||||||
|
}
|
||||||
|
if deny {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.Description = d
|
||||||
|
descs = append(descs, desc)
|
||||||
|
}
|
||||||
|
return descs
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultGoCollectorOptions() internal.GoCollectorOptions {
|
||||||
|
return internal.GoCollectorOptions{
|
||||||
|
RuntimeMetricSumForHist: map[string]string{
|
||||||
|
"/gc/heap/allocs-by-size:bytes": goGCHeapAllocsBytes,
|
||||||
|
"/gc/heap/frees-by-size:bytes": goGCHeapFreesBytes,
|
||||||
|
},
|
||||||
|
RuntimeMetricRules: []internal.GoCollectorRule{
|
||||||
|
//{Matcher: regexp.MustCompile("")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGoCollector is the obsolete version of collectors.NewGoCollector.
|
||||||
|
// See there for documentation.
|
||||||
|
//
|
||||||
|
// Deprecated: Use collectors.NewGoCollector instead.
|
||||||
|
func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
|
||||||
|
opt := defaultGoCollectorOptions()
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
exposedDescriptions := matchRuntimeMetricsRules(opt.RuntimeMetricRules)
|
||||||
|
|
||||||
|
// 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 exposedDescriptions {
|
||||||
|
if d.Kind == metrics.KindFloat64Histogram {
|
||||||
|
histograms = append(histograms, metrics.Sample{Name: d.Name})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(histograms) > 0 {
|
||||||
|
metrics.Read(histograms)
|
||||||
|
}
|
||||||
|
|
||||||
|
bucketsMap := make(map[string][]float64)
|
||||||
|
for i := range histograms {
|
||||||
|
bucketsMap[histograms[i].Name] = histograms[i].Value.Float64Histogram().Buckets
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a collector for each exposed runtime/metrics metric.
|
||||||
|
metricSet := make([]collectorMetric, 0, len(exposedDescriptions))
|
||||||
|
// SampleBuf is used for reading from runtime/metrics.
|
||||||
|
// We are assuming the largest case to have stable pointers for sampleMap purposes.
|
||||||
|
sampleBuf := make([]metrics.Sample, 0, len(exposedDescriptions)+len(opt.RuntimeMetricSumForHist)+len(rmNamesForMemStatsMetrics))
|
||||||
|
sampleMap := make(map[string]*metrics.Sample, len(exposedDescriptions))
|
||||||
|
for _, d := range exposedDescriptions {
|
||||||
|
namespace, subsystem, name, ok := internal.RuntimeMetricsToProm(&d.Description)
|
||||||
|
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 in TestExpectedRuntimeMetrics.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name})
|
||||||
|
sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1]
|
||||||
|
|
||||||
|
var m collectorMetric
|
||||||
|
if d.Kind == metrics.KindFloat64Histogram {
|
||||||
|
_, hasSum := opt.RuntimeMetricSumForHist[d.Name]
|
||||||
|
unit := d.Name[strings.IndexRune(d.Name, ':')+1:]
|
||||||
|
m = newBatchHistogram(
|
||||||
|
NewDesc(
|
||||||
|
BuildFQName(namespace, subsystem, name),
|
||||||
|
d.Description.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.Description,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
m = NewGauge(GaugeOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: name,
|
||||||
|
Help: d.Description.Description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
metricSet = append(metricSet, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add exact sum metrics to sampleBuf if not added before.
|
||||||
|
for _, h := range histograms {
|
||||||
|
sumMetric, ok := opt.RuntimeMetricSumForHist[h.Name]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := sampleMap[sumMetric]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sampleBuf = append(sampleBuf, metrics.Sample{Name: sumMetric})
|
||||||
|
sampleMap[sumMetric] = &sampleBuf[len(sampleBuf)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
msMetrics memStatsMetrics
|
||||||
|
msDescriptions []metrics.Description
|
||||||
|
)
|
||||||
|
|
||||||
|
if !opt.DisableMemStatsLikeMetrics {
|
||||||
|
msMetrics = goRuntimeMemStats()
|
||||||
|
msDescriptions = bestEffortLookupRM(rmNamesForMemStatsMetrics)
|
||||||
|
|
||||||
|
// Check if metric was not exposed before and if not, add to sampleBuf.
|
||||||
|
for _, mdDesc := range msDescriptions {
|
||||||
|
if _, ok := sampleMap[mdDesc.Name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sampleBuf = append(sampleBuf, metrics.Sample{Name: mdDesc.Name})
|
||||||
|
sampleMap[mdDesc.Name] = &sampleBuf[len(sampleBuf)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &goCollector{
|
||||||
|
base: newBaseGoCollector(),
|
||||||
|
sampleBuf: sampleBuf,
|
||||||
|
sampleMap: sampleMap,
|
||||||
|
rmExposedMetrics: metricSet,
|
||||||
|
rmExactSumMapForHist: opt.RuntimeMetricSumForHist,
|
||||||
|
msMetrics: msMetrics,
|
||||||
|
msMetricsEnabled: !opt.DisableMemStatsLikeMetrics,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.rmExposedMetrics {
|
||||||
|
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)
|
||||||
|
|
||||||
|
if len(c.sampleBuf) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect must be thread-safe, so prevent concurrent use of
|
||||||
|
// sampleBuf elements. Just read into sampleBuf 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.sampleBuf)
|
||||||
|
|
||||||
|
// Collect all our runtime/metrics user chose to expose from sampleBuf (if any).
|
||||||
|
for i, metric := range c.rmExposedMetrics {
|
||||||
|
// We created samples for exposed metrics first in order, so indexes match.
|
||||||
|
sample := c.sampleBuf[i]
|
||||||
|
|
||||||
|
// 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 := metric.(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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.msMetricsEnabled {
|
||||||
|
// ms is a dummy MemStats that we populate ourselves so that we can
|
||||||
|
// populate the old metrics from it if goMemStatsCollection is enabled.
|
||||||
|
var ms runtime.MemStats
|
||||||
|
memStatsFromRM(&ms, c.sampleMap)
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 := c.rmExactSumMapForHist[rmName]
|
||||||
|
if !ok {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
s, ok := c.sampleMap[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(goGCHeapTinyAllocsObjects)
|
||||||
|
ms.Mallocs = lookupOrZero(goGCHeapAllocsObjects) + tinyAllocs
|
||||||
|
ms.Frees = lookupOrZero(goGCHeapFreesObjects) + tinyAllocs
|
||||||
|
|
||||||
|
ms.TotalAlloc = lookupOrZero(goGCHeapAllocsBytes)
|
||||||
|
ms.Sys = lookupOrZero(goMemoryClassesTotalBytes)
|
||||||
|
ms.Lookups = 0 // Already always zero.
|
||||||
|
ms.HeapAlloc = lookupOrZero(goMemoryClassesHeapObjectsBytes)
|
||||||
|
ms.Alloc = ms.HeapAlloc
|
||||||
|
ms.HeapInuse = ms.HeapAlloc + lookupOrZero(goMemoryClassesHeapUnusedBytes)
|
||||||
|
ms.HeapReleased = lookupOrZero(goMemoryClassesHeapReleasedBytes)
|
||||||
|
ms.HeapIdle = ms.HeapReleased + lookupOrZero(goMemoryClassesHeapFreeBytes)
|
||||||
|
ms.HeapSys = ms.HeapInuse + ms.HeapIdle
|
||||||
|
ms.HeapObjects = lookupOrZero(goGCHeapObjects)
|
||||||
|
ms.StackInuse = lookupOrZero(goMemoryClassesHeapStacksBytes)
|
||||||
|
ms.StackSys = ms.StackInuse + lookupOrZero(goMemoryClassesOSStacksBytes)
|
||||||
|
ms.MSpanInuse = lookupOrZero(goMemoryClassesMetadataMSpanInuseBytes)
|
||||||
|
ms.MSpanSys = ms.MSpanInuse + lookupOrZero(goMemoryClassesMetadataMSPanFreeBytes)
|
||||||
|
ms.MCacheInuse = lookupOrZero(goMemoryClassesMetadataMCacheInuseBytes)
|
||||||
|
ms.MCacheSys = ms.MCacheInuse + lookupOrZero(goMemoryClassesMetadataMCacheFreeBytes)
|
||||||
|
ms.BuckHashSys = lookupOrZero(goMemoryClassesProfilingBucketsBytes)
|
||||||
|
ms.GCSys = lookupOrZero(goMemoryClassesMetadataOtherBytes)
|
||||||
|
ms.OtherSys = lookupOrZero(goMemoryClassesOtherBytes)
|
||||||
|
ms.NextGC = lookupOrZero(goGCHeapGoalBytes)
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// We need to remove -Inf values. runtime/metrics keeps them around.
|
||||||
|
// But -Inf bucket should not be allowed for prometheus histograms.
|
||||||
|
if buckets[0] == math.Inf(-1) {
|
||||||
|
buckets = buckets[1:]
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
if count != 0 {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
60
vendor/github.com/prometheus/client_golang/prometheus/internal/almost_equal.go
generated
vendored
Normal file
60
vendor/github.com/prometheus/client_golang/prometheus/internal/almost_equal.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright (c) 2015 Björn Rabenstein
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
// The code in this package is copy/paste to avoid a dependency. Hence this file
|
||||||
|
// carries the copyright of the original repo.
|
||||||
|
// https://github.com/beorn7/floats
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// minNormalFloat64 is the smallest positive normal value of type float64.
|
||||||
|
var minNormalFloat64 = math.Float64frombits(0x0010000000000000)
|
||||||
|
|
||||||
|
// AlmostEqualFloat64 returns true if a and b are equal within a relative error
|
||||||
|
// of epsilon. See http://floating-point-gui.de/errors/comparison/ for the
|
||||||
|
// details of the applied method.
|
||||||
|
func AlmostEqualFloat64(a, b, epsilon float64) bool {
|
||||||
|
if a == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
absA := math.Abs(a)
|
||||||
|
absB := math.Abs(b)
|
||||||
|
diff := math.Abs(a - b)
|
||||||
|
if a == 0 || b == 0 || absA+absB < minNormalFloat64 {
|
||||||
|
return diff < epsilon*minNormalFloat64
|
||||||
|
}
|
||||||
|
return diff/math.Min(absA+absB, math.MaxFloat64) < epsilon
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlmostEqualFloat64s is the slice form of AlmostEqualFloat64.
|
||||||
|
func AlmostEqualFloat64s(a, b []float64, epsilon float64) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range a {
|
||||||
|
if !AlmostEqualFloat64(a[i], b[i], epsilon) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
654
vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go
generated
vendored
Normal file
654
vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go
generated
vendored
Normal file
|
|
@ -0,0 +1,654 @@
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// It provides tools to compare sequences of strings and generate textual diffs.
|
||||||
|
//
|
||||||
|
// Maintaining `GetUnifiedDiffString` here because original repository
|
||||||
|
// (https://github.com/pmezard/go-difflib) is no loger maintained.
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func min(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateRatio(matches, length int) float64 {
|
||||||
|
if length > 0 {
|
||||||
|
return 2.0 * float64(matches) / float64(length)
|
||||||
|
}
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Match struct {
|
||||||
|
A int
|
||||||
|
B int
|
||||||
|
Size int
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpCode struct {
|
||||||
|
Tag byte
|
||||||
|
I1 int
|
||||||
|
I2 int
|
||||||
|
J1 int
|
||||||
|
J2 int
|
||||||
|
}
|
||||||
|
|
||||||
|
// SequenceMatcher compares sequence of strings. The basic
|
||||||
|
// algorithm predates, and is a little fancier than, an algorithm
|
||||||
|
// published in the late 1980's by Ratcliff and Obershelp under the
|
||||||
|
// hyperbolic name "gestalt pattern matching". The basic idea is to find
|
||||||
|
// the longest contiguous matching subsequence that contains no "junk"
|
||||||
|
// elements (R-O doesn't address junk). The same idea is then applied
|
||||||
|
// recursively to the pieces of the sequences to the left and to the right
|
||||||
|
// of the matching subsequence. This does not yield minimal edit
|
||||||
|
// sequences, but does tend to yield matches that "look right" to people.
|
||||||
|
//
|
||||||
|
// SequenceMatcher tries to compute a "human-friendly diff" between two
|
||||||
|
// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
|
||||||
|
// longest *contiguous* & junk-free matching subsequence. That's what
|
||||||
|
// catches peoples' eyes. The Windows(tm) windiff has another interesting
|
||||||
|
// notion, pairing up elements that appear uniquely in each sequence.
|
||||||
|
// That, and the method here, appear to yield more intuitive difference
|
||||||
|
// reports than does diff. This method appears to be the least vulnerable
|
||||||
|
// to synching up on blocks of "junk lines", though (like blank lines in
|
||||||
|
// ordinary text files, or maybe "<P>" lines in HTML files). That may be
|
||||||
|
// because this is the only method of the 3 that has a *concept* of
|
||||||
|
// "junk" <wink>.
|
||||||
|
//
|
||||||
|
// Timing: Basic R-O is cubic time worst case and quadratic time expected
|
||||||
|
// case. SequenceMatcher is quadratic time for the worst case and has
|
||||||
|
// expected-case behavior dependent in a complicated way on how many
|
||||||
|
// elements the sequences have in common; best case time is linear.
|
||||||
|
type SequenceMatcher struct {
|
||||||
|
a []string
|
||||||
|
b []string
|
||||||
|
b2j map[string][]int
|
||||||
|
IsJunk func(string) bool
|
||||||
|
autoJunk bool
|
||||||
|
bJunk map[string]struct{}
|
||||||
|
matchingBlocks []Match
|
||||||
|
fullBCount map[string]int
|
||||||
|
bPopular map[string]struct{}
|
||||||
|
opCodes []OpCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMatcher(a, b []string) *SequenceMatcher {
|
||||||
|
m := SequenceMatcher{autoJunk: true}
|
||||||
|
m.SetSeqs(a, b)
|
||||||
|
return &m
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMatcherWithJunk(a, b []string, autoJunk bool,
|
||||||
|
isJunk func(string) bool,
|
||||||
|
) *SequenceMatcher {
|
||||||
|
m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
|
||||||
|
m.SetSeqs(a, b)
|
||||||
|
return &m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set two sequences to be compared.
|
||||||
|
func (m *SequenceMatcher) SetSeqs(a, b []string) {
|
||||||
|
m.SetSeq1(a)
|
||||||
|
m.SetSeq2(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the first sequence to be compared. The second sequence to be compared is
|
||||||
|
// not changed.
|
||||||
|
//
|
||||||
|
// SequenceMatcher computes and caches detailed information about the second
|
||||||
|
// sequence, so if you want to compare one sequence S against many sequences,
|
||||||
|
// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
|
||||||
|
// sequences.
|
||||||
|
//
|
||||||
|
// See also SetSeqs() and SetSeq2().
|
||||||
|
func (m *SequenceMatcher) SetSeq1(a []string) {
|
||||||
|
if &a == &m.a {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.a = a
|
||||||
|
m.matchingBlocks = nil
|
||||||
|
m.opCodes = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the second sequence to be compared. The first sequence to be compared is
|
||||||
|
// not changed.
|
||||||
|
func (m *SequenceMatcher) SetSeq2(b []string) {
|
||||||
|
if &b == &m.b {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.b = b
|
||||||
|
m.matchingBlocks = nil
|
||||||
|
m.opCodes = nil
|
||||||
|
m.fullBCount = nil
|
||||||
|
m.chainB()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SequenceMatcher) chainB() {
|
||||||
|
// Populate line -> index mapping
|
||||||
|
b2j := map[string][]int{}
|
||||||
|
for i, s := range m.b {
|
||||||
|
indices := b2j[s]
|
||||||
|
indices = append(indices, i)
|
||||||
|
b2j[s] = indices
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge junk elements
|
||||||
|
m.bJunk = map[string]struct{}{}
|
||||||
|
if m.IsJunk != nil {
|
||||||
|
junk := m.bJunk
|
||||||
|
for s := range b2j {
|
||||||
|
if m.IsJunk(s) {
|
||||||
|
junk[s] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for s := range junk {
|
||||||
|
delete(b2j, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge remaining popular elements
|
||||||
|
popular := map[string]struct{}{}
|
||||||
|
n := len(m.b)
|
||||||
|
if m.autoJunk && n >= 200 {
|
||||||
|
ntest := n/100 + 1
|
||||||
|
for s, indices := range b2j {
|
||||||
|
if len(indices) > ntest {
|
||||||
|
popular[s] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for s := range popular {
|
||||||
|
delete(b2j, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.bPopular = popular
|
||||||
|
m.b2j = b2j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SequenceMatcher) isBJunk(s string) bool {
|
||||||
|
_, ok := m.bJunk[s]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find longest matching block in a[alo:ahi] and b[blo:bhi].
|
||||||
|
//
|
||||||
|
// If IsJunk is not defined:
|
||||||
|
//
|
||||||
|
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
|
||||||
|
//
|
||||||
|
// alo <= i <= i+k <= ahi
|
||||||
|
// blo <= j <= j+k <= bhi
|
||||||
|
//
|
||||||
|
// and for all (i',j',k') meeting those conditions,
|
||||||
|
//
|
||||||
|
// k >= k'
|
||||||
|
// i <= i'
|
||||||
|
// and if i == i', j <= j'
|
||||||
|
//
|
||||||
|
// In other words, of all maximal matching blocks, return one that
|
||||||
|
// starts earliest in a, and of all those maximal matching blocks that
|
||||||
|
// start earliest in a, return the one that starts earliest in b.
|
||||||
|
//
|
||||||
|
// If IsJunk is defined, first the longest matching block is
|
||||||
|
// determined as above, but with the additional restriction that no
|
||||||
|
// junk element appears in the block. Then that block is extended as
|
||||||
|
// far as possible by matching (only) junk elements on both sides. So
|
||||||
|
// the resulting block never matches on junk except as identical junk
|
||||||
|
// happens to be adjacent to an "interesting" match.
|
||||||
|
//
|
||||||
|
// If no blocks match, return (alo, blo, 0).
|
||||||
|
func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
|
||||||
|
// CAUTION: stripping common prefix or suffix would be incorrect.
|
||||||
|
// E.g.,
|
||||||
|
// ab
|
||||||
|
// acab
|
||||||
|
// Longest matching block is "ab", but if common prefix is
|
||||||
|
// stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
|
||||||
|
// strip, so ends up claiming that ab is changed to acab by
|
||||||
|
// inserting "ca" in the middle. That's minimal but unintuitive:
|
||||||
|
// "it's obvious" that someone inserted "ac" at the front.
|
||||||
|
// Windiff ends up at the same place as diff, but by pairing up
|
||||||
|
// the unique 'b's and then matching the first two 'a's.
|
||||||
|
besti, bestj, bestsize := alo, blo, 0
|
||||||
|
|
||||||
|
// find longest junk-free match
|
||||||
|
// during an iteration of the loop, j2len[j] = length of longest
|
||||||
|
// junk-free match ending with a[i-1] and b[j]
|
||||||
|
j2len := map[int]int{}
|
||||||
|
for i := alo; i != ahi; i++ {
|
||||||
|
// look at all instances of a[i] in b; note that because
|
||||||
|
// b2j has no junk keys, the loop is skipped if a[i] is junk
|
||||||
|
newj2len := map[int]int{}
|
||||||
|
for _, j := range m.b2j[m.a[i]] {
|
||||||
|
// a[i] matches b[j]
|
||||||
|
if j < blo {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if j >= bhi {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
k := j2len[j-1] + 1
|
||||||
|
newj2len[j] = k
|
||||||
|
if k > bestsize {
|
||||||
|
besti, bestj, bestsize = i-k+1, j-k+1, k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j2len = newj2len
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend the best by non-junk elements on each end. In particular,
|
||||||
|
// "popular" non-junk elements aren't in b2j, which greatly speeds
|
||||||
|
// the inner loop above, but also means "the best" match so far
|
||||||
|
// doesn't contain any junk *or* popular non-junk elements.
|
||||||
|
for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
|
||||||
|
m.a[besti-1] == m.b[bestj-1] {
|
||||||
|
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
|
||||||
|
}
|
||||||
|
for besti+bestsize < ahi && bestj+bestsize < bhi &&
|
||||||
|
!m.isBJunk(m.b[bestj+bestsize]) &&
|
||||||
|
m.a[besti+bestsize] == m.b[bestj+bestsize] {
|
||||||
|
bestsize++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we have a wholly interesting match (albeit possibly
|
||||||
|
// empty!), we may as well suck up the matching junk on each
|
||||||
|
// side of it too. Can't think of a good reason not to, and it
|
||||||
|
// saves post-processing the (possibly considerable) expense of
|
||||||
|
// figuring out what to do with it. In the case of an empty
|
||||||
|
// interesting match, this is clearly the right thing to do,
|
||||||
|
// because no other kind of match is possible in the regions.
|
||||||
|
for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
|
||||||
|
m.a[besti-1] == m.b[bestj-1] {
|
||||||
|
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
|
||||||
|
}
|
||||||
|
for besti+bestsize < ahi && bestj+bestsize < bhi &&
|
||||||
|
m.isBJunk(m.b[bestj+bestsize]) &&
|
||||||
|
m.a[besti+bestsize] == m.b[bestj+bestsize] {
|
||||||
|
bestsize++
|
||||||
|
}
|
||||||
|
|
||||||
|
return Match{A: besti, B: bestj, Size: bestsize}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return list of triples describing matching subsequences.
|
||||||
|
//
|
||||||
|
// Each triple is of the form (i, j, n), and means that
|
||||||
|
// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
|
||||||
|
// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
|
||||||
|
// adjacent triples in the list, and the second is not the last triple in the
|
||||||
|
// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
|
||||||
|
// adjacent equal blocks.
|
||||||
|
//
|
||||||
|
// The last triple is a dummy, (len(a), len(b), 0), and is the only
|
||||||
|
// triple with n==0.
|
||||||
|
func (m *SequenceMatcher) GetMatchingBlocks() []Match {
|
||||||
|
if m.matchingBlocks != nil {
|
||||||
|
return m.matchingBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
|
||||||
|
matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
|
||||||
|
match := m.findLongestMatch(alo, ahi, blo, bhi)
|
||||||
|
i, j, k := match.A, match.B, match.Size
|
||||||
|
if match.Size > 0 {
|
||||||
|
if alo < i && blo < j {
|
||||||
|
matched = matchBlocks(alo, i, blo, j, matched)
|
||||||
|
}
|
||||||
|
matched = append(matched, match)
|
||||||
|
if i+k < ahi && j+k < bhi {
|
||||||
|
matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matched
|
||||||
|
}
|
||||||
|
matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
|
||||||
|
|
||||||
|
// It's possible that we have adjacent equal blocks in the
|
||||||
|
// matching_blocks list now.
|
||||||
|
nonAdjacent := []Match{}
|
||||||
|
i1, j1, k1 := 0, 0, 0
|
||||||
|
for _, b := range matched {
|
||||||
|
// Is this block adjacent to i1, j1, k1?
|
||||||
|
i2, j2, k2 := b.A, b.B, b.Size
|
||||||
|
if i1+k1 == i2 && j1+k1 == j2 {
|
||||||
|
// Yes, so collapse them -- this just increases the length of
|
||||||
|
// the first block by the length of the second, and the first
|
||||||
|
// block so lengthened remains the block to compare against.
|
||||||
|
k1 += k2
|
||||||
|
} else {
|
||||||
|
// Not adjacent. Remember the first block (k1==0 means it's
|
||||||
|
// the dummy we started with), and make the second block the
|
||||||
|
// new block to compare against.
|
||||||
|
if k1 > 0 {
|
||||||
|
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
|
||||||
|
}
|
||||||
|
i1, j1, k1 = i2, j2, k2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k1 > 0 {
|
||||||
|
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
|
||||||
|
}
|
||||||
|
|
||||||
|
nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
|
||||||
|
m.matchingBlocks = nonAdjacent
|
||||||
|
return m.matchingBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return list of 5-tuples describing how to turn a into b.
|
||||||
|
//
|
||||||
|
// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
|
||||||
|
// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
|
||||||
|
// tuple preceding it, and likewise for j1 == the previous j2.
|
||||||
|
//
|
||||||
|
// The tags are characters, with these meanings:
|
||||||
|
//
|
||||||
|
// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
|
||||||
|
//
|
||||||
|
// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
|
||||||
|
//
|
||||||
|
// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
|
||||||
|
//
|
||||||
|
// 'e' (equal): a[i1:i2] == b[j1:j2]
|
||||||
|
func (m *SequenceMatcher) GetOpCodes() []OpCode {
|
||||||
|
if m.opCodes != nil {
|
||||||
|
return m.opCodes
|
||||||
|
}
|
||||||
|
i, j := 0, 0
|
||||||
|
matching := m.GetMatchingBlocks()
|
||||||
|
opCodes := make([]OpCode, 0, len(matching))
|
||||||
|
for _, m := range matching {
|
||||||
|
// invariant: we've pumped out correct diffs to change
|
||||||
|
// a[:i] into b[:j], and the next matching block is
|
||||||
|
// a[ai:ai+size] == b[bj:bj+size]. So we need to pump
|
||||||
|
// out a diff to change a[i:ai] into b[j:bj], pump out
|
||||||
|
// the matching block, and move (i,j) beyond the match
|
||||||
|
ai, bj, size := m.A, m.B, m.Size
|
||||||
|
tag := byte(0)
|
||||||
|
if i < ai && j < bj {
|
||||||
|
tag = 'r'
|
||||||
|
} else if i < ai {
|
||||||
|
tag = 'd'
|
||||||
|
} else if j < bj {
|
||||||
|
tag = 'i'
|
||||||
|
}
|
||||||
|
if tag > 0 {
|
||||||
|
opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
|
||||||
|
}
|
||||||
|
i, j = ai+size, bj+size
|
||||||
|
// the list of matching blocks is terminated by a
|
||||||
|
// sentinel with size 0
|
||||||
|
if size > 0 {
|
||||||
|
opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.opCodes = opCodes
|
||||||
|
return m.opCodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Isolate change clusters by eliminating ranges with no changes.
|
||||||
|
//
|
||||||
|
// Return a generator of groups with up to n lines of context.
|
||||||
|
// Each group is in the same format as returned by GetOpCodes().
|
||||||
|
func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
|
||||||
|
if n < 0 {
|
||||||
|
n = 3
|
||||||
|
}
|
||||||
|
codes := m.GetOpCodes()
|
||||||
|
if len(codes) == 0 {
|
||||||
|
codes = []OpCode{{'e', 0, 1, 0, 1}}
|
||||||
|
}
|
||||||
|
// Fixup leading and trailing groups if they show no changes.
|
||||||
|
if codes[0].Tag == 'e' {
|
||||||
|
c := codes[0]
|
||||||
|
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||||
|
codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
|
||||||
|
}
|
||||||
|
if codes[len(codes)-1].Tag == 'e' {
|
||||||
|
c := codes[len(codes)-1]
|
||||||
|
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||||
|
codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
|
||||||
|
}
|
||||||
|
nn := n + n
|
||||||
|
groups := [][]OpCode{}
|
||||||
|
group := []OpCode{}
|
||||||
|
for _, c := range codes {
|
||||||
|
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||||
|
// End the current group and start a new one whenever
|
||||||
|
// there is a large range with no changes.
|
||||||
|
if c.Tag == 'e' && i2-i1 > nn {
|
||||||
|
group = append(group, OpCode{
|
||||||
|
c.Tag, i1, min(i2, i1+n),
|
||||||
|
j1, min(j2, j1+n),
|
||||||
|
})
|
||||||
|
groups = append(groups, group)
|
||||||
|
group = []OpCode{}
|
||||||
|
i1, j1 = max(i1, i2-n), max(j1, j2-n)
|
||||||
|
}
|
||||||
|
group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
|
||||||
|
}
|
||||||
|
if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
|
||||||
|
groups = append(groups, group)
|
||||||
|
}
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a measure of the sequences' similarity (float in [0,1]).
|
||||||
|
//
|
||||||
|
// Where T is the total number of elements in both sequences, and
|
||||||
|
// M is the number of matches, this is 2.0*M / T.
|
||||||
|
// Note that this is 1 if the sequences are identical, and 0 if
|
||||||
|
// they have nothing in common.
|
||||||
|
//
|
||||||
|
// .Ratio() is expensive to compute if you haven't already computed
|
||||||
|
// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
|
||||||
|
// want to try .QuickRatio() or .RealQuickRation() first to get an
|
||||||
|
// upper bound.
|
||||||
|
func (m *SequenceMatcher) Ratio() float64 {
|
||||||
|
matches := 0
|
||||||
|
for _, m := range m.GetMatchingBlocks() {
|
||||||
|
matches += m.Size
|
||||||
|
}
|
||||||
|
return calculateRatio(matches, len(m.a)+len(m.b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an upper bound on ratio() relatively quickly.
|
||||||
|
//
|
||||||
|
// This isn't defined beyond that it is an upper bound on .Ratio(), and
|
||||||
|
// is faster to compute.
|
||||||
|
func (m *SequenceMatcher) QuickRatio() float64 {
|
||||||
|
// viewing a and b as multisets, set matches to the cardinality
|
||||||
|
// of their intersection; this counts the number of matches
|
||||||
|
// without regard to order, so is clearly an upper bound
|
||||||
|
if m.fullBCount == nil {
|
||||||
|
m.fullBCount = map[string]int{}
|
||||||
|
for _, s := range m.b {
|
||||||
|
m.fullBCount[s]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// avail[x] is the number of times x appears in 'b' less the
|
||||||
|
// number of times we've seen it in 'a' so far ... kinda
|
||||||
|
avail := map[string]int{}
|
||||||
|
matches := 0
|
||||||
|
for _, s := range m.a {
|
||||||
|
n, ok := avail[s]
|
||||||
|
if !ok {
|
||||||
|
n = m.fullBCount[s]
|
||||||
|
}
|
||||||
|
avail[s] = n - 1
|
||||||
|
if n > 0 {
|
||||||
|
matches++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return calculateRatio(matches, len(m.a)+len(m.b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an upper bound on ratio() very quickly.
|
||||||
|
//
|
||||||
|
// This isn't defined beyond that it is an upper bound on .Ratio(), and
|
||||||
|
// is faster to compute than either .Ratio() or .QuickRatio().
|
||||||
|
func (m *SequenceMatcher) RealQuickRatio() float64 {
|
||||||
|
la, lb := len(m.a), len(m.b)
|
||||||
|
return calculateRatio(min(la, lb), la+lb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert range to the "ed" format
|
||||||
|
func formatRangeUnified(start, stop int) string {
|
||||||
|
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
||||||
|
beginning := start + 1 // lines start numbering with one
|
||||||
|
length := stop - start
|
||||||
|
if length == 1 {
|
||||||
|
return fmt.Sprintf("%d", beginning)
|
||||||
|
}
|
||||||
|
if length == 0 {
|
||||||
|
beginning-- // empty ranges begin at line just before the range
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d,%d", beginning, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unified diff parameters
|
||||||
|
type UnifiedDiff struct {
|
||||||
|
A []string // First sequence lines
|
||||||
|
FromFile string // First file name
|
||||||
|
FromDate string // First file time
|
||||||
|
B []string // Second sequence lines
|
||||||
|
ToFile string // Second file name
|
||||||
|
ToDate string // Second file time
|
||||||
|
Eol string // Headers end of line, defaults to LF
|
||||||
|
Context int // Number of context lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two sequences of lines; generate the delta as a unified diff.
|
||||||
|
//
|
||||||
|
// Unified diffs are a compact way of showing line changes and a few
|
||||||
|
// lines of context. The number of context lines is set by 'n' which
|
||||||
|
// defaults to three.
|
||||||
|
//
|
||||||
|
// By default, the diff control lines (those with ---, +++, or @@) are
|
||||||
|
// created with a trailing newline. This is helpful so that inputs
|
||||||
|
// created from file.readlines() result in diffs that are suitable for
|
||||||
|
// file.writelines() since both the inputs and outputs have trailing
|
||||||
|
// newlines.
|
||||||
|
//
|
||||||
|
// For inputs that do not have trailing newlines, set the lineterm
|
||||||
|
// argument to "" so that the output will be uniformly newline free.
|
||||||
|
//
|
||||||
|
// The unidiff format normally has a header for filenames and modification
|
||||||
|
// times. Any or all of these may be specified using strings for
|
||||||
|
// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
|
||||||
|
// The modification times are normally expressed in the ISO 8601 format.
|
||||||
|
func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
|
||||||
|
buf := bufio.NewWriter(writer)
|
||||||
|
defer buf.Flush()
|
||||||
|
wf := func(format string, args ...interface{}) error {
|
||||||
|
_, err := buf.WriteString(fmt.Sprintf(format, args...))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ws := func(s string) error {
|
||||||
|
_, err := buf.WriteString(s)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(diff.Eol) == 0 {
|
||||||
|
diff.Eol = "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
started := false
|
||||||
|
m := NewMatcher(diff.A, diff.B)
|
||||||
|
for _, g := range m.GetGroupedOpCodes(diff.Context) {
|
||||||
|
if !started {
|
||||||
|
started = true
|
||||||
|
fromDate := ""
|
||||||
|
if len(diff.FromDate) > 0 {
|
||||||
|
fromDate = "\t" + diff.FromDate
|
||||||
|
}
|
||||||
|
toDate := ""
|
||||||
|
if len(diff.ToDate) > 0 {
|
||||||
|
toDate = "\t" + diff.ToDate
|
||||||
|
}
|
||||||
|
if diff.FromFile != "" || diff.ToFile != "" {
|
||||||
|
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first, last := g[0], g[len(g)-1]
|
||||||
|
range1 := formatRangeUnified(first.I1, last.I2)
|
||||||
|
range2 := formatRangeUnified(first.J1, last.J2)
|
||||||
|
if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, c := range g {
|
||||||
|
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||||
|
if c.Tag == 'e' {
|
||||||
|
for _, line := range diff.A[i1:i2] {
|
||||||
|
if err := ws(" " + line); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.Tag == 'r' || c.Tag == 'd' {
|
||||||
|
for _, line := range diff.A[i1:i2] {
|
||||||
|
if err := ws("-" + line); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Tag == 'r' || c.Tag == 'i' {
|
||||||
|
for _, line := range diff.B[j1:j2] {
|
||||||
|
if err := ws("+" + line); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like WriteUnifiedDiff but returns the diff a string.
|
||||||
|
func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
|
||||||
|
w := &bytes.Buffer{}
|
||||||
|
err := WriteUnifiedDiff(w, diff)
|
||||||
|
return w.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split a string on "\n" while preserving them. The output can be used
|
||||||
|
// as input for UnifiedDiff and ContextDiff structures.
|
||||||
|
func SplitLines(s string) []string {
|
||||||
|
lines := strings.SplitAfter(s, "\n")
|
||||||
|
lines[len(lines)-1] += "\n"
|
||||||
|
return lines
|
||||||
|
}
|
||||||
32
vendor/github.com/prometheus/client_golang/prometheus/internal/go_collector_options.go
generated
vendored
Normal file
32
vendor/github.com/prometheus/client_golang/prometheus/internal/go_collector_options.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// 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 internal
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
type GoCollectorRule struct {
|
||||||
|
Matcher *regexp.Regexp
|
||||||
|
Deny bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoCollectorOptions should not be used be directly by anything, except `collectors` package.
|
||||||
|
// Use it via collectors package instead. See issue
|
||||||
|
// https://github.com/prometheus/client_golang/issues/1030.
|
||||||
|
//
|
||||||
|
// This is internal, so external users only can use it via `collector.WithGoCollector*` methods
|
||||||
|
type GoCollectorOptions struct {
|
||||||
|
DisableMemStatsLikeMetrics bool
|
||||||
|
RuntimeMetricSumForHist map[string]string
|
||||||
|
RuntimeMetricRules []GoCollectorRule
|
||||||
|
}
|
||||||
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 += "_" + unit
|
||||||
|
if d.Cumulative && d.Kind != metrics.KindFloat64Histogram {
|
||||||
|
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":
|
||||||
|
// Re-bucket as powers of 2.
|
||||||
|
return reBucketExp(buckets, 2)
|
||||||
|
case "seconds":
|
||||||
|
// Re-bucket 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)
|
||||||
|
}
|
||||||
|
|
@ -19,18 +19,34 @@ import (
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// metricSorter is a sortable slice of *dto.Metric.
|
// LabelPairSorter implements sort.Interface. It is used to sort a slice of
|
||||||
type metricSorter []*dto.Metric
|
// dto.LabelPair pointers.
|
||||||
|
type LabelPairSorter []*dto.LabelPair
|
||||||
|
|
||||||
func (s metricSorter) Len() int {
|
func (s LabelPairSorter) Len() int {
|
||||||
return len(s)
|
return len(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s metricSorter) Swap(i, j int) {
|
func (s LabelPairSorter) Swap(i, j int) {
|
||||||
s[i], s[j] = s[j], s[i]
|
s[i], s[j] = s[j], s[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s metricSorter) Less(i, j int) bool {
|
func (s LabelPairSorter) Less(i, j int) bool {
|
||||||
|
return s[i].GetName() < s[j].GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetricSorter is a sortable slice of *dto.Metric.
|
||||||
|
type MetricSorter []*dto.Metric
|
||||||
|
|
||||||
|
func (s MetricSorter) Len() int {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s MetricSorter) Swap(i, j int) {
|
||||||
|
s[i], s[j] = s[j], s[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s MetricSorter) Less(i, j int) bool {
|
||||||
if len(s[i].Label) != len(s[j].Label) {
|
if len(s[i].Label) != len(s[j].Label) {
|
||||||
// This should not happen. The metrics are
|
// This should not happen. The metrics are
|
||||||
// inconsistent. However, we have to deal with the fact, as
|
// inconsistent. However, we have to deal with the fact, as
|
||||||
|
|
@ -68,7 +84,7 @@ func (s metricSorter) Less(i, j int) bool {
|
||||||
// the slice, with the contained Metrics sorted within each MetricFamily.
|
// the slice, with the contained Metrics sorted within each MetricFamily.
|
||||||
func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily {
|
func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily {
|
||||||
for _, mf := range metricFamiliesByName {
|
for _, mf := range metricFamiliesByName {
|
||||||
sort.Sort(metricSorter(mf.Metric))
|
sort.Sort(MetricSorter(mf.Metric))
|
||||||
}
|
}
|
||||||
names := make([]string, 0, len(metricFamiliesByName))
|
names := make([]string, 0, len(metricFamiliesByName))
|
||||||
for name, mf := range metricFamiliesByName {
|
for name, mf := range metricFamiliesByName {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ import (
|
||||||
// Labels represents a collection of label name -> value mappings. This type is
|
// Labels represents a collection of label name -> value mappings. This type is
|
||||||
// commonly used with the With(Labels) and GetMetricWith(Labels) methods of
|
// commonly used with the With(Labels) and GetMetricWith(Labels) methods of
|
||||||
// metric vector Collectors, e.g.:
|
// metric vector Collectors, e.g.:
|
||||||
// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
|
//
|
||||||
|
// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
|
||||||
//
|
//
|
||||||
// The other use-case is the specification of constant label pairs in Opts or to
|
// The other use-case is the specification of constant label pairs in Opts or to
|
||||||
// create a Desc.
|
// create a Desc.
|
||||||
|
|
@ -39,7 +40,7 @@ var errInconsistentCardinality = errors.New("inconsistent label cardinality")
|
||||||
|
|
||||||
func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error {
|
func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"%s: %q has %d variable labels named %q but %d values %q were provided",
|
"%w: %q has %d variable labels named %q but %d values %q were provided",
|
||||||
errInconsistentCardinality, fqName,
|
errInconsistentCardinality, fqName,
|
||||||
len(labels), labels,
|
len(labels), labels,
|
||||||
len(labelValues), labelValues,
|
len(labelValues), labelValues,
|
||||||
|
|
@ -49,7 +50,7 @@ func makeInconsistentCardinalityError(fqName string, labels, labelValues []strin
|
||||||
func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error {
|
func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error {
|
||||||
if len(labels) != expectedNumberOfValues {
|
if len(labels) != expectedNumberOfValues {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"%s: expected %d label values but got %d in %#v",
|
"%w: expected %d label values but got %d in %#v",
|
||||||
errInconsistentCardinality, expectedNumberOfValues,
|
errInconsistentCardinality, expectedNumberOfValues,
|
||||||
len(labels), labels,
|
len(labels), labels,
|
||||||
)
|
)
|
||||||
|
|
@ -67,7 +68,7 @@ func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error {
|
||||||
func validateLabelValues(vals []string, expectedNumberOfValues int) error {
|
func validateLabelValues(vals []string, expectedNumberOfValues int) error {
|
||||||
if len(vals) != expectedNumberOfValues {
|
if len(vals) != expectedNumberOfValues {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"%s: expected %d label values but got %d in %#v",
|
"%w: expected %d label values but got %d in %#v",
|
||||||
errInconsistentCardinality, expectedNumberOfValues,
|
errInconsistentCardinality, expectedNumberOfValues,
|
||||||
len(vals), vals,
|
len(vals), vals,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -115,22 +118,6 @@ func BuildFQName(namespace, subsystem, name string) string {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
// labelPairSorter implements sort.Interface. It is used to sort a slice of
|
|
||||||
// dto.LabelPair pointers.
|
|
||||||
type labelPairSorter []*dto.LabelPair
|
|
||||||
|
|
||||||
func (s labelPairSorter) Len() int {
|
|
||||||
return len(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s labelPairSorter) Swap(i, j int) {
|
|
||||||
s[i], s[j] = s[j], s[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s labelPairSorter) Less(i, j int) bool {
|
|
||||||
return s[i].GetName() < s[j].GetName()
|
|
||||||
}
|
|
||||||
|
|
||||||
type invalidMetric struct {
|
type invalidMetric struct {
|
||||||
desc *Desc
|
desc *Desc
|
||||||
err error
|
err error
|
||||||
|
|
@ -174,3 +161,96 @@ func (m timestampedMetric) Write(pb *dto.Metric) error {
|
||||||
func NewMetricWithTimestamp(t time.Time, m Metric) Metric {
|
func NewMetricWithTimestamp(t time.Time, m Metric) Metric {
|
||||||
return timestampedMetric{Metric: m, t: t}
|
return timestampedMetric{Metric: m, t: t}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type withExemplarsMetric struct {
|
||||||
|
Metric
|
||||||
|
|
||||||
|
exemplars []*dto.Exemplar
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *withExemplarsMetric) Write(pb *dto.Metric) error {
|
||||||
|
if err := m.Metric.Write(pb); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case pb.Counter != nil:
|
||||||
|
pb.Counter.Exemplar = m.exemplars[len(m.exemplars)-1]
|
||||||
|
case pb.Histogram != nil:
|
||||||
|
for _, e := range m.exemplars {
|
||||||
|
// pb.Histogram.Bucket are sorted by UpperBound.
|
||||||
|
i := sort.Search(len(pb.Histogram.Bucket), func(i int) bool {
|
||||||
|
return pb.Histogram.Bucket[i].GetUpperBound() >= e.GetValue()
|
||||||
|
})
|
||||||
|
if i < len(pb.Histogram.Bucket) {
|
||||||
|
pb.Histogram.Bucket[i].Exemplar = e
|
||||||
|
} else {
|
||||||
|
// The +Inf bucket should be explicitly added if there is an exemplar for it, similar to non-const histogram logic in https://github.com/prometheus/client_golang/blob/main/prometheus/histogram.go#L357-L365.
|
||||||
|
b := &dto.Bucket{
|
||||||
|
CumulativeCount: proto.Uint64(pb.Histogram.GetSampleCount()),
|
||||||
|
UpperBound: proto.Float64(math.Inf(1)),
|
||||||
|
Exemplar: e,
|
||||||
|
}
|
||||||
|
pb.Histogram.Bucket = append(pb.Histogram.Bucket, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// TODO(bwplotka): Implement Gauge?
|
||||||
|
return errors.New("cannot inject exemplar into Gauge, Summary or Untyped")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exemplar is easier to use, user-facing representation of *dto.Exemplar.
|
||||||
|
type Exemplar struct {
|
||||||
|
Value float64
|
||||||
|
Labels Labels
|
||||||
|
// Optional.
|
||||||
|
// Default value (time.Time{}) indicates its empty, which should be
|
||||||
|
// understood as time.Now() time at the moment of creation of metric.
|
||||||
|
Timestamp time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMetricWithExemplars returns a new Metric wrapping the provided Metric with given
|
||||||
|
// exemplars. Exemplars are validated.
|
||||||
|
//
|
||||||
|
// Only last applicable exemplar is injected from the list.
|
||||||
|
// For example for Counter it means last exemplar is injected.
|
||||||
|
// For Histogram, it means last applicable exemplar for each bucket is injected.
|
||||||
|
//
|
||||||
|
// NewMetricWithExemplars works best with MustNewConstMetric and
|
||||||
|
// MustNewConstHistogram, see example.
|
||||||
|
func NewMetricWithExemplars(m Metric, exemplars ...Exemplar) (Metric, error) {
|
||||||
|
if len(exemplars) == 0 {
|
||||||
|
return nil, errors.New("no exemplar was passed for NewMetricWithExemplars")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
now = time.Now()
|
||||||
|
exs = make([]*dto.Exemplar, len(exemplars))
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
for i, e := range exemplars {
|
||||||
|
ts := e.Timestamp
|
||||||
|
if ts == (time.Time{}) {
|
||||||
|
ts = now
|
||||||
|
}
|
||||||
|
exs[i], err = newExemplar(e.Value, ts, e.Labels)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &withExemplarsMetric{Metric: m, exemplars: exs}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustNewMetricWithExemplars is a version of NewMetricWithExemplars that panics where
|
||||||
|
// NewMetricWithExemplars would have returned an error.
|
||||||
|
func MustNewMetricWithExemplars(m Metric, exemplars ...Exemplar) Metric {
|
||||||
|
ret, err := NewMetricWithExemplars(m, exemplars...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
|
||||||
25
vendor/github.com/prometheus/client_golang/prometheus/num_threads.go
generated
vendored
Normal file
25
vendor/github.com/prometheus/client_golang/prometheus/num_threads.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2018 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 !js || wasm
|
||||||
|
// +build !js wasm
|
||||||
|
|
||||||
|
package prometheus
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
|
||||||
|
// getRuntimeNumThreads returns the number of open OS threads.
|
||||||
|
func getRuntimeNumThreads() float64 {
|
||||||
|
n, _ := runtime.ThreadCreateProfile(nil)
|
||||||
|
return float64(n)
|
||||||
|
}
|
||||||
22
vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go
generated
vendored
Normal file
22
vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2018 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 js && !wasm
|
||||||
|
// +build js,!wasm
|
||||||
|
|
||||||
|
package prometheus
|
||||||
|
|
||||||
|
// getRuntimeNumThreads returns the number of open OS threads.
|
||||||
|
func getRuntimeNumThreads() float64 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ type ObserverVec interface {
|
||||||
// current time as timestamp, and the provided Labels. Empty Labels will lead to
|
// current time as timestamp, and the provided Labels. Empty Labels will lead to
|
||||||
// a valid (label-less) exemplar. But if Labels is nil, the current exemplar is
|
// a valid (label-less) exemplar. But if Labels is nil, the current exemplar is
|
||||||
// left in place. ObserveWithExemplar panics if any of the provided labels are
|
// left in place. ObserveWithExemplar panics if any of the provided labels are
|
||||||
// invalid or if the provided labels contain more than 64 runes in total.
|
// invalid or if the provided labels contain more than 128 runes in total.
|
||||||
type ExemplarObserver interface {
|
type ExemplarObserver interface {
|
||||||
ObserveWithExemplar(value float64, exemplar Labels)
|
ObserveWithExemplar(value float64, exemplar Labels)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ package prometheus
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -104,8 +103,7 @@ func NewProcessCollector(opts ProcessCollectorOpts) Collector {
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.PidFn == nil {
|
if opts.PidFn == nil {
|
||||||
pid := os.Getpid()
|
c.pidFn = getPIDFn()
|
||||||
c.pidFn = func() (int, error) { return pid, nil }
|
|
||||||
} else {
|
} else {
|
||||||
c.pidFn = opts.PidFn
|
c.pidFn = opts.PidFn
|
||||||
}
|
}
|
||||||
|
|
@ -152,13 +150,13 @@ func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error)
|
||||||
// It is meant to be used for the PidFn field in ProcessCollectorOpts.
|
// It is meant to be used for the PidFn field in ProcessCollectorOpts.
|
||||||
func NewPidFileFn(pidFilePath string) func() (int, error) {
|
func NewPidFileFn(pidFilePath string) func() (int, error) {
|
||||||
return func() (int, error) {
|
return func() (int, error) {
|
||||||
content, err := ioutil.ReadFile(pidFilePath)
|
content, err := os.ReadFile(pidFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("can't read pid file %q: %+v", pidFilePath, err)
|
return 0, fmt.Errorf("can't read pid file %q: %w", pidFilePath, err)
|
||||||
}
|
}
|
||||||
pid, err := strconv.Atoi(strings.TrimSpace(string(content)))
|
pid, err := strconv.Atoi(strings.TrimSpace(string(content)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("can't parse pid file %q: %+v", pidFilePath, err)
|
return 0, fmt.Errorf("can't parse pid file %q: %w", pidFilePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid, nil
|
return pid, nil
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2021 The Prometheus Authors
|
// Copyright 2019 The Prometheus Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
|
@ -11,20 +11,16 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build go1.15
|
//go:build js
|
||||||
|
// +build js
|
||||||
|
|
||||||
package collectors
|
package prometheus
|
||||||
|
|
||||||
import (
|
func canCollectProcess() bool {
|
||||||
"database/sql"
|
return false
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *dbStatsCollector) describeNewInGo115(ch chan<- *prometheus.Desc) {
|
|
||||||
ch <- c.maxIdleTimeClosed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *dbStatsCollector) collectNewInGo115(ch chan<- prometheus.Metric, stats sql.DBStats) {
|
func (c *processCollector) processCollect(ch chan<- Metric) {
|
||||||
ch <- prometheus.MustNewConstMetric(c.maxIdleTimeClosed, prometheus.CounterValue, float64(stats.MaxIdleTimeClosed))
|
// noop on this platform
|
||||||
|
return
|
||||||
}
|
}
|
||||||
3
vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go
generated
vendored
3
vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go
generated
vendored
|
|
@ -11,7 +11,8 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build !windows
|
//go:build !windows && !js
|
||||||
|
// +build !windows,!js
|
||||||
|
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,16 +76,19 @@ func (r *responseWriterDelegator) Write(b []byte) (int, error) {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type closeNotifierDelegator struct{ *responseWriterDelegator }
|
type (
|
||||||
type flusherDelegator struct{ *responseWriterDelegator }
|
closeNotifierDelegator struct{ *responseWriterDelegator }
|
||||||
type hijackerDelegator struct{ *responseWriterDelegator }
|
flusherDelegator struct{ *responseWriterDelegator }
|
||||||
type readerFromDelegator struct{ *responseWriterDelegator }
|
hijackerDelegator struct{ *responseWriterDelegator }
|
||||||
type pusherDelegator struct{ *responseWriterDelegator }
|
readerFromDelegator struct{ *responseWriterDelegator }
|
||||||
|
pusherDelegator struct{ *responseWriterDelegator }
|
||||||
|
)
|
||||||
|
|
||||||
func (d closeNotifierDelegator) CloseNotify() <-chan bool {
|
func (d closeNotifierDelegator) CloseNotify() <-chan bool {
|
||||||
//nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users.
|
//nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users.
|
||||||
return d.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
return d.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d flusherDelegator) Flush() {
|
func (d flusherDelegator) Flush() {
|
||||||
// If applicable, call WriteHeader here so that observeWriteHeader is
|
// If applicable, call WriteHeader here so that observeWriteHeader is
|
||||||
// handled appropriately.
|
// handled appropriately.
|
||||||
|
|
@ -94,9 +97,11 @@ func (d flusherDelegator) Flush() {
|
||||||
}
|
}
|
||||||
d.ResponseWriter.(http.Flusher).Flush()
|
d.ResponseWriter.(http.Flusher).Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
return d.ResponseWriter.(http.Hijacker).Hijack()
|
return d.ResponseWriter.(http.Hijacker).Hijack()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) {
|
func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) {
|
||||||
// If applicable, call WriteHeader here so that observeWriteHeader is
|
// If applicable, call WriteHeader here so that observeWriteHeader is
|
||||||
// handled appropriately.
|
// handled appropriately.
|
||||||
|
|
@ -107,6 +112,7 @@ func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) {
|
||||||
d.written += n
|
d.written += n
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d pusherDelegator) Push(target string, opts *http.PushOptions) error {
|
func (d pusherDelegator) Push(target string, opts *http.PushOptions) error {
|
||||||
return d.ResponseWriter.(http.Pusher).Push(target, opts)
|
return d.ResponseWriter.(http.Pusher).Push(target, opts)
|
||||||
}
|
}
|
||||||
|
|
@ -261,7 +267,7 @@ func init() {
|
||||||
http.Flusher
|
http.Flusher
|
||||||
}{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}}
|
}{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}}
|
||||||
}
|
}
|
||||||
pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23
|
pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 23
|
||||||
return struct {
|
return struct {
|
||||||
*responseWriterDelegator
|
*responseWriterDelegator
|
||||||
http.Pusher
|
http.Pusher
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ package promhttp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -84,6 +85,13 @@ func Handler() http.Handler {
|
||||||
// instrumentation. Use the InstrumentMetricHandler function to apply the same
|
// instrumentation. Use the InstrumentMetricHandler function to apply the same
|
||||||
// kind of instrumentation as it is used by the Handler function.
|
// kind of instrumentation as it is used by the Handler function.
|
||||||
func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
|
func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
|
||||||
|
return HandlerForTransactional(prometheus.ToTransactionalGatherer(reg), opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerForTransactional is like HandlerFor, but it uses transactional gather, which
|
||||||
|
// can safely change in-place returned *dto.MetricFamily before call to `Gather` and after
|
||||||
|
// call to `done` of that `Gather`.
|
||||||
|
func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerOpts) http.Handler {
|
||||||
var (
|
var (
|
||||||
inFlightSem chan struct{}
|
inFlightSem chan struct{}
|
||||||
errCnt = prometheus.NewCounterVec(
|
errCnt = prometheus.NewCounterVec(
|
||||||
|
|
@ -103,7 +111,8 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
|
||||||
errCnt.WithLabelValues("gathering")
|
errCnt.WithLabelValues("gathering")
|
||||||
errCnt.WithLabelValues("encoding")
|
errCnt.WithLabelValues("encoding")
|
||||||
if err := opts.Registry.Register(errCnt); err != nil {
|
if err := opts.Registry.Register(errCnt); err != nil {
|
||||||
if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
|
are := &prometheus.AlreadyRegisteredError{}
|
||||||
|
if errors.As(err, are) {
|
||||||
errCnt = are.ExistingCollector.(*prometheus.CounterVec)
|
errCnt = are.ExistingCollector.(*prometheus.CounterVec)
|
||||||
} else {
|
} else {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -123,7 +132,8 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mfs, err := reg.Gather()
|
mfs, done, err := reg.Gather()
|
||||||
|
defer done()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if opts.ErrorLog != nil {
|
if opts.ErrorLog != nil {
|
||||||
opts.ErrorLog.Println("error gathering metrics:", err)
|
opts.ErrorLog.Println("error gathering metrics:", err)
|
||||||
|
|
@ -242,7 +252,8 @@ func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) ht
|
||||||
cnt.WithLabelValues("500")
|
cnt.WithLabelValues("500")
|
||||||
cnt.WithLabelValues("503")
|
cnt.WithLabelValues("503")
|
||||||
if err := reg.Register(cnt); err != nil {
|
if err := reg.Register(cnt); err != nil {
|
||||||
if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
|
are := &prometheus.AlreadyRegisteredError{}
|
||||||
|
if errors.As(err, are) {
|
||||||
cnt = are.ExistingCollector.(*prometheus.CounterVec)
|
cnt = are.ExistingCollector.(*prometheus.CounterVec)
|
||||||
} else {
|
} else {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -254,7 +265,8 @@ func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) ht
|
||||||
Help: "Current number of scrapes being served.",
|
Help: "Current number of scrapes being served.",
|
||||||
})
|
})
|
||||||
if err := reg.Register(gge); err != nil {
|
if err := reg.Register(gge); err != nil {
|
||||||
if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
|
are := &prometheus.AlreadyRegisteredError{}
|
||||||
|
if errors.As(err, are) {
|
||||||
gge = are.ExistingCollector.(prometheus.Gauge)
|
gge = are.ExistingCollector.(prometheus.Gauge)
|
||||||
} else {
|
} else {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
56
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
generated
vendored
56
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
generated
vendored
|
|
@ -38,42 +38,59 @@ func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||||
//
|
//
|
||||||
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
||||||
func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc {
|
func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc {
|
||||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
return func(r *http.Request) (*http.Response, error) {
|
||||||
gauge.Inc()
|
gauge.Inc()
|
||||||
defer gauge.Dec()
|
defer gauge.Dec()
|
||||||
return next.RoundTrip(r)
|
return next.RoundTrip(r)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstrumentRoundTripperCounter is a middleware that wraps the provided
|
// InstrumentRoundTripperCounter is a middleware that wraps the provided
|
||||||
// http.RoundTripper to observe the request result with the provided CounterVec.
|
// 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
|
// 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
|
// 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
|
// and/or HTTP method if the respective instance label names are present in the
|
||||||
// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
|
// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
|
||||||
//
|
//
|
||||||
// If the wrapped RoundTripper panics or returns a non-nil error, the Counter
|
// If the wrapped RoundTripper panics or returns a non-nil error, the Counter
|
||||||
// is not incremented.
|
// is not incremented.
|
||||||
//
|
//
|
||||||
|
// Use with WithExemplarFromContext to instrument the exemplars on the counter of requests.
|
||||||
|
//
|
||||||
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
// 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 := defaultOptions()
|
||||||
|
for _, o := range opts {
|
||||||
|
o.apply(rtOpts)
|
||||||
|
}
|
||||||
|
|
||||||
code, method := checkLabels(counter)
|
code, method := checkLabels(counter)
|
||||||
|
|
||||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
return func(r *http.Request) (*http.Response, error) {
|
||||||
resp, err := next.RoundTrip(r)
|
resp, err := next.RoundTrip(r)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
|
addWithExemplar(
|
||||||
|
counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)),
|
||||||
|
1,
|
||||||
|
rtOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return resp, err
|
return resp, err
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstrumentRoundTripperDuration is a middleware that wraps the provided
|
// InstrumentRoundTripperDuration is a middleware that wraps the provided
|
||||||
// http.RoundTripper to observe the request duration with the provided
|
// http.RoundTripper to observe the request duration with the provided
|
||||||
// ObserverVec. The ObserverVec must have zero, one, or two non-const
|
// ObserverVec. The ObserverVec must have zero, one, or two non-const
|
||||||
// non-curried labels. For those, the only allowed label names are "code" and
|
// 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
|
// in the ObserverVec is called with the request duration in
|
||||||
// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
|
// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
|
||||||
// respective instance label names are present in the ObserverVec. For
|
// respective instance label names are present in the ObserverVec. For
|
||||||
|
|
@ -83,19 +100,30 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
|
||||||
// If the wrapped RoundTripper panics or returns a non-nil error, no values are
|
// If the wrapped RoundTripper panics or returns a non-nil error, no values are
|
||||||
// reported.
|
// reported.
|
||||||
//
|
//
|
||||||
|
// Use with WithExemplarFromContext to instrument the exemplars on the duration histograms.
|
||||||
|
//
|
||||||
// Note that this method is only guaranteed to never observe negative durations
|
// Note that this method is only guaranteed to never observe negative durations
|
||||||
// if used with Go1.9+.
|
// 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 := defaultOptions()
|
||||||
|
for _, o := range opts {
|
||||||
|
o.apply(rtOpts)
|
||||||
|
}
|
||||||
|
|
||||||
code, method := checkLabels(obs)
|
code, method := checkLabels(obs)
|
||||||
|
|
||||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
return func(r *http.Request) (*http.Response, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, err := next.RoundTrip(r)
|
resp, err := next.RoundTrip(r)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
|
observeWithExemplar(
|
||||||
|
obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)),
|
||||||
|
time.Since(start).Seconds(),
|
||||||
|
rtOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return resp, err
|
return resp, err
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstrumentTrace is used to offer flexibility in instrumenting the available
|
// InstrumentTrace is used to offer flexibility in instrumenting the available
|
||||||
|
|
@ -133,7 +161,7 @@ type InstrumentTrace struct {
|
||||||
//
|
//
|
||||||
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
||||||
func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc {
|
func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc {
|
||||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
return func(r *http.Request) (*http.Response, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
trace := &httptrace.ClientTrace{
|
trace := &httptrace.ClientTrace{
|
||||||
|
|
@ -215,5 +243,5 @@ func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) Ro
|
||||||
r = r.WithContext(httptrace.WithClientTrace(r.Context(), trace))
|
r = r.WithContext(httptrace.WithClientTrace(r.Context(), trace))
|
||||||
|
|
||||||
return next.RoundTrip(r)
|
return next.RoundTrip(r)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
196
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
generated
vendored
196
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
generated
vendored
|
|
@ -28,6 +28,26 @@ import (
|
||||||
// magicString is used for the hacky label test in checkLabels. Remove once fixed.
|
// magicString is used for the hacky label test in checkLabels. Remove once fixed.
|
||||||
const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
|
const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
|
||||||
|
|
||||||
|
// observeWithExemplar is a wrapper for [prometheus.ExemplarAdder.ExemplarObserver],
|
||||||
|
// which falls back to [prometheus.Observer.Observe] if no labels are provided.
|
||||||
|
func observeWithExemplar(obs prometheus.Observer, val float64, labels map[string]string) {
|
||||||
|
if labels == nil {
|
||||||
|
obs.Observe(val)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
obs.(prometheus.ExemplarObserver).ObserveWithExemplar(val, labels)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addWithExemplar is a wrapper for [prometheus.ExemplarAdder.AddWithExemplar],
|
||||||
|
// which falls back to [prometheus.Counter.Add] if no labels are provided.
|
||||||
|
func addWithExemplar(obs prometheus.Counter, val float64, labels map[string]string) {
|
||||||
|
if labels == nil {
|
||||||
|
obs.Add(val)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
obs.(prometheus.ExemplarAdder).AddWithExemplar(val, labels)
|
||||||
|
}
|
||||||
|
|
||||||
// InstrumentHandlerInFlight is a middleware that wraps the provided
|
// InstrumentHandlerInFlight is a middleware that wraps the provided
|
||||||
// http.Handler. It sets the provided prometheus.Gauge to the number of
|
// http.Handler. It sets the provided prometheus.Gauge to the number of
|
||||||
// requests currently handled by the wrapped http.Handler.
|
// requests currently handled by the wrapped http.Handler.
|
||||||
|
|
@ -45,7 +65,10 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
|
||||||
// http.Handler to observe the request duration with the provided ObserverVec.
|
// http.Handler to observe the request duration with the provided ObserverVec.
|
||||||
// The ObserverVec must have valid metric and label names and must have zero,
|
// 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
|
// 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
|
// 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
|
// 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
|
// in seconds. Partitioning happens by HTTP status code and/or HTTP method if
|
||||||
// the respective instance label names are present in the ObserverVec. For
|
// the respective instance label names are present in the ObserverVec. For
|
||||||
|
|
@ -58,31 +81,48 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
|
||||||
//
|
//
|
||||||
// Note that this method is only guaranteed to never observe negative durations
|
// Note that this method is only guaranteed to never observe negative durations
|
||||||
// if used with Go1.9+.
|
// 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 {
|
||||||
|
hOpts := defaultOptions()
|
||||||
|
for _, o := range opts {
|
||||||
|
o.apply(hOpts)
|
||||||
|
}
|
||||||
|
|
||||||
code, method := checkLabels(obs)
|
code, method := checkLabels(obs)
|
||||||
|
|
||||||
if code {
|
if code {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
d := newDelegator(w, nil)
|
d := newDelegator(w, nil)
|
||||||
next.ServeHTTP(d, r)
|
next.ServeHTTP(d, r)
|
||||||
|
|
||||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
|
observeWithExemplar(
|
||||||
})
|
obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
|
||||||
|
time.Since(now).Seconds(),
|
||||||
|
hOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds())
|
|
||||||
})
|
observeWithExemplar(
|
||||||
|
obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
|
||||||
|
time.Since(now).Seconds(),
|
||||||
|
hOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstrumentHandlerCounter is a middleware that wraps the provided http.Handler
|
// InstrumentHandlerCounter is a middleware that wraps the provided http.Handler
|
||||||
// to observe the request result with the provided CounterVec. The CounterVec
|
// 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
|
// 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
|
// non-const non-curried labels. For those, the only allowed label names are
|
||||||
// "code" and "method". The function panics otherwise. Partitioning of the
|
// "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
|
// CounterVec happens by HTTP status code and/or HTTP method if the respective
|
||||||
// instance label names are present in the CounterVec. For unpartitioned
|
// instance label names are present in the CounterVec. For unpartitioned
|
||||||
// counting, use a CounterVec with zero labels.
|
// counting, use a CounterVec with zero labels.
|
||||||
|
|
@ -92,21 +132,35 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
|
||||||
// If the wrapped Handler panics, the Counter is not incremented.
|
// If the wrapped Handler panics, the Counter is not incremented.
|
||||||
//
|
//
|
||||||
// See the example for InstrumentHandlerDuration for example usage.
|
// 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 {
|
||||||
|
hOpts := defaultOptions()
|
||||||
|
for _, o := range opts {
|
||||||
|
o.apply(hOpts)
|
||||||
|
}
|
||||||
|
|
||||||
code, method := checkLabels(counter)
|
code, method := checkLabels(counter)
|
||||||
|
|
||||||
if code {
|
if code {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
d := newDelegator(w, nil)
|
d := newDelegator(w, nil)
|
||||||
next.ServeHTTP(d, r)
|
next.ServeHTTP(d, r)
|
||||||
counter.With(labels(code, method, r.Method, d.Status())).Inc()
|
|
||||||
})
|
addWithExemplar(
|
||||||
|
counter.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
|
||||||
|
1,
|
||||||
|
hOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
counter.With(labels(code, method, r.Method, 0)).Inc()
|
addWithExemplar(
|
||||||
})
|
counter.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
|
||||||
|
1,
|
||||||
|
hOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided
|
// InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided
|
||||||
|
|
@ -114,7 +168,10 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
|
||||||
// until the response headers are written. The ObserverVec must have valid
|
// 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
|
// 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
|
// labels. For those, the only allowed label names are "code" and "method". The
|
||||||
// function panics otherwise. The Observe method of the Observer in 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
|
// ObserverVec is called with the request duration in seconds. Partitioning
|
||||||
// happens by HTTP status code and/or HTTP method if the respective instance
|
// happens by HTTP status code and/or HTTP method if the respective instance
|
||||||
// label names are present in the ObserverVec. For unpartitioned observations,
|
// label names are present in the ObserverVec. For unpartitioned observations,
|
||||||
|
|
@ -128,24 +185,36 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
|
||||||
// if used with Go1.9+.
|
// if used with Go1.9+.
|
||||||
//
|
//
|
||||||
// See the example for InstrumentHandlerDuration for example usage.
|
// 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 {
|
||||||
|
hOpts := defaultOptions()
|
||||||
|
for _, o := range opts {
|
||||||
|
o.apply(hOpts)
|
||||||
|
}
|
||||||
|
|
||||||
code, method := checkLabels(obs)
|
code, method := checkLabels(obs)
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
d := newDelegator(w, func(status int) {
|
d := newDelegator(w, func(status int) {
|
||||||
obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds())
|
observeWithExemplar(
|
||||||
|
obs.With(labels(code, method, r.Method, status, hOpts.extraMethods...)),
|
||||||
|
time.Since(now).Seconds(),
|
||||||
|
hOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
next.ServeHTTP(d, r)
|
next.ServeHTTP(d, r)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstrumentHandlerRequestSize is a middleware that wraps the provided
|
// InstrumentHandlerRequestSize is a middleware that wraps the provided
|
||||||
// http.Handler to observe the request size with the provided ObserverVec. The
|
// 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,
|
// 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
|
// 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
|
// are "code" and "method". The function panics otherwise. For the "method"
|
||||||
// the Observer in the ObserverVec is called with the request size in
|
// 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
|
// bytes. Partitioning happens by HTTP status code and/or HTTP method if the
|
||||||
// respective instance label names are present in the ObserverVec. For
|
// respective instance label names are present in the ObserverVec. For
|
||||||
// unpartitioned observations, use an ObserverVec with zero labels. Note that
|
// unpartitioned observations, use an ObserverVec with zero labels. Note that
|
||||||
|
|
@ -156,31 +225,46 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
|
||||||
// If the wrapped Handler panics, no values are reported.
|
// If the wrapped Handler panics, no values are reported.
|
||||||
//
|
//
|
||||||
// See the example for InstrumentHandlerDuration for example usage.
|
// 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 {
|
||||||
code, method := checkLabels(obs)
|
hOpts := defaultOptions()
|
||||||
|
for _, o := range opts {
|
||||||
|
o.apply(hOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
code, method := checkLabels(obs)
|
||||||
if code {
|
if code {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
d := newDelegator(w, nil)
|
d := newDelegator(w, nil)
|
||||||
next.ServeHTTP(d, r)
|
next.ServeHTTP(d, r)
|
||||||
size := computeApproximateRequestSize(r)
|
size := computeApproximateRequestSize(r)
|
||||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
|
observeWithExemplar(
|
||||||
})
|
obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
|
||||||
|
float64(size),
|
||||||
|
hOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
size := computeApproximateRequestSize(r)
|
size := computeApproximateRequestSize(r)
|
||||||
obs.With(labels(code, method, r.Method, 0)).Observe(float64(size))
|
observeWithExemplar(
|
||||||
})
|
obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
|
||||||
|
float64(size),
|
||||||
|
hOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstrumentHandlerResponseSize is a middleware that wraps the provided
|
// InstrumentHandlerResponseSize is a middleware that wraps the provided
|
||||||
// http.Handler to observe the response size with the provided ObserverVec. The
|
// 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,
|
// 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
|
// 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
|
// are "code" and "method". The function panics otherwise. For the "method"
|
||||||
// the Observer in the ObserverVec is called with the response size in
|
// 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
|
// bytes. Partitioning happens by HTTP status code and/or HTTP method if the
|
||||||
// respective instance label names are present in the ObserverVec. For
|
// respective instance label names are present in the ObserverVec. For
|
||||||
// unpartitioned observations, use an ObserverVec with zero labels. Note that
|
// unpartitioned observations, use an ObserverVec with zero labels. Note that
|
||||||
|
|
@ -191,12 +275,22 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
|
||||||
// If the wrapped Handler panics, no values are reported.
|
// If the wrapped Handler panics, no values are reported.
|
||||||
//
|
//
|
||||||
// See the example for InstrumentHandlerDuration for example usage.
|
// 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 {
|
||||||
|
hOpts := defaultOptions()
|
||||||
|
for _, o := range opts {
|
||||||
|
o.apply(hOpts)
|
||||||
|
}
|
||||||
|
|
||||||
code, method := checkLabels(obs)
|
code, method := checkLabels(obs)
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
d := newDelegator(w, nil)
|
d := newDelegator(w, nil)
|
||||||
next.ServeHTTP(d, r)
|
next.ServeHTTP(d, r)
|
||||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
|
observeWithExemplar(
|
||||||
|
obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
|
||||||
|
float64(d.Written()),
|
||||||
|
hOpts.getExemplarFn(r.Context()),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,7 +299,7 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler
|
||||||
// Collector does not have a Desc or has more than one Desc or its Desc is
|
// 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
|
// invalid. It also panics if the Collector has any non-const, non-curried
|
||||||
// labels that are not named "code" or "method".
|
// labels that are not named "code" or "method".
|
||||||
func checkLabels(c prometheus.Collector) (code bool, method bool) {
|
func checkLabels(c prometheus.Collector) (code, method bool) {
|
||||||
// TODO(beorn7): Remove this hacky way to check for instance labels
|
// TODO(beorn7): Remove this hacky way to check for instance labels
|
||||||
// once Descriptors can have their dimensionality queried.
|
// once Descriptors can have their dimensionality queried.
|
||||||
var (
|
var (
|
||||||
|
|
@ -290,7 +384,7 @@ func isLabelCurried(c prometheus.Collector, label string) bool {
|
||||||
// unnecessary allocations on each request.
|
// unnecessary allocations on each request.
|
||||||
var emptyLabels = prometheus.Labels{}
|
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) {
|
if !(code || method) {
|
||||||
return emptyLabels
|
return emptyLabels
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +394,7 @@ func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
|
||||||
labels["code"] = sanitizeCode(status)
|
labels["code"] = sanitizeCode(status)
|
||||||
}
|
}
|
||||||
if method {
|
if method {
|
||||||
labels["method"] = sanitizeMethod(reqMethod)
|
labels["method"] = sanitizeMethod(reqMethod, extraMethods...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return labels
|
return labels
|
||||||
|
|
@ -330,7 +424,12 @@ func computeApproximateRequestSize(r *http.Request) int {
|
||||||
return s
|
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 {
|
switch m {
|
||||||
case "GET", "get":
|
case "GET", "get":
|
||||||
return "get"
|
return "get"
|
||||||
|
|
@ -348,15 +447,25 @@ func sanitizeMethod(m string) string {
|
||||||
return "options"
|
return "options"
|
||||||
case "NOTIFY", "notify":
|
case "NOTIFY", "notify":
|
||||||
return "notify"
|
return "notify"
|
||||||
|
case "TRACE", "trace":
|
||||||
|
return "trace"
|
||||||
|
case "PATCH", "patch":
|
||||||
|
return "patch"
|
||||||
default:
|
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
|
// 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.
|
// the stdlib.
|
||||||
func sanitizeCode(s int) string {
|
func sanitizeCode(s int) string {
|
||||||
|
// See for accepted codes https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||||
switch s {
|
switch s {
|
||||||
case 100:
|
case 100:
|
||||||
return "100"
|
return "100"
|
||||||
|
|
@ -453,6 +562,9 @@ func sanitizeCode(s int) string {
|
||||||
return "511"
|
return "511"
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return strconv.Itoa(s)
|
if s >= 100 && s <= 599 {
|
||||||
|
return strconv.Itoa(s)
|
||||||
|
}
|
||||||
|
return "unknown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
58
vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
generated
vendored
Normal file
58
vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Option are used to configure both handler (middleware) or round tripper.
|
||||||
|
type Option interface {
|
||||||
|
apply(*options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// options store options for both a handler or round tripper.
|
||||||
|
type options struct {
|
||||||
|
extraMethods []string
|
||||||
|
getExemplarFn func(requestCtx context.Context) prometheus.Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultOptions() *options {
|
||||||
|
return &options{getExemplarFn: func(ctx context.Context) prometheus.Labels { return nil }}
|
||||||
|
}
|
||||||
|
|
||||||
|
type optionApplyFunc func(*options)
|
||||||
|
|
||||||
|
func (o optionApplyFunc) apply(opt *options) { o(opt) }
|
||||||
|
|
||||||
|
// 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 optionApplyFunc(func(o *options) {
|
||||||
|
o.extraMethods = methods
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithExemplarFromContext adds allows to put a hook to all counter and histogram metrics.
|
||||||
|
// If the hook function returns non-nil labels, exemplars will be added for that request, otherwise metric
|
||||||
|
// will get instrumented without exemplar.
|
||||||
|
func WithExemplarFromContext(getExemplarFn func(requestCtx context.Context) prometheus.Labels) Option {
|
||||||
|
return optionApplyFunc(func(o *options) {
|
||||||
|
o.getExemplarFn = getExemplarFn
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -15,8 +15,8 @@ package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
@ -252,9 +252,12 @@ func (errs MultiError) MaybeUnwrap() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registry registers Prometheus collectors, collects their metrics, and gathers
|
// Registry registers Prometheus collectors, collects their metrics, and gathers
|
||||||
// them into MetricFamilies for exposition. It implements both Registerer and
|
// them into MetricFamilies for exposition. It implements Registerer, Gatherer,
|
||||||
// Gatherer. The zero value is not usable. Create instances with NewRegistry or
|
// and Collector. The zero value is not usable. Create instances with
|
||||||
// NewPedanticRegistry.
|
// NewRegistry or NewPedanticRegistry.
|
||||||
|
//
|
||||||
|
// Registry implements Collector to allow it to be used for creating groups of
|
||||||
|
// metrics. See the Grouping example for how this can be done.
|
||||||
type Registry struct {
|
type Registry struct {
|
||||||
mtx sync.RWMutex
|
mtx sync.RWMutex
|
||||||
collectorsByID map[uint64]Collector // ID is a hash of the descIDs.
|
collectorsByID map[uint64]Collector // ID is a hash of the descIDs.
|
||||||
|
|
@ -289,7 +292,7 @@ func (r *Registry) Register(c Collector) error {
|
||||||
|
|
||||||
// Is the descriptor valid at all?
|
// Is the descriptor valid at all?
|
||||||
if desc.err != nil {
|
if desc.err != nil {
|
||||||
return fmt.Errorf("descriptor %s is invalid: %s", desc, desc.err)
|
return fmt.Errorf("descriptor %s is invalid: %w", desc, desc.err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the descID unique?
|
// Is the descID unique?
|
||||||
|
|
@ -407,6 +410,14 @@ func (r *Registry) MustRegister(cs ...Collector) {
|
||||||
|
|
||||||
// Gather implements Gatherer.
|
// Gather implements Gatherer.
|
||||||
func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
|
func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
|
||||||
|
r.mtx.RLock()
|
||||||
|
|
||||||
|
if len(r.collectorsByID) == 0 && len(r.uncheckedCollectors) == 0 {
|
||||||
|
// Fast path.
|
||||||
|
r.mtx.RUnlock()
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
checkedMetricChan = make(chan Metric, capMetricChan)
|
checkedMetricChan = make(chan Metric, capMetricChan)
|
||||||
uncheckedMetricChan = make(chan Metric, capMetricChan)
|
uncheckedMetricChan = make(chan Metric, capMetricChan)
|
||||||
|
|
@ -416,7 +427,6 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
|
||||||
registeredDescIDs map[uint64]struct{} // Only used for pedantic checks
|
registeredDescIDs map[uint64]struct{} // Only used for pedantic checks
|
||||||
)
|
)
|
||||||
|
|
||||||
r.mtx.RLock()
|
|
||||||
goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors)
|
goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors)
|
||||||
metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName))
|
metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName))
|
||||||
checkedCollectors := make(chan Collector, len(r.collectorsByID))
|
checkedCollectors := make(chan Collector, len(r.collectorsByID))
|
||||||
|
|
@ -549,6 +559,31 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
|
||||||
return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap()
|
return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe implements Collector.
|
||||||
|
func (r *Registry) Describe(ch chan<- *Desc) {
|
||||||
|
r.mtx.RLock()
|
||||||
|
defer r.mtx.RUnlock()
|
||||||
|
|
||||||
|
// Only report the checked Collectors; unchecked collectors don't report any
|
||||||
|
// Desc.
|
||||||
|
for _, c := range r.collectorsByID {
|
||||||
|
c.Describe(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect implements Collector.
|
||||||
|
func (r *Registry) Collect(ch chan<- Metric) {
|
||||||
|
r.mtx.RLock()
|
||||||
|
defer r.mtx.RUnlock()
|
||||||
|
|
||||||
|
for _, c := range r.collectorsByID {
|
||||||
|
c.Collect(ch)
|
||||||
|
}
|
||||||
|
for _, c := range r.uncheckedCollectors {
|
||||||
|
c.Collect(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the
|
// WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the
|
||||||
// Prometheus text format, and writes it to a temporary file. Upon success, the
|
// Prometheus text format, and writes it to a temporary file. Upon success, the
|
||||||
// temporary file is renamed to the provided filename.
|
// temporary file is renamed to the provided filename.
|
||||||
|
|
@ -556,7 +591,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
|
||||||
// This is intended for use with the textfile collector of the node exporter.
|
// This is intended for use with the textfile collector of the node exporter.
|
||||||
// Note that the node exporter expects the filename to be suffixed with ".prom".
|
// Note that the node exporter expects the filename to be suffixed with ".prom".
|
||||||
func WriteToTextfile(filename string, g Gatherer) error {
|
func WriteToTextfile(filename string, g Gatherer) error {
|
||||||
tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename))
|
tmp, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -575,7 +610,7 @@ func WriteToTextfile(filename string, g Gatherer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Chmod(tmp.Name(), 0644); err != nil {
|
if err := os.Chmod(tmp.Name(), 0o644); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.Rename(tmp.Name(), filename)
|
return os.Rename(tmp.Name(), filename)
|
||||||
|
|
@ -596,7 +631,7 @@ func processMetric(
|
||||||
}
|
}
|
||||||
dtoMetric := &dto.Metric{}
|
dtoMetric := &dto.Metric{}
|
||||||
if err := metric.Write(dtoMetric); err != nil {
|
if err := metric.Write(dtoMetric); err != nil {
|
||||||
return fmt.Errorf("error collecting metric %v: %s", desc, err)
|
return fmt.Errorf("error collecting metric %v: %w", desc, err)
|
||||||
}
|
}
|
||||||
metricFamily, ok := metricFamiliesByName[desc.fqName]
|
metricFamily, ok := metricFamiliesByName[desc.fqName]
|
||||||
if ok { // Existing name.
|
if ok { // Existing name.
|
||||||
|
|
@ -718,12 +753,13 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) {
|
||||||
for i, g := range gs {
|
for i, g := range gs {
|
||||||
mfs, err := g.Gather()
|
mfs, err := g.Gather()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if multiErr, ok := err.(MultiError); ok {
|
multiErr := MultiError{}
|
||||||
|
if errors.As(err, &multiErr) {
|
||||||
for _, err := range multiErr {
|
for _, err := range multiErr {
|
||||||
errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err))
|
errs = append(errs, fmt.Errorf("[from Gatherer #%d] %w", i+1, err))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err))
|
errs = append(errs, fmt.Errorf("[from Gatherer #%d] %w", i+1, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, mf := range mfs {
|
for _, mf := range mfs {
|
||||||
|
|
@ -884,11 +920,11 @@ func checkMetricConsistency(
|
||||||
h.Write(separatorByteSlice)
|
h.Write(separatorByteSlice)
|
||||||
// Make sure label pairs are sorted. We depend on it for the consistency
|
// Make sure label pairs are sorted. We depend on it for the consistency
|
||||||
// check.
|
// check.
|
||||||
if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) {
|
if !sort.IsSorted(internal.LabelPairSorter(dtoMetric.Label)) {
|
||||||
// We cannot sort dtoMetric.Label in place as it is immutable by contract.
|
// We cannot sort dtoMetric.Label in place as it is immutable by contract.
|
||||||
copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label))
|
copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label))
|
||||||
copy(copiedLabels, dtoMetric.Label)
|
copy(copiedLabels, dtoMetric.Label)
|
||||||
sort.Sort(labelPairSorter(copiedLabels))
|
sort.Sort(internal.LabelPairSorter(copiedLabels))
|
||||||
dtoMetric.Label = copiedLabels
|
dtoMetric.Label = copiedLabels
|
||||||
}
|
}
|
||||||
for _, lp := range dtoMetric.Label {
|
for _, lp := range dtoMetric.Label {
|
||||||
|
|
@ -935,7 +971,7 @@ func checkDescConsistency(
|
||||||
metricFamily.GetName(), dtoMetric, desc,
|
metricFamily.GetName(), dtoMetric, desc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
sort.Sort(labelPairSorter(lpsFromDesc))
|
sort.Sort(internal.LabelPairSorter(lpsFromDesc))
|
||||||
for i, lpFromDesc := range lpsFromDesc {
|
for i, lpFromDesc := range lpsFromDesc {
|
||||||
lpFromMetric := dtoMetric.Label[i]
|
lpFromMetric := dtoMetric.Label[i]
|
||||||
if lpFromDesc.GetName() != lpFromMetric.GetName() ||
|
if lpFromDesc.GetName() != lpFromMetric.GetName() ||
|
||||||
|
|
@ -948,3 +984,89 @@ func checkDescConsistency(
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ TransactionalGatherer = &MultiTRegistry{}
|
||||||
|
|
||||||
|
// MultiTRegistry is a TransactionalGatherer that joins gathered metrics from multiple
|
||||||
|
// transactional gatherers.
|
||||||
|
//
|
||||||
|
// It is caller responsibility to ensure two registries have mutually exclusive metric families,
|
||||||
|
// no deduplication will happen.
|
||||||
|
type MultiTRegistry struct {
|
||||||
|
tGatherers []TransactionalGatherer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMultiTRegistry creates MultiTRegistry.
|
||||||
|
func NewMultiTRegistry(tGatherers ...TransactionalGatherer) *MultiTRegistry {
|
||||||
|
return &MultiTRegistry{
|
||||||
|
tGatherers: tGatherers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gather implements TransactionalGatherer interface.
|
||||||
|
func (r *MultiTRegistry) Gather() (mfs []*dto.MetricFamily, done func(), err error) {
|
||||||
|
errs := MultiError{}
|
||||||
|
|
||||||
|
dFns := make([]func(), 0, len(r.tGatherers))
|
||||||
|
// TODO(bwplotka): Implement concurrency for those?
|
||||||
|
for _, g := range r.tGatherers {
|
||||||
|
// TODO(bwplotka): Check for duplicates?
|
||||||
|
m, d, err := g.Gather()
|
||||||
|
errs.Append(err)
|
||||||
|
|
||||||
|
mfs = append(mfs, m...)
|
||||||
|
dFns = append(dFns, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(bwplotka): Consider sort in place, given metric family in gather is sorted already.
|
||||||
|
sort.Slice(mfs, func(i, j int) bool {
|
||||||
|
return *mfs[i].Name < *mfs[j].Name
|
||||||
|
})
|
||||||
|
return mfs, func() {
|
||||||
|
for _, d := range dFns {
|
||||||
|
d()
|
||||||
|
}
|
||||||
|
}, errs.MaybeUnwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransactionalGatherer represents transactional gatherer that can be triggered to notify gatherer that memory
|
||||||
|
// used by metric family is no longer used by a caller. This allows implementations with cache.
|
||||||
|
type TransactionalGatherer interface {
|
||||||
|
// Gather returns metrics in a lexicographically sorted slice
|
||||||
|
// of uniquely named MetricFamily protobufs. Gather ensures that the
|
||||||
|
// returned slice is valid and self-consistent so that it can be used
|
||||||
|
// for valid exposition. As an exception to the strict consistency
|
||||||
|
// requirements described for metric.Desc, Gather will tolerate
|
||||||
|
// different sets of label names for metrics of the same metric family.
|
||||||
|
//
|
||||||
|
// Even if an error occurs, Gather attempts to gather as many metrics as
|
||||||
|
// possible. Hence, if a non-nil error is returned, the returned
|
||||||
|
// MetricFamily slice could be nil (in case of a fatal error that
|
||||||
|
// prevented any meaningful metric collection) or contain a number of
|
||||||
|
// MetricFamily protobufs, some of which might be incomplete, and some
|
||||||
|
// might be missing altogether. The returned error (which might be a
|
||||||
|
// MultiError) explains the details. Note that this is mostly useful for
|
||||||
|
// debugging purposes. If the gathered protobufs are to be used for
|
||||||
|
// exposition in actual monitoring, it is almost always better to not
|
||||||
|
// expose an incomplete result and instead disregard the returned
|
||||||
|
// MetricFamily protobufs in case the returned error is non-nil.
|
||||||
|
//
|
||||||
|
// Important: done is expected to be triggered (even if the error occurs!)
|
||||||
|
// once caller does not need returned slice of dto.MetricFamily.
|
||||||
|
Gather() (_ []*dto.MetricFamily, done func(), err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTransactionalGatherer transforms Gatherer to transactional one with noop as done function.
|
||||||
|
func ToTransactionalGatherer(g Gatherer) TransactionalGatherer {
|
||||||
|
return &noTransactionGatherer{g: g}
|
||||||
|
}
|
||||||
|
|
||||||
|
type noTransactionGatherer struct {
|
||||||
|
g Gatherer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gather implements TransactionalGatherer interface.
|
||||||
|
func (g *noTransactionGatherer) Gather() (_ []*dto.MetricFamily, done func(), err error) {
|
||||||
|
mfs, err := g.g.Gather()
|
||||||
|
return mfs, func() {}, err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -603,7 +603,8 @@ func (v *SummaryVec) GetMetricWith(labels Labels) (Observer, error) {
|
||||||
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||||
// GetMetricWithLabelValues would have returned an error. Not returning an
|
// GetMetricWithLabelValues would have returned an error. Not returning an
|
||||||
// error allows shortcuts like
|
// error allows shortcuts like
|
||||||
// myVec.WithLabelValues("404", "GET").Observe(42.21)
|
//
|
||||||
|
// myVec.WithLabelValues("404", "GET").Observe(42.21)
|
||||||
func (v *SummaryVec) WithLabelValues(lvs ...string) Observer {
|
func (v *SummaryVec) WithLabelValues(lvs ...string) Observer {
|
||||||
s, err := v.GetMetricWithLabelValues(lvs...)
|
s, err := v.GetMetricWithLabelValues(lvs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -614,7 +615,8 @@ func (v *SummaryVec) WithLabelValues(lvs ...string) Observer {
|
||||||
|
|
||||||
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
||||||
// returned an error. Not returning an error allows shortcuts like
|
// returned an error. Not returning an error allows shortcuts like
|
||||||
// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21)
|
//
|
||||||
|
// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21)
|
||||||
func (v *SummaryVec) With(labels Labels) Observer {
|
func (v *SummaryVec) With(labels Labels) Observer {
|
||||||
s, err := v.GetMetricWith(labels)
|
s, err := v.GetMetricWith(labels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -701,7 +703,8 @@ func (s *constSummary) Write(out *dto.Metric) error {
|
||||||
//
|
//
|
||||||
// quantiles maps ranks to quantile values. For example, a median latency of
|
// quantiles maps ranks to quantile values. For example, a median latency of
|
||||||
// 0.23s and a 99th percentile latency of 0.56s would be expressed as:
|
// 0.23s and a 99th percentile latency of 0.56s would be expressed as:
|
||||||
// map[float64]float64{0.5: 0.23, 0.99: 0.56}
|
//
|
||||||
|
// map[float64]float64{0.5: 0.23, 0.99: 0.56}
|
||||||
//
|
//
|
||||||
// NewConstSummary returns an error if the length of labelValues is not
|
// NewConstSummary returns an error if the length of labelValues is not
|
||||||
// consistent with the variable labels in Desc or if Desc is invalid.
|
// consistent with the variable labels in Desc or if Desc is invalid.
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,12 @@ type Timer struct {
|
||||||
// NewTimer creates a new Timer. The provided Observer is used to observe a
|
// NewTimer creates a new Timer. The provided Observer is used to observe a
|
||||||
// duration in seconds. Timer is usually used to time a function call in the
|
// duration in seconds. Timer is usually used to time a function call in the
|
||||||
// following way:
|
// following way:
|
||||||
// func TimeMe() {
|
//
|
||||||
// timer := NewTimer(myHistogram)
|
// func TimeMe() {
|
||||||
// defer timer.ObserveDuration()
|
// timer := NewTimer(myHistogram)
|
||||||
// // Do actual work.
|
// defer timer.ObserveDuration()
|
||||||
// }
|
// // Do actual work.
|
||||||
|
// }
|
||||||
func NewTimer(o Observer) *Timer {
|
func NewTimer(o Observer) *Timer {
|
||||||
return &Timer{
|
return &Timer{
|
||||||
begin: time.Now(),
|
begin: time.Now(),
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@ import (
|
||||||
|
|
||||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/golang/protobuf/ptypes"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus/internal"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
@ -38,6 +40,23 @@ const (
|
||||||
UntypedValue
|
UntypedValue
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CounterMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_COUNTER; return &d }()
|
||||||
|
GaugeMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_GAUGE; return &d }()
|
||||||
|
UntypedMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_UNTYPED; return &d }()
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v ValueType) ToDTO() *dto.MetricType {
|
||||||
|
switch v {
|
||||||
|
case CounterValue:
|
||||||
|
return CounterMetricTypePtr
|
||||||
|
case GaugeValue:
|
||||||
|
return GaugeMetricTypePtr
|
||||||
|
default:
|
||||||
|
return UntypedMetricTypePtr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// valueFunc is a generic metric for simple values retrieved on collect time
|
// valueFunc is a generic metric for simple values retrieved on collect time
|
||||||
// from a function. It implements Metric and Collector. Its effective type is
|
// from a function. It implements Metric and Collector. Its effective type is
|
||||||
// determined by ValueType. This is a low-level building block used by the
|
// determined by ValueType. This is a low-level building block used by the
|
||||||
|
|
@ -91,11 +110,15 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues
|
||||||
if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
|
if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metric := &dto.Metric{}
|
||||||
|
if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &constMetric{
|
return &constMetric{
|
||||||
desc: desc,
|
desc: desc,
|
||||||
valType: valueType,
|
metric: metric,
|
||||||
val: value,
|
|
||||||
labelPairs: MakeLabelPairs(desc, labelValues),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,10 +133,8 @@ func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelVal
|
||||||
}
|
}
|
||||||
|
|
||||||
type constMetric struct {
|
type constMetric struct {
|
||||||
desc *Desc
|
desc *Desc
|
||||||
valType ValueType
|
metric *dto.Metric
|
||||||
val float64
|
|
||||||
labelPairs []*dto.LabelPair
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *constMetric) Desc() *Desc {
|
func (m *constMetric) Desc() *Desc {
|
||||||
|
|
@ -121,7 +142,11 @@ func (m *constMetric) Desc() *Desc {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *constMetric) Write(out *dto.Metric) error {
|
func (m *constMetric) Write(out *dto.Metric) error {
|
||||||
return populateMetric(m.valType, m.val, m.labelPairs, nil, out)
|
out.Label = m.metric.Label
|
||||||
|
out.Counter = m.metric.Counter
|
||||||
|
out.Gauge = m.metric.Gauge
|
||||||
|
out.Untyped = m.metric.Untyped
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func populateMetric(
|
func populateMetric(
|
||||||
|
|
@ -170,12 +195,12 @@ func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
labelPairs = append(labelPairs, desc.constLabelPairs...)
|
labelPairs = append(labelPairs, desc.constLabelPairs...)
|
||||||
sort.Sort(labelPairSorter(labelPairs))
|
sort.Sort(internal.LabelPairSorter(labelPairs))
|
||||||
return labelPairs
|
return labelPairs
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExemplarMaxRunes is the max total number of runes allowed in exemplar labels.
|
// ExemplarMaxRunes is the max total number of runes allowed in exemplar labels.
|
||||||
const ExemplarMaxRunes = 64
|
const ExemplarMaxRunes = 128
|
||||||
|
|
||||||
// newExemplar creates a new dto.Exemplar from the provided values. An error is
|
// newExemplar creates a new dto.Exemplar from the provided values. An error is
|
||||||
// returned if any of the label names or values are invalid or if the total
|
// returned if any of the label names or values are invalid or if the total
|
||||||
|
|
@ -183,8 +208,8 @@ const ExemplarMaxRunes = 64
|
||||||
func newExemplar(value float64, ts time.Time, l Labels) (*dto.Exemplar, error) {
|
func newExemplar(value float64, ts time.Time, l Labels) (*dto.Exemplar, error) {
|
||||||
e := &dto.Exemplar{}
|
e := &dto.Exemplar{}
|
||||||
e.Value = proto.Float64(value)
|
e.Value = proto.Float64(value)
|
||||||
tsProto, err := ptypes.TimestampProto(ts)
|
tsProto := timestamppb.New(ts)
|
||||||
if err != nil {
|
if err := tsProto.CheckValid(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
e.Timestamp = tsProto
|
e.Timestamp = tsProto
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,16 @@ func (m *MetricVec) Delete(labels Labels) bool {
|
||||||
return m.metricMap.deleteByHashWithLabels(h, labels, m.curry)
|
return m.metricMap.deleteByHashWithLabels(h, labels, m.curry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeletePartialMatch deletes all metrics where the variable labels contain all of those
|
||||||
|
// passed in as labels. The order of the labels does not matter.
|
||||||
|
// It returns the number of metrics deleted.
|
||||||
|
//
|
||||||
|
// Note that curried labels will never be matched if deleting from the curried vector.
|
||||||
|
// To match curried labels with DeletePartialMatch, it must be called on the base vector.
|
||||||
|
func (m *MetricVec) DeletePartialMatch(labels Labels) int {
|
||||||
|
return m.metricMap.deleteByLabels(labels, m.curry)
|
||||||
|
}
|
||||||
|
|
||||||
// Without explicit forwarding of Describe, Collect, Reset, those methods won't
|
// Without explicit forwarding of Describe, Collect, Reset, those methods won't
|
||||||
// show up in GoDoc.
|
// show up in GoDoc.
|
||||||
|
|
||||||
|
|
@ -381,6 +391,82 @@ func (m *metricMap) deleteByHashWithLabels(
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deleteByLabels deletes a metric if the given labels are present in the metric.
|
||||||
|
func (m *metricMap) deleteByLabels(labels Labels, curry []curriedLabelValue) int {
|
||||||
|
m.mtx.Lock()
|
||||||
|
defer m.mtx.Unlock()
|
||||||
|
|
||||||
|
var numDeleted int
|
||||||
|
|
||||||
|
for h, metrics := range m.metrics {
|
||||||
|
i := findMetricWithPartialLabels(m.desc, metrics, labels, curry)
|
||||||
|
if i >= len(metrics) {
|
||||||
|
// Didn't find matching labels in this metric slice.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(m.metrics, h)
|
||||||
|
numDeleted++
|
||||||
|
}
|
||||||
|
|
||||||
|
return numDeleted
|
||||||
|
}
|
||||||
|
|
||||||
|
// findMetricWithPartialLabel returns the index of the matching metric or
|
||||||
|
// len(metrics) if not found.
|
||||||
|
func findMetricWithPartialLabels(
|
||||||
|
desc *Desc, metrics []metricWithLabelValues, labels Labels, curry []curriedLabelValue,
|
||||||
|
) int {
|
||||||
|
for i, metric := range metrics {
|
||||||
|
if matchPartialLabels(desc, metric.values, labels, curry) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(metrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
// indexOf searches the given slice of strings for the target string and returns
|
||||||
|
// the index or len(items) as well as a boolean whether the search succeeded.
|
||||||
|
func indexOf(target string, items []string) (int, bool) {
|
||||||
|
for i, l := range items {
|
||||||
|
if l == target {
|
||||||
|
return i, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(items), false
|
||||||
|
}
|
||||||
|
|
||||||
|
// valueMatchesVariableOrCurriedValue determines if a value was previously curried,
|
||||||
|
// and returns whether it matches either the "base" value or the curried value accordingly.
|
||||||
|
// It also indicates whether the match is against a curried or uncurried value.
|
||||||
|
func valueMatchesVariableOrCurriedValue(targetValue string, index int, values []string, curry []curriedLabelValue) (bool, bool) {
|
||||||
|
for _, curriedValue := range curry {
|
||||||
|
if curriedValue.index == index {
|
||||||
|
// This label was curried. See if the curried value matches our target.
|
||||||
|
return curriedValue.value == targetValue, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This label was not curried. See if the current value matches our target label.
|
||||||
|
return values[index] == targetValue, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchPartialLabels searches the current metric and returns whether all of the target label:value pairs are present.
|
||||||
|
func matchPartialLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool {
|
||||||
|
for l, v := range labels {
|
||||||
|
// Check if the target label exists in our metrics and get the index.
|
||||||
|
varLabelIndex, validLabel := indexOf(l, desc.variableLabels)
|
||||||
|
if validLabel {
|
||||||
|
// Check the value of that label against the target value.
|
||||||
|
// We don't consider curried values in partial matches.
|
||||||
|
matches, curried := valueMatchesVariableOrCurriedValue(v, varLabelIndex, values, curry)
|
||||||
|
if matches && !curried {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
|
// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
|
||||||
// or creates it and returns the new one.
|
// or creates it and returns the new one.
|
||||||
//
|
//
|
||||||
|
|
@ -485,7 +571,7 @@ func findMetricWithLabels(
|
||||||
return len(metrics)
|
return len(metrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchLabelValues(values []string, lvs []string, curry []curriedLabelValue) bool {
|
func matchLabelValues(values, lvs []string, curry []curriedLabelValue) bool {
|
||||||
if len(values) != len(lvs)+len(curry) {
|
if len(values) != len(lvs)+len(curry) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ import (
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WrapRegistererWith returns a Registerer wrapping the provided
|
// WrapRegistererWith returns a Registerer wrapping the provided
|
||||||
|
|
@ -182,7 +184,7 @@ func (m *wrappingMetric) Write(out *dto.Metric) error {
|
||||||
Value: proto.String(lv),
|
Value: proto.String(lv),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sort.Sort(labelPairSorter(out.Label))
|
sort.Sort(internal.LabelPairSorter(out.Label))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// source: metrics.proto
|
// source: io/prometheus/client/metrics.proto
|
||||||
|
|
||||||
package io_prometheus_client
|
package io_prometheus_client
|
||||||
|
|
||||||
|
|
@ -24,11 +24,18 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||||
type MetricType int32
|
type MetricType int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MetricType_COUNTER MetricType = 0
|
// COUNTER must use the Metric field "counter".
|
||||||
MetricType_GAUGE MetricType = 1
|
MetricType_COUNTER MetricType = 0
|
||||||
MetricType_SUMMARY MetricType = 2
|
// GAUGE must use the Metric field "gauge".
|
||||||
MetricType_UNTYPED MetricType = 3
|
MetricType_GAUGE MetricType = 1
|
||||||
|
// SUMMARY must use the Metric field "summary".
|
||||||
|
MetricType_SUMMARY MetricType = 2
|
||||||
|
// UNTYPED must use the Metric field "untyped".
|
||||||
|
MetricType_UNTYPED MetricType = 3
|
||||||
|
// HISTOGRAM must use the Metric field "histogram".
|
||||||
MetricType_HISTOGRAM MetricType = 4
|
MetricType_HISTOGRAM MetricType = 4
|
||||||
|
// GAUGE_HISTOGRAM must use the Metric field "histogram".
|
||||||
|
MetricType_GAUGE_HISTOGRAM MetricType = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
var MetricType_name = map[int32]string{
|
var MetricType_name = map[int32]string{
|
||||||
|
|
@ -37,14 +44,16 @@ var MetricType_name = map[int32]string{
|
||||||
2: "SUMMARY",
|
2: "SUMMARY",
|
||||||
3: "UNTYPED",
|
3: "UNTYPED",
|
||||||
4: "HISTOGRAM",
|
4: "HISTOGRAM",
|
||||||
|
5: "GAUGE_HISTOGRAM",
|
||||||
}
|
}
|
||||||
|
|
||||||
var MetricType_value = map[string]int32{
|
var MetricType_value = map[string]int32{
|
||||||
"COUNTER": 0,
|
"COUNTER": 0,
|
||||||
"GAUGE": 1,
|
"GAUGE": 1,
|
||||||
"SUMMARY": 2,
|
"SUMMARY": 2,
|
||||||
"UNTYPED": 3,
|
"UNTYPED": 3,
|
||||||
"HISTOGRAM": 4,
|
"HISTOGRAM": 4,
|
||||||
|
"GAUGE_HISTOGRAM": 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x MetricType) Enum() *MetricType {
|
func (x MetricType) Enum() *MetricType {
|
||||||
|
|
@ -67,7 +76,7 @@ func (x *MetricType) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (MetricType) EnumDescriptor() ([]byte, []int) {
|
func (MetricType) EnumDescriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{0}
|
return fileDescriptor_d1e5ddb18987a258, []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LabelPair struct {
|
type LabelPair struct {
|
||||||
|
|
@ -82,7 +91,7 @@ func (m *LabelPair) Reset() { *m = LabelPair{} }
|
||||||
func (m *LabelPair) String() string { return proto.CompactTextString(m) }
|
func (m *LabelPair) String() string { return proto.CompactTextString(m) }
|
||||||
func (*LabelPair) ProtoMessage() {}
|
func (*LabelPair) ProtoMessage() {}
|
||||||
func (*LabelPair) Descriptor() ([]byte, []int) {
|
func (*LabelPair) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{0}
|
return fileDescriptor_d1e5ddb18987a258, []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *LabelPair) XXX_Unmarshal(b []byte) error {
|
func (m *LabelPair) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -128,7 +137,7 @@ func (m *Gauge) Reset() { *m = Gauge{} }
|
||||||
func (m *Gauge) String() string { return proto.CompactTextString(m) }
|
func (m *Gauge) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Gauge) ProtoMessage() {}
|
func (*Gauge) ProtoMessage() {}
|
||||||
func (*Gauge) Descriptor() ([]byte, []int) {
|
func (*Gauge) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{1}
|
return fileDescriptor_d1e5ddb18987a258, []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Gauge) XXX_Unmarshal(b []byte) error {
|
func (m *Gauge) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -168,7 +177,7 @@ func (m *Counter) Reset() { *m = Counter{} }
|
||||||
func (m *Counter) String() string { return proto.CompactTextString(m) }
|
func (m *Counter) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Counter) ProtoMessage() {}
|
func (*Counter) ProtoMessage() {}
|
||||||
func (*Counter) Descriptor() ([]byte, []int) {
|
func (*Counter) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{2}
|
return fileDescriptor_d1e5ddb18987a258, []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Counter) XXX_Unmarshal(b []byte) error {
|
func (m *Counter) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -215,7 +224,7 @@ func (m *Quantile) Reset() { *m = Quantile{} }
|
||||||
func (m *Quantile) String() string { return proto.CompactTextString(m) }
|
func (m *Quantile) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Quantile) ProtoMessage() {}
|
func (*Quantile) ProtoMessage() {}
|
||||||
func (*Quantile) Descriptor() ([]byte, []int) {
|
func (*Quantile) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{3}
|
return fileDescriptor_d1e5ddb18987a258, []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Quantile) XXX_Unmarshal(b []byte) error {
|
func (m *Quantile) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -263,7 +272,7 @@ func (m *Summary) Reset() { *m = Summary{} }
|
||||||
func (m *Summary) String() string { return proto.CompactTextString(m) }
|
func (m *Summary) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Summary) ProtoMessage() {}
|
func (*Summary) ProtoMessage() {}
|
||||||
func (*Summary) Descriptor() ([]byte, []int) {
|
func (*Summary) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{4}
|
return fileDescriptor_d1e5ddb18987a258, []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Summary) XXX_Unmarshal(b []byte) error {
|
func (m *Summary) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -316,7 +325,7 @@ func (m *Untyped) Reset() { *m = Untyped{} }
|
||||||
func (m *Untyped) String() string { return proto.CompactTextString(m) }
|
func (m *Untyped) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Untyped) ProtoMessage() {}
|
func (*Untyped) ProtoMessage() {}
|
||||||
func (*Untyped) Descriptor() ([]byte, []int) {
|
func (*Untyped) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{5}
|
return fileDescriptor_d1e5ddb18987a258, []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Untyped) XXX_Unmarshal(b []byte) error {
|
func (m *Untyped) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -345,9 +354,34 @@ func (m *Untyped) GetValue() float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Histogram struct {
|
type Histogram struct {
|
||||||
SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"`
|
SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"`
|
||||||
SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"`
|
SampleCountFloat *float64 `protobuf:"fixed64,4,opt,name=sample_count_float,json=sampleCountFloat" json:"sample_count_float,omitempty"`
|
||||||
Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"`
|
SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"`
|
||||||
|
// Buckets for the conventional histogram.
|
||||||
|
Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"`
|
||||||
|
// schema defines the bucket schema. Currently, valid numbers are -4 <= n <= 8.
|
||||||
|
// They are all for base-2 bucket schemas, where 1 is a bucket boundary in each case, and
|
||||||
|
// then each power of two is divided into 2^n logarithmic buckets.
|
||||||
|
// Or in other words, each bucket boundary is the previous boundary times 2^(2^-n).
|
||||||
|
// In the future, more bucket schemas may be added using numbers < -4 or > 8.
|
||||||
|
Schema *int32 `protobuf:"zigzag32,5,opt,name=schema" json:"schema,omitempty"`
|
||||||
|
ZeroThreshold *float64 `protobuf:"fixed64,6,opt,name=zero_threshold,json=zeroThreshold" json:"zero_threshold,omitempty"`
|
||||||
|
ZeroCount *uint64 `protobuf:"varint,7,opt,name=zero_count,json=zeroCount" json:"zero_count,omitempty"`
|
||||||
|
ZeroCountFloat *float64 `protobuf:"fixed64,8,opt,name=zero_count_float,json=zeroCountFloat" json:"zero_count_float,omitempty"`
|
||||||
|
// Negative buckets for the native histogram.
|
||||||
|
NegativeSpan []*BucketSpan `protobuf:"bytes,9,rep,name=negative_span,json=negativeSpan" json:"negative_span,omitempty"`
|
||||||
|
// Use either "negative_delta" or "negative_count", the former for
|
||||||
|
// regular histograms with integer counts, the latter for float
|
||||||
|
// histograms.
|
||||||
|
NegativeDelta []int64 `protobuf:"zigzag64,10,rep,name=negative_delta,json=negativeDelta" json:"negative_delta,omitempty"`
|
||||||
|
NegativeCount []float64 `protobuf:"fixed64,11,rep,name=negative_count,json=negativeCount" json:"negative_count,omitempty"`
|
||||||
|
// Positive buckets for the native histogram.
|
||||||
|
PositiveSpan []*BucketSpan `protobuf:"bytes,12,rep,name=positive_span,json=positiveSpan" json:"positive_span,omitempty"`
|
||||||
|
// Use either "positive_delta" or "positive_count", the former for
|
||||||
|
// regular histograms with integer counts, the latter for float
|
||||||
|
// histograms.
|
||||||
|
PositiveDelta []int64 `protobuf:"zigzag64,13,rep,name=positive_delta,json=positiveDelta" json:"positive_delta,omitempty"`
|
||||||
|
PositiveCount []float64 `protobuf:"fixed64,14,rep,name=positive_count,json=positiveCount" json:"positive_count,omitempty"`
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
XXX_unrecognized []byte `json:"-"`
|
XXX_unrecognized []byte `json:"-"`
|
||||||
XXX_sizecache int32 `json:"-"`
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
|
@ -357,7 +391,7 @@ func (m *Histogram) Reset() { *m = Histogram{} }
|
||||||
func (m *Histogram) String() string { return proto.CompactTextString(m) }
|
func (m *Histogram) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Histogram) ProtoMessage() {}
|
func (*Histogram) ProtoMessage() {}
|
||||||
func (*Histogram) Descriptor() ([]byte, []int) {
|
func (*Histogram) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{6}
|
return fileDescriptor_d1e5ddb18987a258, []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Histogram) XXX_Unmarshal(b []byte) error {
|
func (m *Histogram) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -385,6 +419,13 @@ func (m *Histogram) GetSampleCount() uint64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetSampleCountFloat() float64 {
|
||||||
|
if m != nil && m.SampleCountFloat != nil {
|
||||||
|
return *m.SampleCountFloat
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Histogram) GetSampleSum() float64 {
|
func (m *Histogram) GetSampleSum() float64 {
|
||||||
if m != nil && m.SampleSum != nil {
|
if m != nil && m.SampleSum != nil {
|
||||||
return *m.SampleSum
|
return *m.SampleSum
|
||||||
|
|
@ -399,8 +440,81 @@ func (m *Histogram) GetBucket() []*Bucket {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetSchema() int32 {
|
||||||
|
if m != nil && m.Schema != nil {
|
||||||
|
return *m.Schema
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetZeroThreshold() float64 {
|
||||||
|
if m != nil && m.ZeroThreshold != nil {
|
||||||
|
return *m.ZeroThreshold
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetZeroCount() uint64 {
|
||||||
|
if m != nil && m.ZeroCount != nil {
|
||||||
|
return *m.ZeroCount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetZeroCountFloat() float64 {
|
||||||
|
if m != nil && m.ZeroCountFloat != nil {
|
||||||
|
return *m.ZeroCountFloat
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetNegativeSpan() []*BucketSpan {
|
||||||
|
if m != nil {
|
||||||
|
return m.NegativeSpan
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetNegativeDelta() []int64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.NegativeDelta
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetNegativeCount() []float64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.NegativeCount
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetPositiveSpan() []*BucketSpan {
|
||||||
|
if m != nil {
|
||||||
|
return m.PositiveSpan
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetPositiveDelta() []int64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.PositiveDelta
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Histogram) GetPositiveCount() []float64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.PositiveCount
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Bucket of a conventional histogram, each of which is treated as
|
||||||
|
// an individual counter-like time series by Prometheus.
|
||||||
type Bucket struct {
|
type Bucket struct {
|
||||||
CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count,json=cumulativeCount" json:"cumulative_count,omitempty"`
|
CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count,json=cumulativeCount" json:"cumulative_count,omitempty"`
|
||||||
|
CumulativeCountFloat *float64 `protobuf:"fixed64,4,opt,name=cumulative_count_float,json=cumulativeCountFloat" json:"cumulative_count_float,omitempty"`
|
||||||
UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound,json=upperBound" json:"upper_bound,omitempty"`
|
UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound,json=upperBound" json:"upper_bound,omitempty"`
|
||||||
Exemplar *Exemplar `protobuf:"bytes,3,opt,name=exemplar" json:"exemplar,omitempty"`
|
Exemplar *Exemplar `protobuf:"bytes,3,opt,name=exemplar" json:"exemplar,omitempty"`
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
|
@ -412,7 +526,7 @@ func (m *Bucket) Reset() { *m = Bucket{} }
|
||||||
func (m *Bucket) String() string { return proto.CompactTextString(m) }
|
func (m *Bucket) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Bucket) ProtoMessage() {}
|
func (*Bucket) ProtoMessage() {}
|
||||||
func (*Bucket) Descriptor() ([]byte, []int) {
|
func (*Bucket) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{7}
|
return fileDescriptor_d1e5ddb18987a258, []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Bucket) XXX_Unmarshal(b []byte) error {
|
func (m *Bucket) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -440,6 +554,13 @@ func (m *Bucket) GetCumulativeCount() uint64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Bucket) GetCumulativeCountFloat() float64 {
|
||||||
|
if m != nil && m.CumulativeCountFloat != nil {
|
||||||
|
return *m.CumulativeCountFloat
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Bucket) GetUpperBound() float64 {
|
func (m *Bucket) GetUpperBound() float64 {
|
||||||
if m != nil && m.UpperBound != nil {
|
if m != nil && m.UpperBound != nil {
|
||||||
return *m.UpperBound
|
return *m.UpperBound
|
||||||
|
|
@ -454,6 +575,59 @@ func (m *Bucket) GetExemplar() *Exemplar {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A BucketSpan defines a number of consecutive buckets in a native
|
||||||
|
// histogram with their offset. Logically, it would be more
|
||||||
|
// straightforward to include the bucket counts in the Span. However,
|
||||||
|
// the protobuf representation is more compact in the way the data is
|
||||||
|
// structured here (with all the buckets in a single array separate
|
||||||
|
// from the Spans).
|
||||||
|
type BucketSpan struct {
|
||||||
|
Offset *int32 `protobuf:"zigzag32,1,opt,name=offset" json:"offset,omitempty"`
|
||||||
|
Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"`
|
||||||
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *BucketSpan) Reset() { *m = BucketSpan{} }
|
||||||
|
func (m *BucketSpan) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*BucketSpan) ProtoMessage() {}
|
||||||
|
func (*BucketSpan) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_d1e5ddb18987a258, []int{8}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *BucketSpan) XXX_Unmarshal(b []byte) error {
|
||||||
|
return xxx_messageInfo_BucketSpan.Unmarshal(m, b)
|
||||||
|
}
|
||||||
|
func (m *BucketSpan) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
return xxx_messageInfo_BucketSpan.Marshal(b, m, deterministic)
|
||||||
|
}
|
||||||
|
func (m *BucketSpan) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_BucketSpan.Merge(m, src)
|
||||||
|
}
|
||||||
|
func (m *BucketSpan) XXX_Size() int {
|
||||||
|
return xxx_messageInfo_BucketSpan.Size(m)
|
||||||
|
}
|
||||||
|
func (m *BucketSpan) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_BucketSpan.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_BucketSpan proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *BucketSpan) GetOffset() int32 {
|
||||||
|
if m != nil && m.Offset != nil {
|
||||||
|
return *m.Offset
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *BucketSpan) GetLength() uint32 {
|
||||||
|
if m != nil && m.Length != nil {
|
||||||
|
return *m.Length
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type Exemplar struct {
|
type Exemplar struct {
|
||||||
Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"`
|
Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"`
|
||||||
Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"`
|
Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"`
|
||||||
|
|
@ -467,7 +641,7 @@ func (m *Exemplar) Reset() { *m = Exemplar{} }
|
||||||
func (m *Exemplar) String() string { return proto.CompactTextString(m) }
|
func (m *Exemplar) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Exemplar) ProtoMessage() {}
|
func (*Exemplar) ProtoMessage() {}
|
||||||
func (*Exemplar) Descriptor() ([]byte, []int) {
|
func (*Exemplar) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{8}
|
return fileDescriptor_d1e5ddb18987a258, []int{9}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Exemplar) XXX_Unmarshal(b []byte) error {
|
func (m *Exemplar) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -526,7 +700,7 @@ func (m *Metric) Reset() { *m = Metric{} }
|
||||||
func (m *Metric) String() string { return proto.CompactTextString(m) }
|
func (m *Metric) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Metric) ProtoMessage() {}
|
func (*Metric) ProtoMessage() {}
|
||||||
func (*Metric) Descriptor() ([]byte, []int) {
|
func (*Metric) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{9}
|
return fileDescriptor_d1e5ddb18987a258, []int{10}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Metric) XXX_Unmarshal(b []byte) error {
|
func (m *Metric) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -610,7 +784,7 @@ func (m *MetricFamily) Reset() { *m = MetricFamily{} }
|
||||||
func (m *MetricFamily) String() string { return proto.CompactTextString(m) }
|
func (m *MetricFamily) String() string { return proto.CompactTextString(m) }
|
||||||
func (*MetricFamily) ProtoMessage() {}
|
func (*MetricFamily) ProtoMessage() {}
|
||||||
func (*MetricFamily) Descriptor() ([]byte, []int) {
|
func (*MetricFamily) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_6039342a2ba47b72, []int{10}
|
return fileDescriptor_d1e5ddb18987a258, []int{11}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MetricFamily) XXX_Unmarshal(b []byte) error {
|
func (m *MetricFamily) XXX_Unmarshal(b []byte) error {
|
||||||
|
|
@ -669,55 +843,72 @@ func init() {
|
||||||
proto.RegisterType((*Untyped)(nil), "io.prometheus.client.Untyped")
|
proto.RegisterType((*Untyped)(nil), "io.prometheus.client.Untyped")
|
||||||
proto.RegisterType((*Histogram)(nil), "io.prometheus.client.Histogram")
|
proto.RegisterType((*Histogram)(nil), "io.prometheus.client.Histogram")
|
||||||
proto.RegisterType((*Bucket)(nil), "io.prometheus.client.Bucket")
|
proto.RegisterType((*Bucket)(nil), "io.prometheus.client.Bucket")
|
||||||
|
proto.RegisterType((*BucketSpan)(nil), "io.prometheus.client.BucketSpan")
|
||||||
proto.RegisterType((*Exemplar)(nil), "io.prometheus.client.Exemplar")
|
proto.RegisterType((*Exemplar)(nil), "io.prometheus.client.Exemplar")
|
||||||
proto.RegisterType((*Metric)(nil), "io.prometheus.client.Metric")
|
proto.RegisterType((*Metric)(nil), "io.prometheus.client.Metric")
|
||||||
proto.RegisterType((*MetricFamily)(nil), "io.prometheus.client.MetricFamily")
|
proto.RegisterType((*MetricFamily)(nil), "io.prometheus.client.MetricFamily")
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) }
|
func init() {
|
||||||
|
proto.RegisterFile("io/prometheus/client/metrics.proto", fileDescriptor_d1e5ddb18987a258)
|
||||||
var fileDescriptor_6039342a2ba47b72 = []byte{
|
}
|
||||||
// 665 bytes of a gzipped FileDescriptorProto
|
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x6e, 0xd3, 0x4c,
|
var fileDescriptor_d1e5ddb18987a258 = []byte{
|
||||||
0x14, 0xfd, 0xdc, 0x38, 0x3f, 0xbe, 0x69, 0x3f, 0xa2, 0x51, 0x17, 0x56, 0xa1, 0x24, 0x78, 0x55,
|
// 896 bytes of a gzipped FileDescriptorProto
|
||||||
0x58, 0x38, 0xa2, 0x6a, 0x05, 0x2a, 0xb0, 0x68, 0x4b, 0x48, 0x91, 0x48, 0x5b, 0x26, 0xc9, 0xa2,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x8e, 0xdb, 0x44,
|
||||||
0xb0, 0x88, 0x1c, 0x77, 0x70, 0x2c, 0x3c, 0xb1, 0xb1, 0x67, 0x2a, 0xb2, 0x66, 0xc1, 0x16, 0x5e,
|
0x18, 0xc5, 0x9b, 0x5f, 0x7f, 0xd9, 0x6c, 0xd3, 0x61, 0x55, 0x59, 0x0b, 0xcb, 0x06, 0x4b, 0x48,
|
||||||
0x81, 0x17, 0x05, 0xcd, 0x8f, 0x6d, 0x2a, 0xb9, 0x95, 0x40, 0xec, 0x66, 0xee, 0x3d, 0xe7, 0xfa,
|
0x0b, 0x42, 0x8e, 0x40, 0x5b, 0x81, 0x0a, 0x5c, 0xec, 0xb6, 0xe9, 0x16, 0x89, 0xb4, 0x65, 0x92,
|
||||||
0xcc, 0xf8, 0x9c, 0x81, 0x0d, 0x4a, 0x58, 0x1a, 0xfa, 0x99, 0x9b, 0xa4, 0x31, 0x8b, 0xd1, 0x66,
|
0x5c, 0x14, 0x2e, 0xac, 0x49, 0x32, 0xeb, 0x58, 0x78, 0x3c, 0xc6, 0x1e, 0x57, 0x2c, 0x2f, 0xc0,
|
||||||
0x18, 0x8b, 0x15, 0x25, 0x6c, 0x41, 0x78, 0xe6, 0xfa, 0x51, 0x48, 0x96, 0x6c, 0xab, 0x1b, 0xc4,
|
0x35, 0xaf, 0xc0, 0xc3, 0xf0, 0x22, 0x3c, 0x08, 0x68, 0xfe, 0xec, 0xdd, 0xe2, 0x94, 0xd2, 0x3b,
|
||||||
0x71, 0x10, 0x91, 0xbe, 0xc4, 0xcc, 0xf9, 0x87, 0x3e, 0x0b, 0x29, 0xc9, 0x98, 0x47, 0x13, 0x45,
|
0x7f, 0x67, 0xce, 0xf7, 0xcd, 0x39, 0xe3, 0xc9, 0x71, 0xc0, 0x8f, 0xf9, 0x24, 0xcb, 0x39, 0xa3,
|
||||||
0x73, 0xf6, 0xc1, 0x7a, 0xe3, 0xcd, 0x49, 0x74, 0xee, 0x85, 0x29, 0x42, 0x60, 0x2e, 0x3d, 0x4a,
|
0x62, 0x4b, 0xcb, 0x62, 0xb2, 0x4e, 0x62, 0x9a, 0x8a, 0x09, 0xa3, 0x22, 0x8f, 0xd7, 0x45, 0x90,
|
||||||
0x6c, 0xa3, 0x67, 0xec, 0x58, 0x58, 0xae, 0xd1, 0x26, 0xd4, 0xaf, 0xbc, 0x88, 0x13, 0x7b, 0x4d,
|
0xe5, 0x5c, 0x70, 0x74, 0x18, 0xf3, 0xa0, 0xe6, 0x04, 0x9a, 0x73, 0x74, 0x12, 0x71, 0x1e, 0x25,
|
||||||
0x16, 0xd5, 0xc6, 0xd9, 0x86, 0xfa, 0xd0, 0xe3, 0xc1, 0x6f, 0x6d, 0xc1, 0x31, 0xf2, 0xf6, 0x7b,
|
0x74, 0xa2, 0x38, 0xab, 0xf2, 0x6a, 0x22, 0x62, 0x46, 0x0b, 0x41, 0x58, 0xa6, 0xdb, 0xfc, 0xfb,
|
||||||
0x68, 0x1e, 0xc7, 0x7c, 0xc9, 0x48, 0x5a, 0x0d, 0x40, 0x07, 0xd0, 0x22, 0x9f, 0x09, 0x4d, 0x22,
|
0xe0, 0x7e, 0x47, 0x56, 0x34, 0x79, 0x4e, 0xe2, 0x1c, 0x21, 0x68, 0xa7, 0x84, 0x51, 0xcf, 0x19,
|
||||||
0x2f, 0x95, 0x83, 0xdb, 0xbb, 0xf7, 0xdd, 0xaa, 0x03, 0xb8, 0x03, 0x8d, 0xc2, 0x05, 0xde, 0x79,
|
0x3b, 0xa7, 0x2e, 0x56, 0xcf, 0xe8, 0x10, 0x3a, 0x2f, 0x49, 0x52, 0x52, 0x6f, 0x4f, 0x81, 0xba,
|
||||||
0x0e, 0xad, 0xb7, 0xdc, 0x5b, 0xb2, 0x30, 0x22, 0x68, 0x0b, 0x5a, 0x9f, 0xf4, 0x5a, 0x7f, 0xa0,
|
0xf0, 0x8f, 0xa1, 0x73, 0x49, 0xca, 0xe8, 0xc6, 0xb2, 0xec, 0x71, 0xec, 0xf2, 0x8f, 0xd0, 0x7b,
|
||||||
0xd8, 0x5f, 0x57, 0x5e, 0x48, 0xfb, 0x6a, 0x40, 0x73, 0xcc, 0x29, 0xf5, 0xd2, 0x15, 0x7a, 0x00,
|
0xc8, 0xcb, 0x54, 0xd0, 0xbc, 0x99, 0x80, 0x1e, 0x40, 0x9f, 0xfe, 0x42, 0x59, 0x96, 0x90, 0x5c,
|
||||||
0xeb, 0x99, 0x47, 0x93, 0x88, 0xcc, 0x7c, 0xa1, 0x56, 0x4e, 0x30, 0x71, 0x5b, 0xd5, 0xe4, 0x01,
|
0x0d, 0x1e, 0x7c, 0xfe, 0x41, 0xd0, 0x64, 0x20, 0x98, 0x1a, 0x16, 0xae, 0xf8, 0xfe, 0xd7, 0xd0,
|
||||||
0xd0, 0x36, 0x80, 0x86, 0x64, 0x9c, 0xea, 0x49, 0x96, 0xaa, 0x8c, 0x39, 0x15, 0xe7, 0x28, 0xbe,
|
0xff, 0xbe, 0x24, 0xa9, 0x88, 0x13, 0x8a, 0x8e, 0xa0, 0xff, 0xb3, 0x79, 0x36, 0x1b, 0x54, 0xf5,
|
||||||
0x5f, 0xeb, 0xd5, 0x6e, 0x3e, 0x47, 0xae, 0xb8, 0xd4, 0xe7, 0x74, 0xa1, 0x39, 0x5d, 0xb2, 0x55,
|
0x6d, 0xe5, 0x95, 0xb4, 0xdf, 0x1c, 0xe8, 0xcd, 0x4b, 0xc6, 0x48, 0x7e, 0x8d, 0x3e, 0x84, 0xfd,
|
||||||
0x42, 0x2e, 0x6f, 0xb8, 0xc5, 0x2f, 0x06, 0x58, 0x27, 0x61, 0xc6, 0xe2, 0x20, 0xf5, 0xe8, 0x3f,
|
0x82, 0xb0, 0x2c, 0xa1, 0xe1, 0x5a, 0xaa, 0x55, 0x13, 0xda, 0x78, 0xa0, 0x31, 0x65, 0x00, 0x1d,
|
||||||
0x10, 0xbb, 0x07, 0x8d, 0x39, 0xf7, 0x3f, 0x12, 0xa6, 0xa5, 0xde, 0xab, 0x96, 0x7a, 0x24, 0x31,
|
0x03, 0x18, 0x4a, 0x51, 0x32, 0x33, 0xc9, 0xd5, 0xc8, 0xbc, 0x64, 0xd2, 0x47, 0xb5, 0x7f, 0x6b,
|
||||||
0x58, 0x63, 0x9d, 0x6f, 0x06, 0x34, 0x54, 0x09, 0x3d, 0x84, 0x8e, 0xcf, 0x29, 0x8f, 0x3c, 0x16,
|
0xdc, 0xda, 0xed, 0xc3, 0x2a, 0xae, 0xf5, 0xf9, 0x27, 0xd0, 0x5b, 0xa6, 0xe2, 0x3a, 0xa3, 0x9b,
|
||||||
0x5e, 0x5d, 0x97, 0x71, 0xa7, 0xac, 0x2b, 0x29, 0x5d, 0x68, 0xf3, 0x24, 0x21, 0xe9, 0x6c, 0x1e,
|
0x1d, 0xa7, 0xf8, 0x57, 0x1b, 0xdc, 0x27, 0x71, 0x21, 0x78, 0x94, 0x13, 0xf6, 0x26, 0x62, 0x3f,
|
||||||
0xf3, 0xe5, 0xa5, 0xd6, 0x02, 0xb2, 0x74, 0x24, 0x2a, 0xd7, 0x1c, 0x50, 0xfb, 0x43, 0x07, 0x7c,
|
0x05, 0x74, 0x93, 0x12, 0x5e, 0x25, 0x9c, 0x08, 0xaf, 0xad, 0x66, 0x8e, 0x6e, 0x10, 0x1f, 0x4b,
|
||||||
0x37, 0xa0, 0x95, 0x97, 0xd1, 0x3e, 0xd4, 0x23, 0xe1, 0x60, 0xdb, 0x90, 0x87, 0xea, 0x56, 0x4f,
|
0xfc, 0xbf, 0xac, 0x9d, 0x41, 0x77, 0x55, 0xae, 0x7f, 0xa2, 0xc2, 0x18, 0x7b, 0xbf, 0xd9, 0xd8,
|
||||||
0x29, 0x4c, 0x8e, 0x15, 0xba, 0xda, 0x1d, 0xe8, 0x29, 0x58, 0x45, 0x42, 0xb4, 0xac, 0x2d, 0x57,
|
0x85, 0xe2, 0x60, 0xc3, 0x45, 0xf7, 0xa0, 0x5b, 0xac, 0xb7, 0x94, 0x11, 0xaf, 0x33, 0x76, 0x4e,
|
||||||
0x65, 0xc8, 0xcd, 0x33, 0xe4, 0x4e, 0x72, 0x04, 0x2e, 0xc1, 0xce, 0xcf, 0x35, 0x68, 0x8c, 0x64,
|
0xef, 0x62, 0x53, 0xa1, 0x8f, 0xe0, 0xe0, 0x57, 0x9a, 0xf3, 0x50, 0x6c, 0x73, 0x5a, 0x6c, 0x79,
|
||||||
0x22, 0xff, 0x56, 0xd1, 0x63, 0xa8, 0x07, 0x22, 0x53, 0x3a, 0x10, 0x77, 0xab, 0x69, 0x32, 0x76,
|
0xb2, 0xf1, 0xba, 0x6a, 0xc3, 0xa1, 0x44, 0x17, 0x16, 0x94, 0x9a, 0x14, 0x4d, 0x5b, 0xec, 0x29,
|
||||||
0x58, 0x21, 0xd1, 0x13, 0x68, 0xfa, 0x2a, 0x67, 0x5a, 0xec, 0x76, 0x35, 0x49, 0x87, 0x11, 0xe7,
|
0x8b, 0xae, 0x44, 0xb4, 0xc1, 0x53, 0x18, 0xd5, 0xcb, 0xc6, 0x5e, 0x5f, 0xcd, 0x39, 0xa8, 0x48,
|
||||||
0x68, 0x41, 0xcc, 0x54, 0x08, 0x6c, 0xf3, 0x36, 0xa2, 0x4e, 0x0a, 0xce, 0xd1, 0x82, 0xc8, 0x95,
|
0xda, 0xdc, 0x14, 0x86, 0x29, 0x8d, 0x88, 0x88, 0x5f, 0xd2, 0xb0, 0xc8, 0x48, 0xea, 0xb9, 0xca,
|
||||||
0x69, 0xed, 0xfa, 0x6d, 0x44, 0xed, 0x6c, 0x9c, 0xa3, 0xd1, 0x0b, 0xb0, 0x16, 0xb9, 0x97, 0xed,
|
0xc4, 0xf8, 0x75, 0x26, 0xe6, 0x19, 0x49, 0xf1, 0xbe, 0x6d, 0x93, 0x95, 0x94, 0x5d, 0x8d, 0xd9,
|
||||||
0xa6, 0xa4, 0xde, 0x70, 0x31, 0x85, 0xe5, 0x71, 0xc9, 0x10, 0xee, 0x2f, 0xee, 0x7a, 0x46, 0x33,
|
0xd0, 0x44, 0x10, 0x0f, 0xc6, 0xad, 0x53, 0x84, 0xab, 0xe1, 0x8f, 0x24, 0x78, 0x8b, 0xa6, 0xa5,
|
||||||
0xbb, 0xd1, 0x33, 0x76, 0x6a, 0xb8, 0x5d, 0xd4, 0x46, 0x99, 0xf3, 0xc3, 0x80, 0x75, 0xf5, 0x07,
|
0x0f, 0xc6, 0x2d, 0xe9, 0xce, 0xa2, 0x5a, 0xfe, 0x14, 0x86, 0x19, 0x2f, 0xe2, 0x5a, 0xd4, 0xfe,
|
||||||
0x5e, 0x79, 0x34, 0x8c, 0x56, 0x95, 0xcf, 0x19, 0x02, 0x73, 0x41, 0xa2, 0x44, 0xbf, 0x66, 0x72,
|
0x9b, 0x8a, 0xb2, 0x6d, 0x56, 0x54, 0x35, 0x46, 0x8b, 0x1a, 0x6a, 0x51, 0x16, 0xad, 0x44, 0x55,
|
||||||
0x8d, 0xf6, 0xc0, 0x14, 0x1a, 0xe5, 0x15, 0xfe, 0xbf, 0xdb, 0xab, 0x56, 0xa5, 0x26, 0x4f, 0x56,
|
0x34, 0x2d, 0xea, 0x40, 0x8b, 0xb2, 0xa8, 0x12, 0xe5, 0xff, 0xe9, 0x40, 0x57, 0x6f, 0x85, 0x3e,
|
||||||
0x09, 0xc1, 0x12, 0x2d, 0xd2, 0xa4, 0x5e, 0x60, 0xdb, 0xbc, 0x2d, 0x4d, 0x8a, 0x87, 0x35, 0xf6,
|
0x86, 0xd1, 0xba, 0x64, 0x65, 0x72, 0xd3, 0x88, 0xbe, 0x66, 0x77, 0x6a, 0x5c, 0x5b, 0x39, 0x83,
|
||||||
0xd1, 0x08, 0xa0, 0x9c, 0x84, 0xda, 0xd0, 0x3c, 0x3e, 0x9b, 0x9e, 0x4e, 0x06, 0xb8, 0xf3, 0x1f,
|
0x7b, 0xaf, 0x52, 0x6f, 0x5d, 0xb7, 0xc3, 0x57, 0x1a, 0xf4, 0x5b, 0x39, 0x81, 0x41, 0x99, 0x65,
|
||||||
0xb2, 0xa0, 0x3e, 0x3c, 0x9c, 0x0e, 0x07, 0x1d, 0x43, 0xd4, 0xc7, 0xd3, 0xd1, 0xe8, 0x10, 0x5f,
|
0x34, 0x0f, 0x57, 0xbc, 0x4c, 0x37, 0xe6, 0xce, 0x81, 0x82, 0x2e, 0x24, 0x72, 0x2b, 0x17, 0x5a,
|
||||||
0x74, 0xd6, 0xc4, 0x66, 0x7a, 0x3a, 0xb9, 0x38, 0x1f, 0xbc, 0xec, 0xd4, 0xd0, 0x06, 0x58, 0x27,
|
0xff, 0x3b, 0x17, 0xa0, 0x3e, 0x32, 0x79, 0x11, 0xf9, 0xd5, 0x55, 0x41, 0xb5, 0x83, 0xbb, 0xd8,
|
||||||
0xaf, 0xc7, 0x93, 0xb3, 0x21, 0x3e, 0x1c, 0x75, 0xcc, 0x23, 0x0c, 0x95, 0xef, 0xfe, 0xbb, 0x83,
|
0x54, 0x12, 0x4f, 0x68, 0x1a, 0x89, 0xad, 0xda, 0x7d, 0x88, 0x4d, 0xe5, 0xff, 0xee, 0x40, 0xdf,
|
||||||
0x20, 0x64, 0x0b, 0x3e, 0x77, 0xfd, 0x98, 0xf6, 0xcb, 0x6e, 0x5f, 0x75, 0x67, 0x34, 0xbe, 0x24,
|
0x0e, 0x45, 0xf7, 0xa1, 0x93, 0xc8, 0x54, 0xf4, 0x1c, 0xf5, 0x82, 0x4e, 0x9a, 0x35, 0x54, 0xc1,
|
||||||
0x51, 0x3f, 0x88, 0x9f, 0x85, 0xf1, 0xac, 0xec, 0xce, 0x54, 0xf7, 0x57, 0x00, 0x00, 0x00, 0xff,
|
0x89, 0x35, 0xbb, 0x39, 0x71, 0xd0, 0x97, 0xe0, 0x56, 0xa9, 0x6b, 0x4c, 0x1d, 0x05, 0x3a, 0x97,
|
||||||
0xff, 0xd0, 0x84, 0x91, 0x73, 0x59, 0x06, 0x00, 0x00,
|
0x03, 0x9b, 0xcb, 0xc1, 0xc2, 0x32, 0x70, 0x4d, 0xf6, 0xff, 0xde, 0x83, 0xee, 0x4c, 0xa5, 0xfc,
|
||||||
|
0xdb, 0x2a, 0xfa, 0x0c, 0x3a, 0x91, 0xcc, 0x69, 0x13, 0xb2, 0xef, 0x35, 0xb7, 0xa9, 0x28, 0xc7,
|
||||||
|
0x9a, 0x89, 0xbe, 0x80, 0xde, 0x5a, 0x67, 0xb7, 0x11, 0x7b, 0xdc, 0xdc, 0x64, 0x02, 0x1e, 0x5b,
|
||||||
|
0xb6, 0x6c, 0x2c, 0x74, 0xb0, 0xaa, 0x3b, 0xb0, 0xb3, 0xd1, 0xa4, 0x2f, 0xb6, 0x6c, 0xd9, 0x58,
|
||||||
|
0xea, 0x20, 0x54, 0xa1, 0xb1, 0xb3, 0xd1, 0xa4, 0x25, 0xb6, 0x6c, 0xf4, 0x0d, 0xb8, 0x5b, 0x9b,
|
||||||
|
0x8f, 0x2a, 0x2c, 0x76, 0x1e, 0x4c, 0x15, 0xa3, 0xb8, 0xee, 0x90, 0x89, 0x5a, 0x9d, 0x75, 0xc8,
|
||||||
|
0x0a, 0x95, 0x48, 0x2d, 0x3c, 0xa8, 0xb0, 0x59, 0xe1, 0xff, 0xe1, 0xc0, 0xbe, 0x7e, 0x03, 0x8f,
|
||||||
|
0x09, 0x8b, 0x93, 0xeb, 0xc6, 0x4f, 0x24, 0x82, 0xf6, 0x96, 0x26, 0x99, 0xf9, 0x42, 0xaa, 0x67,
|
||||||
|
0x74, 0x06, 0x6d, 0xa9, 0x51, 0x1d, 0xe1, 0xc1, 0xae, 0x5f, 0xb8, 0x9e, 0xbc, 0xb8, 0xce, 0x28,
|
||||||
|
0x56, 0x6c, 0x99, 0xb9, 0xfa, 0xab, 0xee, 0xb5, 0x5f, 0x97, 0xb9, 0xba, 0x0f, 0x1b, 0xee, 0x27,
|
||||||
|
0x2b, 0x80, 0x7a, 0x12, 0x1a, 0x40, 0xef, 0xe1, 0xb3, 0xe5, 0xd3, 0xc5, 0x14, 0x8f, 0xde, 0x41,
|
||||||
|
0x2e, 0x74, 0x2e, 0xcf, 0x97, 0x97, 0xd3, 0x91, 0x23, 0xf1, 0xf9, 0x72, 0x36, 0x3b, 0xc7, 0x2f,
|
||||||
|
0x46, 0x7b, 0xb2, 0x58, 0x3e, 0x5d, 0xbc, 0x78, 0x3e, 0x7d, 0x34, 0x6a, 0xa1, 0x21, 0xb8, 0x4f,
|
||||||
|
0xbe, 0x9d, 0x2f, 0x9e, 0x5d, 0xe2, 0xf3, 0xd9, 0xa8, 0x8d, 0xde, 0x85, 0x3b, 0xaa, 0x27, 0xac,
|
||||||
|
0xc1, 0xce, 0x05, 0x86, 0xc6, 0x3f, 0x18, 0x3f, 0x3c, 0x88, 0x62, 0xb1, 0x2d, 0x57, 0xc1, 0x9a,
|
||||||
|
0xb3, 0x7f, 0xff, 0x45, 0x09, 0x19, 0xdf, 0xd0, 0x64, 0x12, 0xf1, 0xaf, 0x62, 0x1e, 0xd6, 0xab,
|
||||||
|
0xa1, 0x5e, 0xfd, 0x27, 0x00, 0x00, 0xff, 0xff, 0x16, 0x77, 0x81, 0x98, 0xd7, 0x08, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
|
|
||||||
package ctxhttp // import "golang.org/x/net/context/ctxhttp"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Do sends an HTTP request with the provided http.Client and returns
|
|
||||||
// an HTTP response.
|
|
||||||
//
|
|
||||||
// If the client is nil, http.DefaultClient is used.
|
|
||||||
//
|
|
||||||
// The provided ctx must be non-nil. If it is canceled or times out,
|
|
||||||
// ctx.Err() will be returned.
|
|
||||||
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
|
||||||
if client == nil {
|
|
||||||
client = http.DefaultClient
|
|
||||||
}
|
|
||||||
resp, err := client.Do(req.WithContext(ctx))
|
|
||||||
// If we got an error, and the context has been canceled,
|
|
||||||
// the context's error is probably more useful.
|
|
||||||
if err != nil {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
err = ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get issues a GET request via the Do function.
|
|
||||||
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return Do(ctx, client, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Head issues a HEAD request via the Do function.
|
|
||||||
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
|
||||||
req, err := http.NewRequest("HEAD", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return Do(ctx, client, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post issues a POST request via the Do function.
|
|
||||||
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
|
|
||||||
req, err := http.NewRequest("POST", url, body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", bodyType)
|
|
||||||
return Do(ctx, client, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PostForm issues a POST request via the Do function.
|
|
||||||
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
|
|
||||||
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
# This source code refers to The Go Authors for copyright purposes.
|
|
||||||
# The master list of authors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/AUTHORS.
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
# This source code was written by the Go contributors.
|
|
||||||
# The master list of contributors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
|
||||||
|
|
@ -19,7 +19,7 @@ See pkg.go.dev for further documentation and examples.
|
||||||
* [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2)
|
* [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2)
|
||||||
* [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google)
|
* [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google)
|
||||||
|
|
||||||
## Policy for new packages
|
## Policy for new endpoints
|
||||||
|
|
||||||
We no longer accept new provider-specific packages in this repo if all
|
We no longer accept new provider-specific packages in this repo if all
|
||||||
they do is add a single endpoint variable. If you just want to add a
|
they do is add a single endpoint variable. If you just want to add a
|
||||||
|
|
@ -29,8 +29,12 @@ package.
|
||||||
|
|
||||||
## Report Issues / Send Patches
|
## Report Issues / Send Patches
|
||||||
|
|
||||||
This repository uses Gerrit for code changes. To learn how to submit changes to
|
|
||||||
this repository, see https://golang.org/doc/contribute.html.
|
|
||||||
|
|
||||||
The main issue tracker for the oauth2 repository is located at
|
The main issue tracker for the oauth2 repository is located at
|
||||||
https://github.com/golang/oauth2/issues.
|
https://github.com/golang/oauth2/issues.
|
||||||
|
|
||||||
|
This repository uses Gerrit for code changes. To learn how to submit changes to
|
||||||
|
this repository, see https://golang.org/doc/contribute.html. In particular:
|
||||||
|
|
||||||
|
* Excluding trivial changes, all contributions should be connected to an existing issue.
|
||||||
|
* API changes must go through the [change proposal process](https://go.dev/s/proposal-process) before they can be accepted.
|
||||||
|
* The code owners are listed at [dev.golang.org/owners](https://dev.golang.org/owners#:~:text=x/oauth2).
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
// ParseKey converts the binary contents of a private key file
|
// ParseKey converts the binary contents of a private key file
|
||||||
// to an *rsa.PrivateKey. It detects whether the private key is in a
|
// to an *rsa.PrivateKey. It detects whether the private key is in a
|
||||||
// PEM container or not. If so, it extracts the the private key
|
// PEM container or not. If so, it extracts the private key
|
||||||
// from PEM container before conversion. It only supports PEM
|
// from PEM container before conversion. It only supports PEM
|
||||||
// containers with no passphrase.
|
// containers with no passphrase.
|
||||||
func ParseKey(key []byte) (*rsa.PrivateKey, error) {
|
func ParseKey(key []byte) (*rsa.PrivateKey, error) {
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/context/ctxhttp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Token represents the credentials used to authorize
|
// Token represents the credentials used to authorize
|
||||||
|
|
@ -57,12 +55,18 @@ type Token struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// tokenJSON is the struct representing the HTTP response from OAuth2
|
// tokenJSON is the struct representing the HTTP response from OAuth2
|
||||||
// providers returning a token in JSON form.
|
// providers returning a token or error in JSON form.
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
|
||||||
type tokenJSON struct {
|
type tokenJSON struct {
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
TokenType string `json:"token_type"`
|
TokenType string `json:"token_type"`
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
ExpiresIn expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number
|
ExpiresIn expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number
|
||||||
|
// error fields
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
||||||
|
ErrorCode string `json:"error"`
|
||||||
|
ErrorDescription string `json:"error_description"`
|
||||||
|
ErrorURI string `json:"error_uri"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *tokenJSON) expiry() (t time.Time) {
|
func (e *tokenJSON) expiry() (t time.Time) {
|
||||||
|
|
@ -229,7 +233,7 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
|
||||||
}
|
}
|
||||||
|
|
||||||
func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
|
func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
|
||||||
r, err := ctxhttp.Do(ctx, ContextClient(ctx), req)
|
r, err := ContextClient(ctx).Do(req.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -238,21 +242,29 @@ func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
||||||
}
|
}
|
||||||
if code := r.StatusCode; code < 200 || code > 299 {
|
|
||||||
return nil, &RetrieveError{
|
failureStatus := r.StatusCode < 200 || r.StatusCode > 299
|
||||||
Response: r,
|
retrieveError := &RetrieveError{
|
||||||
Body: body,
|
Response: r,
|
||||||
}
|
Body: body,
|
||||||
|
// attempt to populate error detail below
|
||||||
}
|
}
|
||||||
|
|
||||||
var token *Token
|
var token *Token
|
||||||
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||||
switch content {
|
switch content {
|
||||||
case "application/x-www-form-urlencoded", "text/plain":
|
case "application/x-www-form-urlencoded", "text/plain":
|
||||||
|
// some endpoints return a query string
|
||||||
vals, err := url.ParseQuery(string(body))
|
vals, err := url.ParseQuery(string(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
if failureStatus {
|
||||||
|
return nil, retrieveError
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("oauth2: cannot parse response: %v", err)
|
||||||
}
|
}
|
||||||
|
retrieveError.ErrorCode = vals.Get("error")
|
||||||
|
retrieveError.ErrorDescription = vals.Get("error_description")
|
||||||
|
retrieveError.ErrorURI = vals.Get("error_uri")
|
||||||
token = &Token{
|
token = &Token{
|
||||||
AccessToken: vals.Get("access_token"),
|
AccessToken: vals.Get("access_token"),
|
||||||
TokenType: vals.Get("token_type"),
|
TokenType: vals.Get("token_type"),
|
||||||
|
|
@ -267,8 +279,14 @@ func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
|
||||||
default:
|
default:
|
||||||
var tj tokenJSON
|
var tj tokenJSON
|
||||||
if err = json.Unmarshal(body, &tj); err != nil {
|
if err = json.Unmarshal(body, &tj); err != nil {
|
||||||
return nil, err
|
if failureStatus {
|
||||||
|
return nil, retrieveError
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("oauth2: cannot parse json: %v", err)
|
||||||
}
|
}
|
||||||
|
retrieveError.ErrorCode = tj.ErrorCode
|
||||||
|
retrieveError.ErrorDescription = tj.ErrorDescription
|
||||||
|
retrieveError.ErrorURI = tj.ErrorURI
|
||||||
token = &Token{
|
token = &Token{
|
||||||
AccessToken: tj.AccessToken,
|
AccessToken: tj.AccessToken,
|
||||||
TokenType: tj.TokenType,
|
TokenType: tj.TokenType,
|
||||||
|
|
@ -278,17 +296,37 @@ func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
|
||||||
}
|
}
|
||||||
json.Unmarshal(body, &token.Raw) // no error checks for optional fields
|
json.Unmarshal(body, &token.Raw) // no error checks for optional fields
|
||||||
}
|
}
|
||||||
|
// according to spec, servers should respond status 400 in error case
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc6749#section-5.2
|
||||||
|
// but some unorthodox servers respond 200 in error case
|
||||||
|
if failureStatus || retrieveError.ErrorCode != "" {
|
||||||
|
return nil, retrieveError
|
||||||
|
}
|
||||||
if token.AccessToken == "" {
|
if token.AccessToken == "" {
|
||||||
return nil, errors.New("oauth2: server response missing access_token")
|
return nil, errors.New("oauth2: server response missing access_token")
|
||||||
}
|
}
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mirrors oauth2.RetrieveError
|
||||||
type RetrieveError struct {
|
type RetrieveError struct {
|
||||||
Response *http.Response
|
Response *http.Response
|
||||||
Body []byte
|
Body []byte
|
||||||
|
ErrorCode string
|
||||||
|
ErrorDescription string
|
||||||
|
ErrorURI string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RetrieveError) Error() string {
|
func (r *RetrieveError) Error() string {
|
||||||
|
if r.ErrorCode != "" {
|
||||||
|
s := fmt.Sprintf("oauth2: %q", r.ErrorCode)
|
||||||
|
if r.ErrorDescription != "" {
|
||||||
|
s += fmt.Sprintf(" %q", r.ErrorDescription)
|
||||||
|
}
|
||||||
|
if r.ErrorURI != "" {
|
||||||
|
s += fmt.Sprintf(" %q", r.ErrorURI)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
|
return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/oauth2/internal"
|
"golang.org/x/oauth2/internal"
|
||||||
)
|
)
|
||||||
|
|
@ -140,7 +141,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
|
||||||
//
|
//
|
||||||
// State is a token to protect the user from CSRF attacks. You must
|
// State is a token to protect the user from CSRF attacks. You must
|
||||||
// always provide a non-empty string and validate that it matches the
|
// always provide a non-empty string and validate that it matches the
|
||||||
// the state query parameter on your redirect callback.
|
// state query parameter on your redirect callback.
|
||||||
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
||||||
//
|
//
|
||||||
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
|
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
|
||||||
|
|
@ -290,6 +291,8 @@ type reuseTokenSource struct {
|
||||||
|
|
||||||
mu sync.Mutex // guards t
|
mu sync.Mutex // guards t
|
||||||
t *Token
|
t *Token
|
||||||
|
|
||||||
|
expiryDelta time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token returns the current token if it's still valid, else will
|
// Token returns the current token if it's still valid, else will
|
||||||
|
|
@ -305,6 +308,7 @@ func (s *reuseTokenSource) Token() (*Token, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
t.expiryDelta = s.expiryDelta
|
||||||
s.t = t
|
s.t = t
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
@ -379,3 +383,30 @@ func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
|
||||||
new: src,
|
new: src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReuseTokenSource returns a TokenSource that acts in the same manner as the
|
||||||
|
// TokenSource returned by ReuseTokenSource, except the expiry buffer is
|
||||||
|
// configurable. The expiration time of a token is calculated as
|
||||||
|
// t.Expiry.Add(-earlyExpiry).
|
||||||
|
func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSource {
|
||||||
|
// Don't wrap a reuseTokenSource in itself. That would work,
|
||||||
|
// but cause an unnecessary number of mutex operations.
|
||||||
|
// Just build the equivalent one.
|
||||||
|
if rt, ok := src.(*reuseTokenSource); ok {
|
||||||
|
if t == nil {
|
||||||
|
// Just use it directly, but set the expiryDelta to earlyExpiry,
|
||||||
|
// so the behavior matches what the user expects.
|
||||||
|
rt.expiryDelta = earlyExpiry
|
||||||
|
return rt
|
||||||
|
}
|
||||||
|
src = rt.new
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
t.expiryDelta = earlyExpiry
|
||||||
|
}
|
||||||
|
return &reuseTokenSource{
|
||||||
|
t: t,
|
||||||
|
new: src,
|
||||||
|
expiryDelta: earlyExpiry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ import (
|
||||||
"golang.org/x/oauth2/internal"
|
"golang.org/x/oauth2/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// expiryDelta determines how earlier a token should be considered
|
// defaultExpiryDelta determines how earlier a token should be considered
|
||||||
// expired than its actual expiration time. It is used to avoid late
|
// expired than its actual expiration time. It is used to avoid late
|
||||||
// expirations due to client-server time mismatches.
|
// expirations due to client-server time mismatches.
|
||||||
const expiryDelta = 10 * time.Second
|
const defaultExpiryDelta = 10 * time.Second
|
||||||
|
|
||||||
// Token represents the credentials used to authorize
|
// Token represents the credentials used to authorize
|
||||||
// the requests to access protected resources on the OAuth 2.0
|
// the requests to access protected resources on the OAuth 2.0
|
||||||
|
|
@ -52,6 +52,11 @@ type Token struct {
|
||||||
// raw optionally contains extra metadata from the server
|
// raw optionally contains extra metadata from the server
|
||||||
// when updating a token.
|
// when updating a token.
|
||||||
raw interface{}
|
raw interface{}
|
||||||
|
|
||||||
|
// expiryDelta is used to calculate when a token is considered
|
||||||
|
// expired, by subtracting from Expiry. If zero, defaultExpiryDelta
|
||||||
|
// is used.
|
||||||
|
expiryDelta time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns t.TokenType if non-empty, else "Bearer".
|
// Type returns t.TokenType if non-empty, else "Bearer".
|
||||||
|
|
@ -127,6 +132,11 @@ func (t *Token) expired() bool {
|
||||||
if t.Expiry.IsZero() {
|
if t.Expiry.IsZero() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expiryDelta := defaultExpiryDelta
|
||||||
|
if t.expiryDelta != 0 {
|
||||||
|
expiryDelta = t.expiryDelta
|
||||||
|
}
|
||||||
return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
|
return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,14 +175,31 @@ func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetrieveError is the error returned when the token endpoint returns a
|
// RetrieveError is the error returned when the token endpoint returns a
|
||||||
// non-2XX HTTP status code.
|
// non-2XX HTTP status code or populates RFC 6749's 'error' parameter.
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
||||||
type RetrieveError struct {
|
type RetrieveError struct {
|
||||||
Response *http.Response
|
Response *http.Response
|
||||||
// Body is the body that was consumed by reading Response.Body.
|
// Body is the body that was consumed by reading Response.Body.
|
||||||
// It may be truncated.
|
// It may be truncated.
|
||||||
Body []byte
|
Body []byte
|
||||||
|
// ErrorCode is RFC 6749's 'error' parameter.
|
||||||
|
ErrorCode string
|
||||||
|
// ErrorDescription is RFC 6749's 'error_description' parameter.
|
||||||
|
ErrorDescription string
|
||||||
|
// ErrorURI is RFC 6749's 'error_uri' parameter.
|
||||||
|
ErrorURI string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RetrieveError) Error() string {
|
func (r *RetrieveError) Error() string {
|
||||||
|
if r.ErrorCode != "" {
|
||||||
|
s := fmt.Sprintf("oauth2: %q", r.ErrorCode)
|
||||||
|
if r.ErrorDescription != "" {
|
||||||
|
s += fmt.Sprintf(" %q", r.ErrorDescription)
|
||||||
|
}
|
||||||
|
if r.ErrorURI != "" {
|
||||||
|
s += fmt.Sprintf(" %q", r.ErrorURI)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
|
return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@
|
||||||
// Package xerrors implements functions to manipulate errors.
|
// Package xerrors implements functions to manipulate errors.
|
||||||
//
|
//
|
||||||
// This package is based on the Go 2 proposal for error values:
|
// This package is based on the Go 2 proposal for error values:
|
||||||
// https://golang.org/design/29934-error-values
|
//
|
||||||
|
// https://golang.org/design/29934-error-values
|
||||||
//
|
//
|
||||||
// These functions were incorporated into the standard library's errors package
|
// These functions were incorporated into the standard library's errors package
|
||||||
// in Go 1.13:
|
// in Go 1.13:
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ const percentBangString = "%!"
|
||||||
// It is invalid to include more than one %w verb or to supply it with an
|
// It is invalid to include more than one %w verb or to supply it with an
|
||||||
// operand that does not implement the error interface. The %w verb is otherwise
|
// operand that does not implement the error interface. The %w verb is otherwise
|
||||||
// a synonym for %v.
|
// a synonym for %v.
|
||||||
|
//
|
||||||
|
// Note that as of Go 1.13, the fmt.Errorf function will do error formatting,
|
||||||
|
// but it will not capture a stack backtrace.
|
||||||
func Errorf(format string, a ...interface{}) error {
|
func Errorf(format string, a ...interface{}) error {
|
||||||
format = formatPlusW(format)
|
format = formatPlusW(format)
|
||||||
// Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
|
// Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ func (e noWrapper) FormatError(p Printer) (next error) {
|
||||||
|
|
||||||
// Unwrap returns the result of calling the Unwrap method on err, if err implements
|
// Unwrap returns the result of calling the Unwrap method on err, if err implements
|
||||||
// Unwrap. Otherwise, Unwrap returns nil.
|
// Unwrap. Otherwise, Unwrap returns nil.
|
||||||
|
//
|
||||||
|
// Deprecated: As of Go 1.13, use errors.Unwrap instead.
|
||||||
func Unwrap(err error) error {
|
func Unwrap(err error) error {
|
||||||
u, ok := err.(Wrapper)
|
u, ok := err.(Wrapper)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -47,6 +49,8 @@ func Unwrap(err error) error {
|
||||||
//
|
//
|
||||||
// An error is considered to match a target if it is equal to that target or if
|
// An error is considered to match a target if it is equal to that target or if
|
||||||
// it implements a method Is(error) bool such that Is(target) returns true.
|
// it implements a method Is(error) bool such that Is(target) returns true.
|
||||||
|
//
|
||||||
|
// Deprecated: As of Go 1.13, use errors.Is instead.
|
||||||
func Is(err, target error) bool {
|
func Is(err, target error) bool {
|
||||||
if target == nil {
|
if target == nil {
|
||||||
return err == target
|
return err == target
|
||||||
|
|
@ -77,6 +81,8 @@ func Is(err, target error) bool {
|
||||||
//
|
//
|
||||||
// The As method should set the target to its value and return true if err
|
// The As method should set the target to its value and return true if err
|
||||||
// matches the type to which target points.
|
// matches the type to which target points.
|
||||||
|
//
|
||||||
|
// Deprecated: As of Go 1.13, use errors.As instead.
|
||||||
func As(err error, target interface{}) bool {
|
func As(err error, target interface{}) bool {
|
||||||
if target == nil {
|
if target == nil {
|
||||||
panic("errors: target cannot be nil")
|
panic("errors: target cannot be nil")
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2020 Google LLC
|
// Copyright 2022 Google LLC
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.25.0
|
// protoc-gen-go v1.26.0
|
||||||
// protoc v3.13.0
|
// protoc v3.21.9
|
||||||
// source: google/rpc/status.proto
|
// source: google/rpc/status.proto
|
||||||
|
|
||||||
package status
|
package status
|
||||||
|
|
@ -24,7 +24,6 @@ import (
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
|
|
||||||
proto "github.com/golang/protobuf/proto"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
@ -37,10 +36,6 @@ const (
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
|
||||||
// of the legacy proto package is being used.
|
|
||||||
const _ = proto.ProtoPackageIsVersion4
|
|
||||||
|
|
||||||
// The `Status` type defines a logical error model that is suitable for
|
// The `Status` type defines a logical error model that is suitable for
|
||||||
// different programming environments, including REST APIs and RPC APIs. It is
|
// different programming environments, including REST APIs and RPC APIs. It is
|
||||||
// used by [gRPC](https://github.com/grpc). Each `Status` message contains
|
// used by [gRPC](https://github.com/grpc). Each `Status` message contains
|
||||||
|
|
@ -53,11 +48,13 @@ type Status struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
|
// The status code, which should be an enum value of
|
||||||
|
// [google.rpc.Code][google.rpc.Code].
|
||||||
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
|
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
|
||||||
// A developer-facing error message, which should be in English. Any
|
// A developer-facing error message, which should be in English. Any
|
||||||
// user-facing error message should be localized and sent in the
|
// user-facing error message should be localized and sent in the
|
||||||
// [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
|
// [google.rpc.Status.details][google.rpc.Status.details] field, or localized
|
||||||
|
// by the client.
|
||||||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
|
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
|
||||||
// A list of messages that carry the error details. There is a common set of
|
// A list of messages that carry the error details. There is a common set of
|
||||||
// message types for APIs to use.
|
// message types for APIs to use.
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
language: go
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- go: 1.13.x
|
|
||||||
env: VET=1 GO111MODULE=on
|
|
||||||
- go: 1.13.x
|
|
||||||
env: RACE=1 GO111MODULE=on
|
|
||||||
- go: 1.13.x
|
|
||||||
env: RUN386=1
|
|
||||||
- go: 1.13.x
|
|
||||||
env: GRPC_GO_RETRY=on
|
|
||||||
- go: 1.13.x
|
|
||||||
env: TESTEXTRAS=1
|
|
||||||
- go: 1.12.x
|
|
||||||
env: GO111MODULE=on
|
|
||||||
- go: 1.11.x
|
|
||||||
env: GO111MODULE=on
|
|
||||||
- go: 1.9.x
|
|
||||||
env: GAE=1
|
|
||||||
|
|
||||||
go_import_path: google.golang.org/grpc
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi
|
|
||||||
- if [[ -n "${RUN386}" ]]; then export GOARCH=386; fi
|
|
||||||
- if [[ "${TRAVIS_EVENT_TYPE}" = "cron" && -z "${RUN386}" ]]; then RACE=1; fi
|
|
||||||
- if [[ "${TRAVIS_EVENT_TYPE}" != "cron" ]]; then export VET_SKIP_PROTO=1; fi
|
|
||||||
|
|
||||||
install:
|
|
||||||
- try3() { eval "$*" || eval "$*" || eval "$*"; }
|
|
||||||
- try3 'if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make testdeps; fi'
|
|
||||||
- if [[ -n "${GAE}" ]]; then source ./install_gae.sh; make testappenginedeps; fi
|
|
||||||
- if [[ -n "${VET}" ]]; then ./vet.sh -install; fi
|
|
||||||
|
|
||||||
script:
|
|
||||||
- set -e
|
|
||||||
- if [[ -n "${TESTEXTRAS}" ]]; then examples/examples_test.sh; interop/interop_test.sh; make testsubmodule; exit 0; fi
|
|
||||||
- if [[ -n "${VET}" ]]; then ./vet.sh; fi
|
|
||||||
- if [[ -n "${GAE}" ]]; then make testappengine; exit 0; fi
|
|
||||||
- if [[ -n "${RACE}" ]]; then make testrace; exit 0; fi
|
|
||||||
- make test
|
|
||||||
|
|
@ -20,6 +20,15 @@ How to get your contributions merged smoothly and quickly.
|
||||||
both author's & review's time is wasted. Create more PRs to address different
|
both author's & review's time is wasted. Create more PRs to address different
|
||||||
concerns and everyone will be happy.
|
concerns and everyone will be happy.
|
||||||
|
|
||||||
|
- If you are searching for features to work on, issues labeled [Status: Help
|
||||||
|
Wanted](https://github.com/grpc/grpc-go/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22Status%3A+Help+Wanted%22)
|
||||||
|
is a great place to start. These issues are well-documented and usually can be
|
||||||
|
resolved with a single pull request.
|
||||||
|
|
||||||
|
- If you are adding a new file, make sure it has the copyright message template
|
||||||
|
at the top as a comment. You can copy over the message from an existing file
|
||||||
|
and update the year.
|
||||||
|
|
||||||
- The grpc package should only depend on standard Go packages and a small number
|
- The grpc package should only depend on standard Go packages and a small number
|
||||||
of exceptions. If your contribution introduces new dependencies which are NOT
|
of exceptions. If your contribution introduces new dependencies which are NOT
|
||||||
in the [list](https://godoc.org/google.golang.org/grpc?imports), you need a
|
in the [list](https://godoc.org/google.golang.org/grpc?imports), you need a
|
||||||
|
|
@ -32,14 +41,18 @@ How to get your contributions merged smoothly and quickly.
|
||||||
- Provide a good **PR description** as a record of **what** change is being made
|
- Provide a good **PR description** as a record of **what** change is being made
|
||||||
and **why** it was made. Link to a github issue if it exists.
|
and **why** it was made. Link to a github issue if it exists.
|
||||||
|
|
||||||
- Don't fix code style and formatting unless you are already changing that line
|
- If you want to fix formatting or style, consider whether your changes are an
|
||||||
to address an issue. PRs with irrelevant changes won't be merged. If you do
|
obvious improvement or might be considered a personal preference. If a style
|
||||||
want to fix formatting or style, do that in a separate PR.
|
change is based on preference, it likely will not be accepted. If it corrects
|
||||||
|
widely agreed-upon anti-patterns, then please do create a PR and explain the
|
||||||
|
benefits of the change.
|
||||||
|
|
||||||
- Unless your PR is trivial, you should expect there will be reviewer comments
|
- Unless your PR is trivial, you should expect there will be reviewer comments
|
||||||
that you'll need to address before merging. We expect you to be reasonably
|
that you'll need to address before merging. We'll mark it as `Status: Requires
|
||||||
responsive to those comments, otherwise the PR will be closed after 2-3 weeks
|
Reporter Clarification` if we expect you to respond to these comments in a
|
||||||
of inactivity.
|
timely manner. If the PR remains inactive for 6 days, it will be marked as
|
||||||
|
`stale` and automatically close 7 days after that if we don't hear back from
|
||||||
|
you.
|
||||||
|
|
||||||
- Maintain **clean commit history** and use **meaningful commit messages**. PRs
|
- Maintain **clean commit history** and use **meaningful commit messages**. PRs
|
||||||
with messy commit history are difficult to review and won't be merged. Use
|
with messy commit history are difficult to review and won't be merged. Use
|
||||||
|
|
@ -53,10 +66,8 @@ How to get your contributions merged smoothly and quickly.
|
||||||
- **All tests need to be passing** before your change can be merged. We
|
- **All tests need to be passing** before your change can be merged. We
|
||||||
recommend you **run tests locally** before creating your PR to catch breakages
|
recommend you **run tests locally** before creating your PR to catch breakages
|
||||||
early on.
|
early on.
|
||||||
- `make all` to test everything, OR
|
- `VET_SKIP_PROTO=1 ./vet.sh` to catch vet errors
|
||||||
- `make vet` to catch vet errors
|
- `go test -cpu 1,4 -timeout 7m ./...` to run the tests
|
||||||
- `make test` to run the tests
|
- `go test -race -cpu 1,4 -timeout 7m ./...` to run tests in race mode
|
||||||
- `make testrace` to run tests in race mode
|
|
||||||
- optional `make testappengine` to run tests with appengine
|
|
||||||
|
|
||||||
- Exceptions to the rules can be made if there's a compelling reason for doing so.
|
- Exceptions to the rules can be made if there's a compelling reason for doing so.
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,18 @@ See [CONTRIBUTING.md](https://github.com/grpc/grpc-community/blob/master/CONTRIB
|
||||||
for general contribution guidelines.
|
for general contribution guidelines.
|
||||||
|
|
||||||
## Maintainers (in alphabetical order)
|
## Maintainers (in alphabetical order)
|
||||||
- [canguler](https://github.com/canguler), Google LLC
|
|
||||||
- [cesarghali](https://github.com/cesarghali), Google LLC
|
- [cesarghali](https://github.com/cesarghali), Google LLC
|
||||||
- [dfawley](https://github.com/dfawley), Google LLC
|
- [dfawley](https://github.com/dfawley), Google LLC
|
||||||
- [easwars](https://github.com/easwars), Google LLC
|
- [easwars](https://github.com/easwars), Google LLC
|
||||||
- [jadekler](https://github.com/jadekler), Google LLC
|
|
||||||
- [menghanl](https://github.com/menghanl), Google LLC
|
- [menghanl](https://github.com/menghanl), Google LLC
|
||||||
- [srini100](https://github.com/srini100), Google LLC
|
- [srini100](https://github.com/srini100), Google LLC
|
||||||
|
|
||||||
## Emeritus Maintainers (in alphabetical order)
|
## Emeritus Maintainers (in alphabetical order)
|
||||||
- [adelez](https://github.com/adelez), Google LLC
|
- [adelez](https://github.com/adelez), Google LLC
|
||||||
|
- [canguler](https://github.com/canguler), Google LLC
|
||||||
- [iamqizhao](https://github.com/iamqizhao), Google LLC
|
- [iamqizhao](https://github.com/iamqizhao), Google LLC
|
||||||
|
- [jadekler](https://github.com/jadekler), Google LLC
|
||||||
- [jtattermusch](https://github.com/jtattermusch), Google LLC
|
- [jtattermusch](https://github.com/jtattermusch), Google LLC
|
||||||
- [lyuxuan](https://github.com/lyuxuan), Google LLC
|
- [lyuxuan](https://github.com/lyuxuan), Google LLC
|
||||||
- [makmukhi](https://github.com/makmukhi), Google LLC
|
- [makmukhi](https://github.com/makmukhi), Google LLC
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
all: vet test testrace
|
all: vet test testrace
|
||||||
|
|
||||||
build: deps
|
build:
|
||||||
go build google.golang.org/grpc/...
|
go build google.golang.org/grpc/...
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean -i google.golang.org/grpc/...
|
go clean -i google.golang.org/grpc/...
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
go get -d -v google.golang.org/grpc/...
|
GO111MODULE=on go get -d -v google.golang.org/grpc/...
|
||||||
|
|
||||||
proto:
|
proto:
|
||||||
@ if ! which protoc > /dev/null; then \
|
@ if ! which protoc > /dev/null; then \
|
||||||
|
|
@ -16,29 +16,18 @@ proto:
|
||||||
fi
|
fi
|
||||||
go generate google.golang.org/grpc/...
|
go generate google.golang.org/grpc/...
|
||||||
|
|
||||||
test: testdeps
|
test:
|
||||||
go test -cpu 1,4 -timeout 7m google.golang.org/grpc/...
|
go test -cpu 1,4 -timeout 7m google.golang.org/grpc/...
|
||||||
|
|
||||||
testsubmodule: testdeps
|
testsubmodule:
|
||||||
cd security/advancedtls && go test -cpu 1,4 -timeout 7m google.golang.org/grpc/security/advancedtls/...
|
cd security/advancedtls && go test -cpu 1,4 -timeout 7m google.golang.org/grpc/security/advancedtls/...
|
||||||
|
cd security/authorization && go test -cpu 1,4 -timeout 7m google.golang.org/grpc/security/authorization/...
|
||||||
|
|
||||||
testappengine: testappenginedeps
|
testrace:
|
||||||
goapp test -cpu 1,4 -timeout 7m google.golang.org/grpc/...
|
|
||||||
|
|
||||||
testappenginedeps:
|
|
||||||
goapp get -d -v -t -tags 'appengine appenginevm' google.golang.org/grpc/...
|
|
||||||
|
|
||||||
testdeps:
|
|
||||||
go get -d -v -t google.golang.org/grpc/...
|
|
||||||
|
|
||||||
testrace: testdeps
|
|
||||||
go test -race -cpu 1,4 -timeout 7m google.golang.org/grpc/...
|
go test -race -cpu 1,4 -timeout 7m google.golang.org/grpc/...
|
||||||
|
|
||||||
updatedeps:
|
testdeps:
|
||||||
go get -d -v -u -f google.golang.org/grpc/...
|
GO111MODULE=on go get -d -v -t google.golang.org/grpc/...
|
||||||
|
|
||||||
updatetestdeps:
|
|
||||||
go get -d -v -t -u -f google.golang.org/grpc/...
|
|
||||||
|
|
||||||
vet: vetdeps
|
vet: vetdeps
|
||||||
./vet.sh
|
./vet.sh
|
||||||
|
|
@ -50,14 +39,8 @@ vetdeps:
|
||||||
all \
|
all \
|
||||||
build \
|
build \
|
||||||
clean \
|
clean \
|
||||||
deps \
|
|
||||||
proto \
|
proto \
|
||||||
test \
|
test \
|
||||||
testappengine \
|
|
||||||
testappenginedeps \
|
|
||||||
testdeps \
|
|
||||||
testrace \
|
testrace \
|
||||||
updatedeps \
|
|
||||||
updatetestdeps \
|
|
||||||
vet \
|
vet \
|
||||||
vetdeps
|
vetdeps
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2014 gRPC 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.
|
||||||
|
|
@ -1,64 +1,46 @@
|
||||||
# gRPC-Go
|
# gRPC-Go
|
||||||
|
|
||||||
[](https://travis-ci.org/grpc/grpc-go)
|
[](https://travis-ci.org/grpc/grpc-go)
|
||||||
[](https://godoc.org/google.golang.org/grpc)
|
[][API]
|
||||||
[](https://goreportcard.com/report/github.com/grpc/grpc-go)
|
[](https://goreportcard.com/report/github.com/grpc/grpc-go)
|
||||||
|
|
||||||
The Go implementation of [gRPC](https://grpc.io/): A high performance, open
|
The [Go][] implementation of [gRPC][]: A high performance, open source, general
|
||||||
source, general RPC framework that puts mobile and HTTP/2 first. For more
|
RPC framework that puts mobile and HTTP/2 first. For more information see the
|
||||||
information see the [gRPC Quick Start:
|
[Go gRPC docs][], or jump directly into the [quick start][].
|
||||||
Go](https://grpc.io/docs/quickstart/go.html) guide.
|
|
||||||
|
|
||||||
Installation
|
## Prerequisites
|
||||||
------------
|
|
||||||
|
|
||||||
To install this package, you need to install Go and setup your Go workspace on
|
- **[Go][]**: any one of the **three latest major** [releases][go-releases].
|
||||||
your computer. The simplest way to install the library is to run:
|
|
||||||
|
|
||||||
```
|
## Installation
|
||||||
$ go get -u google.golang.org/grpc
|
|
||||||
|
Simply add the following import to your code, and then `go [build|run|test]`
|
||||||
|
will automatically fetch the necessary dependencies:
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "google.golang.org/grpc"
|
||||||
```
|
```
|
||||||
|
|
||||||
With Go module support (Go 1.11+), simply `import "google.golang.org/grpc"` in
|
> **Note:** If you are trying to access `grpc-go` from **China**, see the
|
||||||
your source code and `go [build|run|test]` will automatically download the
|
> [FAQ](#FAQ) below.
|
||||||
necessary dependencies ([Go modules
|
|
||||||
ref](https://github.com/golang/go/wiki/Modules)).
|
|
||||||
|
|
||||||
If you are trying to access grpc-go from within China, please see the
|
## Learn more
|
||||||
[FAQ](#FAQ) below.
|
|
||||||
|
|
||||||
Prerequisites
|
- [Go gRPC docs][], which include a [quick start][] and [API
|
||||||
-------------
|
reference][API] among other resources
|
||||||
gRPC-Go requires Go 1.9 or later.
|
- [Low-level technical docs](Documentation) from this repository
|
||||||
|
- [Performance benchmark][]
|
||||||
|
- [Examples](examples)
|
||||||
|
|
||||||
Documentation
|
## FAQ
|
||||||
-------------
|
|
||||||
- See [godoc](https://godoc.org/google.golang.org/grpc) for package and API
|
|
||||||
descriptions.
|
|
||||||
- Documentation on specific topics can be found in the [Documentation
|
|
||||||
directory](Documentation/).
|
|
||||||
- Examples can be found in the [examples directory](examples/).
|
|
||||||
|
|
||||||
Performance
|
### I/O Timeout Errors
|
||||||
-----------
|
|
||||||
Performance benchmark data for grpc-go and other languages is maintained in
|
|
||||||
[this
|
|
||||||
dashboard](https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5652536396611584&widget=490377658&container=1286539696).
|
|
||||||
|
|
||||||
Status
|
The `golang.org` domain may be blocked from some countries. `go get` usually
|
||||||
------
|
|
||||||
General Availability [Google Cloud Platform Launch
|
|
||||||
Stages](https://cloud.google.com/terms/launch-stages).
|
|
||||||
|
|
||||||
FAQ
|
|
||||||
---
|
|
||||||
|
|
||||||
#### I/O Timeout Errors
|
|
||||||
|
|
||||||
The `golang.org` domain may be blocked from some countries. `go get` usually
|
|
||||||
produces an error like the following when this happens:
|
produces an error like the following when this happens:
|
||||||
|
|
||||||
```
|
```console
|
||||||
$ go get -u google.golang.org/grpc
|
$ go get -u google.golang.org/grpc
|
||||||
package google.golang.org/grpc: unrecognized import path "google.golang.org/grpc" (https fetch: Get https://google.golang.org/grpc?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
|
package google.golang.org/grpc: unrecognized import path "google.golang.org/grpc" (https fetch: Get https://google.golang.org/grpc?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
|
||||||
```
|
```
|
||||||
|
|
@ -67,19 +49,10 @@ To build Go code, there are several options:
|
||||||
|
|
||||||
- Set up a VPN and access google.golang.org through that.
|
- Set up a VPN and access google.golang.org through that.
|
||||||
|
|
||||||
- Without Go module support: `git clone` the repo manually:
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
|
|
||||||
```
|
|
||||||
|
|
||||||
You will need to do the same for all of grpc's dependencies in `golang.org`,
|
|
||||||
e.g. `golang.org/x/net`.
|
|
||||||
|
|
||||||
- With Go module support: it is possible to use the `replace` feature of `go
|
- With Go module support: it is possible to use the `replace` feature of `go
|
||||||
mod` to create aliases for golang.org packages. In your project's directory:
|
mod` to create aliases for golang.org packages. In your project's directory:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
go mod edit -replace=google.golang.org/grpc=github.com/grpc/grpc-go@latest
|
go mod edit -replace=google.golang.org/grpc=github.com/grpc/grpc-go@latest
|
||||||
go mod tidy
|
go mod tidy
|
||||||
go mod vendor
|
go mod vendor
|
||||||
|
|
@ -87,35 +60,48 @@ To build Go code, there are several options:
|
||||||
```
|
```
|
||||||
|
|
||||||
Again, this will need to be done for all transitive dependencies hosted on
|
Again, this will need to be done for all transitive dependencies hosted on
|
||||||
golang.org as well. Please refer to [this
|
golang.org as well. For details, refer to [golang/go issue
|
||||||
issue](https://github.com/golang/go/issues/28652) in the golang repo regarding
|
#28652](https://github.com/golang/go/issues/28652).
|
||||||
this concern.
|
|
||||||
|
|
||||||
#### Compiling error, undefined: grpc.SupportPackageIsVersion
|
### Compiling error, undefined: grpc.SupportPackageIsVersion
|
||||||
|
|
||||||
Please update proto package, gRPC package and rebuild the proto files:
|
Please update to the latest version of gRPC-Go using
|
||||||
- `go get -u github.com/golang/protobuf/{proto,protoc-gen-go}`
|
`go get google.golang.org/grpc`.
|
||||||
- `go get -u google.golang.org/grpc`
|
|
||||||
- `protoc --go_out=plugins=grpc:. *.proto`
|
|
||||||
|
|
||||||
#### How to turn on logging
|
### How to turn on logging
|
||||||
|
|
||||||
The default logger is controlled by the environment variables. Turn everything
|
The default logger is controlled by environment variables. Turn everything on
|
||||||
on by setting:
|
like this:
|
||||||
|
|
||||||
```
|
```console
|
||||||
GRPC_GO_LOG_VERBOSITY_LEVEL=99 GRPC_GO_LOG_SEVERITY_LEVEL=info
|
$ export GRPC_GO_LOG_VERBOSITY_LEVEL=99
|
||||||
|
$ export GRPC_GO_LOG_SEVERITY_LEVEL=info
|
||||||
```
|
```
|
||||||
|
|
||||||
#### The RPC failed with error `"code = Unavailable desc = transport is closing"`
|
### The RPC failed with error `"code = Unavailable desc = transport is closing"`
|
||||||
|
|
||||||
This error means the connection the RPC is using was closed, and there are many
|
This error means the connection the RPC is using was closed, and there are many
|
||||||
possible reasons, including:
|
possible reasons, including:
|
||||||
1. mis-configured transport credentials, connection failed on handshaking
|
1. mis-configured transport credentials, connection failed on handshaking
|
||||||
1. bytes disrupted, possibly by a proxy in between
|
1. bytes disrupted, possibly by a proxy in between
|
||||||
1. server shutdown
|
1. server shutdown
|
||||||
|
1. Keepalive parameters caused connection shutdown, for example if you have
|
||||||
|
configured your server to terminate connections regularly to [trigger DNS
|
||||||
|
lookups](https://github.com/grpc/grpc-go/issues/3170#issuecomment-552517779).
|
||||||
|
If this is the case, you may want to increase your
|
||||||
|
[MaxConnectionAgeGrace](https://pkg.go.dev/google.golang.org/grpc/keepalive?tab=doc#ServerParameters),
|
||||||
|
to allow longer RPC calls to finish.
|
||||||
|
|
||||||
It can be tricky to debug this because the error happens on the client side but
|
It can be tricky to debug this because the error happens on the client side but
|
||||||
the root cause of the connection being closed is on the server side. Turn on
|
the root cause of the connection being closed is on the server side. Turn on
|
||||||
logging on __both client and server__, and see if there are any transport
|
logging on __both client and server__, and see if there are any transport
|
||||||
errors.
|
errors.
|
||||||
|
|
||||||
|
[API]: https://pkg.go.dev/google.golang.org/grpc
|
||||||
|
[Go]: https://golang.org
|
||||||
|
[Go module]: https://github.com/golang/go/wiki/Modules
|
||||||
|
[gRPC]: https://grpc.io
|
||||||
|
[Go gRPC docs]: https://grpc.io/docs/languages/go
|
||||||
|
[Performance benchmark]: https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5180705743044608
|
||||||
|
[quick start]: https://grpc.io/docs/languages/go/quickstart
|
||||||
|
[go-releases]: https://golang.org/doc/devel/release.html
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
For information on gRPC Security Policy and reporting potentional security issues, please see [gRPC CVE Process](https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md).
|
||||||
|
|
@ -19,52 +19,123 @@
|
||||||
// Package attributes defines a generic key/value store used in various gRPC
|
// Package attributes defines a generic key/value store used in various gRPC
|
||||||
// components.
|
// components.
|
||||||
//
|
//
|
||||||
// All APIs in this package are EXPERIMENTAL.
|
// # Experimental
|
||||||
|
//
|
||||||
|
// Notice: This package is EXPERIMENTAL and may be changed or removed in a
|
||||||
|
// later release.
|
||||||
package attributes
|
package attributes
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// Attributes is an immutable struct for storing and retrieving generic
|
// Attributes is an immutable struct for storing and retrieving generic
|
||||||
// key/value pairs. Keys must be hashable, and users should define their own
|
// key/value pairs. Keys must be hashable, and users should define their own
|
||||||
// types for keys.
|
// types for keys. Values should not be modified after they are added to an
|
||||||
|
// Attributes or if they were received from one. If values implement 'Equal(o
|
||||||
|
// any) bool', it will be called by (*Attributes).Equal to determine whether
|
||||||
|
// two values with the same key should be considered equal.
|
||||||
type Attributes struct {
|
type Attributes struct {
|
||||||
m map[interface{}]interface{}
|
m map[any]any
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Attributes containing all key/value pairs in kvs. If the
|
// New returns a new Attributes containing the key/value pair.
|
||||||
// same key appears multiple times, the last value overwrites all previous
|
func New(key, value any) *Attributes {
|
||||||
// values for that key. Panics if len(kvs) is not even.
|
return &Attributes{m: map[any]any{key: value}}
|
||||||
func New(kvs ...interface{}) *Attributes {
|
|
||||||
if len(kvs)%2 != 0 {
|
|
||||||
panic(fmt.Sprintf("attributes.New called with unexpected input: len(kvs) = %v", len(kvs)))
|
|
||||||
}
|
|
||||||
a := &Attributes{m: make(map[interface{}]interface{}, len(kvs)/2)}
|
|
||||||
for i := 0; i < len(kvs)/2; i++ {
|
|
||||||
a.m[kvs[i*2]] = kvs[i*2+1]
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithValues returns a new Attributes containing all key/value pairs in a and
|
// WithValue returns a new Attributes containing the previous keys and values
|
||||||
// kvs. Panics if len(kvs) is not even. If the same key appears multiple
|
// and the new key/value pair. If the same key appears multiple times, the
|
||||||
// times, the last value overwrites all previous values for that key. To
|
// last value overwrites all previous values for that key. To remove an
|
||||||
// remove an existing key, use a nil value.
|
// existing key, use a nil value. value should not be modified later.
|
||||||
func (a *Attributes) WithValues(kvs ...interface{}) *Attributes {
|
func (a *Attributes) WithValue(key, value any) *Attributes {
|
||||||
if len(kvs)%2 != 0 {
|
if a == nil {
|
||||||
panic(fmt.Sprintf("attributes.New called with unexpected input: len(kvs) = %v", len(kvs)))
|
return New(key, value)
|
||||||
}
|
}
|
||||||
n := &Attributes{m: make(map[interface{}]interface{}, len(a.m)+len(kvs)/2)}
|
n := &Attributes{m: make(map[any]any, len(a.m)+1)}
|
||||||
for k, v := range a.m {
|
for k, v := range a.m {
|
||||||
n.m[k] = v
|
n.m[k] = v
|
||||||
}
|
}
|
||||||
for i := 0; i < len(kvs)/2; i++ {
|
n.m[key] = value
|
||||||
n.m[kvs[i*2]] = kvs[i*2+1]
|
|
||||||
}
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the value associated with these attributes for key, or nil if
|
// Value returns the value associated with these attributes for key, or nil if
|
||||||
// no value is associated with key.
|
// no value is associated with key. The returned value should not be modified.
|
||||||
func (a *Attributes) Value(key interface{}) interface{} {
|
func (a *Attributes) Value(key any) any {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return a.m[key]
|
return a.m[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equal returns whether a and o are equivalent. If 'Equal(o any) bool' is
|
||||||
|
// implemented for a value in the attributes, it is called to determine if the
|
||||||
|
// value matches the one stored in the other attributes. If Equal is not
|
||||||
|
// implemented, standard equality is used to determine if the two values are
|
||||||
|
// equal. Note that some types (e.g. maps) aren't comparable by default, so
|
||||||
|
// they must be wrapped in a struct, or in an alias type, with Equal defined.
|
||||||
|
func (a *Attributes) Equal(o *Attributes) bool {
|
||||||
|
if a == nil && o == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a == nil || o == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(a.m) != len(o.m) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for k, v := range a.m {
|
||||||
|
ov, ok := o.m[k]
|
||||||
|
if !ok {
|
||||||
|
// o missing element of a
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if eq, ok := v.(interface{ Equal(o any) bool }); ok {
|
||||||
|
if !eq.Equal(ov) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if v != ov {
|
||||||
|
// Fallback to a standard equality check if Value is unimplemented.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// String prints the attribute map. If any key or values throughout the map
|
||||||
|
// implement fmt.Stringer, it calls that method and appends.
|
||||||
|
func (a *Attributes) String() string {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString("{")
|
||||||
|
first := true
|
||||||
|
for k, v := range a.m {
|
||||||
|
if !first {
|
||||||
|
sb.WriteString(", ")
|
||||||
|
}
|
||||||
|
sb.WriteString(fmt.Sprintf("%q: %q ", str(k), str(v)))
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
sb.WriteString("}")
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func str(x any) string {
|
||||||
|
if v, ok := x.(fmt.Stringer); ok {
|
||||||
|
return v.String()
|
||||||
|
} else if v, ok := x.(string); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("<%p>", x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON helps implement the json.Marshaler interface, thereby rendering
|
||||||
|
// the Attributes correctly when printing (via pretty.JSON) structs containing
|
||||||
|
// Attributes as fields.
|
||||||
|
//
|
||||||
|
// Is it impossible to unmarshal attributes from a JSON representation and this
|
||||||
|
// method is meant only for debugging purposes.
|
||||||
|
func (a *Attributes) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(a.String()), nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,10 @@ type BackoffConfig struct {
|
||||||
// here for more details:
|
// here for more details:
|
||||||
// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
|
// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
|
||||||
//
|
//
|
||||||
// This API is EXPERIMENTAL.
|
// # Experimental
|
||||||
|
//
|
||||||
|
// Notice: This type is EXPERIMENTAL and may be changed or removed in a
|
||||||
|
// later release.
|
||||||
type ConnectParams struct {
|
type ConnectParams struct {
|
||||||
// Backoff specifies the configuration options for connection backoff.
|
// Backoff specifies the configuration options for connection backoff.
|
||||||
Backoff backoff.Config
|
Backoff backoff.Config
|
||||||
|
|
|
||||||
|
|
@ -1,391 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2016 gRPC 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 grpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
"google.golang.org/grpc/grpclog"
|
|
||||||
"google.golang.org/grpc/naming"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Address represents a server the client connects to.
|
|
||||||
//
|
|
||||||
// Deprecated: please use package balancer.
|
|
||||||
type Address struct {
|
|
||||||
// Addr is the server address on which a connection will be established.
|
|
||||||
Addr string
|
|
||||||
// Metadata is the information associated with Addr, which may be used
|
|
||||||
// to make load balancing decision.
|
|
||||||
Metadata interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BalancerConfig specifies the configurations for Balancer.
|
|
||||||
//
|
|
||||||
// Deprecated: please use package balancer. May be removed in a future 1.x release.
|
|
||||||
type BalancerConfig struct {
|
|
||||||
// DialCreds is the transport credential the Balancer implementation can
|
|
||||||
// use to dial to a remote load balancer server. The Balancer implementations
|
|
||||||
// can ignore this if it does not need to talk to another party securely.
|
|
||||||
DialCreds credentials.TransportCredentials
|
|
||||||
// Dialer is the custom dialer the Balancer implementation can use to dial
|
|
||||||
// to a remote load balancer server. The Balancer implementations
|
|
||||||
// can ignore this if it doesn't need to talk to remote balancer.
|
|
||||||
Dialer func(context.Context, string) (net.Conn, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BalancerGetOptions configures a Get call.
|
|
||||||
//
|
|
||||||
// Deprecated: please use package balancer. May be removed in a future 1.x release.
|
|
||||||
type BalancerGetOptions struct {
|
|
||||||
// BlockingWait specifies whether Get should block when there is no
|
|
||||||
// connected address.
|
|
||||||
BlockingWait bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Balancer chooses network addresses for RPCs.
|
|
||||||
//
|
|
||||||
// Deprecated: please use package balancer. May be removed in a future 1.x release.
|
|
||||||
type Balancer interface {
|
|
||||||
// Start does the initialization work to bootstrap a Balancer. For example,
|
|
||||||
// this function may start the name resolution and watch the updates. It will
|
|
||||||
// be called when dialing.
|
|
||||||
Start(target string, config BalancerConfig) error
|
|
||||||
// Up informs the Balancer that gRPC has a connection to the server at
|
|
||||||
// addr. It returns down which is called once the connection to addr gets
|
|
||||||
// lost or closed.
|
|
||||||
// TODO: It is not clear how to construct and take advantage of the meaningful error
|
|
||||||
// parameter for down. Need realistic demands to guide.
|
|
||||||
Up(addr Address) (down func(error))
|
|
||||||
// Get gets the address of a server for the RPC corresponding to ctx.
|
|
||||||
// i) If it returns a connected address, gRPC internals issues the RPC on the
|
|
||||||
// connection to this address;
|
|
||||||
// ii) If it returns an address on which the connection is under construction
|
|
||||||
// (initiated by Notify(...)) but not connected, gRPC internals
|
|
||||||
// * fails RPC if the RPC is fail-fast and connection is in the TransientFailure or
|
|
||||||
// Shutdown state;
|
|
||||||
// or
|
|
||||||
// * issues RPC on the connection otherwise.
|
|
||||||
// iii) If it returns an address on which the connection does not exist, gRPC
|
|
||||||
// internals treats it as an error and will fail the corresponding RPC.
|
|
||||||
//
|
|
||||||
// Therefore, the following is the recommended rule when writing a custom Balancer.
|
|
||||||
// If opts.BlockingWait is true, it should return a connected address or
|
|
||||||
// block if there is no connected address. It should respect the timeout or
|
|
||||||
// cancellation of ctx when blocking. If opts.BlockingWait is false (for fail-fast
|
|
||||||
// RPCs), it should return an address it has notified via Notify(...) immediately
|
|
||||||
// instead of blocking.
|
|
||||||
//
|
|
||||||
// The function returns put which is called once the rpc has completed or failed.
|
|
||||||
// put can collect and report RPC stats to a remote load balancer.
|
|
||||||
//
|
|
||||||
// This function should only return the errors Balancer cannot recover by itself.
|
|
||||||
// gRPC internals will fail the RPC if an error is returned.
|
|
||||||
Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error)
|
|
||||||
// Notify returns a channel that is used by gRPC internals to watch the addresses
|
|
||||||
// gRPC needs to connect. The addresses might be from a name resolver or remote
|
|
||||||
// load balancer. gRPC internals will compare it with the existing connected
|
|
||||||
// addresses. If the address Balancer notified is not in the existing connected
|
|
||||||
// addresses, gRPC starts to connect the address. If an address in the existing
|
|
||||||
// connected addresses is not in the notification list, the corresponding connection
|
|
||||||
// is shutdown gracefully. Otherwise, there are no operations to take. Note that
|
|
||||||
// the Address slice must be the full list of the Addresses which should be connected.
|
|
||||||
// It is NOT delta.
|
|
||||||
Notify() <-chan []Address
|
|
||||||
// Close shuts down the balancer.
|
|
||||||
Close() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoundRobin returns a Balancer that selects addresses round-robin. It uses r to watch
|
|
||||||
// the name resolution updates and updates the addresses available correspondingly.
|
|
||||||
//
|
|
||||||
// Deprecated: please use package balancer/roundrobin. May be removed in a future 1.x release.
|
|
||||||
func RoundRobin(r naming.Resolver) Balancer {
|
|
||||||
return &roundRobin{r: r}
|
|
||||||
}
|
|
||||||
|
|
||||||
type addrInfo struct {
|
|
||||||
addr Address
|
|
||||||
connected bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type roundRobin struct {
|
|
||||||
r naming.Resolver
|
|
||||||
w naming.Watcher
|
|
||||||
addrs []*addrInfo // all the addresses the client should potentially connect
|
|
||||||
mu sync.Mutex
|
|
||||||
addrCh chan []Address // the channel to notify gRPC internals the list of addresses the client should connect to.
|
|
||||||
next int // index of the next address to return for Get()
|
|
||||||
waitCh chan struct{} // the channel to block when there is no connected address available
|
|
||||||
done bool // The Balancer is closed.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rr *roundRobin) watchAddrUpdates() error {
|
|
||||||
updates, err := rr.w.Next()
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Warningf("grpc: the naming watcher stops working due to %v.", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rr.mu.Lock()
|
|
||||||
defer rr.mu.Unlock()
|
|
||||||
for _, update := range updates {
|
|
||||||
addr := Address{
|
|
||||||
Addr: update.Addr,
|
|
||||||
Metadata: update.Metadata,
|
|
||||||
}
|
|
||||||
switch update.Op {
|
|
||||||
case naming.Add:
|
|
||||||
var exist bool
|
|
||||||
for _, v := range rr.addrs {
|
|
||||||
if addr == v.addr {
|
|
||||||
exist = true
|
|
||||||
grpclog.Infoln("grpc: The name resolver wanted to add an existing address: ", addr)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if exist {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rr.addrs = append(rr.addrs, &addrInfo{addr: addr})
|
|
||||||
case naming.Delete:
|
|
||||||
for i, v := range rr.addrs {
|
|
||||||
if addr == v.addr {
|
|
||||||
copy(rr.addrs[i:], rr.addrs[i+1:])
|
|
||||||
rr.addrs = rr.addrs[:len(rr.addrs)-1]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
grpclog.Errorln("Unknown update.Op ", update.Op)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make a copy of rr.addrs and write it onto rr.addrCh so that gRPC internals gets notified.
|
|
||||||
open := make([]Address, len(rr.addrs))
|
|
||||||
for i, v := range rr.addrs {
|
|
||||||
open[i] = v.addr
|
|
||||||
}
|
|
||||||
if rr.done {
|
|
||||||
return ErrClientConnClosing
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-rr.addrCh:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
rr.addrCh <- open
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rr *roundRobin) Start(target string, config BalancerConfig) error {
|
|
||||||
rr.mu.Lock()
|
|
||||||
defer rr.mu.Unlock()
|
|
||||||
if rr.done {
|
|
||||||
return ErrClientConnClosing
|
|
||||||
}
|
|
||||||
if rr.r == nil {
|
|
||||||
// If there is no name resolver installed, it is not needed to
|
|
||||||
// do name resolution. In this case, target is added into rr.addrs
|
|
||||||
// as the only address available and rr.addrCh stays nil.
|
|
||||||
rr.addrs = append(rr.addrs, &addrInfo{addr: Address{Addr: target}})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
w, err := rr.r.Resolve(target)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rr.w = w
|
|
||||||
rr.addrCh = make(chan []Address, 1)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
if err := rr.watchAddrUpdates(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Up sets the connected state of addr and sends notification if there are pending
|
|
||||||
// Get() calls.
|
|
||||||
func (rr *roundRobin) Up(addr Address) func(error) {
|
|
||||||
rr.mu.Lock()
|
|
||||||
defer rr.mu.Unlock()
|
|
||||||
var cnt int
|
|
||||||
for _, a := range rr.addrs {
|
|
||||||
if a.addr == addr {
|
|
||||||
if a.connected {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
a.connected = true
|
|
||||||
}
|
|
||||||
if a.connected {
|
|
||||||
cnt++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// addr is only one which is connected. Notify the Get() callers who are blocking.
|
|
||||||
if cnt == 1 && rr.waitCh != nil {
|
|
||||||
close(rr.waitCh)
|
|
||||||
rr.waitCh = nil
|
|
||||||
}
|
|
||||||
return func(err error) {
|
|
||||||
rr.down(addr, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// down unsets the connected state of addr.
|
|
||||||
func (rr *roundRobin) down(addr Address, err error) {
|
|
||||||
rr.mu.Lock()
|
|
||||||
defer rr.mu.Unlock()
|
|
||||||
for _, a := range rr.addrs {
|
|
||||||
if addr == a.addr {
|
|
||||||
a.connected = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the next addr in the rotation.
|
|
||||||
func (rr *roundRobin) Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error) {
|
|
||||||
var ch chan struct{}
|
|
||||||
rr.mu.Lock()
|
|
||||||
if rr.done {
|
|
||||||
rr.mu.Unlock()
|
|
||||||
err = ErrClientConnClosing
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.addrs) > 0 {
|
|
||||||
if rr.next >= len(rr.addrs) {
|
|
||||||
rr.next = 0
|
|
||||||
}
|
|
||||||
next := rr.next
|
|
||||||
for {
|
|
||||||
a := rr.addrs[next]
|
|
||||||
next = (next + 1) % len(rr.addrs)
|
|
||||||
if a.connected {
|
|
||||||
addr = a.addr
|
|
||||||
rr.next = next
|
|
||||||
rr.mu.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if next == rr.next {
|
|
||||||
// Has iterated all the possible address but none is connected.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !opts.BlockingWait {
|
|
||||||
if len(rr.addrs) == 0 {
|
|
||||||
rr.mu.Unlock()
|
|
||||||
err = status.Errorf(codes.Unavailable, "there is no address available")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Returns the next addr on rr.addrs for failfast RPCs.
|
|
||||||
addr = rr.addrs[rr.next].addr
|
|
||||||
rr.next++
|
|
||||||
rr.mu.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Wait on rr.waitCh for non-failfast RPCs.
|
|
||||||
if rr.waitCh == nil {
|
|
||||||
ch = make(chan struct{})
|
|
||||||
rr.waitCh = ch
|
|
||||||
} else {
|
|
||||||
ch = rr.waitCh
|
|
||||||
}
|
|
||||||
rr.mu.Unlock()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
err = ctx.Err()
|
|
||||||
return
|
|
||||||
case <-ch:
|
|
||||||
rr.mu.Lock()
|
|
||||||
if rr.done {
|
|
||||||
rr.mu.Unlock()
|
|
||||||
err = ErrClientConnClosing
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rr.addrs) > 0 {
|
|
||||||
if rr.next >= len(rr.addrs) {
|
|
||||||
rr.next = 0
|
|
||||||
}
|
|
||||||
next := rr.next
|
|
||||||
for {
|
|
||||||
a := rr.addrs[next]
|
|
||||||
next = (next + 1) % len(rr.addrs)
|
|
||||||
if a.connected {
|
|
||||||
addr = a.addr
|
|
||||||
rr.next = next
|
|
||||||
rr.mu.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if next == rr.next {
|
|
||||||
// Has iterated all the possible address but none is connected.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// The newly added addr got removed by Down() again.
|
|
||||||
if rr.waitCh == nil {
|
|
||||||
ch = make(chan struct{})
|
|
||||||
rr.waitCh = ch
|
|
||||||
} else {
|
|
||||||
ch = rr.waitCh
|
|
||||||
}
|
|
||||||
rr.mu.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rr *roundRobin) Notify() <-chan []Address {
|
|
||||||
return rr.addrCh
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rr *roundRobin) Close() error {
|
|
||||||
rr.mu.Lock()
|
|
||||||
defer rr.mu.Unlock()
|
|
||||||
if rr.done {
|
|
||||||
return errBalancerClosed
|
|
||||||
}
|
|
||||||
rr.done = true
|
|
||||||
if rr.w != nil {
|
|
||||||
rr.w.Close()
|
|
||||||
}
|
|
||||||
if rr.waitCh != nil {
|
|
||||||
close(rr.waitCh)
|
|
||||||
rr.waitCh = nil
|
|
||||||
}
|
|
||||||
if rr.addrCh != nil {
|
|
||||||
close(rr.addrCh)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// pickFirst is used to test multi-addresses in one addrConn in which all addresses share the same addrConn.
|
|
||||||
// It is a wrapper around roundRobin balancer. The logic of all methods works fine because balancer.Get()
|
|
||||||
// returns the only address Up by resetTransport().
|
|
||||||
type pickFirst struct {
|
|
||||||
*roundRobin
|
|
||||||
}
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/channelz"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/internal"
|
"google.golang.org/grpc/internal"
|
||||||
|
|
@ -75,24 +76,26 @@ func Get(name string) Builder {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubConn represents a gRPC sub connection.
|
// A SubConn represents a single connection to a gRPC backend service.
|
||||||
// Each sub connection contains a list of addresses. gRPC will
|
|
||||||
// try to connect to them (in sequence), and stop trying the
|
|
||||||
// remainder once one connection is successful.
|
|
||||||
//
|
//
|
||||||
// The reconnect backoff will be applied on the list, not a single address.
|
// Each SubConn contains a list of addresses.
|
||||||
// For example, try_on_all_addresses -> backoff -> try_on_all_addresses.
|
|
||||||
//
|
//
|
||||||
// All SubConns start in IDLE, and will not try to connect. To trigger
|
// All SubConns start in IDLE, and will not try to connect. To trigger the
|
||||||
// the connecting, Balancers must call Connect.
|
// connecting, Balancers must call Connect. If a connection re-enters IDLE,
|
||||||
// When the connection encounters an error, it will reconnect immediately.
|
// Balancers must call Connect again to trigger a new connection attempt.
|
||||||
// When the connection becomes IDLE, it will not reconnect unless Connect is
|
|
||||||
// called.
|
|
||||||
//
|
//
|
||||||
// This interface is to be implemented by gRPC. Users should not need a
|
// gRPC will try to connect to the addresses in sequence, and stop trying the
|
||||||
// brand new implementation of this interface. For the situations like
|
// remainder once the first connection is successful. If an attempt to connect
|
||||||
// testing, the new implementation should embed this interface. This allows
|
// to all addresses encounters an error, the SubConn will enter
|
||||||
// gRPC to add new methods to this interface.
|
// TRANSIENT_FAILURE for a backoff period, and then transition to IDLE.
|
||||||
|
//
|
||||||
|
// Once established, if a connection is lost, the SubConn will transition
|
||||||
|
// directly to IDLE.
|
||||||
|
//
|
||||||
|
// This interface is to be implemented by gRPC. Users should not need their own
|
||||||
|
// implementation of this interface. For situations like testing, any
|
||||||
|
// implementations should embed this interface. This allows gRPC to add new
|
||||||
|
// methods to this interface.
|
||||||
type SubConn interface {
|
type SubConn interface {
|
||||||
// UpdateAddresses updates the addresses used in this SubConn.
|
// UpdateAddresses updates the addresses used in this SubConn.
|
||||||
// gRPC checks if currently-connected address is still in the new list.
|
// gRPC checks if currently-connected address is still in the new list.
|
||||||
|
|
@ -101,9 +104,24 @@ type SubConn interface {
|
||||||
// a new connection will be created.
|
// a new connection will be created.
|
||||||
//
|
//
|
||||||
// This will trigger a state transition for the SubConn.
|
// This will trigger a state transition for the SubConn.
|
||||||
|
//
|
||||||
|
// Deprecated: this method will be removed. Create new SubConns for new
|
||||||
|
// addresses instead.
|
||||||
UpdateAddresses([]resolver.Address)
|
UpdateAddresses([]resolver.Address)
|
||||||
// Connect starts the connecting for this SubConn.
|
// Connect starts the connecting for this SubConn.
|
||||||
Connect()
|
Connect()
|
||||||
|
// GetOrBuildProducer returns a reference to the existing Producer for this
|
||||||
|
// ProducerBuilder in this SubConn, or, if one does not currently exist,
|
||||||
|
// creates a new one and returns it. Returns a close function which must
|
||||||
|
// be called when the Producer is no longer needed.
|
||||||
|
GetOrBuildProducer(ProducerBuilder) (p Producer, close func())
|
||||||
|
// Shutdown shuts down the SubConn gracefully. Any started RPCs will be
|
||||||
|
// allowed to complete. No future calls should be made on the SubConn.
|
||||||
|
// One final state update will be delivered to the StateListener (or
|
||||||
|
// UpdateSubConnState; deprecated) with ConnectivityState of Shutdown to
|
||||||
|
// indicate the shutdown operation. This may be delivered before
|
||||||
|
// in-progress RPCs are complete and the actual connection is closed.
|
||||||
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSubConnOptions contains options to create new SubConn.
|
// NewSubConnOptions contains options to create new SubConn.
|
||||||
|
|
@ -111,10 +129,18 @@ type NewSubConnOptions struct {
|
||||||
// CredsBundle is the credentials bundle that will be used in the created
|
// CredsBundle is the credentials bundle that will be used in the created
|
||||||
// SubConn. If it's nil, the original creds from grpc DialOptions will be
|
// SubConn. If it's nil, the original creds from grpc DialOptions will be
|
||||||
// used.
|
// used.
|
||||||
|
//
|
||||||
|
// Deprecated: Use the Attributes field in resolver.Address to pass
|
||||||
|
// arbitrary data to the credential handshaker.
|
||||||
CredsBundle credentials.Bundle
|
CredsBundle credentials.Bundle
|
||||||
// HealthCheckEnabled indicates whether health check service should be
|
// HealthCheckEnabled indicates whether health check service should be
|
||||||
// enabled on this SubConn
|
// enabled on this SubConn
|
||||||
HealthCheckEnabled bool
|
HealthCheckEnabled bool
|
||||||
|
// StateListener is called when the state of the subconn changes. If nil,
|
||||||
|
// Balancer.UpdateSubConnState will be called instead. Will never be
|
||||||
|
// invoked until after Connect() is called on the SubConn created with
|
||||||
|
// these options.
|
||||||
|
StateListener func(SubConnState)
|
||||||
}
|
}
|
||||||
|
|
||||||
// State contains the balancer's state relevant to the gRPC ClientConn.
|
// State contains the balancer's state relevant to the gRPC ClientConn.
|
||||||
|
|
@ -123,7 +149,7 @@ type State struct {
|
||||||
// determine the state of the ClientConn.
|
// determine the state of the ClientConn.
|
||||||
ConnectivityState connectivity.State
|
ConnectivityState connectivity.State
|
||||||
// Picker is used to choose connections (SubConns) for RPCs.
|
// Picker is used to choose connections (SubConns) for RPCs.
|
||||||
Picker V2Picker
|
Picker Picker
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientConn represents a gRPC ClientConn.
|
// ClientConn represents a gRPC ClientConn.
|
||||||
|
|
@ -136,25 +162,31 @@ type ClientConn interface {
|
||||||
// NewSubConn is called by balancer to create a new SubConn.
|
// NewSubConn is called by balancer to create a new SubConn.
|
||||||
// It doesn't block and wait for the connections to be established.
|
// It doesn't block and wait for the connections to be established.
|
||||||
// Behaviors of the SubConn can be controlled by options.
|
// Behaviors of the SubConn can be controlled by options.
|
||||||
|
//
|
||||||
|
// Deprecated: please be aware that in a future version, SubConns will only
|
||||||
|
// support one address per SubConn.
|
||||||
NewSubConn([]resolver.Address, NewSubConnOptions) (SubConn, error)
|
NewSubConn([]resolver.Address, NewSubConnOptions) (SubConn, error)
|
||||||
// RemoveSubConn removes the SubConn from ClientConn.
|
// RemoveSubConn removes the SubConn from ClientConn.
|
||||||
// The SubConn will be shutdown.
|
// The SubConn will be shutdown.
|
||||||
|
//
|
||||||
|
// Deprecated: use SubConn.Shutdown instead.
|
||||||
RemoveSubConn(SubConn)
|
RemoveSubConn(SubConn)
|
||||||
|
// UpdateAddresses updates the addresses used in the passed in SubConn.
|
||||||
// UpdateBalancerState is called by balancer to notify gRPC that some internal
|
// gRPC checks if the currently connected address is still in the new list.
|
||||||
// state in balancer has changed.
|
// If so, the connection will be kept. Else, the connection will be
|
||||||
|
// gracefully closed, and a new connection will be created.
|
||||||
//
|
//
|
||||||
// gRPC will update the connectivity state of the ClientConn, and will call pick
|
// This may trigger a state transition for the SubConn.
|
||||||
// on the new picker to pick new SubConn.
|
|
||||||
//
|
//
|
||||||
// Deprecated: use UpdateState instead
|
// Deprecated: this method will be removed. Create new SubConns for new
|
||||||
UpdateBalancerState(s connectivity.State, p Picker)
|
// addresses instead.
|
||||||
|
UpdateAddresses(SubConn, []resolver.Address)
|
||||||
|
|
||||||
// UpdateState notifies gRPC that the balancer's internal state has
|
// UpdateState notifies gRPC that the balancer's internal state has
|
||||||
// changed.
|
// changed.
|
||||||
//
|
//
|
||||||
// gRPC will update the connectivity state of the ClientConn, and will call pick
|
// gRPC will update the connectivity state of the ClientConn, and will call
|
||||||
// on the new picker to pick new SubConns.
|
// Pick on the new Picker to pick new SubConns.
|
||||||
UpdateState(State)
|
UpdateState(State)
|
||||||
|
|
||||||
// ResolveNow is called by balancer to notify gRPC to do a name resolving.
|
// ResolveNow is called by balancer to notify gRPC to do a name resolving.
|
||||||
|
|
@ -168,21 +200,32 @@ type ClientConn interface {
|
||||||
|
|
||||||
// BuildOptions contains additional information for Build.
|
// BuildOptions contains additional information for Build.
|
||||||
type BuildOptions struct {
|
type BuildOptions struct {
|
||||||
// DialCreds is the transport credential the Balancer implementation can
|
// DialCreds is the transport credentials to use when communicating with a
|
||||||
// use to dial to a remote load balancer server. The Balancer implementations
|
// remote load balancer server. Balancer implementations which do not
|
||||||
// can ignore this if it does not need to talk to another party securely.
|
// communicate with a remote load balancer server can ignore this field.
|
||||||
DialCreds credentials.TransportCredentials
|
DialCreds credentials.TransportCredentials
|
||||||
// CredsBundle is the credentials bundle that the Balancer can use.
|
// CredsBundle is the credentials bundle to use when communicating with a
|
||||||
|
// remote load balancer server. Balancer implementations which do not
|
||||||
|
// communicate with a remote load balancer server can ignore this field.
|
||||||
CredsBundle credentials.Bundle
|
CredsBundle credentials.Bundle
|
||||||
// Dialer is the custom dialer the Balancer implementation can use to dial
|
// Dialer is the custom dialer to use when communicating with a remote load
|
||||||
// to a remote load balancer server. The Balancer implementations
|
// balancer server. Balancer implementations which do not communicate with a
|
||||||
// can ignore this if it doesn't need to talk to remote balancer.
|
// remote load balancer server can ignore this field.
|
||||||
Dialer func(context.Context, string) (net.Conn, error)
|
Dialer func(context.Context, string) (net.Conn, error)
|
||||||
// ChannelzParentID is the entity parent's channelz unique identification number.
|
// Authority is the server name to use as part of the authentication
|
||||||
ChannelzParentID int64
|
// handshake when communicating with a remote load balancer server. Balancer
|
||||||
// Target contains the parsed address info of the dial target. It is the same resolver.Target as
|
// implementations which do not communicate with a remote load balancer
|
||||||
// passed to the resolver.
|
// server can ignore this field.
|
||||||
// See the documentation for the resolver.Target type for details about what it contains.
|
Authority string
|
||||||
|
// ChannelzParentID is the parent ClientConn's channelz ID.
|
||||||
|
ChannelzParentID *channelz.Identifier
|
||||||
|
// CustomUserAgent is the custom user agent set on the parent ClientConn.
|
||||||
|
// The balancer should set the same custom user agent if it creates a
|
||||||
|
// ClientConn.
|
||||||
|
CustomUserAgent string
|
||||||
|
// Target contains the parsed address info of the dial target. It is the
|
||||||
|
// same resolver.Target as passed to the resolver. See the documentation for
|
||||||
|
// the resolver.Target type for details about what it contains.
|
||||||
Target resolver.Target
|
Target resolver.Target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,62 +269,23 @@ type DoneInfo struct {
|
||||||
// ServerLoad is the load received from server. It's usually sent as part of
|
// ServerLoad is the load received from server. It's usually sent as part of
|
||||||
// trailing metadata.
|
// trailing metadata.
|
||||||
//
|
//
|
||||||
// The only supported type now is *orca_v1.LoadReport.
|
// The only supported type now is *orca_v3.LoadReport.
|
||||||
ServerLoad interface{}
|
ServerLoad any
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrNoSubConnAvailable indicates no SubConn is available for pick().
|
// ErrNoSubConnAvailable indicates no SubConn is available for pick().
|
||||||
// gRPC will block the RPC until a new picker is available via UpdateBalancerState().
|
// gRPC will block the RPC until a new picker is available via UpdateState().
|
||||||
ErrNoSubConnAvailable = errors.New("no SubConn is available")
|
ErrNoSubConnAvailable = errors.New("no SubConn is available")
|
||||||
// ErrTransientFailure indicates all SubConns are in TransientFailure.
|
// ErrTransientFailure indicates all SubConns are in TransientFailure.
|
||||||
// WaitForReady RPCs will block, non-WaitForReady RPCs will fail.
|
// WaitForReady RPCs will block, non-WaitForReady RPCs will fail.
|
||||||
ErrTransientFailure = TransientFailureError(errors.New("all SubConns are in TransientFailure"))
|
//
|
||||||
|
// Deprecated: return an appropriate error based on the last resolution or
|
||||||
|
// connection attempt instead. The behavior is the same for any non-gRPC
|
||||||
|
// status error.
|
||||||
|
ErrTransientFailure = errors.New("all SubConns are in TransientFailure")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Picker is used by gRPC to pick a SubConn to send an RPC.
|
|
||||||
// Balancer is expected to generate a new picker from its snapshot every time its
|
|
||||||
// internal state has changed.
|
|
||||||
//
|
|
||||||
// The pickers used by gRPC can be updated by ClientConn.UpdateBalancerState().
|
|
||||||
//
|
|
||||||
// Deprecated: use V2Picker instead
|
|
||||||
type Picker interface {
|
|
||||||
// Pick returns the SubConn to be used to send the RPC.
|
|
||||||
// The returned SubConn must be one returned by NewSubConn().
|
|
||||||
//
|
|
||||||
// This functions is expected to return:
|
|
||||||
// - a SubConn that is known to be READY;
|
|
||||||
// - ErrNoSubConnAvailable if no SubConn is available, but progress is being
|
|
||||||
// made (for example, some SubConn is in CONNECTING mode);
|
|
||||||
// - other errors if no active connecting is happening (for example, all SubConn
|
|
||||||
// are in TRANSIENT_FAILURE mode).
|
|
||||||
//
|
|
||||||
// If a SubConn is returned:
|
|
||||||
// - If it is READY, gRPC will send the RPC on it;
|
|
||||||
// - If it is not ready, or becomes not ready after it's returned, gRPC will
|
|
||||||
// block until UpdateBalancerState() is called and will call pick on the
|
|
||||||
// new picker. The done function returned from Pick(), if not nil, will be
|
|
||||||
// called with nil error, no bytes sent and no bytes received.
|
|
||||||
//
|
|
||||||
// If the returned error is not nil:
|
|
||||||
// - If the error is ErrNoSubConnAvailable, gRPC will block until UpdateBalancerState()
|
|
||||||
// - If the error is ErrTransientFailure or implements IsTransientFailure()
|
|
||||||
// bool, returning true:
|
|
||||||
// - If the RPC is wait-for-ready, gRPC will block until UpdateBalancerState()
|
|
||||||
// is called to pick again;
|
|
||||||
// - Otherwise, RPC will fail with unavailable error.
|
|
||||||
// - Else (error is other non-nil error):
|
|
||||||
// - The RPC will fail with the error's status code, or Unknown if it is
|
|
||||||
// not a status error.
|
|
||||||
//
|
|
||||||
// The returned done() function will be called once the rpc has finished,
|
|
||||||
// with the final status of that RPC. If the SubConn returned is not a
|
|
||||||
// valid SubConn type, done may not be called. done may be nil if balancer
|
|
||||||
// doesn't care about the RPC status.
|
|
||||||
Pick(ctx context.Context, info PickInfo) (conn SubConn, done func(DoneInfo), err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PickResult contains information related to a connection chosen for an RPC.
|
// PickResult contains information related to a connection chosen for an RPC.
|
||||||
type PickResult struct {
|
type PickResult struct {
|
||||||
// SubConn is the connection to use for this pick, if its state is Ready.
|
// SubConn is the connection to use for this pick, if its state is Ready.
|
||||||
|
|
@ -295,26 +299,29 @@ type PickResult struct {
|
||||||
// type, Done may not be called. May be nil if the balancer does not wish
|
// type, Done may not be called. May be nil if the balancer does not wish
|
||||||
// to be notified when the RPC completes.
|
// to be notified when the RPC completes.
|
||||||
Done func(DoneInfo)
|
Done func(DoneInfo)
|
||||||
|
|
||||||
|
// Metadata provides a way for LB policies to inject arbitrary per-call
|
||||||
|
// metadata. Any metadata returned here will be merged with existing
|
||||||
|
// metadata added by the client application.
|
||||||
|
//
|
||||||
|
// LB policies with child policies are responsible for propagating metadata
|
||||||
|
// injected by their children to the ClientConn, as part of Pick().
|
||||||
|
Metadata metadata.MD
|
||||||
}
|
}
|
||||||
|
|
||||||
type transientFailureError struct {
|
// TransientFailureError returns e. It exists for backward compatibility and
|
||||||
error
|
// will be deleted soon.
|
||||||
}
|
//
|
||||||
|
// Deprecated: no longer necessary, picker errors are treated this way by
|
||||||
|
// default.
|
||||||
|
func TransientFailureError(e error) error { return e }
|
||||||
|
|
||||||
func (e *transientFailureError) IsTransientFailure() bool { return true }
|
// Picker is used by gRPC to pick a SubConn to send an RPC.
|
||||||
|
|
||||||
// TransientFailureError wraps err in an error implementing
|
|
||||||
// IsTransientFailure() bool, returning true.
|
|
||||||
func TransientFailureError(err error) error {
|
|
||||||
return &transientFailureError{error: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
// V2Picker is used by gRPC to pick a SubConn to send an RPC.
|
|
||||||
// Balancer is expected to generate a new picker from its snapshot every time its
|
// Balancer is expected to generate a new picker from its snapshot every time its
|
||||||
// internal state has changed.
|
// internal state has changed.
|
||||||
//
|
//
|
||||||
// The pickers used by gRPC can be updated by ClientConn.UpdateBalancerState().
|
// The pickers used by gRPC can be updated by ClientConn.UpdateState().
|
||||||
type V2Picker interface {
|
type Picker interface {
|
||||||
// Pick returns the connection to use for this RPC and related information.
|
// Pick returns the connection to use for this RPC and related information.
|
||||||
//
|
//
|
||||||
// Pick should not block. If the balancer needs to do I/O or any blocking
|
// Pick should not block. If the balancer needs to do I/O or any blocking
|
||||||
|
|
@ -327,14 +334,13 @@ type V2Picker interface {
|
||||||
// - If the error is ErrNoSubConnAvailable, gRPC will block until a new
|
// - If the error is ErrNoSubConnAvailable, gRPC will block until a new
|
||||||
// Picker is provided by the balancer (using ClientConn.UpdateState).
|
// Picker is provided by the balancer (using ClientConn.UpdateState).
|
||||||
//
|
//
|
||||||
// - If the error implements IsTransientFailure() bool, returning true,
|
// - If the error is a status error (implemented by the grpc/status
|
||||||
// wait for ready RPCs will wait, but non-wait for ready RPCs will be
|
// package), gRPC will terminate the RPC with the code and message
|
||||||
// terminated with this error's Error() string and status code
|
// provided.
|
||||||
// Unavailable.
|
|
||||||
//
|
//
|
||||||
// - Any other errors terminate all RPCs with the code and message
|
// - For all other errors, wait for ready RPCs will wait, but non-wait for
|
||||||
// provided. If the error is not a status error, it will be converted by
|
// ready RPCs will be terminated with this error's Error() string and
|
||||||
// gRPC to a status error with code Unknown.
|
// status code Unavailable.
|
||||||
Pick(info PickInfo) (PickResult, error)
|
Pick(info PickInfo) (PickResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,34 +349,44 @@ type V2Picker interface {
|
||||||
//
|
//
|
||||||
// It also generates and updates the Picker used by gRPC to pick SubConns for RPCs.
|
// It also generates and updates the Picker used by gRPC to pick SubConns for RPCs.
|
||||||
//
|
//
|
||||||
// HandleSubConnectionStateChange, HandleResolvedAddrs and Close are guaranteed
|
// UpdateClientConnState, ResolverError, UpdateSubConnState, and Close are
|
||||||
// to be called synchronously from the same goroutine.
|
// guaranteed to be called synchronously from the same goroutine. There's no
|
||||||
// There's no guarantee on picker.Pick, it may be called anytime.
|
// guarantee on picker.Pick, it may be called anytime.
|
||||||
type Balancer interface {
|
type Balancer interface {
|
||||||
// HandleSubConnStateChange is called by gRPC when the connectivity state
|
// UpdateClientConnState is called by gRPC when the state of the ClientConn
|
||||||
// of sc has changed.
|
// changes. If the error returned is ErrBadResolverState, the ClientConn
|
||||||
// Balancer is expected to aggregate all the state of SubConn and report
|
// will begin calling ResolveNow on the active name resolver with
|
||||||
// that back to gRPC.
|
// exponential backoff until a subsequent call to UpdateClientConnState
|
||||||
// Balancer should also generate and update Pickers when its internal state has
|
// returns a nil error. Any other errors are currently ignored.
|
||||||
// been changed by the new state.
|
UpdateClientConnState(ClientConnState) error
|
||||||
|
// ResolverError is called by gRPC when the name resolver reports an error.
|
||||||
|
ResolverError(error)
|
||||||
|
// UpdateSubConnState is called by gRPC when the state of a SubConn
|
||||||
|
// changes.
|
||||||
//
|
//
|
||||||
// Deprecated: if V2Balancer is implemented by the Balancer,
|
// Deprecated: Use NewSubConnOptions.StateListener when creating the
|
||||||
// UpdateSubConnState will be called instead.
|
// SubConn instead.
|
||||||
HandleSubConnStateChange(sc SubConn, state connectivity.State)
|
UpdateSubConnState(SubConn, SubConnState)
|
||||||
// HandleResolvedAddrs is called by gRPC to send updated resolved addresses to
|
// Close closes the balancer. The balancer is not currently required to
|
||||||
// balancers.
|
// call SubConn.Shutdown for its existing SubConns; however, this will be
|
||||||
// Balancer can create new SubConn or remove SubConn with the addresses.
|
// required in a future release, so it is recommended.
|
||||||
// An empty address slice and a non-nil error will be passed if the resolver returns
|
|
||||||
// non-nil error to gRPC.
|
|
||||||
//
|
|
||||||
// Deprecated: if V2Balancer is implemented by the Balancer,
|
|
||||||
// UpdateClientConnState will be called instead.
|
|
||||||
HandleResolvedAddrs([]resolver.Address, error)
|
|
||||||
// Close closes the balancer. The balancer is not required to call
|
|
||||||
// ClientConn.RemoveSubConn for its existing SubConns.
|
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExitIdler is an optional interface for balancers to implement. If
|
||||||
|
// implemented, ExitIdle will be called when ClientConn.Connect is called, if
|
||||||
|
// the ClientConn is idle. If unimplemented, ClientConn.Connect will cause
|
||||||
|
// all SubConns to connect.
|
||||||
|
//
|
||||||
|
// Notice: it will be required for all balancers to implement this in a future
|
||||||
|
// release.
|
||||||
|
type ExitIdler interface {
|
||||||
|
// ExitIdle instructs the LB policy to reconnect to backends / exit the
|
||||||
|
// IDLE state, if appropriate and possible. Note that SubConns that enter
|
||||||
|
// the IDLE state will not reconnect until SubConn.Connect is called.
|
||||||
|
ExitIdle()
|
||||||
|
}
|
||||||
|
|
||||||
// SubConnState describes the state of a SubConn.
|
// SubConnState describes the state of a SubConn.
|
||||||
type SubConnState struct {
|
type SubConnState struct {
|
||||||
// ConnectivityState is the connectivity state of the SubConn.
|
// ConnectivityState is the connectivity state of the SubConn.
|
||||||
|
|
@ -393,62 +409,19 @@ type ClientConnState struct {
|
||||||
// problem with the provided name resolver data.
|
// problem with the provided name resolver data.
|
||||||
var ErrBadResolverState = errors.New("bad resolver state")
|
var ErrBadResolverState = errors.New("bad resolver state")
|
||||||
|
|
||||||
// V2Balancer is defined for documentation purposes. If a Balancer also
|
// A ProducerBuilder is a simple constructor for a Producer. It is used by the
|
||||||
// implements V2Balancer, its UpdateClientConnState method will be called
|
// SubConn to create producers when needed.
|
||||||
// instead of HandleResolvedAddrs and its UpdateSubConnState will be called
|
type ProducerBuilder interface {
|
||||||
// instead of HandleSubConnStateChange.
|
// Build creates a Producer. The first parameter is always a
|
||||||
type V2Balancer interface {
|
// grpc.ClientConnInterface (a type to allow creating RPCs/streams on the
|
||||||
// UpdateClientConnState is called by gRPC when the state of the ClientConn
|
// associated SubConn), but is declared as `any` to avoid a dependency
|
||||||
// changes. If the error returned is ErrBadResolverState, the ClientConn
|
// cycle. Should also return a close function that will be called when all
|
||||||
// will begin calling ResolveNow on the active name resolver with
|
// references to the Producer have been given up.
|
||||||
// exponential backoff until a subsequent call to UpdateClientConnState
|
Build(grpcClientConnInterface any) (p Producer, close func())
|
||||||
// returns a nil error. Any other errors are currently ignored.
|
|
||||||
UpdateClientConnState(ClientConnState) error
|
|
||||||
// ResolverError is called by gRPC when the name resolver reports an error.
|
|
||||||
ResolverError(error)
|
|
||||||
// UpdateSubConnState is called by gRPC when the state of a SubConn
|
|
||||||
// changes.
|
|
||||||
UpdateSubConnState(SubConn, SubConnState)
|
|
||||||
// Close closes the balancer. The balancer is not required to call
|
|
||||||
// ClientConn.RemoveSubConn for its existing SubConns.
|
|
||||||
Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectivityStateEvaluator takes the connectivity states of multiple SubConns
|
// A Producer is a type shared among potentially many consumers. It is
|
||||||
// and returns one aggregated connectivity state.
|
// associated with a SubConn, and an implementation will typically contain
|
||||||
//
|
// other methods to provide additional functionality, e.g. configuration or
|
||||||
// It's not thread safe.
|
// subscription registration.
|
||||||
type ConnectivityStateEvaluator struct {
|
type Producer any
|
||||||
numReady uint64 // Number of addrConns in ready state.
|
|
||||||
numConnecting uint64 // Number of addrConns in connecting state.
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecordTransition records state change happening in subConn and based on that
|
|
||||||
// it evaluates what aggregated state should be.
|
|
||||||
//
|
|
||||||
// - If at least one SubConn in Ready, the aggregated state is Ready;
|
|
||||||
// - Else if at least one SubConn in Connecting, the aggregated state is Connecting;
|
|
||||||
// - Else the aggregated state is TransientFailure.
|
|
||||||
//
|
|
||||||
// Idle and Shutdown are not considered.
|
|
||||||
func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState connectivity.State) connectivity.State {
|
|
||||||
// Update counters.
|
|
||||||
for idx, state := range []connectivity.State{oldState, newState} {
|
|
||||||
updateVal := 2*uint64(idx) - 1 // -1 for oldState and +1 for new.
|
|
||||||
switch state {
|
|
||||||
case connectivity.Ready:
|
|
||||||
cse.numReady += updateVal
|
|
||||||
case connectivity.Connecting:
|
|
||||||
cse.numConnecting += updateVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate.
|
|
||||||
if cse.numReady > 0 {
|
|
||||||
return connectivity.Ready
|
|
||||||
}
|
|
||||||
if cse.numConnecting > 0 {
|
|
||||||
return connectivity.Connecting
|
|
||||||
}
|
|
||||||
return connectivity.TransientFailure
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@
|
||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
|
|
@ -28,32 +28,29 @@ import (
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var logger = grpclog.Component("balancer")
|
||||||
|
|
||||||
type baseBuilder struct {
|
type baseBuilder struct {
|
||||||
name string
|
name string
|
||||||
pickerBuilder PickerBuilder
|
pickerBuilder PickerBuilder
|
||||||
v2PickerBuilder V2PickerBuilder
|
config Config
|
||||||
config Config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
|
func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
|
||||||
bal := &baseBalancer{
|
bal := &baseBalancer{
|
||||||
cc: cc,
|
cc: cc,
|
||||||
pickerBuilder: bb.pickerBuilder,
|
pickerBuilder: bb.pickerBuilder,
|
||||||
v2PickerBuilder: bb.v2PickerBuilder,
|
|
||||||
|
|
||||||
subConns: make(map[resolver.Address]balancer.SubConn),
|
subConns: resolver.NewAddressMap(),
|
||||||
scStates: make(map[balancer.SubConn]connectivity.State),
|
scStates: make(map[balancer.SubConn]connectivity.State),
|
||||||
csEvltr: &balancer.ConnectivityStateEvaluator{},
|
csEvltr: &balancer.ConnectivityStateEvaluator{},
|
||||||
config: bb.config,
|
config: bb.config,
|
||||||
|
state: connectivity.Connecting,
|
||||||
}
|
}
|
||||||
// Initialize picker to a picker that always returns
|
// Initialize picker to a picker that always returns
|
||||||
// ErrNoSubConnAvailable, because when state of a SubConn changes, we
|
// ErrNoSubConnAvailable, because when state of a SubConn changes, we
|
||||||
// may call UpdateState with this picker.
|
// may call UpdateState with this picker.
|
||||||
if bb.pickerBuilder != nil {
|
bal.picker = NewErrPicker(balancer.ErrNoSubConnAvailable)
|
||||||
bal.picker = NewErrPicker(balancer.ErrNoSubConnAvailable)
|
|
||||||
} else {
|
|
||||||
bal.v2Picker = NewErrPickerV2(balancer.ErrNoSubConnAvailable)
|
|
||||||
}
|
|
||||||
return bal
|
return bal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,129 +58,154 @@ func (bb *baseBuilder) Name() string {
|
||||||
return bb.name
|
return bb.name
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ balancer.V2Balancer = (*baseBalancer)(nil) // Assert that we implement V2Balancer
|
|
||||||
|
|
||||||
type baseBalancer struct {
|
type baseBalancer struct {
|
||||||
cc balancer.ClientConn
|
cc balancer.ClientConn
|
||||||
pickerBuilder PickerBuilder
|
pickerBuilder PickerBuilder
|
||||||
v2PickerBuilder V2PickerBuilder
|
|
||||||
|
|
||||||
csEvltr *balancer.ConnectivityStateEvaluator
|
csEvltr *balancer.ConnectivityStateEvaluator
|
||||||
state connectivity.State
|
state connectivity.State
|
||||||
|
|
||||||
subConns map[resolver.Address]balancer.SubConn
|
subConns *resolver.AddressMap
|
||||||
scStates map[balancer.SubConn]connectivity.State
|
scStates map[balancer.SubConn]connectivity.State
|
||||||
picker balancer.Picker
|
picker balancer.Picker
|
||||||
v2Picker balancer.V2Picker
|
|
||||||
config Config
|
config Config
|
||||||
}
|
|
||||||
|
|
||||||
func (b *baseBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) {
|
resolverErr error // the last error reported by the resolver; cleared on successful resolution
|
||||||
panic("not implemented")
|
connErr error // the last connection error; cleared upon leaving TransientFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *baseBalancer) ResolverError(err error) {
|
func (b *baseBalancer) ResolverError(err error) {
|
||||||
switch b.state {
|
b.resolverErr = err
|
||||||
case connectivity.TransientFailure, connectivity.Idle, connectivity.Connecting:
|
if b.subConns.Len() == 0 {
|
||||||
if b.picker != nil {
|
b.state = connectivity.TransientFailure
|
||||||
b.picker = NewErrPicker(err)
|
|
||||||
} else {
|
|
||||||
b.v2Picker = NewErrPickerV2(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.state != connectivity.TransientFailure {
|
||||||
|
// The picker will not change since the balancer does not currently
|
||||||
|
// report an error.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.regeneratePicker()
|
||||||
|
b.cc.UpdateState(balancer.State{
|
||||||
|
ConnectivityState: b.state,
|
||||||
|
Picker: b.picker,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
|
func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
|
||||||
// TODO: handle s.ResolverState.Err (log if not nil) once implemented.
|
|
||||||
// TODO: handle s.ResolverState.ServiceConfig?
|
// TODO: handle s.ResolverState.ServiceConfig?
|
||||||
if grpclog.V(2) {
|
if logger.V(2) {
|
||||||
grpclog.Infoln("base.baseBalancer: got new ClientConn state: ", s)
|
logger.Info("base.baseBalancer: got new ClientConn state: ", s)
|
||||||
}
|
}
|
||||||
|
// Successful resolution; clear resolver error and ensure we return nil.
|
||||||
|
b.resolverErr = nil
|
||||||
// addrsSet is the set converted from addrs, it's used for quick lookup of an address.
|
// addrsSet is the set converted from addrs, it's used for quick lookup of an address.
|
||||||
addrsSet := make(map[resolver.Address]struct{})
|
addrsSet := resolver.NewAddressMap()
|
||||||
for _, a := range s.ResolverState.Addresses {
|
for _, a := range s.ResolverState.Addresses {
|
||||||
addrsSet[a] = struct{}{}
|
addrsSet.Set(a, nil)
|
||||||
if _, ok := b.subConns[a]; !ok {
|
if _, ok := b.subConns.Get(a); !ok {
|
||||||
// a is a new address (not existing in b.subConns).
|
// a is a new address (not existing in b.subConns).
|
||||||
sc, err := b.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{HealthCheckEnabled: b.config.HealthCheck})
|
var sc balancer.SubConn
|
||||||
|
opts := balancer.NewSubConnOptions{
|
||||||
|
HealthCheckEnabled: b.config.HealthCheck,
|
||||||
|
StateListener: func(scs balancer.SubConnState) { b.updateSubConnState(sc, scs) },
|
||||||
|
}
|
||||||
|
sc, err := b.cc.NewSubConn([]resolver.Address{a}, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
grpclog.Warningf("base.baseBalancer: failed to create new SubConn: %v", err)
|
logger.Warningf("base.baseBalancer: failed to create new SubConn: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.subConns[a] = sc
|
b.subConns.Set(a, sc)
|
||||||
b.scStates[sc] = connectivity.Idle
|
b.scStates[sc] = connectivity.Idle
|
||||||
|
b.csEvltr.RecordTransition(connectivity.Shutdown, connectivity.Idle)
|
||||||
sc.Connect()
|
sc.Connect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for a, sc := range b.subConns {
|
for _, a := range b.subConns.Keys() {
|
||||||
|
sci, _ := b.subConns.Get(a)
|
||||||
|
sc := sci.(balancer.SubConn)
|
||||||
// a was removed by resolver.
|
// a was removed by resolver.
|
||||||
if _, ok := addrsSet[a]; !ok {
|
if _, ok := addrsSet.Get(a); !ok {
|
||||||
b.cc.RemoveSubConn(sc)
|
sc.Shutdown()
|
||||||
delete(b.subConns, a)
|
b.subConns.Delete(a)
|
||||||
// Keep the state of this sc in b.scStates until sc's state becomes Shutdown.
|
// Keep the state of this sc in b.scStates until sc's state becomes Shutdown.
|
||||||
// The entry will be deleted in HandleSubConnStateChange.
|
// The entry will be deleted in updateSubConnState.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If resolver state contains no addresses, return an error so ClientConn
|
||||||
|
// will trigger re-resolve. Also records this as an resolver error, so when
|
||||||
|
// the overall state turns transient failure, the error message will have
|
||||||
|
// the zero address information.
|
||||||
|
if len(s.ResolverState.Addresses) == 0 {
|
||||||
|
b.ResolverError(errors.New("produced zero addresses"))
|
||||||
|
return balancer.ErrBadResolverState
|
||||||
|
}
|
||||||
|
|
||||||
|
b.regeneratePicker()
|
||||||
|
b.cc.UpdateState(balancer.State{ConnectivityState: b.state, Picker: b.picker})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mergeErrors builds an error from the last connection error and the last
|
||||||
|
// resolver error. Must only be called if b.state is TransientFailure.
|
||||||
|
func (b *baseBalancer) mergeErrors() error {
|
||||||
|
// connErr must always be non-nil unless there are no SubConns, in which
|
||||||
|
// case resolverErr must be non-nil.
|
||||||
|
if b.connErr == nil {
|
||||||
|
return fmt.Errorf("last resolver error: %v", b.resolverErr)
|
||||||
|
}
|
||||||
|
if b.resolverErr == nil {
|
||||||
|
return fmt.Errorf("last connection error: %v", b.connErr)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("last connection error: %v; last resolver error: %v", b.connErr, b.resolverErr)
|
||||||
|
}
|
||||||
|
|
||||||
// regeneratePicker takes a snapshot of the balancer, and generates a picker
|
// regeneratePicker takes a snapshot of the balancer, and generates a picker
|
||||||
// from it. The picker is
|
// from it. The picker is
|
||||||
// - errPicker with ErrTransientFailure if the balancer is in TransientFailure,
|
// - errPicker if the balancer is in TransientFailure,
|
||||||
// - built by the pickerBuilder with all READY SubConns otherwise.
|
// - built by the pickerBuilder with all READY SubConns otherwise.
|
||||||
func (b *baseBalancer) regeneratePicker(err error) {
|
func (b *baseBalancer) regeneratePicker() {
|
||||||
if b.state == connectivity.TransientFailure {
|
if b.state == connectivity.TransientFailure {
|
||||||
if b.pickerBuilder != nil {
|
b.picker = NewErrPicker(b.mergeErrors())
|
||||||
b.picker = NewErrPicker(balancer.ErrTransientFailure)
|
|
||||||
} else {
|
|
||||||
if err != nil {
|
|
||||||
b.v2Picker = NewErrPickerV2(balancer.TransientFailureError(err))
|
|
||||||
} else {
|
|
||||||
// This means the last subchannel transition was not to
|
|
||||||
// TransientFailure (otherwise err must be set), but the
|
|
||||||
// aggregate state of the balancer is TransientFailure, meaning
|
|
||||||
// there are no other addresses.
|
|
||||||
b.v2Picker = NewErrPickerV2(balancer.TransientFailureError(errors.New("resolver returned no addresses")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if b.pickerBuilder != nil {
|
readySCs := make(map[balancer.SubConn]SubConnInfo)
|
||||||
readySCs := make(map[resolver.Address]balancer.SubConn)
|
|
||||||
|
|
||||||
// Filter out all ready SCs from full subConn map.
|
// Filter out all ready SCs from full subConn map.
|
||||||
for addr, sc := range b.subConns {
|
for _, addr := range b.subConns.Keys() {
|
||||||
if st, ok := b.scStates[sc]; ok && st == connectivity.Ready {
|
sci, _ := b.subConns.Get(addr)
|
||||||
readySCs[addr] = sc
|
sc := sci.(balancer.SubConn)
|
||||||
}
|
if st, ok := b.scStates[sc]; ok && st == connectivity.Ready {
|
||||||
|
readySCs[sc] = SubConnInfo{Address: addr}
|
||||||
}
|
}
|
||||||
b.picker = b.pickerBuilder.Build(readySCs)
|
|
||||||
} else {
|
|
||||||
readySCs := make(map[balancer.SubConn]SubConnInfo)
|
|
||||||
|
|
||||||
// Filter out all ready SCs from full subConn map.
|
|
||||||
for addr, sc := range b.subConns {
|
|
||||||
if st, ok := b.scStates[sc]; ok && st == connectivity.Ready {
|
|
||||||
readySCs[sc] = SubConnInfo{Address: addr}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.v2Picker = b.v2PickerBuilder.Build(PickerBuildInfo{ReadySCs: readySCs})
|
|
||||||
}
|
}
|
||||||
|
b.picker = b.pickerBuilder.Build(PickerBuildInfo{ReadySCs: readySCs})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *baseBalancer) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) {
|
// UpdateSubConnState is a nop because a StateListener is always set in NewSubConn.
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
|
func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
|
||||||
|
logger.Errorf("base.baseBalancer: UpdateSubConnState(%v, %+v) called unexpectedly", sc, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *baseBalancer) updateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
|
||||||
s := state.ConnectivityState
|
s := state.ConnectivityState
|
||||||
if grpclog.V(2) {
|
if logger.V(2) {
|
||||||
grpclog.Infof("base.baseBalancer: handle SubConn state change: %p, %v", sc, s)
|
logger.Infof("base.baseBalancer: handle SubConn state change: %p, %v", sc, s)
|
||||||
}
|
}
|
||||||
oldS, ok := b.scStates[sc]
|
oldS, ok := b.scStates[sc]
|
||||||
if !ok {
|
if !ok {
|
||||||
if grpclog.V(2) {
|
if logger.V(2) {
|
||||||
grpclog.Infof("base.baseBalancer: got state changes for an unknown SubConn: %p, %v", sc, s)
|
logger.Infof("base.baseBalancer: got state changes for an unknown SubConn: %p, %v", sc, s)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if oldS == connectivity.TransientFailure &&
|
||||||
|
(s == connectivity.Connecting || s == connectivity.Idle) {
|
||||||
|
// Once a subconn enters TRANSIENT_FAILURE, ignore subsequent IDLE or
|
||||||
|
// CONNECTING transitions to prevent the aggregated state from being
|
||||||
|
// always CONNECTING when many backends exist but are all down.
|
||||||
|
if s == connectivity.Idle {
|
||||||
|
sc.Connect()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -192,58 +214,51 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su
|
||||||
case connectivity.Idle:
|
case connectivity.Idle:
|
||||||
sc.Connect()
|
sc.Connect()
|
||||||
case connectivity.Shutdown:
|
case connectivity.Shutdown:
|
||||||
// When an address was removed by resolver, b called RemoveSubConn but
|
// When an address was removed by resolver, b called Shutdown but kept
|
||||||
// kept the sc's state in scStates. Remove state for this sc here.
|
// the sc's state in scStates. Remove state for this sc here.
|
||||||
delete(b.scStates, sc)
|
delete(b.scStates, sc)
|
||||||
|
case connectivity.TransientFailure:
|
||||||
|
// Save error to be reported via picker.
|
||||||
|
b.connErr = state.ConnectionError
|
||||||
}
|
}
|
||||||
|
|
||||||
oldAggrState := b.state
|
|
||||||
b.state = b.csEvltr.RecordTransition(oldS, s)
|
b.state = b.csEvltr.RecordTransition(oldS, s)
|
||||||
|
|
||||||
// Regenerate picker when one of the following happens:
|
// Regenerate picker when one of the following happens:
|
||||||
// - this sc became ready from not-ready
|
// - this sc entered or left ready
|
||||||
// - this sc became not-ready from ready
|
// - the aggregated state of balancer is TransientFailure
|
||||||
// - the aggregated state of balancer became TransientFailure from non-TransientFailure
|
// (may need to update error message)
|
||||||
// - the aggregated state of balancer became non-TransientFailure from TransientFailure
|
|
||||||
if (s == connectivity.Ready) != (oldS == connectivity.Ready) ||
|
if (s == connectivity.Ready) != (oldS == connectivity.Ready) ||
|
||||||
(b.state == connectivity.TransientFailure) != (oldAggrState == connectivity.TransientFailure) {
|
b.state == connectivity.TransientFailure {
|
||||||
b.regeneratePicker(state.ConnectionError)
|
b.regeneratePicker()
|
||||||
}
|
|
||||||
|
|
||||||
if b.picker != nil {
|
|
||||||
b.cc.UpdateBalancerState(b.state, b.picker)
|
|
||||||
} else {
|
|
||||||
b.cc.UpdateState(balancer.State{ConnectivityState: b.state, Picker: b.v2Picker})
|
|
||||||
}
|
}
|
||||||
|
b.cc.UpdateState(balancer.State{ConnectivityState: b.state, Picker: b.picker})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close is a nop because base balancer doesn't have internal state to clean up,
|
// Close is a nop because base balancer doesn't have internal state to clean up,
|
||||||
// and it doesn't need to call RemoveSubConn for the SubConns.
|
// and it doesn't need to call Shutdown for the SubConns.
|
||||||
func (b *baseBalancer) Close() {
|
func (b *baseBalancer) Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewErrPicker returns a picker that always returns err on Pick().
|
// ExitIdle is a nop because the base balancer attempts to stay connected to
|
||||||
|
// all SubConns at all times.
|
||||||
|
func (b *baseBalancer) ExitIdle() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrPicker returns a Picker that always returns err on Pick().
|
||||||
func NewErrPicker(err error) balancer.Picker {
|
func NewErrPicker(err error) balancer.Picker {
|
||||||
return &errPicker{err: err}
|
return &errPicker{err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewErrPickerV2 is temporarily defined for backward compatibility reasons.
|
||||||
|
//
|
||||||
|
// Deprecated: use NewErrPicker instead.
|
||||||
|
var NewErrPickerV2 = NewErrPicker
|
||||||
|
|
||||||
type errPicker struct {
|
type errPicker struct {
|
||||||
err error // Pick() always returns this err.
|
err error // Pick() always returns this err.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *errPicker) Pick(context.Context, balancer.PickInfo) (balancer.SubConn, func(balancer.DoneInfo), error) {
|
func (p *errPicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
|
||||||
return nil, nil, p.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewErrPickerV2 returns a V2Picker that always returns err on Pick().
|
|
||||||
func NewErrPickerV2(err error) balancer.V2Picker {
|
|
||||||
return &errPickerV2{err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
type errPickerV2 struct {
|
|
||||||
err error // Pick() always returns this err.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *errPickerV2) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
|
|
||||||
return balancer.PickResult{}, p.err
|
return balancer.PickResult{}, p.err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,15 +37,8 @@ import (
|
||||||
|
|
||||||
// PickerBuilder creates balancer.Picker.
|
// PickerBuilder creates balancer.Picker.
|
||||||
type PickerBuilder interface {
|
type PickerBuilder interface {
|
||||||
// Build takes a slice of ready SubConns, and returns a picker that will be
|
|
||||||
// used by gRPC to pick a SubConn.
|
|
||||||
Build(readySCs map[resolver.Address]balancer.SubConn) balancer.Picker
|
|
||||||
}
|
|
||||||
|
|
||||||
// V2PickerBuilder creates balancer.V2Picker.
|
|
||||||
type V2PickerBuilder interface {
|
|
||||||
// Build returns a picker that will be used by gRPC to pick a SubConn.
|
// Build returns a picker that will be used by gRPC to pick a SubConn.
|
||||||
Build(info PickerBuildInfo) balancer.V2Picker
|
Build(info PickerBuildInfo) balancer.Picker
|
||||||
}
|
}
|
||||||
|
|
||||||
// PickerBuildInfo contains information needed by the picker builder to
|
// PickerBuildInfo contains information needed by the picker builder to
|
||||||
|
|
@ -62,32 +55,17 @@ type SubConnInfo struct {
|
||||||
Address resolver.Address // the address used to create this SubConn
|
Address resolver.Address // the address used to create this SubConn
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBalancerBuilder returns a balancer builder. The balancers
|
|
||||||
// built by this builder will use the picker builder to build pickers.
|
|
||||||
func NewBalancerBuilder(name string, pb PickerBuilder) balancer.Builder {
|
|
||||||
return NewBalancerBuilderWithConfig(name, pb, Config{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config contains the config info about the base balancer builder.
|
// Config contains the config info about the base balancer builder.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// HealthCheck indicates whether health checking should be enabled for this specific balancer.
|
// HealthCheck indicates whether health checking should be enabled for this specific balancer.
|
||||||
HealthCheck bool
|
HealthCheck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBalancerBuilderWithConfig returns a base balancer builder configured by the provided config.
|
// NewBalancerBuilder returns a base balancer builder configured by the provided config.
|
||||||
func NewBalancerBuilderWithConfig(name string, pb PickerBuilder, config Config) balancer.Builder {
|
func NewBalancerBuilder(name string, pb PickerBuilder, config Config) balancer.Builder {
|
||||||
return &baseBuilder{
|
return &baseBuilder{
|
||||||
name: name,
|
name: name,
|
||||||
pickerBuilder: pb,
|
pickerBuilder: pb,
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBalancerBuilderV2 returns a base balancer builder configured by the provided config.
|
|
||||||
func NewBalancerBuilderV2(name string, pb V2PickerBuilder, config Config) balancer.Builder {
|
|
||||||
return &baseBuilder{
|
|
||||||
name: name,
|
|
||||||
v2PickerBuilder: pb,
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2022 gRPC 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 balancer
|
||||||
|
|
||||||
|
import "google.golang.org/grpc/connectivity"
|
||||||
|
|
||||||
|
// ConnectivityStateEvaluator takes the connectivity states of multiple SubConns
|
||||||
|
// and returns one aggregated connectivity state.
|
||||||
|
//
|
||||||
|
// It's not thread safe.
|
||||||
|
type ConnectivityStateEvaluator struct {
|
||||||
|
numReady uint64 // Number of addrConns in ready state.
|
||||||
|
numConnecting uint64 // Number of addrConns in connecting state.
|
||||||
|
numTransientFailure uint64 // Number of addrConns in transient failure state.
|
||||||
|
numIdle uint64 // Number of addrConns in idle state.
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordTransition records state change happening in subConn and based on that
|
||||||
|
// it evaluates what aggregated state should be.
|
||||||
|
//
|
||||||
|
// - If at least one SubConn in Ready, the aggregated state is Ready;
|
||||||
|
// - Else if at least one SubConn in Connecting, the aggregated state is Connecting;
|
||||||
|
// - Else if at least one SubConn is Idle, the aggregated state is Idle;
|
||||||
|
// - Else if at least one SubConn is TransientFailure (or there are no SubConns), the aggregated state is Transient Failure.
|
||||||
|
//
|
||||||
|
// Shutdown is not considered.
|
||||||
|
func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState connectivity.State) connectivity.State {
|
||||||
|
// Update counters.
|
||||||
|
for idx, state := range []connectivity.State{oldState, newState} {
|
||||||
|
updateVal := 2*uint64(idx) - 1 // -1 for oldState and +1 for new.
|
||||||
|
switch state {
|
||||||
|
case connectivity.Ready:
|
||||||
|
cse.numReady += updateVal
|
||||||
|
case connectivity.Connecting:
|
||||||
|
cse.numConnecting += updateVal
|
||||||
|
case connectivity.TransientFailure:
|
||||||
|
cse.numTransientFailure += updateVal
|
||||||
|
case connectivity.Idle:
|
||||||
|
cse.numIdle += updateVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cse.CurrentState()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentState returns the current aggregate conn state by evaluating the counters
|
||||||
|
func (cse *ConnectivityStateEvaluator) CurrentState() connectivity.State {
|
||||||
|
// Evaluate.
|
||||||
|
if cse.numReady > 0 {
|
||||||
|
return connectivity.Ready
|
||||||
|
}
|
||||||
|
if cse.numConnecting > 0 {
|
||||||
|
return connectivity.Connecting
|
||||||
|
}
|
||||||
|
if cse.numIdle > 0 {
|
||||||
|
return connectivity.Idle
|
||||||
|
}
|
||||||
|
return connectivity.TransientFailure
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2020 gRPC 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 state declares grpclb types to be set by resolvers wishing to pass
|
||||||
|
// information to grpclb via resolver.State Attributes.
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"google.golang.org/grpc/resolver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// keyType is the key to use for storing State in Attributes.
|
||||||
|
type keyType string
|
||||||
|
|
||||||
|
const key = keyType("grpc.grpclb.state")
|
||||||
|
|
||||||
|
// State contains gRPCLB-relevant data passed from the name resolver.
|
||||||
|
type State struct {
|
||||||
|
// BalancerAddresses contains the remote load balancer address(es). If
|
||||||
|
// set, overrides any resolver-provided addresses with Type of GRPCLB.
|
||||||
|
BalancerAddresses []resolver.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set returns a copy of the provided state with attributes containing s. s's
|
||||||
|
// data should not be mutated after calling Set.
|
||||||
|
func Set(state resolver.State, s *State) resolver.State {
|
||||||
|
state.Attributes = state.Attributes.WithValue(key, s)
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the grpclb State in the resolver.State, or nil if not present.
|
||||||
|
// The returned data should not be mutated.
|
||||||
|
func Get(state resolver.State) *State {
|
||||||
|
s, _ := state.Attributes.Value(key).(*State)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
package roundrobin
|
package roundrobin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync/atomic"
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
"google.golang.org/grpc/balancer/base"
|
"google.golang.org/grpc/balancer/base"
|
||||||
|
|
@ -33,9 +33,11 @@ import (
|
||||||
// Name is the name of round_robin balancer.
|
// Name is the name of round_robin balancer.
|
||||||
const Name = "round_robin"
|
const Name = "round_robin"
|
||||||
|
|
||||||
|
var logger = grpclog.Component("roundrobin")
|
||||||
|
|
||||||
// newBuilder creates a new roundrobin balancer builder.
|
// newBuilder creates a new roundrobin balancer builder.
|
||||||
func newBuilder() balancer.Builder {
|
func newBuilder() balancer.Builder {
|
||||||
return base.NewBalancerBuilderV2(Name, &rrPickerBuilder{}, base.Config{HealthCheck: true})
|
return base.NewBalancerBuilder(Name, &rrPickerBuilder{}, base.Config{HealthCheck: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -44,12 +46,12 @@ func init() {
|
||||||
|
|
||||||
type rrPickerBuilder struct{}
|
type rrPickerBuilder struct{}
|
||||||
|
|
||||||
func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.V2Picker {
|
func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker {
|
||||||
grpclog.Infof("roundrobinPicker: newPicker called with info: %v", info)
|
logger.Infof("roundrobinPicker: Build called with info: %v", info)
|
||||||
if len(info.ReadySCs) == 0 {
|
if len(info.ReadySCs) == 0 {
|
||||||
return base.NewErrPickerV2(balancer.ErrNoSubConnAvailable)
|
return base.NewErrPicker(balancer.ErrNoSubConnAvailable)
|
||||||
}
|
}
|
||||||
var scs []balancer.SubConn
|
scs := make([]balancer.SubConn, 0, len(info.ReadySCs))
|
||||||
for sc := range info.ReadySCs {
|
for sc := range info.ReadySCs {
|
||||||
scs = append(scs, sc)
|
scs = append(scs, sc)
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +60,7 @@ func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.V2Picker {
|
||||||
// Start at a random index, as the same RR balancer rebuilds a new
|
// Start at a random index, as the same RR balancer rebuilds a new
|
||||||
// picker when SubConn states change, and we don't want to apply excess
|
// picker when SubConn states change, and we don't want to apply excess
|
||||||
// load to the first server in the list.
|
// load to the first server in the list.
|
||||||
next: grpcrand.Intn(len(scs)),
|
next: uint32(grpcrand.Intn(len(scs))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,15 +69,13 @@ type rrPicker struct {
|
||||||
// created. The slice is immutable. Each Get() will do a round robin
|
// created. The slice is immutable. Each Get() will do a round robin
|
||||||
// selection from it and return the selected SubConn.
|
// selection from it and return the selected SubConn.
|
||||||
subConns []balancer.SubConn
|
subConns []balancer.SubConn
|
||||||
|
next uint32
|
||||||
mu sync.Mutex
|
|
||||||
next int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *rrPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
|
func (p *rrPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
|
||||||
p.mu.Lock()
|
subConnsLen := uint32(len(p.subConns))
|
||||||
sc := p.subConns[p.next]
|
nextIndex := atomic.AddUint32(&p.next, 1)
|
||||||
p.next = (p.next + 1) % len(p.subConns)
|
|
||||||
p.mu.Unlock()
|
sc := p.subConns[nextIndex%subConnsLen]
|
||||||
return balancer.PickResult{SubConn: sc}, nil
|
return balancer.PickResult{SubConn: sc}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,191 +19,333 @@
|
||||||
package grpc
|
package grpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/grpclog"
|
"google.golang.org/grpc/internal/balancer/gracefulswitch"
|
||||||
"google.golang.org/grpc/internal/buffer"
|
"google.golang.org/grpc/internal/channelz"
|
||||||
"google.golang.org/grpc/internal/grpcsync"
|
"google.golang.org/grpc/internal/grpcsync"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// scStateUpdate contains the subConn and the new state it changed to.
|
type ccbMode int
|
||||||
type scStateUpdate struct {
|
|
||||||
sc balancer.SubConn
|
|
||||||
state connectivity.State
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ccBalancerWrapper is a wrapper on top of cc for balancers.
|
const (
|
||||||
// It implements balancer.ClientConn interface.
|
ccbModeActive = iota
|
||||||
|
ccbModeIdle
|
||||||
|
ccbModeClosed
|
||||||
|
ccbModeExitingIdle
|
||||||
|
)
|
||||||
|
|
||||||
|
// ccBalancerWrapper sits between the ClientConn and the Balancer.
|
||||||
|
//
|
||||||
|
// ccBalancerWrapper implements methods corresponding to the ones on the
|
||||||
|
// balancer.Balancer interface. The ClientConn is free to call these methods
|
||||||
|
// concurrently and the ccBalancerWrapper ensures that calls from the ClientConn
|
||||||
|
// to the Balancer happen synchronously and in order.
|
||||||
|
//
|
||||||
|
// ccBalancerWrapper also implements the balancer.ClientConn interface and is
|
||||||
|
// passed to the Balancer implementations. It invokes unexported methods on the
|
||||||
|
// ClientConn to handle these calls from the Balancer.
|
||||||
|
//
|
||||||
|
// It uses the gracefulswitch.Balancer internally to ensure that balancer
|
||||||
|
// switches happen in a graceful manner.
|
||||||
type ccBalancerWrapper struct {
|
type ccBalancerWrapper struct {
|
||||||
cc *ClientConn
|
// The following fields are initialized when the wrapper is created and are
|
||||||
balancerMu sync.Mutex // synchronizes calls to the balancer
|
// read-only afterwards, and therefore can be accessed without a mutex.
|
||||||
balancer balancer.Balancer
|
cc *ClientConn
|
||||||
scBuffer *buffer.Unbounded
|
opts balancer.BuildOptions
|
||||||
done *grpcsync.Event
|
|
||||||
|
|
||||||
mu sync.Mutex
|
// Outgoing (gRPC --> balancer) calls are guaranteed to execute in a
|
||||||
subConns map[*acBalancerWrapper]struct{}
|
// mutually exclusive manner as they are scheduled in the serializer. Fields
|
||||||
|
// accessed *only* in these serializer callbacks, can therefore be accessed
|
||||||
|
// without a mutex.
|
||||||
|
balancer *gracefulswitch.Balancer
|
||||||
|
curBalancerName string
|
||||||
|
|
||||||
|
// mu guards access to the below fields. Access to the serializer and its
|
||||||
|
// cancel function needs to be mutex protected because they are overwritten
|
||||||
|
// when the wrapper exits idle mode.
|
||||||
|
mu sync.Mutex
|
||||||
|
serializer *grpcsync.CallbackSerializer // To serialize all outoing calls.
|
||||||
|
serializerCancel context.CancelFunc // To close the seralizer at close/enterIdle time.
|
||||||
|
mode ccbMode // Tracks the current mode of the wrapper.
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCCBalancerWrapper(cc *ClientConn, b balancer.Builder, bopts balancer.BuildOptions) *ccBalancerWrapper {
|
// newCCBalancerWrapper creates a new balancer wrapper. The underlying balancer
|
||||||
|
// is not created until the switchTo() method is invoked.
|
||||||
|
func newCCBalancerWrapper(cc *ClientConn, bopts balancer.BuildOptions) *ccBalancerWrapper {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
ccb := &ccBalancerWrapper{
|
ccb := &ccBalancerWrapper{
|
||||||
cc: cc,
|
cc: cc,
|
||||||
scBuffer: buffer.NewUnbounded(),
|
opts: bopts,
|
||||||
done: grpcsync.NewEvent(),
|
serializer: grpcsync.NewCallbackSerializer(ctx),
|
||||||
subConns: make(map[*acBalancerWrapper]struct{}),
|
serializerCancel: cancel,
|
||||||
}
|
}
|
||||||
go ccb.watcher()
|
ccb.balancer = gracefulswitch.NewBalancer(ccb, bopts)
|
||||||
ccb.balancer = b.Build(ccb, bopts)
|
|
||||||
return ccb
|
return ccb
|
||||||
}
|
}
|
||||||
|
|
||||||
// watcher balancer functions sequentially, so the balancer can be implemented
|
// updateClientConnState is invoked by grpc to push a ClientConnState update to
|
||||||
// lock-free.
|
// the underlying balancer.
|
||||||
func (ccb *ccBalancerWrapper) watcher() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case t := <-ccb.scBuffer.Get():
|
|
||||||
ccb.scBuffer.Load()
|
|
||||||
if ccb.done.HasFired() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ccb.balancerMu.Lock()
|
|
||||||
su := t.(*scStateUpdate)
|
|
||||||
if ub, ok := ccb.balancer.(balancer.V2Balancer); ok {
|
|
||||||
ub.UpdateSubConnState(su.sc, balancer.SubConnState{ConnectivityState: su.state, ConnectionError: su.err})
|
|
||||||
} else {
|
|
||||||
ccb.balancer.HandleSubConnStateChange(su.sc, su.state)
|
|
||||||
}
|
|
||||||
ccb.balancerMu.Unlock()
|
|
||||||
case <-ccb.done.Done():
|
|
||||||
}
|
|
||||||
|
|
||||||
if ccb.done.HasFired() {
|
|
||||||
ccb.balancer.Close()
|
|
||||||
ccb.mu.Lock()
|
|
||||||
scs := ccb.subConns
|
|
||||||
ccb.subConns = nil
|
|
||||||
ccb.mu.Unlock()
|
|
||||||
for acbw := range scs {
|
|
||||||
ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain)
|
|
||||||
}
|
|
||||||
ccb.UpdateState(balancer.State{ConnectivityState: connectivity.Connecting, Picker: nil})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) close() {
|
|
||||||
ccb.done.Fire()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) handleSubConnStateChange(sc balancer.SubConn, s connectivity.State, err error) {
|
|
||||||
// When updating addresses for a SubConn, if the address in use is not in
|
|
||||||
// the new addresses, the old ac will be tearDown() and a new ac will be
|
|
||||||
// created. tearDown() generates a state change with Shutdown state, we
|
|
||||||
// don't want the balancer to receive this state change. So before
|
|
||||||
// tearDown() on the old ac, ac.acbw (acWrapper) will be set to nil, and
|
|
||||||
// this function will be called with (nil, Shutdown). We don't need to call
|
|
||||||
// balancer method in this case.
|
|
||||||
if sc == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ccb.scBuffer.Put(&scStateUpdate{
|
|
||||||
sc: sc,
|
|
||||||
state: s,
|
|
||||||
err: err,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error {
|
func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error {
|
||||||
ccb.balancerMu.Lock()
|
ccb.mu.Lock()
|
||||||
defer ccb.balancerMu.Unlock()
|
errCh := make(chan error, 1)
|
||||||
if ub, ok := ccb.balancer.(balancer.V2Balancer); ok {
|
// Here and everywhere else where Schedule() is called, it is done with the
|
||||||
return ub.UpdateClientConnState(*ccs)
|
// lock held. But the lock guards only the scheduling part. The actual
|
||||||
|
// callback is called asynchronously without the lock being held.
|
||||||
|
ok := ccb.serializer.Schedule(func(_ context.Context) {
|
||||||
|
errCh <- ccb.balancer.UpdateClientConnState(*ccs)
|
||||||
|
})
|
||||||
|
if !ok {
|
||||||
|
// If we are unable to schedule a function with the serializer, it
|
||||||
|
// indicates that it has been closed. A serializer is only closed when
|
||||||
|
// the wrapper is closed or is in idle.
|
||||||
|
ccb.mu.Unlock()
|
||||||
|
return fmt.Errorf("grpc: cannot send state update to a closed or idle balancer")
|
||||||
}
|
}
|
||||||
ccb.balancer.HandleResolvedAddrs(ccs.ResolverState.Addresses, nil)
|
ccb.mu.Unlock()
|
||||||
return nil
|
|
||||||
|
// We get here only if the above call to Schedule succeeds, in which case it
|
||||||
|
// is guaranteed that the scheduled function will run. Therefore it is safe
|
||||||
|
// to block on this channel.
|
||||||
|
err := <-errCh
|
||||||
|
if logger.V(2) && err != nil {
|
||||||
|
logger.Infof("error from balancer.UpdateClientConnState: %v", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateSubConnState is invoked by grpc to push a subConn state update to the
|
||||||
|
// underlying balancer.
|
||||||
|
func (ccb *ccBalancerWrapper) updateSubConnState(sc balancer.SubConn, s connectivity.State, err error) {
|
||||||
|
ccb.mu.Lock()
|
||||||
|
ccb.serializer.Schedule(func(_ context.Context) {
|
||||||
|
// Even though it is optional for balancers, gracefulswitch ensures
|
||||||
|
// opts.StateListener is set, so this cannot ever be nil.
|
||||||
|
sc.(*acBalancerWrapper).stateListener(balancer.SubConnState{ConnectivityState: s, ConnectionError: err})
|
||||||
|
})
|
||||||
|
ccb.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) resolverError(err error) {
|
func (ccb *ccBalancerWrapper) resolverError(err error) {
|
||||||
if ub, ok := ccb.balancer.(balancer.V2Balancer); ok {
|
ccb.mu.Lock()
|
||||||
ccb.balancerMu.Lock()
|
ccb.serializer.Schedule(func(_ context.Context) {
|
||||||
ub.ResolverError(err)
|
ccb.balancer.ResolverError(err)
|
||||||
ccb.balancerMu.Unlock()
|
})
|
||||||
|
ccb.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// switchTo is invoked by grpc to instruct the balancer wrapper to switch to the
|
||||||
|
// LB policy identified by name.
|
||||||
|
//
|
||||||
|
// ClientConn calls newCCBalancerWrapper() at creation time. Upon receipt of the
|
||||||
|
// first good update from the name resolver, it determines the LB policy to use
|
||||||
|
// and invokes the switchTo() method. Upon receipt of every subsequent update
|
||||||
|
// from the name resolver, it invokes this method.
|
||||||
|
//
|
||||||
|
// the ccBalancerWrapper keeps track of the current LB policy name, and skips
|
||||||
|
// the graceful balancer switching process if the name does not change.
|
||||||
|
func (ccb *ccBalancerWrapper) switchTo(name string) {
|
||||||
|
ccb.mu.Lock()
|
||||||
|
ccb.serializer.Schedule(func(_ context.Context) {
|
||||||
|
// TODO: Other languages use case-sensitive balancer registries. We should
|
||||||
|
// switch as well. See: https://github.com/grpc/grpc-go/issues/5288.
|
||||||
|
if strings.EqualFold(ccb.curBalancerName, name) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ccb.buildLoadBalancingPolicy(name)
|
||||||
|
})
|
||||||
|
ccb.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildLoadBalancingPolicy performs the following:
|
||||||
|
// - retrieve a balancer builder for the given name. Use the default LB
|
||||||
|
// policy, pick_first, if no LB policy with name is found in the registry.
|
||||||
|
// - instruct the gracefulswitch balancer to switch to the above builder. This
|
||||||
|
// will actually build the new balancer.
|
||||||
|
// - update the `curBalancerName` field
|
||||||
|
//
|
||||||
|
// Must be called from a serializer callback.
|
||||||
|
func (ccb *ccBalancerWrapper) buildLoadBalancingPolicy(name string) {
|
||||||
|
builder := balancer.Get(name)
|
||||||
|
if builder == nil {
|
||||||
|
channelz.Warningf(logger, ccb.cc.channelzID, "Channel switches to new LB policy %q, since the specified LB policy %q was not registered", PickFirstBalancerName, name)
|
||||||
|
builder = newPickfirstBuilder()
|
||||||
|
} else {
|
||||||
|
channelz.Infof(logger, ccb.cc.channelzID, "Channel switches to new LB policy %q", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := ccb.balancer.SwitchTo(builder); err != nil {
|
||||||
|
channelz.Errorf(logger, ccb.cc.channelzID, "Channel failed to build new LB policy %q: %v", name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ccb.curBalancerName = builder.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccb *ccBalancerWrapper) close() {
|
||||||
|
channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: closing")
|
||||||
|
ccb.closeBalancer(ccbModeClosed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// enterIdleMode is invoked by grpc when the channel enters idle mode upon
|
||||||
|
// expiry of idle_timeout. This call blocks until the balancer is closed.
|
||||||
|
func (ccb *ccBalancerWrapper) enterIdleMode() {
|
||||||
|
channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: entering idle mode")
|
||||||
|
ccb.closeBalancer(ccbModeIdle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// closeBalancer is invoked when the channel is being closed or when it enters
|
||||||
|
// idle mode upon expiry of idle_timeout.
|
||||||
|
func (ccb *ccBalancerWrapper) closeBalancer(m ccbMode) {
|
||||||
|
ccb.mu.Lock()
|
||||||
|
if ccb.mode == ccbModeClosed || ccb.mode == ccbModeIdle {
|
||||||
|
ccb.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ccb.mode = m
|
||||||
|
done := ccb.serializer.Done()
|
||||||
|
b := ccb.balancer
|
||||||
|
ok := ccb.serializer.Schedule(func(_ context.Context) {
|
||||||
|
// Close the serializer to ensure that no more calls from gRPC are sent
|
||||||
|
// to the balancer.
|
||||||
|
ccb.serializerCancel()
|
||||||
|
// Empty the current balancer name because we don't have a balancer
|
||||||
|
// anymore and also so that we act on the next call to switchTo by
|
||||||
|
// creating a new balancer specified by the new resolver.
|
||||||
|
ccb.curBalancerName = ""
|
||||||
|
})
|
||||||
|
if !ok {
|
||||||
|
ccb.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ccb.mu.Unlock()
|
||||||
|
|
||||||
|
// Give enqueued callbacks a chance to finish before closing the balancer.
|
||||||
|
<-done
|
||||||
|
b.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// exitIdleMode is invoked by grpc when the channel exits idle mode either
|
||||||
|
// because of an RPC or because of an invocation of the Connect() API. This
|
||||||
|
// recreates the balancer that was closed previously when entering idle mode.
|
||||||
|
//
|
||||||
|
// If the channel is not in idle mode, we know for a fact that we are here as a
|
||||||
|
// result of the user calling the Connect() method on the ClientConn. In this
|
||||||
|
// case, we can simply forward the call to the underlying balancer, instructing
|
||||||
|
// it to reconnect to the backends.
|
||||||
|
func (ccb *ccBalancerWrapper) exitIdleMode() {
|
||||||
|
ccb.mu.Lock()
|
||||||
|
if ccb.mode == ccbModeClosed {
|
||||||
|
// Request to exit idle is a no-op when wrapper is already closed.
|
||||||
|
ccb.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ccb.mode == ccbModeIdle {
|
||||||
|
// Recreate the serializer which was closed when we entered idle.
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
ccb.serializer = grpcsync.NewCallbackSerializer(ctx)
|
||||||
|
ccb.serializerCancel = cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ClientConn guarantees that mutual exclusion between close() and
|
||||||
|
// exitIdleMode(), and since we just created a new serializer, we can be
|
||||||
|
// sure that the below function will be scheduled.
|
||||||
|
done := make(chan struct{})
|
||||||
|
ccb.serializer.Schedule(func(_ context.Context) {
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
|
ccb.mu.Lock()
|
||||||
|
defer ccb.mu.Unlock()
|
||||||
|
|
||||||
|
if ccb.mode != ccbModeIdle {
|
||||||
|
ccb.balancer.ExitIdle()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gracefulswitch balancer does not support a switchTo operation after
|
||||||
|
// being closed. Hence we need to create a new one here.
|
||||||
|
ccb.balancer = gracefulswitch.NewBalancer(ccb, ccb.opts)
|
||||||
|
ccb.mode = ccbModeActive
|
||||||
|
channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: exiting idle mode")
|
||||||
|
|
||||||
|
})
|
||||||
|
ccb.mu.Unlock()
|
||||||
|
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccb *ccBalancerWrapper) isIdleOrClosed() bool {
|
||||||
|
ccb.mu.Lock()
|
||||||
|
defer ccb.mu.Unlock()
|
||||||
|
return ccb.mode == ccbModeIdle || ccb.mode == ccbModeClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) {
|
func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) {
|
||||||
if len(addrs) <= 0 {
|
if ccb.isIdleOrClosed() {
|
||||||
return nil, fmt.Errorf("grpc: cannot create SubConn with empty address list")
|
return nil, fmt.Errorf("grpc: cannot create SubConn when balancer is closed or idle")
|
||||||
}
|
}
|
||||||
ccb.mu.Lock()
|
|
||||||
defer ccb.mu.Unlock()
|
if len(addrs) == 0 {
|
||||||
if ccb.subConns == nil {
|
return nil, fmt.Errorf("grpc: cannot create SubConn with empty address list")
|
||||||
return nil, fmt.Errorf("grpc: ClientConn balancer wrapper was closed")
|
|
||||||
}
|
}
|
||||||
ac, err := ccb.cc.newAddrConn(addrs, opts)
|
ac, err := ccb.cc.newAddrConn(addrs, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
channelz.Warningf(logger, ccb.cc.channelzID, "acBalancerWrapper: NewSubConn: failed to newAddrConn: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
acbw := &acBalancerWrapper{ac: ac}
|
acbw := &acBalancerWrapper{
|
||||||
acbw.ac.mu.Lock()
|
ccb: ccb,
|
||||||
|
ac: ac,
|
||||||
|
producers: make(map[balancer.ProducerBuilder]*refCountedProducer),
|
||||||
|
stateListener: opts.StateListener,
|
||||||
|
}
|
||||||
ac.acbw = acbw
|
ac.acbw = acbw
|
||||||
acbw.ac.mu.Unlock()
|
|
||||||
ccb.subConns[acbw] = struct{}{}
|
|
||||||
return acbw, nil
|
return acbw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) RemoveSubConn(sc balancer.SubConn) {
|
func (ccb *ccBalancerWrapper) RemoveSubConn(sc balancer.SubConn) {
|
||||||
|
// The graceful switch balancer will never call this.
|
||||||
|
logger.Errorf("ccb RemoveSubConn(%v) called unexpectedly, sc")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccb *ccBalancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resolver.Address) {
|
||||||
|
if ccb.isIdleOrClosed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
acbw, ok := sc.(*acBalancerWrapper)
|
acbw, ok := sc.(*acBalancerWrapper)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ccb.mu.Lock()
|
acbw.UpdateAddresses(addrs)
|
||||||
defer ccb.mu.Unlock()
|
|
||||||
if ccb.subConns == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
delete(ccb.subConns, acbw)
|
|
||||||
ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) UpdateBalancerState(s connectivity.State, p balancer.Picker) {
|
|
||||||
ccb.mu.Lock()
|
|
||||||
defer ccb.mu.Unlock()
|
|
||||||
if ccb.subConns == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Update picker before updating state. Even though the ordering here does
|
|
||||||
// not matter, it can lead to multiple calls of Pick in the common start-up
|
|
||||||
// case where we wait for ready and then perform an RPC. If the picker is
|
|
||||||
// updated later, we could call the "connecting" picker when the state is
|
|
||||||
// updated, and then call the "ready" picker after the picker gets updated.
|
|
||||||
ccb.cc.blockingpicker.updatePicker(p)
|
|
||||||
ccb.cc.csMgr.updateState(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) UpdateState(s balancer.State) {
|
func (ccb *ccBalancerWrapper) UpdateState(s balancer.State) {
|
||||||
ccb.mu.Lock()
|
if ccb.isIdleOrClosed() {
|
||||||
defer ccb.mu.Unlock()
|
|
||||||
if ccb.subConns == nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update picker before updating state. Even though the ordering here does
|
// Update picker before updating state. Even though the ordering here does
|
||||||
// not matter, it can lead to multiple calls of Pick in the common start-up
|
// not matter, it can lead to multiple calls of Pick in the common start-up
|
||||||
// case where we wait for ready and then perform an RPC. If the picker is
|
// case where we wait for ready and then perform an RPC. If the picker is
|
||||||
// updated later, we could call the "connecting" picker when the state is
|
// updated later, we could call the "connecting" picker when the state is
|
||||||
// updated, and then call the "ready" picker after the picker gets updated.
|
// updated, and then call the "ready" picker after the picker gets updated.
|
||||||
ccb.cc.blockingpicker.updatePickerV2(s.Picker)
|
ccb.cc.blockingpicker.updatePicker(s.Picker)
|
||||||
ccb.cc.csMgr.updateState(s.ConnectivityState)
|
ccb.cc.csMgr.updateState(s.ConnectivityState)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ccb *ccBalancerWrapper) ResolveNow(o resolver.ResolveNowOptions) {
|
func (ccb *ccBalancerWrapper) ResolveNow(o resolver.ResolveNowOptions) {
|
||||||
|
if ccb.isIdleOrClosed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ccb.cc.resolveNow(o)
|
ccb.cc.resolveNow(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,58 +356,99 @@ func (ccb *ccBalancerWrapper) Target() string {
|
||||||
// acBalancerWrapper is a wrapper on top of ac for balancers.
|
// acBalancerWrapper is a wrapper on top of ac for balancers.
|
||||||
// It implements balancer.SubConn interface.
|
// It implements balancer.SubConn interface.
|
||||||
type acBalancerWrapper struct {
|
type acBalancerWrapper struct {
|
||||||
mu sync.Mutex
|
ac *addrConn // read-only
|
||||||
ac *addrConn
|
ccb *ccBalancerWrapper // read-only
|
||||||
|
stateListener func(balancer.SubConnState)
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
producers map[balancer.ProducerBuilder]*refCountedProducer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (acbw *acBalancerWrapper) String() string {
|
||||||
|
return fmt.Sprintf("SubConn(id:%d)", acbw.ac.channelzID.Int())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) {
|
func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) {
|
||||||
acbw.mu.Lock()
|
acbw.ac.updateAddrs(addrs)
|
||||||
defer acbw.mu.Unlock()
|
|
||||||
if len(addrs) <= 0 {
|
|
||||||
acbw.ac.tearDown(errConnDrain)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !acbw.ac.tryUpdateAddrs(addrs) {
|
|
||||||
cc := acbw.ac.cc
|
|
||||||
opts := acbw.ac.scopts
|
|
||||||
acbw.ac.mu.Lock()
|
|
||||||
// Set old ac.acbw to nil so the Shutdown state update will be ignored
|
|
||||||
// by balancer.
|
|
||||||
//
|
|
||||||
// TODO(bar) the state transition could be wrong when tearDown() old ac
|
|
||||||
// and creating new ac, fix the transition.
|
|
||||||
acbw.ac.acbw = nil
|
|
||||||
acbw.ac.mu.Unlock()
|
|
||||||
acState := acbw.ac.getState()
|
|
||||||
acbw.ac.tearDown(errConnDrain)
|
|
||||||
|
|
||||||
if acState == connectivity.Shutdown {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ac, err := cc.newAddrConn(addrs, opts)
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Warningf("acBalancerWrapper: UpdateAddresses: failed to newAddrConn: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
acbw.ac = ac
|
|
||||||
ac.mu.Lock()
|
|
||||||
ac.acbw = acbw
|
|
||||||
ac.mu.Unlock()
|
|
||||||
if acState != connectivity.Idle {
|
|
||||||
ac.connect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acbw *acBalancerWrapper) Connect() {
|
func (acbw *acBalancerWrapper) Connect() {
|
||||||
acbw.mu.Lock()
|
go acbw.ac.connect()
|
||||||
defer acbw.mu.Unlock()
|
|
||||||
acbw.ac.connect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acbw *acBalancerWrapper) getAddrConn() *addrConn {
|
func (acbw *acBalancerWrapper) Shutdown() {
|
||||||
|
ccb := acbw.ccb
|
||||||
|
if ccb.isIdleOrClosed() {
|
||||||
|
// It it safe to ignore this call when the balancer is closed or in idle
|
||||||
|
// because the ClientConn takes care of closing the connections.
|
||||||
|
//
|
||||||
|
// Not returning early from here when the balancer is closed or in idle
|
||||||
|
// leads to a deadlock though, because of the following sequence of
|
||||||
|
// calls when holding cc.mu:
|
||||||
|
// cc.exitIdleMode --> ccb.enterIdleMode --> gsw.Close -->
|
||||||
|
// ccb.RemoveAddrConn --> cc.removeAddrConn
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ccb.cc.removeAddrConn(acbw.ac, errConnDrain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStream begins a streaming RPC on the addrConn. If the addrConn is not
|
||||||
|
// ready, blocks until it is or ctx expires. Returns an error when the context
|
||||||
|
// expires or the addrConn is shut down.
|
||||||
|
func (acbw *acBalancerWrapper) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) {
|
||||||
|
transport, err := acbw.ac.getTransport(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newNonRetryClientStream(ctx, desc, method, transport, acbw.ac, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke performs a unary RPC. If the addrConn is not ready, returns
|
||||||
|
// errSubConnNotReady.
|
||||||
|
func (acbw *acBalancerWrapper) Invoke(ctx context.Context, method string, args any, reply any, opts ...CallOption) error {
|
||||||
|
cs, err := acbw.NewStream(ctx, unaryStreamDesc, method, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := cs.SendMsg(args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cs.RecvMsg(reply)
|
||||||
|
}
|
||||||
|
|
||||||
|
type refCountedProducer struct {
|
||||||
|
producer balancer.Producer
|
||||||
|
refs int // number of current refs to the producer
|
||||||
|
close func() // underlying producer's close function
|
||||||
|
}
|
||||||
|
|
||||||
|
func (acbw *acBalancerWrapper) GetOrBuildProducer(pb balancer.ProducerBuilder) (balancer.Producer, func()) {
|
||||||
acbw.mu.Lock()
|
acbw.mu.Lock()
|
||||||
defer acbw.mu.Unlock()
|
defer acbw.mu.Unlock()
|
||||||
return acbw.ac
|
|
||||||
|
// Look up existing producer from this builder.
|
||||||
|
pData := acbw.producers[pb]
|
||||||
|
if pData == nil {
|
||||||
|
// Not found; create a new one and add it to the producers map.
|
||||||
|
p, close := pb.Build(acbw)
|
||||||
|
pData = &refCountedProducer{producer: p, close: close}
|
||||||
|
acbw.producers[pb] = pData
|
||||||
|
}
|
||||||
|
// Account for this new reference.
|
||||||
|
pData.refs++
|
||||||
|
|
||||||
|
// Return a cleanup function wrapped in a OnceFunc to remove this reference
|
||||||
|
// and delete the refCountedProducer from the map if the total reference
|
||||||
|
// count goes to zero.
|
||||||
|
unref := func() {
|
||||||
|
acbw.mu.Lock()
|
||||||
|
pData.refs--
|
||||||
|
if pData.refs == 0 {
|
||||||
|
defer pData.close() // Run outside the acbw mutex
|
||||||
|
delete(acbw.producers, pb)
|
||||||
|
}
|
||||||
|
acbw.mu.Unlock()
|
||||||
|
}
|
||||||
|
return pData.producer, grpcsync.OnceFunc(unref)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,334 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2017 gRPC 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 grpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
|
||||||
"google.golang.org/grpc/connectivity"
|
|
||||||
"google.golang.org/grpc/grpclog"
|
|
||||||
"google.golang.org/grpc/resolver"
|
|
||||||
)
|
|
||||||
|
|
||||||
type balancerWrapperBuilder struct {
|
|
||||||
b Balancer // The v1 balancer.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bwb *balancerWrapperBuilder) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer {
|
|
||||||
bwb.b.Start(opts.Target.Endpoint, BalancerConfig{
|
|
||||||
DialCreds: opts.DialCreds,
|
|
||||||
Dialer: opts.Dialer,
|
|
||||||
})
|
|
||||||
_, pickfirst := bwb.b.(*pickFirst)
|
|
||||||
bw := &balancerWrapper{
|
|
||||||
balancer: bwb.b,
|
|
||||||
pickfirst: pickfirst,
|
|
||||||
cc: cc,
|
|
||||||
targetAddr: opts.Target.Endpoint,
|
|
||||||
startCh: make(chan struct{}),
|
|
||||||
conns: make(map[resolver.Address]balancer.SubConn),
|
|
||||||
connSt: make(map[balancer.SubConn]*scState),
|
|
||||||
csEvltr: &balancer.ConnectivityStateEvaluator{},
|
|
||||||
state: connectivity.Idle,
|
|
||||||
}
|
|
||||||
cc.UpdateState(balancer.State{ConnectivityState: connectivity.Idle, Picker: bw})
|
|
||||||
go bw.lbWatcher()
|
|
||||||
return bw
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bwb *balancerWrapperBuilder) Name() string {
|
|
||||||
return "wrapper"
|
|
||||||
}
|
|
||||||
|
|
||||||
type scState struct {
|
|
||||||
addr Address // The v1 address type.
|
|
||||||
s connectivity.State
|
|
||||||
down func(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type balancerWrapper struct {
|
|
||||||
balancer Balancer // The v1 balancer.
|
|
||||||
pickfirst bool
|
|
||||||
|
|
||||||
cc balancer.ClientConn
|
|
||||||
targetAddr string // Target without the scheme.
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
conns map[resolver.Address]balancer.SubConn
|
|
||||||
connSt map[balancer.SubConn]*scState
|
|
||||||
// This channel is closed when handling the first resolver result.
|
|
||||||
// lbWatcher blocks until this is closed, to avoid race between
|
|
||||||
// - NewSubConn is created, cc wants to notify balancer of state changes;
|
|
||||||
// - Build hasn't return, cc doesn't have access to balancer.
|
|
||||||
startCh chan struct{}
|
|
||||||
|
|
||||||
// To aggregate the connectivity state.
|
|
||||||
csEvltr *balancer.ConnectivityStateEvaluator
|
|
||||||
state connectivity.State
|
|
||||||
}
|
|
||||||
|
|
||||||
// lbWatcher watches the Notify channel of the balancer and manages
|
|
||||||
// connections accordingly.
|
|
||||||
func (bw *balancerWrapper) lbWatcher() {
|
|
||||||
<-bw.startCh
|
|
||||||
notifyCh := bw.balancer.Notify()
|
|
||||||
if notifyCh == nil {
|
|
||||||
// There's no resolver in the balancer. Connect directly.
|
|
||||||
a := resolver.Address{
|
|
||||||
Addr: bw.targetAddr,
|
|
||||||
Type: resolver.Backend,
|
|
||||||
}
|
|
||||||
sc, err := bw.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{})
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Warningf("Error creating connection to %v. Err: %v", a, err)
|
|
||||||
} else {
|
|
||||||
bw.mu.Lock()
|
|
||||||
bw.conns[a] = sc
|
|
||||||
bw.connSt[sc] = &scState{
|
|
||||||
addr: Address{Addr: bw.targetAddr},
|
|
||||||
s: connectivity.Idle,
|
|
||||||
}
|
|
||||||
bw.mu.Unlock()
|
|
||||||
sc.Connect()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for addrs := range notifyCh {
|
|
||||||
grpclog.Infof("balancerWrapper: got update addr from Notify: %v", addrs)
|
|
||||||
if bw.pickfirst {
|
|
||||||
var (
|
|
||||||
oldA resolver.Address
|
|
||||||
oldSC balancer.SubConn
|
|
||||||
)
|
|
||||||
bw.mu.Lock()
|
|
||||||
for oldA, oldSC = range bw.conns {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
bw.mu.Unlock()
|
|
||||||
if len(addrs) <= 0 {
|
|
||||||
if oldSC != nil {
|
|
||||||
// Teardown old sc.
|
|
||||||
bw.mu.Lock()
|
|
||||||
delete(bw.conns, oldA)
|
|
||||||
delete(bw.connSt, oldSC)
|
|
||||||
bw.mu.Unlock()
|
|
||||||
bw.cc.RemoveSubConn(oldSC)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var newAddrs []resolver.Address
|
|
||||||
for _, a := range addrs {
|
|
||||||
newAddr := resolver.Address{
|
|
||||||
Addr: a.Addr,
|
|
||||||
Type: resolver.Backend, // All addresses from balancer are all backends.
|
|
||||||
ServerName: "",
|
|
||||||
Metadata: a.Metadata,
|
|
||||||
}
|
|
||||||
newAddrs = append(newAddrs, newAddr)
|
|
||||||
}
|
|
||||||
if oldSC == nil {
|
|
||||||
// Create new sc.
|
|
||||||
sc, err := bw.cc.NewSubConn(newAddrs, balancer.NewSubConnOptions{})
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Warningf("Error creating connection to %v. Err: %v", newAddrs, err)
|
|
||||||
} else {
|
|
||||||
bw.mu.Lock()
|
|
||||||
// For pickfirst, there should be only one SubConn, so the
|
|
||||||
// address doesn't matter. All states updating (up and down)
|
|
||||||
// and picking should all happen on that only SubConn.
|
|
||||||
bw.conns[resolver.Address{}] = sc
|
|
||||||
bw.connSt[sc] = &scState{
|
|
||||||
addr: addrs[0], // Use the first address.
|
|
||||||
s: connectivity.Idle,
|
|
||||||
}
|
|
||||||
bw.mu.Unlock()
|
|
||||||
sc.Connect()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bw.mu.Lock()
|
|
||||||
bw.connSt[oldSC].addr = addrs[0]
|
|
||||||
bw.mu.Unlock()
|
|
||||||
oldSC.UpdateAddresses(newAddrs)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var (
|
|
||||||
add []resolver.Address // Addresses need to setup connections.
|
|
||||||
del []balancer.SubConn // Connections need to tear down.
|
|
||||||
)
|
|
||||||
resAddrs := make(map[resolver.Address]Address)
|
|
||||||
for _, a := range addrs {
|
|
||||||
resAddrs[resolver.Address{
|
|
||||||
Addr: a.Addr,
|
|
||||||
Type: resolver.Backend, // All addresses from balancer are all backends.
|
|
||||||
ServerName: "",
|
|
||||||
Metadata: a.Metadata,
|
|
||||||
}] = a
|
|
||||||
}
|
|
||||||
bw.mu.Lock()
|
|
||||||
for a := range resAddrs {
|
|
||||||
if _, ok := bw.conns[a]; !ok {
|
|
||||||
add = append(add, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for a, c := range bw.conns {
|
|
||||||
if _, ok := resAddrs[a]; !ok {
|
|
||||||
del = append(del, c)
|
|
||||||
delete(bw.conns, a)
|
|
||||||
// Keep the state of this sc in bw.connSt until its state becomes Shutdown.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bw.mu.Unlock()
|
|
||||||
for _, a := range add {
|
|
||||||
sc, err := bw.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{})
|
|
||||||
if err != nil {
|
|
||||||
grpclog.Warningf("Error creating connection to %v. Err: %v", a, err)
|
|
||||||
} else {
|
|
||||||
bw.mu.Lock()
|
|
||||||
bw.conns[a] = sc
|
|
||||||
bw.connSt[sc] = &scState{
|
|
||||||
addr: resAddrs[a],
|
|
||||||
s: connectivity.Idle,
|
|
||||||
}
|
|
||||||
bw.mu.Unlock()
|
|
||||||
sc.Connect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, c := range del {
|
|
||||||
bw.cc.RemoveSubConn(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bw *balancerWrapper) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) {
|
|
||||||
bw.mu.Lock()
|
|
||||||
defer bw.mu.Unlock()
|
|
||||||
scSt, ok := bw.connSt[sc]
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s == connectivity.Idle {
|
|
||||||
sc.Connect()
|
|
||||||
}
|
|
||||||
oldS := scSt.s
|
|
||||||
scSt.s = s
|
|
||||||
if oldS != connectivity.Ready && s == connectivity.Ready {
|
|
||||||
scSt.down = bw.balancer.Up(scSt.addr)
|
|
||||||
} else if oldS == connectivity.Ready && s != connectivity.Ready {
|
|
||||||
if scSt.down != nil {
|
|
||||||
scSt.down(errConnClosing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sa := bw.csEvltr.RecordTransition(oldS, s)
|
|
||||||
if bw.state != sa {
|
|
||||||
bw.state = sa
|
|
||||||
}
|
|
||||||
bw.cc.UpdateState(balancer.State{ConnectivityState: bw.state, Picker: bw})
|
|
||||||
if s == connectivity.Shutdown {
|
|
||||||
// Remove state for this sc.
|
|
||||||
delete(bw.connSt, sc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bw *balancerWrapper) HandleResolvedAddrs([]resolver.Address, error) {
|
|
||||||
bw.mu.Lock()
|
|
||||||
defer bw.mu.Unlock()
|
|
||||||
select {
|
|
||||||
case <-bw.startCh:
|
|
||||||
default:
|
|
||||||
close(bw.startCh)
|
|
||||||
}
|
|
||||||
// There should be a resolver inside the balancer.
|
|
||||||
// All updates here, if any, are ignored.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bw *balancerWrapper) Close() {
|
|
||||||
bw.mu.Lock()
|
|
||||||
defer bw.mu.Unlock()
|
|
||||||
select {
|
|
||||||
case <-bw.startCh:
|
|
||||||
default:
|
|
||||||
close(bw.startCh)
|
|
||||||
}
|
|
||||||
bw.balancer.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// The picker is the balancerWrapper itself.
|
|
||||||
// It either blocks or returns error, consistent with v1 balancer Get().
|
|
||||||
func (bw *balancerWrapper) Pick(info balancer.PickInfo) (result balancer.PickResult, err error) {
|
|
||||||
failfast := true // Default failfast is true.
|
|
||||||
if ss, ok := rpcInfoFromContext(info.Ctx); ok {
|
|
||||||
failfast = ss.failfast
|
|
||||||
}
|
|
||||||
a, p, err := bw.balancer.Get(info.Ctx, BalancerGetOptions{BlockingWait: !failfast})
|
|
||||||
if err != nil {
|
|
||||||
return balancer.PickResult{}, toRPCErr(err)
|
|
||||||
}
|
|
||||||
if p != nil {
|
|
||||||
result.Done = func(balancer.DoneInfo) { p() }
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
p()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
bw.mu.Lock()
|
|
||||||
defer bw.mu.Unlock()
|
|
||||||
if bw.pickfirst {
|
|
||||||
// Get the first sc in conns.
|
|
||||||
for _, result.SubConn = range bw.conns {
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
return balancer.PickResult{}, balancer.ErrNoSubConnAvailable
|
|
||||||
}
|
|
||||||
var ok1 bool
|
|
||||||
result.SubConn, ok1 = bw.conns[resolver.Address{
|
|
||||||
Addr: a.Addr,
|
|
||||||
Type: resolver.Backend,
|
|
||||||
ServerName: "",
|
|
||||||
Metadata: a.Metadata,
|
|
||||||
}]
|
|
||||||
s, ok2 := bw.connSt[result.SubConn]
|
|
||||||
if !ok1 || !ok2 {
|
|
||||||
// This can only happen due to a race where Get() returned an address
|
|
||||||
// that was subsequently removed by Notify. In this case we should
|
|
||||||
// retry always.
|
|
||||||
return balancer.PickResult{}, balancer.ErrNoSubConnAvailable
|
|
||||||
}
|
|
||||||
switch s.s {
|
|
||||||
case connectivity.Ready, connectivity.Idle:
|
|
||||||
return result, nil
|
|
||||||
case connectivity.Shutdown, connectivity.TransientFailure:
|
|
||||||
// If the returned sc has been shut down or is in transient failure,
|
|
||||||
// return error, and this RPC will fail or wait for another picker (if
|
|
||||||
// non-failfast).
|
|
||||||
return balancer.PickResult{}, balancer.ErrTransientFailure
|
|
||||||
default:
|
|
||||||
// For other states (connecting or unknown), the v1 balancer would
|
|
||||||
// traditionally wait until ready and then issue the RPC. Returning
|
|
||||||
// ErrNoSubConnAvailable will be a slight improvement in that it will
|
|
||||||
// allow the balancer to choose another address in case others are
|
|
||||||
// connected.
|
|
||||||
return balancer.PickResult{}, balancer.ErrNoSubConnAvailable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -26,7 +26,7 @@ import (
|
||||||
// received. This is typically called by generated code.
|
// received. This is typically called by generated code.
|
||||||
//
|
//
|
||||||
// All errors returned by Invoke are compatible with the status package.
|
// All errors returned by Invoke are compatible with the status package.
|
||||||
func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error {
|
func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply any, opts ...CallOption) error {
|
||||||
// allow interceptor to see all applicable call options, which means those
|
// allow interceptor to see all applicable call options, which means those
|
||||||
// configured as defaults from dial option as well as per-call options
|
// configured as defaults from dial option as well as per-call options
|
||||||
opts = combine(cc.dopts.callOptions, opts)
|
opts = combine(cc.dopts.callOptions, opts)
|
||||||
|
|
@ -56,13 +56,13 @@ func combine(o1 []CallOption, o2 []CallOption) []CallOption {
|
||||||
// received. This is typically called by generated code.
|
// received. This is typically called by generated code.
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use ClientConn.Invoke instead.
|
// DEPRECATED: Use ClientConn.Invoke instead.
|
||||||
func Invoke(ctx context.Context, method string, args, reply interface{}, cc *ClientConn, opts ...CallOption) error {
|
func Invoke(ctx context.Context, method string, args, reply any, cc *ClientConn, opts ...CallOption) error {
|
||||||
return cc.Invoke(ctx, method, args, reply, opts...)
|
return cc.Invoke(ctx, method, args, reply, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var unaryStreamDesc = &StreamDesc{ServerStreams: false, ClientStreams: false}
|
var unaryStreamDesc = &StreamDesc{ServerStreams: false, ClientStreams: false}
|
||||||
|
|
||||||
func invoke(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error {
|
func invoke(ctx context.Context, method string, req, reply any, cc *ClientConn, opts ...CallOption) error {
|
||||||
cs, err := newClientStream(ctx, unaryStreamDesc, cc, method, opts...)
|
cs, err := newClientStream(ctx, unaryStreamDesc, cc, method, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2020 gRPC 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 channelz exports internals of the channelz implementation as required
|
||||||
|
// by other gRPC packages.
|
||||||
|
//
|
||||||
|
// The implementation of the channelz spec as defined in
|
||||||
|
// https://github.com/grpc/proposal/blob/master/A14-channelz.md, is provided by
|
||||||
|
// the `internal/channelz` package.
|
||||||
|
//
|
||||||
|
// # Experimental
|
||||||
|
//
|
||||||
|
// Notice: All APIs in this package are experimental and may be removed in a
|
||||||
|
// later release.
|
||||||
|
package channelz
|
||||||
|
|
||||||
|
import "google.golang.org/grpc/internal/channelz"
|
||||||
|
|
||||||
|
// Identifier is an opaque identifier which uniquely identifies an entity in the
|
||||||
|
// channelz database.
|
||||||
|
type Identifier = channelz.Identifier
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -27,8 +27,8 @@ import (
|
||||||
// omits the name/string, which vary between the two and are not needed for
|
// omits the name/string, which vary between the two and are not needed for
|
||||||
// anything besides the registry in the encoding package.
|
// anything besides the registry in the encoding package.
|
||||||
type baseCodec interface {
|
type baseCodec interface {
|
||||||
Marshal(v interface{}) ([]byte, error)
|
Marshal(v any) ([]byte, error)
|
||||||
Unmarshal(data []byte, v interface{}) error
|
Unmarshal(data []byte, v any) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ baseCodec = Codec(nil)
|
var _ baseCodec = Codec(nil)
|
||||||
|
|
@ -41,9 +41,9 @@ var _ baseCodec = encoding.Codec(nil)
|
||||||
// Deprecated: use encoding.Codec instead.
|
// Deprecated: use encoding.Codec instead.
|
||||||
type Codec interface {
|
type Codec interface {
|
||||||
// Marshal returns the wire format of v.
|
// Marshal returns the wire format of v.
|
||||||
Marshal(v interface{}) ([]byte, error)
|
Marshal(v any) ([]byte, error)
|
||||||
// Unmarshal parses the wire format into v.
|
// Unmarshal parses the wire format into v.
|
||||||
Unmarshal(data []byte, v interface{}) error
|
Unmarshal(data []byte, v any) error
|
||||||
// String returns the name of the Codec implementation. This is unused by
|
// String returns the name of the Codec implementation. This is unused by
|
||||||
// gRPC.
|
// gRPC.
|
||||||
String() string
|
String() string
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,15 @@
|
||||||
|
|
||||||
package codes
|
package codes
|
||||||
|
|
||||||
import "strconv"
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
internal.CanonicalString = canonicalString
|
||||||
|
}
|
||||||
|
|
||||||
func (c Code) String() string {
|
func (c Code) String() string {
|
||||||
switch c {
|
switch c {
|
||||||
|
|
@ -60,3 +68,44 @@ func (c Code) String() string {
|
||||||
return "Code(" + strconv.FormatInt(int64(c), 10) + ")"
|
return "Code(" + strconv.FormatInt(int64(c), 10) + ")"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func canonicalString(c Code) string {
|
||||||
|
switch c {
|
||||||
|
case OK:
|
||||||
|
return "OK"
|
||||||
|
case Canceled:
|
||||||
|
return "CANCELLED"
|
||||||
|
case Unknown:
|
||||||
|
return "UNKNOWN"
|
||||||
|
case InvalidArgument:
|
||||||
|
return "INVALID_ARGUMENT"
|
||||||
|
case DeadlineExceeded:
|
||||||
|
return "DEADLINE_EXCEEDED"
|
||||||
|
case NotFound:
|
||||||
|
return "NOT_FOUND"
|
||||||
|
case AlreadyExists:
|
||||||
|
return "ALREADY_EXISTS"
|
||||||
|
case PermissionDenied:
|
||||||
|
return "PERMISSION_DENIED"
|
||||||
|
case ResourceExhausted:
|
||||||
|
return "RESOURCE_EXHAUSTED"
|
||||||
|
case FailedPrecondition:
|
||||||
|
return "FAILED_PRECONDITION"
|
||||||
|
case Aborted:
|
||||||
|
return "ABORTED"
|
||||||
|
case OutOfRange:
|
||||||
|
return "OUT_OF_RANGE"
|
||||||
|
case Unimplemented:
|
||||||
|
return "UNIMPLEMENTED"
|
||||||
|
case Internal:
|
||||||
|
return "INTERNAL"
|
||||||
|
case Unavailable:
|
||||||
|
return "UNAVAILABLE"
|
||||||
|
case DataLoss:
|
||||||
|
return "DATA_LOSS"
|
||||||
|
case Unauthenticated:
|
||||||
|
return "UNAUTHENTICATED"
|
||||||
|
default:
|
||||||
|
return "CODE(" + strconv.FormatInt(int64(c), 10) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue