mirror of https://github.com/docker/cli.git
Merge pull request #5590 from thaJeztah/bump_engine_28
vendor: github.com/docker/docker 6ac445c42bad (master, v28.0-dev)
This commit is contained in:
commit
750b8ebcdc
66
vendor.mod
66
vendor.mod
|
@ -13,7 +13,7 @@ require (
|
||||||
github.com/distribution/reference v0.6.0
|
github.com/distribution/reference v0.6.0
|
||||||
github.com/docker/cli-docs-tool v0.8.0
|
github.com/docker/cli-docs-tool v0.8.0
|
||||||
github.com/docker/distribution v2.8.3+incompatible
|
github.com/docker/distribution v2.8.3+incompatible
|
||||||
github.com/docker/docker v27.0.2-0.20241018142220-36a3bd090489+incompatible // master (v-next)
|
github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible // master (v-next)
|
||||||
github.com/docker/docker-credential-helpers v0.8.2
|
github.com/docker/docker-credential-helpers v0.8.2
|
||||||
github.com/docker/go-connections v0.5.0
|
github.com/docker/go-connections v0.5.0
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
|
@ -41,65 +41,65 @@ require (
|
||||||
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a
|
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a
|
||||||
github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d
|
github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
go.opentelemetry.io/otel v1.21.0
|
go.opentelemetry.io/otel v1.28.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0
|
||||||
go.opentelemetry.io/otel/metric v1.21.0
|
go.opentelemetry.io/otel/metric v1.28.0
|
||||||
go.opentelemetry.io/otel/sdk v1.21.0
|
go.opentelemetry.io/otel/sdk v1.28.0
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.21.0
|
go.opentelemetry.io/otel/sdk/metric v1.28.0
|
||||||
go.opentelemetry.io/otel/trace v1.21.0
|
go.opentelemetry.io/otel/trace v1.28.0
|
||||||
golang.org/x/sync v0.8.0
|
golang.org/x/sync v0.8.0
|
||||||
golang.org/x/sys v0.25.0
|
golang.org/x/sys v0.26.0
|
||||||
golang.org/x/term v0.24.0
|
golang.org/x/term v0.25.0
|
||||||
golang.org/x/text v0.18.0
|
golang.org/x/text v0.19.0
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gotest.tools/v3 v3.5.1
|
gotest.tools/v3 v3.5.1
|
||||||
tags.cncf.io/container-device-interface v0.8.0
|
tags.cncf.io/container-device-interface v0.8.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||||
github.com/docker/go-metrics v0.0.1 // indirect
|
github.com/docker/go-metrics v0.0.1 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/go-logr/logr v1.4.1 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.1 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/klauspost/compress v1.17.9 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
|
||||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/moby/sys/symlink v0.3.0 // indirect
|
github.com/moby/sys/symlink v0.3.0 // indirect
|
||||||
github.com/moby/sys/user v0.3.0 // indirect
|
github.com/moby/sys/user v0.3.0 // indirect
|
||||||
github.com/moby/sys/userns v0.1.0 // indirect
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
github.com/prometheus/client_golang v1.17.0 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/prometheus/client_model v0.5.0 // indirect
|
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||||
github.com/prometheus/common v0.44.0 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.55.0 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/stretchr/testify v1.9.0 // indirect
|
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.6 // indirect
|
go.etcd.io/etcd/raft/v3 v3.5.16 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
golang.org/x/crypto v0.27.0 // indirect
|
golang.org/x/crypto v0.28.0 // indirect
|
||||||
golang.org/x/net v0.29.0 // indirect
|
golang.org/x/net v0.30.0 // indirect
|
||||||
golang.org/x/time v0.6.0 // indirect
|
golang.org/x/time v0.6.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect
|
||||||
google.golang.org/grpc v1.66.2 // indirect
|
google.golang.org/grpc v1.67.1 // indirect
|
||||||
google.golang.org/protobuf v1.34.1 // indirect
|
google.golang.org/protobuf v1.35.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
161
vendor.sum
161
vendor.sum
|
@ -1,9 +1,9 @@
|
||||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
|
@ -25,23 +25,17 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj
|
||||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
||||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||||
github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8=
|
github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8=
|
||||||
github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0=
|
github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
|
||||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||||
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||||
|
@ -57,8 +51,8 @@ github.com/docker/cli-docs-tool v0.8.0/go.mod h1:8TQQ3E7mOXoYUs811LiPdUnAhXrcVsB
|
||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v27.0.2-0.20241018142220-36a3bd090489+incompatible h1:utxxyIvPGk7UmtlGHirUyNUP2Spf8yL660PCbmb7tsk=
|
github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible h1:kSQ4U+63JfFxIOrTo6wMW1mqkOkPpiTe/7ZfvUdNLVE=
|
||||||
github.com/docker/docker v27.0.2-0.20241018142220-36a3bd090489+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||||
|
@ -82,15 +76,14 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
|
github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
|
||||||
github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||||
|
@ -98,39 +91,34 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
|
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
|
||||||
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
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-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
|
|
||||||
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||||
github.com/google/certificate-transparency-go v1.1.4 h1:hCyXHDbtqlr/lMXU0D4WgbalXL0Zk4dSWWMbPV8VrqY=
|
github.com/google/certificate-transparency-go v1.1.4 h1:hCyXHDbtqlr/lMXU0D4WgbalXL0Zk4dSWWMbPV8VrqY=
|
||||||
github.com/google/certificate-transparency-go v1.1.4/go.mod h1:D6lvbfwckhNrbM9WVl1EVeMOyzC19mpIjMOI4nxBHtQ=
|
github.com/google/certificate-transparency-go v1.1.4/go.mod h1:D6lvbfwckhNrbM9WVl1EVeMOyzC19mpIjMOI4nxBHtQ=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
@ -148,11 +136,10 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
@ -162,6 +149,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/magiconair/properties v1.5.3 h1:C8fxWnhYyME3n0klPOhVM7PtYUB3eV1W3DeFmN3j53Y=
|
github.com/magiconair/properties v1.5.3 h1:C8fxWnhYyME3n0klPOhVM7PtYUB3eV1W3DeFmN3j53Y=
|
||||||
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
@ -169,8 +158,6 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
|
||||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||||
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||||
|
@ -202,6 +189,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
@ -218,7 +207,6 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
@ -227,18 +215,18 @@ github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
@ -247,8 +235,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
@ -297,36 +285,32 @@ github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc h1:zkGwegkOW709y0oiAr
|
||||||
github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc/go.mod h1:FM4U1E3NzlNMRnSUTU3P1UdukWhYGifqEsjk9fn7BCk=
|
github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc/go.mod h1:FM4U1E3NzlNMRnSUTU3P1UdukWhYGifqEsjk9fn7BCk=
|
||||||
github.com/zmap/zlint/v3 v3.1.0 h1:WjVytZo79m/L1+/Mlphl09WBob6YTGljN5IGWZFpAv0=
|
github.com/zmap/zlint/v3 v3.1.0 h1:WjVytZo79m/L1+/Mlphl09WBob6YTGljN5IGWZFpAv0=
|
||||||
github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU=
|
github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ=
|
go.etcd.io/etcd/raft/v3 v3.5.16 h1:zBXA3ZUpYs1AwiLGPafYAKKl/CORn/uaxYDwlNwndAk=
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.6 h1:tOmx6Ym6rn2GpZOrvTGJZciJHek6RnC3U/zNInzIN50=
|
go.etcd.io/etcd/raft/v3 v3.5.16/go.mod h1:P4UP14AxofMJ/54boWilabqqWoW9eLodl6I5GdGzazI=
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.6/go.mod h1:wL8kkRGx1Hp8FmZUuHfL3K2/OaGIDaXGr1N7i2G07J0=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
|
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
|
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
|
||||||
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
|
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
|
||||||
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
|
go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0=
|
go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q=
|
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
@ -336,8 +320,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||||
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||||
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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
@ -353,8 +337,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/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.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
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=
|
||||||
|
@ -375,7 +359,6 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
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-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -385,28 +368,27 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.26.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-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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
||||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
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.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.7.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.9.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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
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-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/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=
|
||||||
|
@ -416,17 +398,15 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||||
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
|
google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
|
google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
|
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
|
||||||
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
|
||||||
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/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
||||||
|
@ -447,7 +427,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
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-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||||
|
|
||||||
|
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
|
||||||
|
|
||||||
|
## Reporting Security Issues
|
||||||
|
|
||||||
|
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||||
|
|
||||||
|
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
|
||||||
|
|
||||||
|
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
|
||||||
|
|
||||||
|
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
|
||||||
|
|
||||||
|
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||||
|
|
||||||
|
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||||
|
* Full paths of source file(s) related to the manifestation of the issue
|
||||||
|
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||||
|
* Any special configuration required to reproduce the issue
|
||||||
|
* Step-by-step instructions to reproduce the issue
|
||||||
|
* Proof-of-concept or exploit code (if possible)
|
||||||
|
* Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
|
||||||
|
This information will help us triage your report more quickly.
|
||||||
|
|
||||||
|
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
|
||||||
|
|
||||||
|
## Preferred Languages
|
||||||
|
|
||||||
|
We prefer all communications to be in English.
|
||||||
|
|
||||||
|
## Policy
|
||||||
|
|
||||||
|
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
|
||||||
|
|
||||||
|
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
|
@ -1,4 +1,4 @@
|
||||||
# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls]
|
# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Coverage Status][coveralls image]][coveralls]
|
||||||
|
|
||||||
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
|
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
|
||||||
|
|
||||||
|
@ -21,8 +21,6 @@ Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
|
||||||
|
|
||||||
[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4
|
[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4
|
||||||
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
|
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
|
||||||
[travis]: https://travis-ci.org/cenkalti/backoff
|
|
||||||
[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master
|
|
||||||
[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
|
[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
|
||||||
[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
|
[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,9 @@ type Clock interface {
|
||||||
Now() time.Time
|
Now() time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExponentialBackOffOpts is a function type used to configure ExponentialBackOff options.
|
||||||
|
type ExponentialBackOffOpts func(*ExponentialBackOff)
|
||||||
|
|
||||||
// Default values for ExponentialBackOff.
|
// Default values for ExponentialBackOff.
|
||||||
const (
|
const (
|
||||||
DefaultInitialInterval = 500 * time.Millisecond
|
DefaultInitialInterval = 500 * time.Millisecond
|
||||||
|
@ -81,7 +84,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
||||||
func NewExponentialBackOff() *ExponentialBackOff {
|
func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff {
|
||||||
b := &ExponentialBackOff{
|
b := &ExponentialBackOff{
|
||||||
InitialInterval: DefaultInitialInterval,
|
InitialInterval: DefaultInitialInterval,
|
||||||
RandomizationFactor: DefaultRandomizationFactor,
|
RandomizationFactor: DefaultRandomizationFactor,
|
||||||
|
@ -91,10 +94,62 @@ func NewExponentialBackOff() *ExponentialBackOff {
|
||||||
Stop: Stop,
|
Stop: Stop,
|
||||||
Clock: SystemClock,
|
Clock: SystemClock,
|
||||||
}
|
}
|
||||||
|
for _, fn := range opts {
|
||||||
|
fn(b)
|
||||||
|
}
|
||||||
b.Reset()
|
b.Reset()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithInitialInterval sets the initial interval between retries.
|
||||||
|
func WithInitialInterval(duration time.Duration) ExponentialBackOffOpts {
|
||||||
|
return func(ebo *ExponentialBackOff) {
|
||||||
|
ebo.InitialInterval = duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRandomizationFactor sets the randomization factor to add jitter to intervals.
|
||||||
|
func WithRandomizationFactor(randomizationFactor float64) ExponentialBackOffOpts {
|
||||||
|
return func(ebo *ExponentialBackOff) {
|
||||||
|
ebo.RandomizationFactor = randomizationFactor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMultiplier sets the multiplier for increasing the interval after each retry.
|
||||||
|
func WithMultiplier(multiplier float64) ExponentialBackOffOpts {
|
||||||
|
return func(ebo *ExponentialBackOff) {
|
||||||
|
ebo.Multiplier = multiplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxInterval sets the maximum interval between retries.
|
||||||
|
func WithMaxInterval(duration time.Duration) ExponentialBackOffOpts {
|
||||||
|
return func(ebo *ExponentialBackOff) {
|
||||||
|
ebo.MaxInterval = duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxElapsedTime sets the maximum total time for retries.
|
||||||
|
func WithMaxElapsedTime(duration time.Duration) ExponentialBackOffOpts {
|
||||||
|
return func(ebo *ExponentialBackOff) {
|
||||||
|
ebo.MaxElapsedTime = duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRetryStopDuration sets the duration after which retries should stop.
|
||||||
|
func WithRetryStopDuration(duration time.Duration) ExponentialBackOffOpts {
|
||||||
|
return func(ebo *ExponentialBackOff) {
|
||||||
|
ebo.Stop = duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithClockProvider sets the clock used to measure time.
|
||||||
|
func WithClockProvider(clock Clock) ExponentialBackOffOpts {
|
||||||
|
return func(ebo *ExponentialBackOff) {
|
||||||
|
ebo.Clock = clock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type systemClock struct{}
|
type systemClock struct{}
|
||||||
|
|
||||||
func (t systemClock) Now() time.Time {
|
func (t systemClock) Now() time.Time {
|
||||||
|
|
|
@ -22,16 +22,3 @@ func (e invalidFilter) Error() string {
|
||||||
|
|
||||||
// InvalidParameter marks this error as ErrInvalidParameter
|
// InvalidParameter marks this error as ErrInvalidParameter
|
||||||
func (e invalidFilter) InvalidParameter() {}
|
func (e invalidFilter) InvalidParameter() {}
|
||||||
|
|
||||||
// unreachableCode is an error indicating that the code path was not expected to be reached.
|
|
||||||
type unreachableCode struct {
|
|
||||||
Filter string
|
|
||||||
Value []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// System marks this error as ErrSystem
|
|
||||||
func (e unreachableCode) System() {}
|
|
||||||
|
|
||||||
func (e unreachableCode) Error() string {
|
|
||||||
return fmt.Sprintf("unreachable code reached for filter: %q with values: %s", e.Filter, e.Value)
|
|
||||||
}
|
|
||||||
|
|
|
@ -200,7 +200,6 @@ func (args Args) Match(field, source string) bool {
|
||||||
// Error is not nil only if the filter values are not valid boolean or are conflicting.
|
// Error is not nil only if the filter values are not valid boolean or are conflicting.
|
||||||
func (args Args) GetBoolOrDefault(key string, defaultValue bool) (bool, error) {
|
func (args Args) GetBoolOrDefault(key string, defaultValue bool) (bool, error) {
|
||||||
fieldValues, ok := args.fields[key]
|
fieldValues, ok := args.fields[key]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return defaultValue, nil
|
return defaultValue, nil
|
||||||
}
|
}
|
||||||
|
@ -211,20 +210,11 @@ func (args Args) GetBoolOrDefault(key string, defaultValue bool) (bool, error) {
|
||||||
|
|
||||||
isFalse := fieldValues["0"] || fieldValues["false"]
|
isFalse := fieldValues["0"] || fieldValues["false"]
|
||||||
isTrue := fieldValues["1"] || fieldValues["true"]
|
isTrue := fieldValues["1"] || fieldValues["true"]
|
||||||
|
if isFalse == isTrue {
|
||||||
conflicting := isFalse && isTrue
|
// Either no or conflicting truthy/falsy value were provided
|
||||||
invalid := !isFalse && !isTrue
|
|
||||||
|
|
||||||
if conflicting || invalid {
|
|
||||||
return defaultValue, &invalidFilter{key, args.Get(key)}
|
return defaultValue, &invalidFilter{key, args.Get(key)}
|
||||||
} else if isFalse {
|
|
||||||
return false, nil
|
|
||||||
} else if isTrue {
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
|
return isTrue, nil
|
||||||
// This code shouldn't be reached.
|
|
||||||
return defaultValue, &unreachableCode{Filter: key, Value: args.Get(key)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExactMatch returns true if the source matches exactly one of the values.
|
// ExactMatch returns true if the source matches exactly one of the values.
|
||||||
|
|
|
@ -17,8 +17,6 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePru
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
report := types.BuildCachePruneReport{}
|
|
||||||
|
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
if opts.All {
|
if opts.All {
|
||||||
query.Set("all", "1")
|
query.Set("all", "1")
|
||||||
|
@ -37,6 +35,7 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePru
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
report := types.BuildCachePruneReport{}
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||||
return nil, errors.Wrap(err, "error retrieving disk usage")
|
return nil, errors.Wrap(err, "error retrieving disk usage")
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,6 +247,14 @@ func (cli *Client) tlsConfig() *tls.Config {
|
||||||
|
|
||||||
func defaultHTTPClient(hostURL *url.URL) (*http.Client, error) {
|
func defaultHTTPClient(hostURL *url.URL) (*http.Client, error) {
|
||||||
transport := &http.Transport{}
|
transport := &http.Transport{}
|
||||||
|
// Necessary to prevent long-lived processes using the
|
||||||
|
// client from leaking connections due to idle connections
|
||||||
|
// not being released.
|
||||||
|
// TODO: see if we can also address this from the server side,
|
||||||
|
// or in go-connections.
|
||||||
|
// see: https://github.com/moby/moby/issues/45539
|
||||||
|
transport.MaxIdleConns = 6
|
||||||
|
transport.IdleConnTimeout = 30 * time.Second
|
||||||
err := sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host)
|
err := sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -11,25 +11,24 @@ import (
|
||||||
|
|
||||||
// ContainersPrune requests the daemon to delete unused data
|
// ContainersPrune requests the daemon to delete unused data
|
||||||
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
||||||
var report container.PruneReport
|
|
||||||
|
|
||||||
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
|
||||||
return report, err
|
return container.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
query, err := getFiltersQuery(pruneFilters)
|
query, err := getFiltersQuery(pruneFilters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return container.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
|
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
|
||||||
defer ensureReaderClosed(serverResp)
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return container.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var report container.PruneReport
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||||
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
|
return container.PruneReport{}, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return report, nil
|
return report, nil
|
||||||
|
|
|
@ -11,25 +11,24 @@ import (
|
||||||
|
|
||||||
// ImagesPrune requests the daemon to delete unused data
|
// ImagesPrune requests the daemon to delete unused data
|
||||||
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
|
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
|
||||||
var report image.PruneReport
|
|
||||||
|
|
||||||
if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil {
|
||||||
return report, err
|
return image.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
query, err := getFiltersQuery(pruneFilters)
|
query, err := getFiltersQuery(pruneFilters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return image.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
|
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
|
||||||
defer ensureReaderClosed(serverResp)
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return image.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var report image.PruneReport
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||||
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
|
return image.PruneReport{}, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return report, nil
|
return report, nil
|
||||||
|
|
|
@ -11,25 +11,24 @@ import (
|
||||||
|
|
||||||
// NetworksPrune requests the daemon to delete unused networks
|
// NetworksPrune requests the daemon to delete unused networks
|
||||||
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
|
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
|
||||||
var report network.PruneReport
|
|
||||||
|
|
||||||
if err := cli.NewVersionError(ctx, "1.25", "network prune"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.25", "network prune"); err != nil {
|
||||||
return report, err
|
return network.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
query, err := getFiltersQuery(pruneFilters)
|
query, err := getFiltersQuery(pruneFilters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return network.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
|
serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
|
||||||
defer ensureReaderClosed(serverResp)
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return network.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var report network.PruneReport
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||||
return report, fmt.Errorf("Error retrieving network prune report: %v", err)
|
return network.PruneReport{}, fmt.Errorf("Error retrieving network prune report: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return report, nil
|
return report, nil
|
||||||
|
|
|
@ -11,25 +11,24 @@ import (
|
||||||
|
|
||||||
// VolumesPrune requests the daemon to delete unused data
|
// VolumesPrune requests the daemon to delete unused data
|
||||||
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (volume.PruneReport, error) {
|
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (volume.PruneReport, error) {
|
||||||
var report volume.PruneReport
|
|
||||||
|
|
||||||
if err := cli.NewVersionError(ctx, "1.25", "volume prune"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.25", "volume prune"); err != nil {
|
||||||
return report, err
|
return volume.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
query, err := getFiltersQuery(pruneFilters)
|
query, err := getFiltersQuery(pruneFilters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return volume.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/volumes/prune", query, nil, nil)
|
serverResp, err := cli.post(ctx, "/volumes/prune", query, nil, nil)
|
||||||
defer ensureReaderClosed(serverResp)
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return volume.PruneReport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var report volume.PruneReport
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||||
return report, fmt.Errorf("Error retrieving volume prune report: %v", err)
|
return volume.PruneReport{}, fmt.Errorf("Error retrieving volume prune report: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return report, nil
|
return report, nil
|
||||||
|
|
|
@ -531,15 +531,6 @@ func newTarAppender(idMapping idtools.IdentityMapping, writer io.Writer, chownOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanonicalTarNameForPath canonicalizes relativePath to a POSIX-style path using
|
|
||||||
// forward slashes. It is an alias for [filepath.ToSlash], which is a no-op on
|
|
||||||
// Linux and Unix.
|
|
||||||
//
|
|
||||||
// Deprecated: use [filepath.ToSlash]. This function will be removed in the next release.
|
|
||||||
func CanonicalTarNameForPath(relativePath string) string {
|
|
||||||
return filepath.ToSlash(relativePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// canonicalTarName provides a platform-independent and consistent POSIX-style
|
// canonicalTarName provides a platform-independent and consistent POSIX-style
|
||||||
// path for files and directories to be archived regardless of the platform.
|
// path for files and directories to be archived regardless of the platform.
|
||||||
func canonicalTarName(name string, isDir bool) string {
|
func canonicalTarName(name string, isDir bool) string {
|
||||||
|
@ -1441,60 +1432,3 @@ func cmdStream(cmd *exec.Cmd, input io.Reader) (io.ReadCloser, error) {
|
||||||
return err
|
return err
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTempArchive reads the content of src into a temporary file, and returns the contents
|
|
||||||
// of that file as an archive. The archive can only be read once - as soon as reading completes,
|
|
||||||
// the file will be deleted.
|
|
||||||
//
|
|
||||||
// Deprecated: NewTempArchive is only used in tests and will be removed in the next release.
|
|
||||||
func NewTempArchive(src io.Reader, dir string) (*TempArchive, error) {
|
|
||||||
f, err := os.CreateTemp(dir, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := io.Copy(f, src); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := f.Seek(0, 0); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
st, err := f.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
size := st.Size()
|
|
||||||
return &TempArchive{File: f, Size: size}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TempArchive is a temporary archive. The archive can only be read once - as soon as reading completes,
|
|
||||||
// the file will be deleted.
|
|
||||||
//
|
|
||||||
// Deprecated: TempArchive is only used in tests and will be removed in the next release.
|
|
||||||
type TempArchive struct {
|
|
||||||
*os.File
|
|
||||||
Size int64 // Pre-computed from Stat().Size() as a convenience
|
|
||||||
read int64
|
|
||||||
closed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes the underlying file if it's still open, or does a no-op
|
|
||||||
// to allow callers to try to close the TempArchive multiple times safely.
|
|
||||||
func (archive *TempArchive) Close() error {
|
|
||||||
if archive.closed {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
archive.closed = true
|
|
||||||
|
|
||||||
return archive.File.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (archive *TempArchive) Read(data []byte) (int, error) {
|
|
||||||
n, err := archive.File.Read(data)
|
|
||||||
archive.read += int64(n)
|
|
||||||
if err != nil || archive.read == archive.Size {
|
|
||||||
archive.Close()
|
|
||||||
os.Remove(archive.File.Name())
|
|
||||||
}
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,11 +11,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Prefix is the longpath prefix for Windows file paths.
|
|
||||||
//
|
|
||||||
// Deprecated: this const is only used internally, and will be removed in the next release
|
|
||||||
const Prefix = longPathPrefix
|
|
||||||
|
|
||||||
// longPathPrefix is the longpath prefix for Windows file paths.
|
// longPathPrefix is the longpath prefix for Windows file paths.
|
||||||
const longPathPrefix = `\\?\`
|
const longPathPrefix = `\\?\`
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,6 @@ package stringid // import "github.com/docker/docker/pkg/stringid"
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,22 +12,6 @@ const (
|
||||||
fullLen = 64
|
fullLen = 64
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
validShortID = regexp.MustCompile("^[a-f0-9]{12}$")
|
|
||||||
validHex = regexp.MustCompile(`^[a-f0-9]{64}$`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsShortID determines if id has the correct format and length for a short ID.
|
|
||||||
// It checks the IDs length and if it consists of valid characters for IDs (a-f0-9).
|
|
||||||
//
|
|
||||||
// Deprecated: this function is no longer used, and will be removed in the next release.
|
|
||||||
func IsShortID(id string) bool {
|
|
||||||
if len(id) != shortLen {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return validShortID.MatchString(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TruncateID returns a shorthand version of a string identifier for convenience.
|
// TruncateID returns a shorthand version of a string identifier for convenience.
|
||||||
// A collision with other shorthands is very unlikely, but possible.
|
// A collision with other shorthands is very unlikely, but possible.
|
||||||
// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
|
// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
|
||||||
|
@ -45,7 +26,10 @@ func TruncateID(id string) string {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateRandomID returns a unique id.
|
// GenerateRandomID returns a unique, 64-character ID consisting of a-z, 0-9.
|
||||||
|
// It guarantees that the ID, when truncated ([TruncateID]) does not consist
|
||||||
|
// of numbers only, so that the truncated ID can be used as hostname for
|
||||||
|
// containers.
|
||||||
func GenerateRandomID() string {
|
func GenerateRandomID() string {
|
||||||
b := make([]byte, 32)
|
b := make([]byte, 32)
|
||||||
for {
|
for {
|
||||||
|
@ -53,25 +37,27 @@ func GenerateRandomID() string {
|
||||||
panic(err) // This shouldn't happen
|
panic(err) // This shouldn't happen
|
||||||
}
|
}
|
||||||
id := hex.EncodeToString(b)
|
id := hex.EncodeToString(b)
|
||||||
// if we try to parse the truncated for as an int and we don't have
|
|
||||||
// an error then the value is all numeric and causes issues when
|
// make sure that the truncated ID does not consist of only numeric
|
||||||
// used as a hostname. ref #3869
|
// characters, as it's used as default hostname for containers.
|
||||||
if _, err := strconv.ParseInt(TruncateID(id), 10, 64); err == nil {
|
//
|
||||||
|
// See:
|
||||||
|
// - https://github.com/moby/moby/issues/3869
|
||||||
|
// - https://bugzilla.redhat.com/show_bug.cgi?id=1059122
|
||||||
|
if allNum(id[:shortLen]) {
|
||||||
|
// all numbers; try again
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateID checks whether an ID string is a valid, full-length image ID.
|
// allNum checks whether id consists of only numbers (0-9).
|
||||||
//
|
func allNum(id string) bool {
|
||||||
// Deprecated: use [github.com/docker/docker/image/v1.ValidateID] instead. Will be removed in the next release.
|
for _, c := range []byte(id) {
|
||||||
func ValidateID(id string) error {
|
if c > '9' || c < '0' {
|
||||||
if len(id) != fullLen {
|
return false
|
||||||
return errors.New("image ID '" + id + "' is invalid")
|
}
|
||||||
}
|
}
|
||||||
if !validHex.MatchString(id) {
|
return true
|
||||||
return errors.New("image ID '" + id + "' is invalid")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# A minimal logging API for Go
|
# A minimal logging API for Go
|
||||||
|
|
||||||
[![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/logr.svg)](https://pkg.go.dev/github.com/go-logr/logr)
|
[![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/logr.svg)](https://pkg.go.dev/github.com/go-logr/logr)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/go-logr/logr)](https://goreportcard.com/report/github.com/go-logr/logr)
|
||||||
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-logr/logr/badge)](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr)
|
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-logr/logr/badge)](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr)
|
||||||
|
|
||||||
logr offers an(other) opinion on how Go programs and libraries can do logging
|
logr offers an(other) opinion on how Go programs and libraries can do logging
|
||||||
|
|
|
@ -236,15 +236,14 @@ func newFormatter(opts Options, outfmt outputFormat) Formatter {
|
||||||
// implementation. It should be constructed with NewFormatter. Some of
|
// implementation. It should be constructed with NewFormatter. Some of
|
||||||
// its methods directly implement logr.LogSink.
|
// its methods directly implement logr.LogSink.
|
||||||
type Formatter struct {
|
type Formatter struct {
|
||||||
outputFormat outputFormat
|
outputFormat outputFormat
|
||||||
prefix string
|
prefix string
|
||||||
values []any
|
values []any
|
||||||
valuesStr string
|
valuesStr string
|
||||||
parentValuesStr string
|
depth int
|
||||||
depth int
|
opts *Options
|
||||||
opts *Options
|
groupName string // for slog groups
|
||||||
group string // for slog groups
|
groups []groupDef
|
||||||
groupDepth int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// outputFormat indicates which outputFormat to use.
|
// outputFormat indicates which outputFormat to use.
|
||||||
|
@ -257,6 +256,13 @@ const (
|
||||||
outputJSON
|
outputJSON
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// groupDef represents a saved group. The values may be empty, but we don't
|
||||||
|
// know if we need to render the group until the final record is rendered.
|
||||||
|
type groupDef struct {
|
||||||
|
name string
|
||||||
|
values string
|
||||||
|
}
|
||||||
|
|
||||||
// PseudoStruct is a list of key-value pairs that gets logged as a struct.
|
// PseudoStruct is a list of key-value pairs that gets logged as a struct.
|
||||||
type PseudoStruct []any
|
type PseudoStruct []any
|
||||||
|
|
||||||
|
@ -264,76 +270,102 @@ type PseudoStruct []any
|
||||||
func (f Formatter) render(builtins, args []any) string {
|
func (f Formatter) render(builtins, args []any) string {
|
||||||
// Empirically bytes.Buffer is faster than strings.Builder for this.
|
// Empirically bytes.Buffer is faster than strings.Builder for this.
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||||
|
|
||||||
if f.outputFormat == outputJSON {
|
if f.outputFormat == outputJSON {
|
||||||
buf.WriteByte('{') // for the whole line
|
buf.WriteByte('{') // for the whole record
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render builtins
|
||||||
vals := builtins
|
vals := builtins
|
||||||
if hook := f.opts.RenderBuiltinsHook; hook != nil {
|
if hook := f.opts.RenderBuiltinsHook; hook != nil {
|
||||||
vals = hook(f.sanitize(vals))
|
vals = hook(f.sanitize(vals))
|
||||||
}
|
}
|
||||||
f.flatten(buf, vals, false, false) // keys are ours, no need to escape
|
f.flatten(buf, vals, false) // keys are ours, no need to escape
|
||||||
continuing := len(builtins) > 0
|
continuing := len(builtins) > 0
|
||||||
|
|
||||||
if f.parentValuesStr != "" {
|
// Turn the inner-most group into a string
|
||||||
|
argsStr := func() string {
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||||
|
|
||||||
|
vals = args
|
||||||
|
if hook := f.opts.RenderArgsHook; hook != nil {
|
||||||
|
vals = hook(f.sanitize(vals))
|
||||||
|
}
|
||||||
|
f.flatten(buf, vals, true) // escape user-provided keys
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Render the stack of groups from the inside out.
|
||||||
|
bodyStr := f.renderGroup(f.groupName, f.valuesStr, argsStr)
|
||||||
|
for i := len(f.groups) - 1; i >= 0; i-- {
|
||||||
|
grp := &f.groups[i]
|
||||||
|
if grp.values == "" && bodyStr == "" {
|
||||||
|
// no contents, so we must elide the whole group
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bodyStr = f.renderGroup(grp.name, grp.values, bodyStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bodyStr != "" {
|
||||||
if continuing {
|
if continuing {
|
||||||
buf.WriteByte(f.comma())
|
buf.WriteByte(f.comma())
|
||||||
}
|
}
|
||||||
buf.WriteString(f.parentValuesStr)
|
buf.WriteString(bodyStr)
|
||||||
continuing = true
|
|
||||||
}
|
|
||||||
|
|
||||||
groupDepth := f.groupDepth
|
|
||||||
if f.group != "" {
|
|
||||||
if f.valuesStr != "" || len(args) != 0 {
|
|
||||||
if continuing {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
buf.WriteString(f.quoted(f.group, true)) // escape user-provided keys
|
|
||||||
buf.WriteByte(f.colon())
|
|
||||||
buf.WriteByte('{') // for the group
|
|
||||||
continuing = false
|
|
||||||
} else {
|
|
||||||
// The group was empty
|
|
||||||
groupDepth--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.valuesStr != "" {
|
|
||||||
if continuing {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
buf.WriteString(f.valuesStr)
|
|
||||||
continuing = true
|
|
||||||
}
|
|
||||||
|
|
||||||
vals = args
|
|
||||||
if hook := f.opts.RenderArgsHook; hook != nil {
|
|
||||||
vals = hook(f.sanitize(vals))
|
|
||||||
}
|
|
||||||
f.flatten(buf, vals, continuing, true) // escape user-provided keys
|
|
||||||
|
|
||||||
for i := 0; i < groupDepth; i++ {
|
|
||||||
buf.WriteByte('}') // for the groups
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.outputFormat == outputJSON {
|
if f.outputFormat == outputJSON {
|
||||||
buf.WriteByte('}') // for the whole line
|
buf.WriteByte('}') // for the whole record
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// flatten renders a list of key-value pairs into a buffer. If continuing is
|
// renderGroup returns a string representation of the named group with rendered
|
||||||
// true, it assumes that the buffer has previous values and will emit a
|
// values and args. If the name is empty, this will return the values and args,
|
||||||
// separator (which depends on the output format) before the first pair it
|
// joined. If the name is not empty, this will return a single key-value pair,
|
||||||
// writes. If escapeKeys is true, the keys are assumed to have
|
// where the value is a grouping of the values and args. If the values and
|
||||||
// non-JSON-compatible characters in them and must be evaluated for escapes.
|
// args are both empty, this will return an empty string, even if the name was
|
||||||
|
// specified.
|
||||||
|
func (f Formatter) renderGroup(name string, values string, args string) string {
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||||
|
|
||||||
|
needClosingBrace := false
|
||||||
|
if name != "" && (values != "" || args != "") {
|
||||||
|
buf.WriteString(f.quoted(name, true)) // escape user-provided keys
|
||||||
|
buf.WriteByte(f.colon())
|
||||||
|
buf.WriteByte('{')
|
||||||
|
needClosingBrace = true
|
||||||
|
}
|
||||||
|
|
||||||
|
continuing := false
|
||||||
|
if values != "" {
|
||||||
|
buf.WriteString(values)
|
||||||
|
continuing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if args != "" {
|
||||||
|
if continuing {
|
||||||
|
buf.WriteByte(f.comma())
|
||||||
|
}
|
||||||
|
buf.WriteString(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
if needClosingBrace {
|
||||||
|
buf.WriteByte('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatten renders a list of key-value pairs into a buffer. If escapeKeys is
|
||||||
|
// true, the keys are assumed to have non-JSON-compatible characters in them
|
||||||
|
// and must be evaluated for escapes.
|
||||||
//
|
//
|
||||||
// This function returns a potentially modified version of kvList, which
|
// This function returns a potentially modified version of kvList, which
|
||||||
// ensures that there is a value for every key (adding a value if needed) and
|
// ensures that there is a value for every key (adding a value if needed) and
|
||||||
// that each key is a string (substituting a key if needed).
|
// that each key is a string (substituting a key if needed).
|
||||||
func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, continuing bool, escapeKeys bool) []any {
|
func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, escapeKeys bool) []any {
|
||||||
// This logic overlaps with sanitize() but saves one type-cast per key,
|
// This logic overlaps with sanitize() but saves one type-cast per key,
|
||||||
// which can be measurable.
|
// which can be measurable.
|
||||||
if len(kvList)%2 != 0 {
|
if len(kvList)%2 != 0 {
|
||||||
|
@ -354,7 +386,7 @@ func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, continuing bool, esc
|
||||||
}
|
}
|
||||||
v := kvList[i+1]
|
v := kvList[i+1]
|
||||||
|
|
||||||
if i > 0 || continuing {
|
if i > 0 {
|
||||||
if f.outputFormat == outputJSON {
|
if f.outputFormat == outputJSON {
|
||||||
buf.WriteByte(f.comma())
|
buf.WriteByte(f.comma())
|
||||||
} else {
|
} else {
|
||||||
|
@ -766,46 +798,17 @@ func (f Formatter) sanitize(kvList []any) []any {
|
||||||
// startGroup opens a new group scope (basically a sub-struct), which locks all
|
// startGroup opens a new group scope (basically a sub-struct), which locks all
|
||||||
// the current saved values and starts them anew. This is needed to satisfy
|
// the current saved values and starts them anew. This is needed to satisfy
|
||||||
// slog.
|
// slog.
|
||||||
func (f *Formatter) startGroup(group string) {
|
func (f *Formatter) startGroup(name string) {
|
||||||
// Unnamed groups are just inlined.
|
// Unnamed groups are just inlined.
|
||||||
if group == "" {
|
if name == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any saved values can no longer be changed.
|
n := len(f.groups)
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
f.groups = append(f.groups[:n:n], groupDef{f.groupName, f.valuesStr})
|
||||||
continuing := false
|
|
||||||
|
|
||||||
if f.parentValuesStr != "" {
|
|
||||||
buf.WriteString(f.parentValuesStr)
|
|
||||||
continuing = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.group != "" && f.valuesStr != "" {
|
|
||||||
if continuing {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
buf.WriteString(f.quoted(f.group, true)) // escape user-provided keys
|
|
||||||
buf.WriteByte(f.colon())
|
|
||||||
buf.WriteByte('{') // for the group
|
|
||||||
continuing = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.valuesStr != "" {
|
|
||||||
if continuing {
|
|
||||||
buf.WriteByte(f.comma())
|
|
||||||
}
|
|
||||||
buf.WriteString(f.valuesStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: We don't close the scope here - that's done later, when a log line
|
|
||||||
// is actually rendered (because we have N scopes to close).
|
|
||||||
|
|
||||||
f.parentValuesStr = buf.String()
|
|
||||||
|
|
||||||
// Start collecting new values.
|
// Start collecting new values.
|
||||||
f.group = group
|
f.groupName = name
|
||||||
f.groupDepth++
|
|
||||||
f.valuesStr = ""
|
f.valuesStr = ""
|
||||||
f.values = nil
|
f.values = nil
|
||||||
}
|
}
|
||||||
|
@ -900,7 +903,7 @@ func (f *Formatter) AddValues(kvList []any) {
|
||||||
|
|
||||||
// Pre-render values, so we don't have to do it on each Info/Error call.
|
// Pre-render values, so we don't have to do it on each Info/Error call.
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||||
f.flatten(buf, vals, false, true) // escape user-provided keys
|
f.flatten(buf, vals, true) // escape user-provided keys
|
||||||
f.valuesStr = buf.String()
|
f.valuesStr = buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06))
|
||||||
|
* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6))
|
||||||
|
|
||||||
|
## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29))
|
||||||
|
|
||||||
|
## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4))
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior)
|
||||||
|
|
||||||
|
## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0))
|
||||||
|
|
||||||
|
## Changelog
|
|
@ -0,0 +1,26 @@
|
||||||
|
# How to contribute
|
||||||
|
|
||||||
|
We definitely welcome patches and contribution to this project!
|
||||||
|
|
||||||
|
### Tips
|
||||||
|
|
||||||
|
Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org).
|
||||||
|
|
||||||
|
Always try to include a test case! If it is not possible or not necessary,
|
||||||
|
please explain why in the pull request description.
|
||||||
|
|
||||||
|
### Releasing
|
||||||
|
|
||||||
|
Commits that would precipitate a SemVer change, as described in the Conventional
|
||||||
|
Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action)
|
||||||
|
to create a release candidate pull request. Once submitted, `release-please`
|
||||||
|
will create a release.
|
||||||
|
|
||||||
|
For tips on how to work with `release-please`, see its documentation.
|
||||||
|
|
||||||
|
### Legal requirements
|
||||||
|
|
||||||
|
In order to protect both you and ourselves, you will need to sign the
|
||||||
|
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||||
|
|
||||||
|
You may have already signed it for other Google projects.
|
|
@ -0,0 +1,9 @@
|
||||||
|
Paul Borman <borman@google.com>
|
||||||
|
bmatsuo
|
||||||
|
shawnps
|
||||||
|
theory
|
||||||
|
jboverfelt
|
||||||
|
dsymonds
|
||||||
|
cd1
|
||||||
|
wallclockbuilder
|
||||||
|
dansouza
|
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009,2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,21 @@
|
||||||
|
# uuid
|
||||||
|
The uuid package generates and inspects UUIDs based on
|
||||||
|
[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)
|
||||||
|
and DCE 1.1: Authentication and Security Services.
|
||||||
|
|
||||||
|
This package is based on the github.com/pborman/uuid package (previously named
|
||||||
|
code.google.com/p/go-uuid). It differs from these earlier packages in that
|
||||||
|
a UUID is a 16 byte array rather than a byte slice. One loss due to this
|
||||||
|
change is the ability to represent an invalid UUID (vs a NIL UUID).
|
||||||
|
|
||||||
|
###### Install
|
||||||
|
```sh
|
||||||
|
go get github.com/google/uuid
|
||||||
|
```
|
||||||
|
|
||||||
|
###### Documentation
|
||||||
|
[![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid)
|
||||||
|
|
||||||
|
Full `go doc` style documentation for the package can be viewed online without
|
||||||
|
installing this package by using the GoDoc site here:
|
||||||
|
http://pkg.go.dev/github.com/google/uuid
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Domain represents a Version 2 domain
|
||||||
|
type Domain byte
|
||||||
|
|
||||||
|
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||||
|
const (
|
||||||
|
Person = Domain(0)
|
||||||
|
Group = Domain(1)
|
||||||
|
Org = Domain(2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||||
|
//
|
||||||
|
// The domain should be one of Person, Group or Org.
|
||||||
|
// On a POSIX system the id should be the users UID for the Person
|
||||||
|
// domain and the users GID for the Group. The meaning of id for
|
||||||
|
// the domain Org or on non-POSIX systems is site defined.
|
||||||
|
//
|
||||||
|
// For a given domain/id pair the same token may be returned for up to
|
||||||
|
// 7 minutes and 10 seconds.
|
||||||
|
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||||
|
uuid, err := NewUUID()
|
||||||
|
if err == nil {
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||||
|
uuid[9] = byte(domain)
|
||||||
|
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||||
|
}
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||||
|
// domain with the id returned by os.Getuid.
|
||||||
|
//
|
||||||
|
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||||
|
func NewDCEPerson() (UUID, error) {
|
||||||
|
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||||
|
// domain with the id returned by os.Getgid.
|
||||||
|
//
|
||||||
|
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||||
|
func NewDCEGroup() (UUID, error) {
|
||||||
|
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain returns the domain for a Version 2 UUID. Domains are only defined
|
||||||
|
// for Version 2 UUIDs.
|
||||||
|
func (uuid UUID) Domain() Domain {
|
||||||
|
return Domain(uuid[9])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
|
||||||
|
// UUIDs.
|
||||||
|
func (uuid UUID) ID() uint32 {
|
||||||
|
return binary.BigEndian.Uint32(uuid[0:4])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Domain) String() string {
|
||||||
|
switch d {
|
||||||
|
case Person:
|
||||||
|
return "Person"
|
||||||
|
case Group:
|
||||||
|
return "Group"
|
||||||
|
case Org:
|
||||||
|
return "Org"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Domain%d", int(d))
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright 2016 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 generates and inspects UUIDs.
|
||||||
|
//
|
||||||
|
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
|
||||||
|
// Services.
|
||||||
|
//
|
||||||
|
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
|
||||||
|
// maps or compared directly.
|
||||||
|
package uuid
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/sha1"
|
||||||
|
"hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Well known namespace IDs and UUIDs
|
||||||
|
var (
|
||||||
|
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
Nil UUID // empty UUID, all zeros
|
||||||
|
|
||||||
|
// The Max UUID is special form of UUID that is specified to have all 128 bits set to 1.
|
||||||
|
Max = UUID{
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewHash returns a new UUID derived from the hash of space concatenated with
|
||||||
|
// data generated by h. The hash should be at least 16 byte in length. The
|
||||||
|
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||||
|
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||||
|
// NewMD5 and NewSHA1.
|
||||||
|
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||||
|
h.Reset()
|
||||||
|
h.Write(space[:]) //nolint:errcheck
|
||||||
|
h.Write(data) //nolint:errcheck
|
||||||
|
s := h.Sum(nil)
|
||||||
|
var uuid UUID
|
||||||
|
copy(uuid[:], s)
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||||
|
// supplied name space and data. It is the same as calling:
|
||||||
|
//
|
||||||
|
// NewHash(md5.New(), space, data, 3)
|
||||||
|
func NewMD5(space UUID, data []byte) UUID {
|
||||||
|
return NewHash(md5.New(), space, data, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||||
|
// supplied name space and data. It is the same as calling:
|
||||||
|
//
|
||||||
|
// NewHash(sha1.New(), space, data, 5)
|
||||||
|
func NewSHA1(space UUID, data []byte) UUID {
|
||||||
|
return NewHash(sha1.New(), space, data, 5)
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2016 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 "fmt"
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
|
func (uuid UUID) MarshalText() ([]byte, error) {
|
||||||
|
var js [36]byte
|
||||||
|
encodeHex(js[:], uuid)
|
||||||
|
return js[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (uuid *UUID) UnmarshalText(data []byte) error {
|
||||||
|
id, err := ParseBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*uuid = id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
|
func (uuid UUID) MarshalBinary() ([]byte, error) {
|
||||||
|
return uuid[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||||
|
func (uuid *UUID) UnmarshalBinary(data []byte) error {
|
||||||
|
if len(data) != 16 {
|
||||||
|
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||||
|
}
|
||||||
|
copy(uuid[:], data)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
nodeMu sync.Mutex
|
||||||
|
ifname string // name of interface being used
|
||||||
|
nodeID [6]byte // hardware for version 1 UUIDs
|
||||||
|
zeroID [6]byte // nodeID with only 0's
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeInterface returns the name of the interface from which the NodeID was
|
||||||
|
// derived. The interface "user" is returned if the NodeID was set by
|
||||||
|
// SetNodeID.
|
||||||
|
func NodeInterface() string {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
return ifname
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||||
|
// If name is "" then the first usable interface found will be used or a random
|
||||||
|
// Node ID will be generated. If a named interface cannot be found then false
|
||||||
|
// is returned.
|
||||||
|
//
|
||||||
|
// SetNodeInterface never fails when name is "".
|
||||||
|
func SetNodeInterface(name string) bool {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
return setNodeInterface(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNodeInterface(name string) bool {
|
||||||
|
iname, addr := getHardwareInterface(name) // null implementation for js
|
||||||
|
if iname != "" && addr != nil {
|
||||||
|
ifname = iname
|
||||||
|
copy(nodeID[:], addr)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found no interfaces with a valid hardware address. If name
|
||||||
|
// does not specify a specific interface generate a random Node ID
|
||||||
|
// (section 4.1.6)
|
||||||
|
if name == "" {
|
||||||
|
ifname = "random"
|
||||||
|
randomBits(nodeID[:])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||||
|
// if not already set.
|
||||||
|
func NodeID() []byte {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
nid := nodeID
|
||||||
|
return nid[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||||
|
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||||
|
// Node ID is not set.
|
||||||
|
func SetNodeID(id []byte) bool {
|
||||||
|
if len(id) < 6 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
copy(nodeID[:], id)
|
||||||
|
ifname = "user"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||||
|
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||||
|
func (uuid UUID) NodeID() []byte {
|
||||||
|
var node [6]byte
|
||||||
|
copy(node[:], uuid[10:])
|
||||||
|
return node[:]
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// +build js
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
// getHardwareInterface returns nil values for the JS version of the code.
|
||||||
|
// This removes the "net" dependency, because it is not used in the browser.
|
||||||
|
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||||
|
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// +build !js
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
var interfaces []net.Interface // cached list of interfaces
|
||||||
|
|
||||||
|
// getHardwareInterface returns the name and hardware address of interface name.
|
||||||
|
// If name is "" then the name and hardware address of one of the system's
|
||||||
|
// interfaces is returned. If no interfaces are found (name does not exist or
|
||||||
|
// there are no interfaces) then "", nil is returned.
|
||||||
|
//
|
||||||
|
// Only addresses of at least 6 bytes are returned.
|
||||||
|
func getHardwareInterface(name string) (string, []byte) {
|
||||||
|
if interfaces == nil {
|
||||||
|
var err error
|
||||||
|
interfaces, err = net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, ifs := range interfaces {
|
||||||
|
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||||
|
return ifs.Name, ifs.HardwareAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scan implements sql.Scanner so UUIDs can be read from databases transparently.
|
||||||
|
// Currently, database types that map to string and []byte are supported. Please
|
||||||
|
// consult database-specific driver documentation for matching types.
|
||||||
|
func (uuid *UUID) Scan(src interface{}) error {
|
||||||
|
switch src := src.(type) {
|
||||||
|
case nil:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case string:
|
||||||
|
// if an empty UUID comes from a table, we return a null UUID
|
||||||
|
if src == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// see Parse for required string format
|
||||||
|
u, err := Parse(src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Scan: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*uuid = u
|
||||||
|
|
||||||
|
case []byte:
|
||||||
|
// if an empty UUID comes from a table, we return a null UUID
|
||||||
|
if len(src) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assumes a simple slice of bytes if 16 bytes
|
||||||
|
// otherwise attempts to parse
|
||||||
|
if len(src) != 16 {
|
||||||
|
return uuid.Scan(string(src))
|
||||||
|
}
|
||||||
|
copy((*uuid)[:], src)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements sql.Valuer so that UUIDs can be written to databases
|
||||||
|
// transparently. Currently, UUIDs map to strings. Please consult
|
||||||
|
// database-specific driver documentation for matching types.
|
||||||
|
func (uuid UUID) Value() (driver.Value, error) {
|
||||||
|
return uuid.String(), nil
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"encoding/binary"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||||
|
// 1582.
|
||||||
|
type Time int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||||
|
unix = 2440587 // Julian day of 1 Jan 1970
|
||||||
|
epoch = unix - lillian // Days between epochs
|
||||||
|
g1582 = epoch * 86400 // seconds between epochs
|
||||||
|
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
timeMu sync.Mutex
|
||||||
|
lasttime uint64 // last time we returned
|
||||||
|
clockSeq uint16 // clock sequence for this run
|
||||||
|
|
||||||
|
timeNow = time.Now // for testing
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||||
|
// epoch of 1 Jan 1970.
|
||||||
|
func (t Time) UnixTime() (sec, nsec int64) {
|
||||||
|
sec = int64(t - g1582ns100)
|
||||||
|
nsec = (sec % 10000000) * 100
|
||||||
|
sec /= 10000000
|
||||||
|
return sec, nsec
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||||
|
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||||
|
// is returned if the current time cannot be determined.
|
||||||
|
func GetTime() (Time, uint16, error) {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
return getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTime() (Time, uint16, error) {
|
||||||
|
t := timeNow()
|
||||||
|
|
||||||
|
// If we don't have a clock sequence already, set one.
|
||||||
|
if clockSeq == 0 {
|
||||||
|
setClockSequence(-1)
|
||||||
|
}
|
||||||
|
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||||
|
|
||||||
|
// If time has gone backwards with this clock sequence then we
|
||||||
|
// increment the clock sequence
|
||||||
|
if now <= lasttime {
|
||||||
|
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
|
||||||
|
}
|
||||||
|
lasttime = now
|
||||||
|
return Time(now), clockSeq, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClockSequence returns the current clock sequence, generating one if not
|
||||||
|
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||||
|
//
|
||||||
|
// The uuid package does not use global static storage for the clock sequence or
|
||||||
|
// the last time a UUID was generated. Unless SetClockSequence is used, a new
|
||||||
|
// random clock sequence is generated the first time a clock sequence is
|
||||||
|
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
|
||||||
|
func ClockSequence() int {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
return clockSequence()
|
||||||
|
}
|
||||||
|
|
||||||
|
func clockSequence() int {
|
||||||
|
if clockSeq == 0 {
|
||||||
|
setClockSequence(-1)
|
||||||
|
}
|
||||||
|
return int(clockSeq & 0x3fff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||||
|
// -1 causes a new sequence to be generated.
|
||||||
|
func SetClockSequence(seq int) {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
setClockSequence(seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setClockSequence(seq int) {
|
||||||
|
if seq == -1 {
|
||||||
|
var b [2]byte
|
||||||
|
randomBits(b[:]) // clock sequence
|
||||||
|
seq = int(b[0])<<8 | int(b[1])
|
||||||
|
}
|
||||||
|
oldSeq := clockSeq
|
||||||
|
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||||
|
if oldSeq != clockSeq {
|
||||||
|
lasttime = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||||
|
// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs.
|
||||||
|
func (uuid UUID) Time() Time {
|
||||||
|
var t Time
|
||||||
|
switch uuid.Version() {
|
||||||
|
case 6:
|
||||||
|
time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110
|
||||||
|
t = Time(time)
|
||||||
|
case 7:
|
||||||
|
time := binary.BigEndian.Uint64(uuid[:8])
|
||||||
|
t = Time((time>>16)*10000 + g1582ns100)
|
||||||
|
default: // forward compatible
|
||||||
|
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||||
|
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||||
|
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||||
|
t = Time(time)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClockSequence returns the clock sequence encoded in uuid.
|
||||||
|
// The clock sequence is only well defined for version 1 and 2 UUIDs.
|
||||||
|
func (uuid UUID) ClockSequence() int {
|
||||||
|
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// randomBits completely fills slice b with random data.
|
||||||
|
func randomBits(b []byte) {
|
||||||
|
if _, err := io.ReadFull(rander, b); err != nil {
|
||||||
|
panic(err.Error()) // rand should never fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||||
|
var xvalues = [256]byte{
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
}
|
||||||
|
|
||||||
|
// xtob converts hex characters x1 and x2 into a byte.
|
||||||
|
func xtob(x1, x2 byte) (byte, bool) {
|
||||||
|
b1 := xvalues[x1]
|
||||||
|
b2 := xvalues[x2]
|
||||||
|
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||||
|
}
|
|
@ -0,0 +1,365 @@
|
||||||
|
// Copyright 2018 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"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||||
|
// 4122.
|
||||||
|
type UUID [16]byte
|
||||||
|
|
||||||
|
// A Version represents a UUID's version.
|
||||||
|
type Version byte
|
||||||
|
|
||||||
|
// A Variant represents a UUID's variant.
|
||||||
|
type Variant byte
|
||||||
|
|
||||||
|
// Constants returned by Variant.
|
||||||
|
const (
|
||||||
|
Invalid = Variant(iota) // Invalid UUID
|
||||||
|
RFC4122 // The variant specified in RFC4122
|
||||||
|
Reserved // Reserved, NCS backward compatibility.
|
||||||
|
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||||
|
Future // Reserved for future definition.
|
||||||
|
)
|
||||||
|
|
||||||
|
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 if it cannot be parsed. Both
|
||||||
|
// the standard UUID forms defined in RFC 4122
|
||||||
|
// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition,
|
||||||
|
// Parse accepts non-standard strings such as the raw hex encoding
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings,
|
||||||
|
// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are
|
||||||
|
// examined in the latter case. Parse should not be used to validate strings as
|
||||||
|
// it parses non-standard encodings as indicated above.
|
||||||
|
func Parse(s string) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
switch len(s) {
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36:
|
||||||
|
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36 + 9:
|
||||||
|
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||||
|
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||||
|
}
|
||||||
|
s = s[9:]
|
||||||
|
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
case 36 + 2:
|
||||||
|
s = s[1:]
|
||||||
|
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
case 32:
|
||||||
|
var ok bool
|
||||||
|
for i := range uuid {
|
||||||
|
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
default:
|
||||||
|
return uuid, invalidLengthError{len(s)}
|
||||||
|
}
|
||||||
|
// s is now at least 36 bytes long
|
||||||
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for i, x := range [16]int{
|
||||||
|
0, 2, 4, 6,
|
||||||
|
9, 11,
|
||||||
|
14, 16,
|
||||||
|
19, 21,
|
||||||
|
24, 26, 28, 30, 32, 34,
|
||||||
|
} {
|
||||||
|
v, ok := xtob(s[x], s[x+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
uuid[i] = v
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||||
|
func ParseBytes(b []byte) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
switch len(b) {
|
||||||
|
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
|
||||||
|
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||||
|
}
|
||||||
|
b = b[9:]
|
||||||
|
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
b = b[1:]
|
||||||
|
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
var ok bool
|
||||||
|
for i := 0; i < 32; i += 2 {
|
||||||
|
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
default:
|
||||||
|
return uuid, invalidLengthError{len(b)}
|
||||||
|
}
|
||||||
|
// s is now at least 36 bytes long
|
||||||
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for i, x := range [16]int{
|
||||||
|
0, 2, 4, 6,
|
||||||
|
9, 11,
|
||||||
|
14, 16,
|
||||||
|
19, 21,
|
||||||
|
24, 26, 28, 30, 32, 34,
|
||||||
|
} {
|
||||||
|
v, ok := xtob(b[x], b[x+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
uuid[i] = v
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||||
|
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||||
|
func MustParse(s string) UUID {
|
||||||
|
uuid, err := Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||||
|
// does not have a length of 16. The bytes are copied from the slice.
|
||||||
|
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||||
|
err = uuid.UnmarshalBinary(b)
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must returns uuid if err is nil and panics otherwise.
|
||||||
|
func Must(uuid UUID, err error) UUID {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate returns an error if s is not a properly formatted UUID in one of the following formats:
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
// It returns an error if the format is invalid, otherwise nil.
|
||||||
|
func Validate(s string) error {
|
||||||
|
switch len(s) {
|
||||||
|
// Standard UUID format
|
||||||
|
case 36:
|
||||||
|
|
||||||
|
// UUID with "urn:uuid:" prefix
|
||||||
|
case 36 + 9:
|
||||||
|
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||||
|
return fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||||
|
}
|
||||||
|
s = s[9:]
|
||||||
|
|
||||||
|
// UUID enclosed in braces
|
||||||
|
case 36 + 2:
|
||||||
|
if s[0] != '{' || s[len(s)-1] != '}' {
|
||||||
|
return fmt.Errorf("invalid bracketed UUID format")
|
||||||
|
}
|
||||||
|
s = s[1 : len(s)-1]
|
||||||
|
|
||||||
|
// UUID without hyphens
|
||||||
|
case 32:
|
||||||
|
for i := 0; i < len(s); i += 2 {
|
||||||
|
_, ok := xtob(s[i], s[i+1])
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return invalidLengthError{len(s)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for standard UUID format
|
||||||
|
if len(s) == 36 {
|
||||||
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} {
|
||||||
|
if _, ok := xtob(s[x], s[x+1]); !ok {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// , or "" if uuid is invalid.
|
||||||
|
func (uuid UUID) String() string {
|
||||||
|
var buf [36]byte
|
||||||
|
encodeHex(buf[:], uuid)
|
||||||
|
return string(buf[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// URN returns the RFC 2141 URN form of uuid,
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||||
|
func (uuid UUID) URN() string {
|
||||||
|
var buf [36 + 9]byte
|
||||||
|
copy(buf[:], "urn:uuid:")
|
||||||
|
encodeHex(buf[9:], uuid)
|
||||||
|
return string(buf[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeHex(dst []byte, uuid UUID) {
|
||||||
|
hex.Encode(dst, uuid[:4])
|
||||||
|
dst[8] = '-'
|
||||||
|
hex.Encode(dst[9:13], uuid[4:6])
|
||||||
|
dst[13] = '-'
|
||||||
|
hex.Encode(dst[14:18], uuid[6:8])
|
||||||
|
dst[18] = '-'
|
||||||
|
hex.Encode(dst[19:23], uuid[8:10])
|
||||||
|
dst[23] = '-'
|
||||||
|
hex.Encode(dst[24:], uuid[10:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variant returns the variant encoded in uuid.
|
||||||
|
func (uuid UUID) Variant() Variant {
|
||||||
|
switch {
|
||||||
|
case (uuid[8] & 0xc0) == 0x80:
|
||||||
|
return RFC4122
|
||||||
|
case (uuid[8] & 0xe0) == 0xc0:
|
||||||
|
return Microsoft
|
||||||
|
case (uuid[8] & 0xe0) == 0xe0:
|
||||||
|
return Future
|
||||||
|
default:
|
||||||
|
return Reserved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns the version of uuid.
|
||||||
|
func (uuid UUID) Version() Version {
|
||||||
|
return Version(uuid[6] >> 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Version) String() string {
|
||||||
|
if v > 15 {
|
||||||
|
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("VERSION_%d", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Variant) String() string {
|
||||||
|
switch v {
|
||||||
|
case RFC4122:
|
||||||
|
return "RFC4122"
|
||||||
|
case Reserved:
|
||||||
|
return "Reserved"
|
||||||
|
case Microsoft:
|
||||||
|
return "Microsoft"
|
||||||
|
case Future:
|
||||||
|
return "Future"
|
||||||
|
case Invalid:
|
||||||
|
return "Invalid"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("BadVariant%d", int(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||||
|
// If r.Read returns an error when the package requests random data then
|
||||||
|
// a panic will be issued.
|
||||||
|
//
|
||||||
|
// Calling SetRand with nil sets the random number generator to the default
|
||||||
|
// generator.
|
||||||
|
func SetRand(r io.Reader) {
|
||||||
|
if r == nil {
|
||||||
|
rander = rand.Reader
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// UUIDs is a slice of UUID types.
|
||||||
|
type UUIDs []UUID
|
||||||
|
|
||||||
|
// Strings returns a string slice containing the string form of each UUID in uuids.
|
||||||
|
func (uuids UUIDs) Strings() []string {
|
||||||
|
var uuidStrs = make([]string, len(uuids))
|
||||||
|
for i, uuid := range uuids {
|
||||||
|
uuidStrs[i] = uuid.String()
|
||||||
|
}
|
||||||
|
return uuidStrs
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||||
|
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||||
|
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||||
|
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||||
|
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||||
|
// return the current NewUUID returns nil and an error.
|
||||||
|
//
|
||||||
|
// In most cases, New should be used.
|
||||||
|
func NewUUID() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
now, seq, err := GetTime()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
timeLow := uint32(now & 0xffffffff)
|
||||||
|
timeMid := uint16((now >> 32) & 0xffff)
|
||||||
|
timeHi := uint16((now >> 48) & 0x0fff)
|
||||||
|
timeHi |= 0x1000 // Version 1
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(uuid[0:], timeLow)
|
||||||
|
binary.BigEndian.PutUint16(uuid[4:], timeMid)
|
||||||
|
binary.BigEndian.PutUint16(uuid[6:], timeHi)
|
||||||
|
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||||
|
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
copy(uuid[10:], nodeID[:])
|
||||||
|
nodeMu.Unlock()
|
||||||
|
|
||||||
|
return uuid, nil
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright 2016 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 "io"
|
||||||
|
|
||||||
|
// New creates a new random UUID or panics. New is equivalent to
|
||||||
|
// the expression
|
||||||
|
//
|
||||||
|
// uuid.Must(uuid.NewRandom())
|
||||||
|
func New() UUID {
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||||
|
// package.
|
||||||
|
//
|
||||||
|
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||||
|
//
|
||||||
|
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||||
|
//
|
||||||
|
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||||
|
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||||
|
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||||
|
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||||
|
// year and having one duplicate.
|
||||||
|
func NewRandom() (UUID, error) {
|
||||||
|
if !poolEnabled {
|
||||||
|
return NewRandomFromReader(rander)
|
||||||
|
}
|
||||||
|
return newRandomFromPool()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
|
||||||
|
func NewRandomFromReader(r io.Reader) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
_, err := io.ReadFull(r, uuid[:])
|
||||||
|
if err != nil {
|
||||||
|
return Nil, err
|
||||||
|
}
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2023 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 "encoding/binary"
|
||||||
|
|
||||||
|
// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality.
|
||||||
|
// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs.
|
||||||
|
// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.
|
||||||
|
//
|
||||||
|
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6
|
||||||
|
//
|
||||||
|
// NewV6 returns a Version 6 UUID based on the current NodeID and clock
|
||||||
|
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||||
|
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||||
|
// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by
|
||||||
|
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||||
|
// return the current NewV6 returns Nil and an error.
|
||||||
|
func NewV6() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
now, seq, err := GetTime()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| time_high |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| time_mid | time_low_and_version |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|clk_seq_hi_res | clk_seq_low | node (0-1) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| node (2-5) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint64(uuid[0:], uint64(now))
|
||||||
|
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||||
|
|
||||||
|
uuid[6] = 0x60 | (uuid[6] & 0x0F)
|
||||||
|
uuid[8] = 0x80 | (uuid[8] & 0x3F)
|
||||||
|
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
copy(uuid[10:], nodeID[:])
|
||||||
|
nodeMu.Unlock()
|
||||||
|
|
||||||
|
return uuid, nil
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright 2023 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 (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UUID version 7 features a time-ordered value field derived from the widely
|
||||||
|
// implemented and well known Unix Epoch timestamp source,
|
||||||
|
// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded.
|
||||||
|
// As well as improved entropy characteristics over versions 1 or 6.
|
||||||
|
//
|
||||||
|
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7
|
||||||
|
//
|
||||||
|
// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible.
|
||||||
|
//
|
||||||
|
// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch).
|
||||||
|
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||||
|
// On error, NewV7 returns Nil and an error
|
||||||
|
func NewV7() (UUID, error) {
|
||||||
|
uuid, err := NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
makeV7(uuid[:])
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch).
|
||||||
|
// it use NewRandomFromReader fill random bits.
|
||||||
|
// On error, NewV7FromReader returns Nil and an error.
|
||||||
|
func NewV7FromReader(r io.Reader) (UUID, error) {
|
||||||
|
uuid, err := NewRandomFromReader(r)
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
makeV7(uuid[:])
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6])
|
||||||
|
// uuid[8] already has the right version number (Variant is 10)
|
||||||
|
// see function NewV7 and NewV7FromReader
|
||||||
|
func makeV7(uuid []byte) {
|
||||||
|
/*
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| unix_ts_ms |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| unix_ts_ms | ver | rand_a (12 bit seq) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|var| rand_b |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| rand_b |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
_ = uuid[15] // bounds check
|
||||||
|
|
||||||
|
t, s := getV7Time()
|
||||||
|
|
||||||
|
uuid[0] = byte(t >> 40)
|
||||||
|
uuid[1] = byte(t >> 32)
|
||||||
|
uuid[2] = byte(t >> 24)
|
||||||
|
uuid[3] = byte(t >> 16)
|
||||||
|
uuid[4] = byte(t >> 8)
|
||||||
|
uuid[5] = byte(t)
|
||||||
|
|
||||||
|
uuid[6] = 0x70 | (0x0F & byte(s>>8))
|
||||||
|
uuid[7] = byte(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lastV7time is the last time we returned stored as:
|
||||||
|
//
|
||||||
|
// 52 bits of time in milliseconds since epoch
|
||||||
|
// 12 bits of (fractional nanoseconds) >> 8
|
||||||
|
var lastV7time int64
|
||||||
|
|
||||||
|
const nanoPerMilli = 1000000
|
||||||
|
|
||||||
|
// getV7Time returns the time in milliseconds and nanoseconds / 256.
|
||||||
|
// The returned (milli << 12 + seq) is guarenteed to be greater than
|
||||||
|
// (milli << 12 + seq) returned by any previous call to getV7Time.
|
||||||
|
func getV7Time() (milli, seq int64) {
|
||||||
|
timeMu.Lock()
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
|
||||||
|
nano := timeNow().UnixNano()
|
||||||
|
milli = nano / nanoPerMilli
|
||||||
|
// Sequence number is between 0 and 3906 (nanoPerMilli>>8)
|
||||||
|
seq = (nano - milli*nanoPerMilli) >> 8
|
||||||
|
now := milli<<12 + seq
|
||||||
|
if now <= lastV7time {
|
||||||
|
now = lastV7time + 1
|
||||||
|
milli = now >> 12
|
||||||
|
seq = now & 0xfff
|
||||||
|
}
|
||||||
|
lastV7time = now
|
||||||
|
return milli, seq
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ go_test(
|
||||||
embed = [":httprule"],
|
embed = [":httprule"],
|
||||||
deps = [
|
deps = [
|
||||||
"//utilities",
|
"//utilities",
|
||||||
"@com_github_golang_glog//:glog",
|
"@org_golang_google_grpc//grpclog",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ go_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/httprule",
|
"//internal/httprule",
|
||||||
"//utilities",
|
"//utilities",
|
||||||
"@go_googleapis//google/api:httpbody_go_proto",
|
"@org_golang_google_genproto_googleapis_api//httpbody",
|
||||||
"@org_golang_google_grpc//codes",
|
"@org_golang_google_grpc//codes",
|
||||||
"@org_golang_google_grpc//grpclog",
|
"@org_golang_google_grpc//grpclog",
|
||||||
"@org_golang_google_grpc//health/grpc_health_v1",
|
"@org_golang_google_grpc//health/grpc_health_v1",
|
||||||
|
@ -70,9 +70,9 @@ go_test(
|
||||||
"//utilities",
|
"//utilities",
|
||||||
"@com_github_google_go_cmp//cmp",
|
"@com_github_google_go_cmp//cmp",
|
||||||
"@com_github_google_go_cmp//cmp/cmpopts",
|
"@com_github_google_go_cmp//cmp/cmpopts",
|
||||||
"@go_googleapis//google/api:httpbody_go_proto",
|
"@org_golang_google_genproto_googleapis_api//httpbody",
|
||||||
"@go_googleapis//google/rpc:errdetails_go_proto",
|
"@org_golang_google_genproto_googleapis_rpc//errdetails",
|
||||||
"@go_googleapis//google/rpc:status_go_proto",
|
"@org_golang_google_genproto_googleapis_rpc//status",
|
||||||
"@org_golang_google_grpc//:go_default_library",
|
"@org_golang_google_grpc//:go_default_library",
|
||||||
"@org_golang_google_grpc//codes",
|
"@org_golang_google_grpc//codes",
|
||||||
"@org_golang_google_grpc//health/grpc_health_v1",
|
"@org_golang_google_grpc//health/grpc_health_v1",
|
||||||
|
|
|
@ -148,6 +148,12 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM
|
||||||
var pairs []string
|
var pairs []string
|
||||||
for key, vals := range req.Header {
|
for key, vals := range req.Header {
|
||||||
key = textproto.CanonicalMIMEHeaderKey(key)
|
key = textproto.CanonicalMIMEHeaderKey(key)
|
||||||
|
switch key {
|
||||||
|
case xForwardedFor, xForwardedHost:
|
||||||
|
// Handled separately below
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
// For backwards-compatibility, pass through 'authorization' header with no prefix.
|
// For backwards-compatibility, pass through 'authorization' header with no prefix.
|
||||||
if key == "Authorization" {
|
if key == "Authorization" {
|
||||||
|
@ -181,18 +187,17 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM
|
||||||
pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host)
|
pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xff := req.Header.Values(xForwardedFor)
|
||||||
if addr := req.RemoteAddr; addr != "" {
|
if addr := req.RemoteAddr; addr != "" {
|
||||||
if remoteIP, _, err := net.SplitHostPort(addr); err == nil {
|
if remoteIP, _, err := net.SplitHostPort(addr); err == nil {
|
||||||
if fwd := req.Header.Get(xForwardedFor); fwd == "" {
|
xff = append(xff, remoteIP)
|
||||||
pairs = append(pairs, strings.ToLower(xForwardedFor), remoteIP)
|
|
||||||
} else {
|
|
||||||
pairs = append(pairs, strings.ToLower(xForwardedFor), fmt.Sprintf("%s, %s", fwd, remoteIP))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(xff) > 0 {
|
||||||
|
pairs = append(pairs, strings.ToLower(xForwardedFor), strings.Join(xff, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
if timeout != 0 {
|
if timeout != 0 {
|
||||||
//nolint:govet // The context outlives this function
|
|
||||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
ctx, _ = context.WithTimeout(ctx, timeout)
|
||||||
}
|
}
|
||||||
if len(pairs) == 0 {
|
if len(pairs) == 0 {
|
||||||
|
|
|
@ -71,7 +71,7 @@ func HTTPStatusFromCode(code codes.Code) int {
|
||||||
case codes.DataLoss:
|
case codes.DataLoss:
|
||||||
return http.StatusInternalServerError
|
return http.StatusInternalServerError
|
||||||
default:
|
default:
|
||||||
grpclog.Infof("Unknown gRPC error code: %v", code)
|
grpclog.Warningf("Unknown gRPC error code: %v", code)
|
||||||
return http.StatusInternalServerError
|
return http.StatusInternalServerError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,17 +114,17 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh
|
||||||
|
|
||||||
buf, merr := marshaler.Marshal(pb)
|
buf, merr := marshaler.Marshal(pb)
|
||||||
if merr != nil {
|
if merr != nil {
|
||||||
grpclog.Infof("Failed to marshal error message %q: %v", s, merr)
|
grpclog.Errorf("Failed to marshal error message %q: %v", s, merr)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
if _, err := io.WriteString(w, fallback); err != nil {
|
if _, err := io.WriteString(w, fallback); err != nil {
|
||||||
grpclog.Infof("Failed to write response: %v", err)
|
grpclog.Errorf("Failed to write response: %v", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
md, ok := ServerMetadataFromContext(ctx)
|
md, ok := ServerMetadataFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
grpclog.Infof("Failed to extract ServerMetadata from context")
|
grpclog.Error("Failed to extract ServerMetadata from context")
|
||||||
}
|
}
|
||||||
|
|
||||||
handleForwardResponseServerMetadata(w, mux, md)
|
handleForwardResponseServerMetadata(w, mux, md)
|
||||||
|
@ -137,7 +137,7 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh
|
||||||
doForwardTrailers := requestAcceptsTrailers(r)
|
doForwardTrailers := requestAcceptsTrailers(r)
|
||||||
|
|
||||||
if doForwardTrailers {
|
if doForwardTrailers {
|
||||||
handleForwardResponseTrailerHeader(w, md)
|
handleForwardResponseTrailerHeader(w, mux, md)
|
||||||
w.Header().Set("Transfer-Encoding", "chunked")
|
w.Header().Set("Transfer-Encoding", "chunked")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,11 +148,11 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh
|
||||||
|
|
||||||
w.WriteHeader(st)
|
w.WriteHeader(st)
|
||||||
if _, err := w.Write(buf); err != nil {
|
if _, err := w.Write(buf); err != nil {
|
||||||
grpclog.Infof("Failed to write response: %v", err)
|
grpclog.Errorf("Failed to write response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if doForwardTrailers {
|
if doForwardTrailers {
|
||||||
handleForwardResponseTrailer(w, md)
|
handleForwardResponseTrailer(w, mux, md)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field
|
||||||
var root interface{}
|
var root interface{}
|
||||||
|
|
||||||
if err := json.NewDecoder(r).Decode(&root); err != nil {
|
if err := json.NewDecoder(r).Decode(&root); err != nil {
|
||||||
if err == io.EOF {
|
if errors.Is(err, io.EOF) {
|
||||||
return fm, nil
|
return fm, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -41,7 +41,7 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field
|
||||||
|
|
||||||
m, ok := item.node.(map[string]interface{})
|
m, ok := item.node.(map[string]interface{})
|
||||||
switch {
|
switch {
|
||||||
case ok:
|
case ok && len(m) > 0:
|
||||||
// if the item is an object, then enqueue all of its children
|
// if the item is an object, then enqueue all of its children
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
if item.msg == nil {
|
if item.msg == nil {
|
||||||
|
@ -96,6 +96,8 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field
|
||||||
queue = append(queue, child)
|
queue = append(queue, child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case ok && len(m) == 0:
|
||||||
|
fallthrough
|
||||||
case len(item.path) > 0:
|
case len(item.path) > 0:
|
||||||
// otherwise, it's a leaf node so print its path
|
// otherwise, it's a leaf node so print its path
|
||||||
fm.Paths = append(fm.Paths, item.path)
|
fm.Paths = append(fm.Paths, item.path)
|
||||||
|
|
|
@ -2,10 +2,11 @@ package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"google.golang.org/genproto/googleapis/api/httpbody"
|
"google.golang.org/genproto/googleapis/api/httpbody"
|
||||||
|
@ -17,16 +18,10 @@ import (
|
||||||
|
|
||||||
// ForwardResponseStream forwards the stream from gRPC server to REST client.
|
// ForwardResponseStream forwards the stream from gRPC server to REST client.
|
||||||
func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
|
func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
|
||||||
f, ok := w.(http.Flusher)
|
rc := http.NewResponseController(w)
|
||||||
if !ok {
|
|
||||||
grpclog.Infof("Flush not supported in %T", w)
|
|
||||||
http.Error(w, "unexpected type of web server", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
md, ok := ServerMetadataFromContext(ctx)
|
md, ok := ServerMetadataFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
grpclog.Infof("Failed to extract ServerMetadata from context")
|
grpclog.Error("Failed to extract ServerMetadata from context")
|
||||||
http.Error(w, "unexpected error", http.StatusInternalServerError)
|
http.Error(w, "unexpected error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -48,7 +43,7 @@ func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshal
|
||||||
var wroteHeader bool
|
var wroteHeader bool
|
||||||
for {
|
for {
|
||||||
resp, err := recv()
|
resp, err := recv()
|
||||||
if err == io.EOF {
|
if errors.Is(err, io.EOF) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -81,20 +76,29 @@ func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshal
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
grpclog.Infof("Failed to marshal response chunk: %v", err)
|
grpclog.Errorf("Failed to marshal response chunk: %v", err)
|
||||||
handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err, delimiter)
|
handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err, delimiter)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, err := w.Write(buf); err != nil {
|
if _, err := w.Write(buf); err != nil {
|
||||||
grpclog.Infof("Failed to send response chunk: %v", err)
|
grpclog.Errorf("Failed to send response chunk: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wroteHeader = true
|
wroteHeader = true
|
||||||
if _, err := w.Write(delimiter); err != nil {
|
if _, err := w.Write(delimiter); err != nil {
|
||||||
grpclog.Infof("Failed to send delimiter chunk: %v", err)
|
grpclog.Errorf("Failed to send delimiter chunk: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = rc.Flush()
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, http.ErrNotSupported) {
|
||||||
|
grpclog.Errorf("Flush not supported in %T", w)
|
||||||
|
http.Error(w, "unexpected type of web server", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
grpclog.Errorf("Failed to flush response to client: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.Flush()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,18 +112,20 @@ func handleForwardResponseServerMetadata(w http.ResponseWriter, mux *ServeMux, m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleForwardResponseTrailerHeader(w http.ResponseWriter, md ServerMetadata) {
|
func handleForwardResponseTrailerHeader(w http.ResponseWriter, mux *ServeMux, md ServerMetadata) {
|
||||||
for k := range md.TrailerMD {
|
for k := range md.TrailerMD {
|
||||||
tKey := textproto.CanonicalMIMEHeaderKey(fmt.Sprintf("%s%s", MetadataTrailerPrefix, k))
|
if h, ok := mux.outgoingTrailerMatcher(k); ok {
|
||||||
w.Header().Add("Trailer", tKey)
|
w.Header().Add("Trailer", textproto.CanonicalMIMEHeaderKey(h))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleForwardResponseTrailer(w http.ResponseWriter, md ServerMetadata) {
|
func handleForwardResponseTrailer(w http.ResponseWriter, mux *ServeMux, md ServerMetadata) {
|
||||||
for k, vs := range md.TrailerMD {
|
for k, vs := range md.TrailerMD {
|
||||||
tKey := fmt.Sprintf("%s%s", MetadataTrailerPrefix, k)
|
if h, ok := mux.outgoingTrailerMatcher(k); ok {
|
||||||
for _, v := range vs {
|
for _, v := range vs {
|
||||||
w.Header().Add(tKey, v)
|
w.Header().Add(h, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +140,7 @@ type responseBody interface {
|
||||||
func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
|
func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
|
||||||
md, ok := ServerMetadataFromContext(ctx)
|
md, ok := ServerMetadataFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
grpclog.Infof("Failed to extract ServerMetadata from context")
|
grpclog.Error("Failed to extract ServerMetadata from context")
|
||||||
}
|
}
|
||||||
|
|
||||||
handleForwardResponseServerMetadata(w, mux, md)
|
handleForwardResponseServerMetadata(w, mux, md)
|
||||||
|
@ -147,12 +153,10 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha
|
||||||
doForwardTrailers := requestAcceptsTrailers(req)
|
doForwardTrailers := requestAcceptsTrailers(req)
|
||||||
|
|
||||||
if doForwardTrailers {
|
if doForwardTrailers {
|
||||||
handleForwardResponseTrailerHeader(w, md)
|
handleForwardResponseTrailerHeader(w, mux, md)
|
||||||
w.Header().Set("Transfer-Encoding", "chunked")
|
w.Header().Set("Transfer-Encoding", "chunked")
|
||||||
}
|
}
|
||||||
|
|
||||||
handleForwardResponseTrailerHeader(w, md)
|
|
||||||
|
|
||||||
contentType := marshaler.ContentType(resp)
|
contentType := marshaler.ContentType(resp)
|
||||||
w.Header().Set("Content-Type", contentType)
|
w.Header().Set("Content-Type", contentType)
|
||||||
|
|
||||||
|
@ -168,17 +172,21 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha
|
||||||
buf, err = marshaler.Marshal(resp)
|
buf, err = marshaler.Marshal(resp)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
grpclog.Infof("Marshal error: %v", err)
|
grpclog.Errorf("Marshal error: %v", err)
|
||||||
HTTPError(ctx, mux, marshaler, w, req, err)
|
HTTPError(ctx, mux, marshaler, w, req, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !doForwardTrailers {
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(len(buf)))
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = w.Write(buf); err != nil {
|
if _, err = w.Write(buf); err != nil {
|
||||||
grpclog.Infof("Failed to write response: %v", err)
|
grpclog.Errorf("Failed to write response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if doForwardTrailers {
|
if doForwardTrailers {
|
||||||
handleForwardResponseTrailer(w, md)
|
handleForwardResponseTrailer(w, mux, md)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +201,7 @@ func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, re
|
||||||
}
|
}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
if err := opt(ctx, w, resp); err != nil {
|
if err := opt(ctx, w, resp); err != nil {
|
||||||
grpclog.Infof("Error handling ForwardResponseOptions: %v", err)
|
grpclog.Errorf("Error handling ForwardResponseOptions: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,15 +217,15 @@ func handleForwardResponseStreamError(ctx context.Context, wroteHeader bool, mar
|
||||||
}
|
}
|
||||||
buf, err := marshaler.Marshal(msg)
|
buf, err := marshaler.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
grpclog.Infof("Failed to marshal an error: %v", err)
|
grpclog.Errorf("Failed to marshal an error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, err := w.Write(buf); err != nil {
|
if _, err := w.Write(buf); err != nil {
|
||||||
grpclog.Infof("Failed to notify error to client: %v", err)
|
grpclog.Errorf("Failed to notify error to client: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, err := w.Write(delimiter); err != nil {
|
if _, err := w.Write(delimiter); err != nil {
|
||||||
grpclog.Infof("Failed to send delimiter chunk: %v", err)
|
grpclog.Errorf("Failed to send delimiter chunk: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_httpbodyproto.go
generated
vendored
2
vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_httpbodyproto.go
generated
vendored
|
@ -26,7 +26,7 @@ func (h *HTTPBodyMarshaler) ContentType(v interface{}) string {
|
||||||
// google.api.HttpBody message, otherwise it falls back to the default Marshaler.
|
// google.api.HttpBody message, otherwise it falls back to the default Marshaler.
|
||||||
func (h *HTTPBodyMarshaler) Marshal(v interface{}) ([]byte, error) {
|
func (h *HTTPBodyMarshaler) Marshal(v interface{}) ([]byte, error) {
|
||||||
if httpBody, ok := v.(*httpbody.HttpBody); ok {
|
if httpBody, ok := v.(*httpbody.HttpBody); ok {
|
||||||
return httpBody.Data, nil
|
return httpBody.GetData(), nil
|
||||||
}
|
}
|
||||||
return h.Marshaler.Marshal(v)
|
return h.Marshaler.Marshal(v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,11 @@ func (j *JSONBuiltin) Marshal(v interface{}) ([]byte, error) {
|
||||||
return json.Marshal(v)
|
return json.Marshal(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalIndent is like Marshal but applies Indent to format the output
|
||||||
|
func (j *JSONBuiltin) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
|
||||||
|
return json.MarshalIndent(v, prefix, indent)
|
||||||
|
}
|
||||||
|
|
||||||
// Unmarshal unmarshals JSON data into "v".
|
// Unmarshal unmarshals JSON data into "v".
|
||||||
func (j *JSONBuiltin) Unmarshal(data []byte, v interface{}) error {
|
func (j *JSONBuiltin) Unmarshal(data []byte, v interface{}) error {
|
||||||
return json.Unmarshal(data, v)
|
return json.Unmarshal(data, v)
|
||||||
|
|
|
@ -30,10 +30,6 @@ func (*JSONPb) ContentType(_ interface{}) string {
|
||||||
|
|
||||||
// Marshal marshals "v" into JSON.
|
// Marshal marshals "v" into JSON.
|
||||||
func (j *JSONPb) Marshal(v interface{}) ([]byte, error) {
|
func (j *JSONPb) Marshal(v interface{}) ([]byte, error) {
|
||||||
if _, ok := v.(proto.Message); !ok {
|
|
||||||
return j.marshalNonProtoField(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := j.marshalTo(&buf, v); err != nil {
|
if err := j.marshalTo(&buf, v); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -48,9 +44,17 @@ func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if j.Indent != "" {
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
if err := json.Indent(b, buf, "", j.Indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buf = b.Bytes()
|
||||||
|
}
|
||||||
_, err = w.Write(buf)
|
_, err = w.Write(buf)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := j.MarshalOptions.Marshal(p)
|
b, err := j.MarshalOptions.Marshal(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -150,9 +154,6 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
|
||||||
}
|
}
|
||||||
m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
|
m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
|
||||||
}
|
}
|
||||||
if j.Indent != "" {
|
|
||||||
return json.MarshalIndent(m, "", j.Indent)
|
|
||||||
}
|
|
||||||
return json.Marshal(m)
|
return json.Marshal(m)
|
||||||
}
|
}
|
||||||
if enum, ok := rv.Interface().(protoEnum); ok && !j.UseEnumNumbers {
|
if enum, ok := rv.Interface().(protoEnum); ok && !j.UseEnumNumbers {
|
||||||
|
|
|
@ -46,7 +46,7 @@ func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, out
|
||||||
for _, contentTypeVal := range r.Header[contentTypeHeader] {
|
for _, contentTypeVal := range r.Header[contentTypeHeader] {
|
||||||
contentType, _, err := mime.ParseMediaType(contentTypeVal)
|
contentType, _, err := mime.ParseMediaType(contentTypeVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
grpclog.Infof("Failed to parse Content-Type %s: %v", contentTypeVal, err)
|
grpclog.Errorf("Failed to parse Content-Type %s: %v", contentTypeVal, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if m, ok := mux.marshalers.mimeMap[contentType]; ok {
|
if m, ok := mux.marshalers.mimeMap[contentType]; ok {
|
||||||
|
|
|
@ -57,6 +57,7 @@ type ServeMux struct {
|
||||||
marshalers marshalerRegistry
|
marshalers marshalerRegistry
|
||||||
incomingHeaderMatcher HeaderMatcherFunc
|
incomingHeaderMatcher HeaderMatcherFunc
|
||||||
outgoingHeaderMatcher HeaderMatcherFunc
|
outgoingHeaderMatcher HeaderMatcherFunc
|
||||||
|
outgoingTrailerMatcher HeaderMatcherFunc
|
||||||
metadataAnnotators []func(context.Context, *http.Request) metadata.MD
|
metadataAnnotators []func(context.Context, *http.Request) metadata.MD
|
||||||
errorHandler ErrorHandlerFunc
|
errorHandler ErrorHandlerFunc
|
||||||
streamErrorHandler StreamErrorHandlerFunc
|
streamErrorHandler StreamErrorHandlerFunc
|
||||||
|
@ -114,10 +115,18 @@ func DefaultHeaderMatcher(key string) (string, bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func defaultOutgoingHeaderMatcher(key string) (string, bool) {
|
||||||
|
return fmt.Sprintf("%s%s", MetadataHeaderPrefix, key), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultOutgoingTrailerMatcher(key string) (string, bool) {
|
||||||
|
return fmt.Sprintf("%s%s", MetadataTrailerPrefix, key), true
|
||||||
|
}
|
||||||
|
|
||||||
// WithIncomingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for incoming request to gateway.
|
// WithIncomingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for incoming request to gateway.
|
||||||
//
|
//
|
||||||
// This matcher will be called with each header in http.Request. If matcher returns true, that header will be
|
// This matcher will be called with each header in http.Request. If matcher returns true, that header will be
|
||||||
// passed to gRPC context. To transform the header before passing to gRPC context, matcher should return modified header.
|
// passed to gRPC context. To transform the header before passing to gRPC context, matcher should return the modified header.
|
||||||
func WithIncomingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption {
|
func WithIncomingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption {
|
||||||
for _, header := range fn.matchedMalformedHeaders() {
|
for _, header := range fn.matchedMalformedHeaders() {
|
||||||
grpclog.Warningf("The configured forwarding filter would allow %q to be sent to the gRPC server, which will likely cause errors. See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more information.", header)
|
grpclog.Warningf("The configured forwarding filter would allow %q to be sent to the gRPC server, which will likely cause errors. See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more information.", header)
|
||||||
|
@ -147,13 +156,24 @@ func (fn HeaderMatcherFunc) matchedMalformedHeaders() []string {
|
||||||
//
|
//
|
||||||
// This matcher will be called with each header in response header metadata. If matcher returns true, that header will be
|
// This matcher will be called with each header in response header metadata. If matcher returns true, that header will be
|
||||||
// passed to http response returned from gateway. To transform the header before passing to response,
|
// passed to http response returned from gateway. To transform the header before passing to response,
|
||||||
// matcher should return modified header.
|
// matcher should return the modified header.
|
||||||
func WithOutgoingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption {
|
func WithOutgoingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption {
|
||||||
return func(mux *ServeMux) {
|
return func(mux *ServeMux) {
|
||||||
mux.outgoingHeaderMatcher = fn
|
mux.outgoingHeaderMatcher = fn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithOutgoingTrailerMatcher returns a ServeMuxOption representing a headerMatcher for outgoing response from gateway.
|
||||||
|
//
|
||||||
|
// This matcher will be called with each header in response trailer metadata. If matcher returns true, that header will be
|
||||||
|
// passed to http response returned from gateway. To transform the header before passing to response,
|
||||||
|
// matcher should return the modified header.
|
||||||
|
func WithOutgoingTrailerMatcher(fn HeaderMatcherFunc) ServeMuxOption {
|
||||||
|
return func(mux *ServeMux) {
|
||||||
|
mux.outgoingTrailerMatcher = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithMetadata returns a ServeMuxOption for passing metadata to a gRPC context.
|
// WithMetadata returns a ServeMuxOption for passing metadata to a gRPC context.
|
||||||
//
|
//
|
||||||
// This can be used by services that need to read from http.Request and modify gRPC context. A common use case
|
// This can be used by services that need to read from http.Request and modify gRPC context. A common use case
|
||||||
|
@ -273,11 +293,11 @@ func NewServeMux(opts ...ServeMuxOption) *ServeMux {
|
||||||
if serveMux.incomingHeaderMatcher == nil {
|
if serveMux.incomingHeaderMatcher == nil {
|
||||||
serveMux.incomingHeaderMatcher = DefaultHeaderMatcher
|
serveMux.incomingHeaderMatcher = DefaultHeaderMatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
if serveMux.outgoingHeaderMatcher == nil {
|
if serveMux.outgoingHeaderMatcher == nil {
|
||||||
serveMux.outgoingHeaderMatcher = func(key string) (string, bool) {
|
serveMux.outgoingHeaderMatcher = defaultOutgoingHeaderMatcher
|
||||||
return fmt.Sprintf("%s%s", MetadataHeaderPrefix, key), true
|
}
|
||||||
}
|
if serveMux.outgoingTrailerMatcher == nil {
|
||||||
|
serveMux.outgoingTrailerMatcher = defaultOutgoingTrailerMatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
return serveMux
|
return serveMux
|
||||||
|
@ -321,13 +341,13 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) {
|
if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) {
|
||||||
r.Method = strings.ToUpper(override)
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
_, outboundMarshaler := MarshalerForRequest(s, r)
|
_, outboundMarshaler := MarshalerForRequest(s, r)
|
||||||
sterr := status.Error(codes.InvalidArgument, err.Error())
|
sterr := status.Error(codes.InvalidArgument, err.Error())
|
||||||
s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr)
|
s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
r.Method = strings.ToUpper(override)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pathComponents []string
|
var pathComponents []string
|
||||||
|
|
|
@ -52,13 +52,13 @@ type Pattern struct {
|
||||||
// It returns an error if the given definition is invalid.
|
// It returns an error if the given definition is invalid.
|
||||||
func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, error) {
|
func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, error) {
|
||||||
if version != 1 {
|
if version != 1 {
|
||||||
grpclog.Infof("unsupported version: %d", version)
|
grpclog.Errorf("unsupported version: %d", version)
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
|
|
||||||
l := len(ops)
|
l := len(ops)
|
||||||
if l%2 != 0 {
|
if l%2 != 0 {
|
||||||
grpclog.Infof("odd number of ops codes: %d", l)
|
grpclog.Errorf("odd number of ops codes: %d", l)
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,14 +81,14 @@ func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, er
|
||||||
stack++
|
stack++
|
||||||
case utilities.OpPushM:
|
case utilities.OpPushM:
|
||||||
if pushMSeen {
|
if pushMSeen {
|
||||||
grpclog.Infof("pushM appears twice")
|
grpclog.Error("pushM appears twice")
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
pushMSeen = true
|
pushMSeen = true
|
||||||
stack++
|
stack++
|
||||||
case utilities.OpLitPush:
|
case utilities.OpLitPush:
|
||||||
if op.operand < 0 || len(pool) <= op.operand {
|
if op.operand < 0 || len(pool) <= op.operand {
|
||||||
grpclog.Infof("negative literal index: %d", op.operand)
|
grpclog.Errorf("negative literal index: %d", op.operand)
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
if pushMSeen {
|
if pushMSeen {
|
||||||
|
@ -97,18 +97,18 @@ func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, er
|
||||||
stack++
|
stack++
|
||||||
case utilities.OpConcatN:
|
case utilities.OpConcatN:
|
||||||
if op.operand <= 0 {
|
if op.operand <= 0 {
|
||||||
grpclog.Infof("negative concat size: %d", op.operand)
|
grpclog.Errorf("negative concat size: %d", op.operand)
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
stack -= op.operand
|
stack -= op.operand
|
||||||
if stack < 0 {
|
if stack < 0 {
|
||||||
grpclog.Info("stack underflow")
|
grpclog.Error("stack underflow")
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
stack++
|
stack++
|
||||||
case utilities.OpCapture:
|
case utilities.OpCapture:
|
||||||
if op.operand < 0 || len(pool) <= op.operand {
|
if op.operand < 0 || len(pool) <= op.operand {
|
||||||
grpclog.Infof("variable name index out of bound: %d", op.operand)
|
grpclog.Errorf("variable name index out of bound: %d", op.operand)
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
v := pool[op.operand]
|
v := pool[op.operand]
|
||||||
|
@ -116,11 +116,11 @@ func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, er
|
||||||
vars = append(vars, v)
|
vars = append(vars, v)
|
||||||
stack--
|
stack--
|
||||||
if stack < 0 {
|
if stack < 0 {
|
||||||
grpclog.Infof("stack underflow")
|
grpclog.Error("stack underflow")
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
grpclog.Infof("invalid opcode: %d", op.code)
|
grpclog.Errorf("invalid opcode: %d", op.code)
|
||||||
return Pattern{}, ErrInvalidPattern
|
return Pattern{}, ErrInvalidPattern
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,13 @@ func (*DefaultQueryParser) Parse(msg proto.Message, values url.Values, filter *u
|
||||||
key = match[1]
|
key = match[1]
|
||||||
values = append([]string{match[2]}, values...)
|
values = append([]string{match[2]}, values...)
|
||||||
}
|
}
|
||||||
fieldPath := strings.Split(key, ".")
|
|
||||||
|
msgValue := msg.ProtoReflect()
|
||||||
|
fieldPath := normalizeFieldPath(msgValue, strings.Split(key, "."))
|
||||||
if filter.HasCommonPrefix(fieldPath) {
|
if filter.HasCommonPrefix(fieldPath) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := populateFieldValueFromPath(msg.ProtoReflect(), fieldPath, values); err != nil {
|
if err := populateFieldValueFromPath(msgValue, fieldPath, values); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +70,38 @@ func PopulateFieldFromPath(msg proto.Message, fieldPathString string, value stri
|
||||||
return populateFieldValueFromPath(msg.ProtoReflect(), fieldPath, []string{value})
|
return populateFieldValueFromPath(msg.ProtoReflect(), fieldPath, []string{value})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func normalizeFieldPath(msgValue protoreflect.Message, fieldPath []string) []string {
|
||||||
|
newFieldPath := make([]string, 0, len(fieldPath))
|
||||||
|
for i, fieldName := range fieldPath {
|
||||||
|
fields := msgValue.Descriptor().Fields()
|
||||||
|
fieldDesc := fields.ByTextName(fieldName)
|
||||||
|
if fieldDesc == nil {
|
||||||
|
fieldDesc = fields.ByJSONName(fieldName)
|
||||||
|
}
|
||||||
|
if fieldDesc == nil {
|
||||||
|
// return initial field path values if no matching message field was found
|
||||||
|
return fieldPath
|
||||||
|
}
|
||||||
|
|
||||||
|
newFieldPath = append(newFieldPath, string(fieldDesc.Name()))
|
||||||
|
|
||||||
|
// If this is the last element, we're done
|
||||||
|
if i == len(fieldPath)-1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only singular message fields are allowed
|
||||||
|
if fieldDesc.Message() == nil || fieldDesc.Cardinality() == protoreflect.Repeated {
|
||||||
|
return fieldPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the nested message
|
||||||
|
msgValue = msgValue.Get(fieldDesc).Message()
|
||||||
|
}
|
||||||
|
|
||||||
|
return newFieldPath
|
||||||
|
}
|
||||||
|
|
||||||
func populateFieldValueFromPath(msgValue protoreflect.Message, fieldPath []string, values []string) error {
|
func populateFieldValueFromPath(msgValue protoreflect.Message, fieldPath []string, values []string) error {
|
||||||
if len(fieldPath) < 1 {
|
if len(fieldPath) < 1 {
|
||||||
return errors.New("no field path")
|
return errors.New("no field path")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# This is an example goreleaser.yaml file with some sane defaults.
|
version: 2
|
||||||
# Make sure to check the documentation at http://goreleaser.com
|
|
||||||
before:
|
before:
|
||||||
hooks:
|
hooks:
|
||||||
- ./gen.sh
|
- ./gen.sh
|
||||||
|
@ -99,7 +99,7 @@ archives:
|
||||||
checksum:
|
checksum:
|
||||||
name_template: 'checksums.txt'
|
name_template: 'checksums.txt'
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: "{{ .Tag }}-next"
|
version_template: "{{ .Tag }}-next"
|
||||||
changelog:
|
changelog:
|
||||||
sort: asc
|
sort: asc
|
||||||
filters:
|
filters:
|
||||||
|
|
|
@ -16,6 +16,27 @@ This package provides various compression algorithms.
|
||||||
|
|
||||||
# changelog
|
# changelog
|
||||||
|
|
||||||
|
* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10)
|
||||||
|
* gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978
|
||||||
|
* gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002
|
||||||
|
* s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982
|
||||||
|
* zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007
|
||||||
|
* flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996
|
||||||
|
|
||||||
|
* Jun 12th, 2024 - [1.17.9](https://github.com/klauspost/compress/releases/tag/v1.17.9)
|
||||||
|
* s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949
|
||||||
|
* flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963
|
||||||
|
* Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971
|
||||||
|
* zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951
|
||||||
|
|
||||||
|
* Apr 9th, 2024 - [1.17.8](https://github.com/klauspost/compress/releases/tag/v1.17.8)
|
||||||
|
* zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885
|
||||||
|
* zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938
|
||||||
|
|
||||||
|
* Feb 21st, 2024 - [1.17.7](https://github.com/klauspost/compress/releases/tag/v1.17.7)
|
||||||
|
* s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927
|
||||||
|
* s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930
|
||||||
|
|
||||||
* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6)
|
* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6)
|
||||||
* zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923
|
* zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923
|
||||||
* s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925
|
* s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925
|
||||||
|
@ -81,7 +102,7 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
|
||||||
* zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795
|
* zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795
|
||||||
* s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779
|
* s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779
|
||||||
* s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780
|
* s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780
|
||||||
* gzhttp: Suppport ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799
|
* gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799
|
||||||
|
|
||||||
* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
|
* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
|
||||||
* zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
|
* zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
|
||||||
|
@ -136,7 +157,7 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
|
||||||
* zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649
|
* zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649
|
||||||
* Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651
|
* Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651
|
||||||
* flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656
|
* flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656
|
||||||
* zstd: Improve "better" compresssion https://github.com/klauspost/compress/pull/657
|
* zstd: Improve "better" compression https://github.com/klauspost/compress/pull/657
|
||||||
* s2: Improve "best" compression https://github.com/klauspost/compress/pull/658
|
* s2: Improve "best" compression https://github.com/klauspost/compress/pull/658
|
||||||
* s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635
|
* s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635
|
||||||
* s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646
|
* s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646
|
||||||
|
@ -339,7 +360,7 @@ While the release has been extensively tested, it is recommended to testing when
|
||||||
* s2: Fix binaries.
|
* s2: Fix binaries.
|
||||||
|
|
||||||
* Feb 25, 2021 (v1.11.8)
|
* Feb 25, 2021 (v1.11.8)
|
||||||
* s2: Fixed occational out-of-bounds write on amd64. Upgrade recommended.
|
* s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended.
|
||||||
* s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315)
|
* s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315)
|
||||||
* s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322)
|
* s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322)
|
||||||
* zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314)
|
* zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314)
|
||||||
|
@ -518,7 +539,7 @@ While the release has been extensively tested, it is recommended to testing when
|
||||||
* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster.
|
* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster.
|
||||||
* Feb 19, 2016: Handle small payloads faster in level 1-3.
|
* Feb 19, 2016: Handle small payloads faster in level 1-3.
|
||||||
* Feb 19, 2016: Added faster level 2 + 3 compression modes.
|
* Feb 19, 2016: Added faster level 2 + 3 compression modes.
|
||||||
* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progresssion in terms of compression. New default level is 5.
|
* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progression in terms of compression. New default level is 5.
|
||||||
* Feb 14, 2016: Snappy: Merge upstream changes.
|
* Feb 14, 2016: Snappy: Merge upstream changes.
|
||||||
* Feb 14, 2016: Snappy: Fix aggressive skipping.
|
* Feb 14, 2016: Snappy: Fix aggressive skipping.
|
||||||
* Feb 14, 2016: Snappy: Update benchmark.
|
* Feb 14, 2016: Snappy: Update benchmark.
|
||||||
|
|
|
@ -15,7 +15,7 @@ const (
|
||||||
// It is possible, but by no way guaranteed that corrupt data will
|
// It is possible, but by no way guaranteed that corrupt data will
|
||||||
// return an error.
|
// return an error.
|
||||||
// It is up to the caller to verify integrity of the returned data.
|
// It is up to the caller to verify integrity of the returned data.
|
||||||
// Use a predefined Scrach to set maximum acceptable output size.
|
// Use a predefined Scratch to set maximum acceptable output size.
|
||||||
func Decompress(b []byte, s *Scratch) ([]byte, error) {
|
func Decompress(b []byte, s *Scratch) ([]byte, error) {
|
||||||
s, err := s.prepare(b)
|
s, err := s.prepare(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1136,7 +1136,7 @@ func (s *Scratch) matches(ct cTable, w io.Writer) {
|
||||||
errs++
|
errs++
|
||||||
}
|
}
|
||||||
if errs > 0 {
|
if errs > 0 {
|
||||||
fmt.Fprintf(w, "%d errros in base, stopping\n", errs)
|
fmt.Fprintf(w, "%d errors in base, stopping\n", errs)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Ensure that all combinations are covered.
|
// Ensure that all combinations are covered.
|
||||||
|
@ -1152,7 +1152,7 @@ func (s *Scratch) matches(ct cTable, w io.Writer) {
|
||||||
errs++
|
errs++
|
||||||
}
|
}
|
||||||
if errs > 20 {
|
if errs > 20 {
|
||||||
fmt.Fprintf(w, "%d errros, stopping\n", errs)
|
fmt.Fprintf(w, "%d errors, stopping\n", errs)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -598,7 +598,9 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) {
|
||||||
printf("RLE set to 0x%x, code: %v", symb, v)
|
printf("RLE set to 0x%x, code: %v", symb, v)
|
||||||
}
|
}
|
||||||
case compModeFSE:
|
case compModeFSE:
|
||||||
println("Reading table for", tableIndex(i))
|
if debugDecoder {
|
||||||
|
println("Reading table for", tableIndex(i))
|
||||||
|
}
|
||||||
if seq.fse == nil || seq.fse.preDefined {
|
if seq.fse == nil || seq.fse.preDefined {
|
||||||
seq.fse = fseDecoderPool.Get().(*fseDecoder)
|
seq.fse = fseDecoderPool.Get().(*fseDecoder)
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,9 +179,9 @@ encodeLoop:
|
||||||
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
||||||
// Consider history as well.
|
// Consider history as well.
|
||||||
var seq seq
|
var seq seq
|
||||||
lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
||||||
|
|
||||||
seq.matchLen = uint32(lenght - zstdMinMatch)
|
seq.matchLen = uint32(length - zstdMinMatch)
|
||||||
|
|
||||||
// We might be able to match backwards.
|
// We might be able to match backwards.
|
||||||
// Extend as long as we can.
|
// Extend as long as we can.
|
||||||
|
@ -210,12 +210,12 @@ encodeLoop:
|
||||||
|
|
||||||
// Index match start+1 (long) -> s - 1
|
// Index match start+1 (long) -> s - 1
|
||||||
index0 := s + repOff
|
index0 := s + repOff
|
||||||
s += lenght + repOff
|
s += length + repOff
|
||||||
|
|
||||||
nextEmit = s
|
nextEmit = s
|
||||||
if s >= sLimit {
|
if s >= sLimit {
|
||||||
if debugEncoder {
|
if debugEncoder {
|
||||||
println("repeat ended", s, lenght)
|
println("repeat ended", s, length)
|
||||||
|
|
||||||
}
|
}
|
||||||
break encodeLoop
|
break encodeLoop
|
||||||
|
@ -241,9 +241,9 @@ encodeLoop:
|
||||||
if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) {
|
if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) {
|
||||||
// Consider history as well.
|
// Consider history as well.
|
||||||
var seq seq
|
var seq seq
|
||||||
lenght := 8 + e.matchlen(s+8+repOff2, repIndex+8, src)
|
length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src)
|
||||||
|
|
||||||
seq.matchLen = uint32(lenght - zstdMinMatch)
|
seq.matchLen = uint32(length - zstdMinMatch)
|
||||||
|
|
||||||
// We might be able to match backwards.
|
// We might be able to match backwards.
|
||||||
// Extend as long as we can.
|
// Extend as long as we can.
|
||||||
|
@ -270,11 +270,11 @@ encodeLoop:
|
||||||
}
|
}
|
||||||
blk.sequences = append(blk.sequences, seq)
|
blk.sequences = append(blk.sequences, seq)
|
||||||
|
|
||||||
s += lenght + repOff2
|
s += length + repOff2
|
||||||
nextEmit = s
|
nextEmit = s
|
||||||
if s >= sLimit {
|
if s >= sLimit {
|
||||||
if debugEncoder {
|
if debugEncoder {
|
||||||
println("repeat ended", s, lenght)
|
println("repeat ended", s, length)
|
||||||
|
|
||||||
}
|
}
|
||||||
break encodeLoop
|
break encodeLoop
|
||||||
|
@ -708,9 +708,9 @@ encodeLoop:
|
||||||
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
||||||
// Consider history as well.
|
// Consider history as well.
|
||||||
var seq seq
|
var seq seq
|
||||||
lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
||||||
|
|
||||||
seq.matchLen = uint32(lenght - zstdMinMatch)
|
seq.matchLen = uint32(length - zstdMinMatch)
|
||||||
|
|
||||||
// We might be able to match backwards.
|
// We might be able to match backwards.
|
||||||
// Extend as long as we can.
|
// Extend as long as we can.
|
||||||
|
@ -738,12 +738,12 @@ encodeLoop:
|
||||||
blk.sequences = append(blk.sequences, seq)
|
blk.sequences = append(blk.sequences, seq)
|
||||||
|
|
||||||
// Index match start+1 (long) -> s - 1
|
// Index match start+1 (long) -> s - 1
|
||||||
s += lenght + repOff
|
s += length + repOff
|
||||||
|
|
||||||
nextEmit = s
|
nextEmit = s
|
||||||
if s >= sLimit {
|
if s >= sLimit {
|
||||||
if debugEncoder {
|
if debugEncoder {
|
||||||
println("repeat ended", s, lenght)
|
println("repeat ended", s, length)
|
||||||
|
|
||||||
}
|
}
|
||||||
break encodeLoop
|
break encodeLoop
|
||||||
|
@ -772,9 +772,9 @@ encodeLoop:
|
||||||
if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) {
|
if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) {
|
||||||
// Consider history as well.
|
// Consider history as well.
|
||||||
var seq seq
|
var seq seq
|
||||||
lenght := 8 + e.matchlen(s+8+repOff2, repIndex+8, src)
|
length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src)
|
||||||
|
|
||||||
seq.matchLen = uint32(lenght - zstdMinMatch)
|
seq.matchLen = uint32(length - zstdMinMatch)
|
||||||
|
|
||||||
// We might be able to match backwards.
|
// We might be able to match backwards.
|
||||||
// Extend as long as we can.
|
// Extend as long as we can.
|
||||||
|
@ -801,11 +801,11 @@ encodeLoop:
|
||||||
}
|
}
|
||||||
blk.sequences = append(blk.sequences, seq)
|
blk.sequences = append(blk.sequences, seq)
|
||||||
|
|
||||||
s += lenght + repOff2
|
s += length + repOff2
|
||||||
nextEmit = s
|
nextEmit = s
|
||||||
if s >= sLimit {
|
if s >= sLimit {
|
||||||
if debugEncoder {
|
if debugEncoder {
|
||||||
println("repeat ended", s, lenght)
|
println("repeat ended", s, length)
|
||||||
|
|
||||||
}
|
}
|
||||||
break encodeLoop
|
break encodeLoop
|
||||||
|
|
|
@ -138,9 +138,9 @@ encodeLoop:
|
||||||
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
||||||
// Consider history as well.
|
// Consider history as well.
|
||||||
var seq seq
|
var seq seq
|
||||||
lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
||||||
|
|
||||||
seq.matchLen = uint32(lenght - zstdMinMatch)
|
seq.matchLen = uint32(length - zstdMinMatch)
|
||||||
|
|
||||||
// We might be able to match backwards.
|
// We might be able to match backwards.
|
||||||
// Extend as long as we can.
|
// Extend as long as we can.
|
||||||
|
@ -166,11 +166,11 @@ encodeLoop:
|
||||||
println("repeat sequence", seq, "next s:", s)
|
println("repeat sequence", seq, "next s:", s)
|
||||||
}
|
}
|
||||||
blk.sequences = append(blk.sequences, seq)
|
blk.sequences = append(blk.sequences, seq)
|
||||||
s += lenght + repOff
|
s += length + repOff
|
||||||
nextEmit = s
|
nextEmit = s
|
||||||
if s >= sLimit {
|
if s >= sLimit {
|
||||||
if debugEncoder {
|
if debugEncoder {
|
||||||
println("repeat ended", s, lenght)
|
println("repeat ended", s, length)
|
||||||
|
|
||||||
}
|
}
|
||||||
break encodeLoop
|
break encodeLoop
|
||||||
|
@ -798,9 +798,9 @@ encodeLoop:
|
||||||
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
||||||
// Consider history as well.
|
// Consider history as well.
|
||||||
var seq seq
|
var seq seq
|
||||||
lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
|
||||||
|
|
||||||
seq.matchLen = uint32(lenght - zstdMinMatch)
|
seq.matchLen = uint32(length - zstdMinMatch)
|
||||||
|
|
||||||
// We might be able to match backwards.
|
// We might be able to match backwards.
|
||||||
// Extend as long as we can.
|
// Extend as long as we can.
|
||||||
|
@ -826,11 +826,11 @@ encodeLoop:
|
||||||
println("repeat sequence", seq, "next s:", s)
|
println("repeat sequence", seq, "next s:", s)
|
||||||
}
|
}
|
||||||
blk.sequences = append(blk.sequences, seq)
|
blk.sequences = append(blk.sequences, seq)
|
||||||
s += lenght + repOff
|
s += length + repOff
|
||||||
nextEmit = s
|
nextEmit = s
|
||||||
if s >= sLimit {
|
if s >= sLimit {
|
||||||
if debugEncoder {
|
if debugEncoder {
|
||||||
println("repeat ended", s, lenght)
|
println("repeat ended", s, length)
|
||||||
|
|
||||||
}
|
}
|
||||||
break encodeLoop
|
break encodeLoop
|
||||||
|
|
|
@ -6,6 +6,7 @@ package zstd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
@ -149,6 +150,9 @@ func (e *Encoder) ResetContentSize(w io.Writer, size int64) {
|
||||||
// and write CRC if requested.
|
// and write CRC if requested.
|
||||||
func (e *Encoder) Write(p []byte) (n int, err error) {
|
func (e *Encoder) Write(p []byte) (n int, err error) {
|
||||||
s := &e.state
|
s := &e.state
|
||||||
|
if s.eofWritten {
|
||||||
|
return 0, ErrEncoderClosed
|
||||||
|
}
|
||||||
for len(p) > 0 {
|
for len(p) > 0 {
|
||||||
if len(p)+len(s.filling) < e.o.blockSize {
|
if len(p)+len(s.filling) < e.o.blockSize {
|
||||||
if e.o.crc {
|
if e.o.crc {
|
||||||
|
@ -202,7 +206,7 @@ func (e *Encoder) nextBlock(final bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if final && len(s.filling) > 0 {
|
if final && len(s.filling) > 0 {
|
||||||
s.current = e.EncodeAll(s.filling, s.current[:0])
|
s.current = e.encodeAll(s.encoder, s.filling, s.current[:0])
|
||||||
var n2 int
|
var n2 int
|
||||||
n2, s.err = s.w.Write(s.current)
|
n2, s.err = s.w.Write(s.current)
|
||||||
if s.err != nil {
|
if s.err != nil {
|
||||||
|
@ -288,6 +292,9 @@ func (e *Encoder) nextBlock(final bool) error {
|
||||||
s.filling, s.current, s.previous = s.previous[:0], s.filling, s.current
|
s.filling, s.current, s.previous = s.previous[:0], s.filling, s.current
|
||||||
s.nInput += int64(len(s.current))
|
s.nInput += int64(len(s.current))
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
|
if final {
|
||||||
|
s.eofWritten = true
|
||||||
|
}
|
||||||
go func(src []byte) {
|
go func(src []byte) {
|
||||||
if debugEncoder {
|
if debugEncoder {
|
||||||
println("Adding block,", len(src), "bytes, final:", final)
|
println("Adding block,", len(src), "bytes, final:", final)
|
||||||
|
@ -303,9 +310,6 @@ func (e *Encoder) nextBlock(final bool) error {
|
||||||
blk := enc.Block()
|
blk := enc.Block()
|
||||||
enc.Encode(blk, src)
|
enc.Encode(blk, src)
|
||||||
blk.last = final
|
blk.last = final
|
||||||
if final {
|
|
||||||
s.eofWritten = true
|
|
||||||
}
|
|
||||||
// Wait for pending writes.
|
// Wait for pending writes.
|
||||||
s.wWg.Wait()
|
s.wWg.Wait()
|
||||||
if s.writeErr != nil {
|
if s.writeErr != nil {
|
||||||
|
@ -401,12 +405,20 @@ func (e *Encoder) Flush() error {
|
||||||
if len(s.filling) > 0 {
|
if len(s.filling) > 0 {
|
||||||
err := e.nextBlock(false)
|
err := e.nextBlock(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Ignore Flush after Close.
|
||||||
|
if errors.Is(s.err, ErrEncoderClosed) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
s.wWg.Wait()
|
s.wWg.Wait()
|
||||||
if s.err != nil {
|
if s.err != nil {
|
||||||
|
// Ignore Flush after Close.
|
||||||
|
if errors.Is(s.err, ErrEncoderClosed) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return s.err
|
return s.err
|
||||||
}
|
}
|
||||||
return s.writeErr
|
return s.writeErr
|
||||||
|
@ -422,6 +434,9 @@ func (e *Encoder) Close() error {
|
||||||
}
|
}
|
||||||
err := e.nextBlock(true)
|
err := e.nextBlock(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(s.err, ErrEncoderClosed) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if s.frameContentSize > 0 {
|
if s.frameContentSize > 0 {
|
||||||
|
@ -459,6 +474,11 @@ func (e *Encoder) Close() error {
|
||||||
}
|
}
|
||||||
_, s.err = s.w.Write(frame)
|
_, s.err = s.w.Write(frame)
|
||||||
}
|
}
|
||||||
|
if s.err == nil {
|
||||||
|
s.err = ErrEncoderClosed
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return s.err
|
return s.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,6 +489,15 @@ func (e *Encoder) Close() error {
|
||||||
// Data compressed with EncodeAll can be decoded with the Decoder,
|
// Data compressed with EncodeAll can be decoded with the Decoder,
|
||||||
// using either a stream or DecodeAll.
|
// using either a stream or DecodeAll.
|
||||||
func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
||||||
|
e.init.Do(e.initialize)
|
||||||
|
enc := <-e.encoders
|
||||||
|
defer func() {
|
||||||
|
e.encoders <- enc
|
||||||
|
}()
|
||||||
|
return e.encodeAll(enc, src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encodeAll(enc encoder, src, dst []byte) []byte {
|
||||||
if len(src) == 0 {
|
if len(src) == 0 {
|
||||||
if e.o.fullZero {
|
if e.o.fullZero {
|
||||||
// Add frame header.
|
// Add frame header.
|
||||||
|
@ -491,13 +520,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
||||||
}
|
}
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
e.init.Do(e.initialize)
|
|
||||||
enc := <-e.encoders
|
|
||||||
defer func() {
|
|
||||||
// Release encoder reference to last block.
|
|
||||||
// If a non-single block is needed the encoder will reset again.
|
|
||||||
e.encoders <- enc
|
|
||||||
}()
|
|
||||||
// Use single segments when above minimum window and below window size.
|
// Use single segments when above minimum window and below window size.
|
||||||
single := len(src) <= e.o.windowSize && len(src) > MinWindowSize
|
single := len(src) <= e.o.windowSize && len(src) > MinWindowSize
|
||||||
if e.o.single != nil {
|
if e.o.single != nil {
|
||||||
|
|
|
@ -146,7 +146,9 @@ func (d *frameDec) reset(br byteBuffer) error {
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
printf("raw: %x, mantissa: %d, exponent: %d\n", wd, wd&7, wd>>3)
|
if debugDecoder {
|
||||||
|
printf("raw: %x, mantissa: %d, exponent: %d\n", wd, wd&7, wd>>3)
|
||||||
|
}
|
||||||
windowLog := 10 + (wd >> 3)
|
windowLog := 10 + (wd >> 3)
|
||||||
windowBase := uint64(1) << windowLog
|
windowBase := uint64(1) << windowLog
|
||||||
windowAdd := (windowBase / 8) * uint64(wd&0x7)
|
windowAdd := (windowBase / 8) * uint64(wd&0x7)
|
||||||
|
|
|
@ -146,7 +146,7 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
|
||||||
return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return true, fmt.Errorf("sequenceDecs_decode returned erronous code %d", errCode)
|
return true, fmt.Errorf("sequenceDecs_decode returned erroneous code %d", errCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.seqSize += ctx.litRemain
|
s.seqSize += ctx.litRemain
|
||||||
|
@ -292,7 +292,7 @@ func (s *sequenceDecs) decode(seqs []seqVals) error {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("sequenceDecs_decode_amd64 returned erronous code %d", errCode)
|
return fmt.Errorf("sequenceDecs_decode_amd64 returned erroneous code %d", errCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.litRemain < 0 {
|
if ctx.litRemain < 0 {
|
||||||
|
|
|
@ -1814,7 +1814,7 @@ TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32
|
||||||
MOVQ 40(SP), AX
|
MOVQ 40(SP), AX
|
||||||
ADDQ AX, 48(SP)
|
ADDQ AX, 48(SP)
|
||||||
|
|
||||||
// Calculate poiter to s.out[cap(s.out)] (a past-end pointer)
|
// Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
|
||||||
ADDQ R10, 32(SP)
|
ADDQ R10, 32(SP)
|
||||||
|
|
||||||
// outBase += outPosition
|
// outBase += outPosition
|
||||||
|
@ -2376,7 +2376,7 @@ TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32
|
||||||
MOVQ 40(SP), CX
|
MOVQ 40(SP), CX
|
||||||
ADDQ CX, 48(SP)
|
ADDQ CX, 48(SP)
|
||||||
|
|
||||||
// Calculate poiter to s.out[cap(s.out)] (a past-end pointer)
|
// Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
|
||||||
ADDQ R9, 32(SP)
|
ADDQ R9, 32(SP)
|
||||||
|
|
||||||
// outBase += outPosition
|
// outBase += outPosition
|
||||||
|
@ -2896,7 +2896,7 @@ TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32
|
||||||
MOVQ 40(SP), AX
|
MOVQ 40(SP), AX
|
||||||
ADDQ AX, 48(SP)
|
ADDQ AX, 48(SP)
|
||||||
|
|
||||||
// Calculate poiter to s.out[cap(s.out)] (a past-end pointer)
|
// Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
|
||||||
ADDQ R10, 32(SP)
|
ADDQ R10, 32(SP)
|
||||||
|
|
||||||
// outBase += outPosition
|
// outBase += outPosition
|
||||||
|
@ -3560,7 +3560,7 @@ TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32
|
||||||
MOVQ 40(SP), CX
|
MOVQ 40(SP), CX
|
||||||
ADDQ CX, 48(SP)
|
ADDQ CX, 48(SP)
|
||||||
|
|
||||||
// Calculate poiter to s.out[cap(s.out)] (a past-end pointer)
|
// Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
|
||||||
ADDQ R9, 32(SP)
|
ADDQ R9, 32(SP)
|
||||||
|
|
||||||
// outBase += outPosition
|
// outBase += outPosition
|
||||||
|
|
|
@ -88,6 +88,10 @@ var (
|
||||||
// Close has been called.
|
// Close has been called.
|
||||||
ErrDecoderClosed = errors.New("decoder used after Close")
|
ErrDecoderClosed = errors.New("decoder used after Close")
|
||||||
|
|
||||||
|
// ErrEncoderClosed will be returned if the Encoder was used after
|
||||||
|
// Close has been called.
|
||||||
|
ErrEncoderClosed = errors.New("encoder used after Close")
|
||||||
|
|
||||||
// ErrDecoderNilInput is returned when a nil Reader was provided
|
// ErrDecoderNilInput is returned when a nil Reader was provided
|
||||||
// and an operation other than Reset/DecodeAll/Close was attempted.
|
// and an operation other than Reset/DecodeAll/Close was attempted.
|
||||||
ErrDecoderNilInput = errors.New("nil input provided as reader")
|
ErrDecoderNilInput = errors.New("nil input provided as reader")
|
||||||
|
|
|
@ -1,201 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
|
@ -1 +0,0 @@
|
||||||
Copyright 2012 Matt T. Proud (matt.proud@gmail.com)
|
|
|
@ -1 +0,0 @@
|
||||||
cover.dat
|
|
|
@ -1,7 +0,0 @@
|
||||||
all:
|
|
||||||
|
|
||||||
cover:
|
|
||||||
go test -cover -v -coverprofile=cover.dat ./...
|
|
||||||
go tool cover -func cover.dat
|
|
||||||
|
|
||||||
.PHONY: cover
|
|
|
@ -1,75 +0,0 @@
|
||||||
// Copyright 2013 Matt T. Proud
|
|
||||||
//
|
|
||||||
// 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 pbutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
var errInvalidVarint = errors.New("invalid varint32 encountered")
|
|
||||||
|
|
||||||
// ReadDelimited decodes a message from the provided length-delimited stream,
|
|
||||||
// where the length is encoded as 32-bit varint prefix to the message body.
|
|
||||||
// It returns the total number of bytes read and any applicable error. This is
|
|
||||||
// roughly equivalent to the companion Java API's
|
|
||||||
// MessageLite#parseDelimitedFrom. As per the reader contract, this function
|
|
||||||
// calls r.Read repeatedly as required until exactly one message including its
|
|
||||||
// prefix is read and decoded (or an error has occurred). The function never
|
|
||||||
// reads more bytes from the stream than required. The function never returns
|
|
||||||
// an error if a message has been read and decoded correctly, even if the end
|
|
||||||
// of the stream has been reached in doing so. In that case, any subsequent
|
|
||||||
// calls return (0, io.EOF).
|
|
||||||
func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) {
|
|
||||||
// Per AbstractParser#parsePartialDelimitedFrom with
|
|
||||||
// CodedInputStream#readRawVarint32.
|
|
||||||
var headerBuf [binary.MaxVarintLen32]byte
|
|
||||||
var bytesRead, varIntBytes int
|
|
||||||
var messageLength uint64
|
|
||||||
for varIntBytes == 0 { // i.e. no varint has been decoded yet.
|
|
||||||
if bytesRead >= len(headerBuf) {
|
|
||||||
return bytesRead, errInvalidVarint
|
|
||||||
}
|
|
||||||
// We have to read byte by byte here to avoid reading more bytes
|
|
||||||
// than required. Each read byte is appended to what we have
|
|
||||||
// read before.
|
|
||||||
newBytesRead, err := r.Read(headerBuf[bytesRead : bytesRead+1])
|
|
||||||
if newBytesRead == 0 {
|
|
||||||
if err != nil {
|
|
||||||
return bytesRead, err
|
|
||||||
}
|
|
||||||
// A Reader should not return (0, nil), but if it does,
|
|
||||||
// it should be treated as no-op (according to the
|
|
||||||
// Reader contract). So let's go on...
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
bytesRead += newBytesRead
|
|
||||||
// Now present everything read so far to the varint decoder and
|
|
||||||
// see if a varint can be decoded already.
|
|
||||||
messageLength, varIntBytes = proto.DecodeVarint(headerBuf[:bytesRead])
|
|
||||||
}
|
|
||||||
|
|
||||||
messageBuf := make([]byte, messageLength)
|
|
||||||
newBytesRead, err := io.ReadFull(r, messageBuf)
|
|
||||||
bytesRead += newBytesRead
|
|
||||||
if err != nil {
|
|
||||||
return bytesRead, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytesRead, proto.Unmarshal(messageBuf, m)
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright 2013 Matt T. Proud
|
|
||||||
//
|
|
||||||
// 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 pbutil provides record length-delimited Protocol Buffer streaming.
|
|
||||||
package pbutil
|
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright 2013 Matt T. Proud
|
|
||||||
//
|
|
||||||
// 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 pbutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WriteDelimited encodes and dumps a message to the provided writer prefixed
|
|
||||||
// with a 32-bit varint indicating the length of the encoded message, producing
|
|
||||||
// a length-delimited record stream, which can be used to chain together
|
|
||||||
// encoded messages of the same type together in a file. It returns the total
|
|
||||||
// number of bytes written and any applicable error. This is roughly
|
|
||||||
// equivalent to the companion Java API's MessageLite#writeDelimitedTo.
|
|
||||||
func WriteDelimited(w io.Writer, m proto.Message) (n int, err error) {
|
|
||||||
buffer, err := proto.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf [binary.MaxVarintLen32]byte
|
|
||||||
encodedLength := binary.PutUvarint(buf[:], uint64(len(buffer)))
|
|
||||||
|
|
||||||
sync, err := w.Write(buf[:encodedLength])
|
|
||||||
if err != nil {
|
|
||||||
return sync, err
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err = w.Write(buffer)
|
|
||||||
return n + sync, err
|
|
||||||
}
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
Copyright (c) 2011, Open Knowledge Foundation Ltd.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||||
|
names of its contributors may be used to endorse or promote
|
||||||
|
products derived from this software without specific prior written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,13 @@
|
||||||
|
include $(GOROOT)/src/Make.inc
|
||||||
|
|
||||||
|
TARG=bitbucket.org/ww/goautoneg
|
||||||
|
GOFILES=autoneg.go
|
||||||
|
|
||||||
|
include $(GOROOT)/src/Make.pkg
|
||||||
|
|
||||||
|
format:
|
||||||
|
gofmt -w *.go
|
||||||
|
|
||||||
|
docs:
|
||||||
|
gomake clean
|
||||||
|
godoc ${TARG} > README.txt
|
|
@ -1,28 +1,28 @@
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2011, Open Knowledge Foundation Ltd.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
HTTP Content-Type Autonegotiation.
|
HTTP Content-Type Autonegotiation.
|
||||||
|
|
||||||
The functions in this package implement the behaviour specified in
|
The functions in this package implement the behaviour specified in
|
||||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||||
|
|
||||||
|
Copyright (c) 2011, Open Knowledge Foundation Ltd.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
met:
|
met:
|
||||||
|
|
||||||
Redistributions of source code must retain the above copyright
|
Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
Redistributions in binary form must reproduce the above copyright
|
Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in
|
notice, this list of conditions and the following disclaimer in
|
||||||
the documentation and/or other materials provided with the
|
the documentation and/or other materials provided with the
|
||||||
distribution.
|
distribution.
|
||||||
|
|
||||||
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||||
names of its contributors may be used to endorse or promote
|
names of its contributors may be used to endorse or promote
|
||||||
products derived from this software without specific prior written
|
products derived from this software without specific prior written
|
||||||
permission.
|
permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
@ -36,6 +36,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package goautoneg
|
package goautoneg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -51,16 +52,14 @@ type Accept struct {
|
||||||
Params map[string]string
|
Params map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// For internal use, so that we can use the sort interface
|
// acceptSlice is defined to implement sort interface.
|
||||||
type accept_slice []Accept
|
type acceptSlice []Accept
|
||||||
|
|
||||||
func (accept accept_slice) Len() int {
|
func (slice acceptSlice) Len() int {
|
||||||
slice := []Accept(accept)
|
|
||||||
return len(slice)
|
return len(slice)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (accept accept_slice) Less(i, j int) bool {
|
func (slice acceptSlice) Less(i, j int) bool {
|
||||||
slice := []Accept(accept)
|
|
||||||
ai, aj := slice[i], slice[j]
|
ai, aj := slice[i], slice[j]
|
||||||
if ai.Q > aj.Q {
|
if ai.Q > aj.Q {
|
||||||
return true
|
return true
|
||||||
|
@ -74,63 +73,93 @@ func (accept accept_slice) Less(i, j int) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (accept accept_slice) Swap(i, j int) {
|
func (slice acceptSlice) Swap(i, j int) {
|
||||||
slice := []Accept(accept)
|
|
||||||
slice[i], slice[j] = slice[j], slice[i]
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stringTrimSpaceCutset(r rune) bool {
|
||||||
|
return r == ' '
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextSplitElement(s, sep string) (item string, remaining string) {
|
||||||
|
if index := strings.Index(s, sep); index != -1 {
|
||||||
|
return s[:index], s[index+1:]
|
||||||
|
}
|
||||||
|
return s, ""
|
||||||
|
}
|
||||||
|
|
||||||
// Parse an Accept Header string returning a sorted list
|
// Parse an Accept Header string returning a sorted list
|
||||||
// of clauses
|
// of clauses
|
||||||
func ParseAccept(header string) (accept []Accept) {
|
func ParseAccept(header string) acceptSlice {
|
||||||
parts := strings.Split(header, ",")
|
partsCount := 0
|
||||||
accept = make([]Accept, 0, len(parts))
|
remaining := header
|
||||||
for _, part := range parts {
|
for len(remaining) > 0 {
|
||||||
part := strings.Trim(part, " ")
|
partsCount++
|
||||||
|
_, remaining = nextSplitElement(remaining, ",")
|
||||||
|
}
|
||||||
|
accept := make(acceptSlice, 0, partsCount)
|
||||||
|
|
||||||
a := Accept{}
|
remaining = header
|
||||||
a.Params = make(map[string]string)
|
var part string
|
||||||
a.Q = 1.0
|
for len(remaining) > 0 {
|
||||||
|
part, remaining = nextSplitElement(remaining, ",")
|
||||||
|
part = strings.TrimFunc(part, stringTrimSpaceCutset)
|
||||||
|
|
||||||
mrp := strings.Split(part, ";")
|
a := Accept{
|
||||||
|
Q: 1.0,
|
||||||
media_range := mrp[0]
|
|
||||||
sp := strings.Split(media_range, "/")
|
|
||||||
a.Type = strings.Trim(sp[0], " ")
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case len(sp) == 1 && a.Type == "*":
|
|
||||||
a.SubType = "*"
|
|
||||||
case len(sp) == 2:
|
|
||||||
a.SubType = strings.Trim(sp[1], " ")
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(mrp) == 1 {
|
sp, remainingPart := nextSplitElement(part, ";")
|
||||||
|
|
||||||
|
sp0, spRemaining := nextSplitElement(sp, "/")
|
||||||
|
a.Type = strings.TrimFunc(sp0, stringTrimSpaceCutset)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(spRemaining) == 0:
|
||||||
|
if a.Type == "*" {
|
||||||
|
a.SubType = "*"
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
var sp1 string
|
||||||
|
sp1, spRemaining = nextSplitElement(spRemaining, "/")
|
||||||
|
if len(spRemaining) > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
a.SubType = strings.TrimFunc(sp1, stringTrimSpaceCutset)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(remainingPart) == 0 {
|
||||||
accept = append(accept, a)
|
accept = append(accept, a)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, param := range mrp[1:] {
|
a.Params = make(map[string]string)
|
||||||
sp := strings.SplitN(param, "=", 2)
|
for len(remainingPart) > 0 {
|
||||||
if len(sp) != 2 {
|
sp, remainingPart = nextSplitElement(remainingPart, ";")
|
||||||
|
sp0, spRemaining = nextSplitElement(sp, "=")
|
||||||
|
if len(spRemaining) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
token := strings.Trim(sp[0], " ")
|
var sp1 string
|
||||||
|
sp1, spRemaining = nextSplitElement(spRemaining, "=")
|
||||||
|
if len(spRemaining) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
token := strings.TrimFunc(sp0, stringTrimSpaceCutset)
|
||||||
if token == "q" {
|
if token == "q" {
|
||||||
a.Q, _ = strconv.ParseFloat(sp[1], 32)
|
a.Q, _ = strconv.ParseFloat(sp1, 32)
|
||||||
} else {
|
} else {
|
||||||
a.Params[token] = strings.Trim(sp[1], " ")
|
a.Params[token] = strings.TrimFunc(sp1, stringTrimSpaceCutset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
accept = append(accept, a)
|
accept = append(accept, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
slice := accept_slice(accept)
|
sort.Sort(accept)
|
||||||
sort.Sort(slice)
|
return accept
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Negotiate the most appropriate content_type given the accept header
|
// Negotiate the most appropriate content_type given the accept header
|
|
@ -16,8 +16,3 @@ Go support for Protocol Buffers - Google's data interchange format
|
||||||
http://github.com/golang/protobuf/
|
http://github.com/golang/protobuf/
|
||||||
Copyright 2010 The Go Authors
|
Copyright 2010 The Go Authors
|
||||||
See source code for license details.
|
See source code for license details.
|
||||||
|
|
||||||
Support for streaming Protocol Buffer messages for the Go language (golang).
|
|
||||||
https://github.com/matttproud/golang_protobuf_extensions
|
|
||||||
Copyright 2013 Matt T. Proud
|
|
||||||
Licensed under the Apache License, Version 2.0
|
|
||||||
|
|
27
vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/LICENSE
generated
vendored
Normal file
27
vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2013 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
145
vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go
generated
vendored
Normal file
145
vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
// Copyright 2013 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 or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd.
|
||||||
|
|
||||||
|
// Package header provides functions for parsing HTTP headers.
|
||||||
|
package header
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Octet types from RFC 2616.
|
||||||
|
var octetTypes [256]octetType
|
||||||
|
|
||||||
|
type octetType byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
isToken octetType = 1 << iota
|
||||||
|
isSpace
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// OCTET = <any 8-bit sequence of data>
|
||||||
|
// CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||||
|
// CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
|
||||||
|
// CR = <US-ASCII CR, carriage return (13)>
|
||||||
|
// LF = <US-ASCII LF, linefeed (10)>
|
||||||
|
// SP = <US-ASCII SP, space (32)>
|
||||||
|
// HT = <US-ASCII HT, horizontal-tab (9)>
|
||||||
|
// <"> = <US-ASCII double-quote mark (34)>
|
||||||
|
// CRLF = CR LF
|
||||||
|
// LWS = [CRLF] 1*( SP | HT )
|
||||||
|
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||||
|
// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
|
||||||
|
// | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
|
||||||
|
// token = 1*<any CHAR except CTLs or separators>
|
||||||
|
// qdtext = <any TEXT except <">>
|
||||||
|
|
||||||
|
for c := 0; c < 256; c++ {
|
||||||
|
var t octetType
|
||||||
|
isCtl := c <= 31 || c == 127
|
||||||
|
isChar := 0 <= c && c <= 127
|
||||||
|
isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
|
||||||
|
if strings.ContainsRune(" \t\r\n", rune(c)) {
|
||||||
|
t |= isSpace
|
||||||
|
}
|
||||||
|
if isChar && !isCtl && !isSeparator {
|
||||||
|
t |= isToken
|
||||||
|
}
|
||||||
|
octetTypes[c] = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceptSpec describes an Accept* header.
|
||||||
|
type AcceptSpec struct {
|
||||||
|
Value string
|
||||||
|
Q float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAccept parses Accept* headers.
|
||||||
|
func ParseAccept(header http.Header, key string) (specs []AcceptSpec) {
|
||||||
|
loop:
|
||||||
|
for _, s := range header[key] {
|
||||||
|
for {
|
||||||
|
var spec AcceptSpec
|
||||||
|
spec.Value, s = expectTokenSlash(s)
|
||||||
|
if spec.Value == "" {
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
spec.Q = 1.0
|
||||||
|
s = skipSpace(s)
|
||||||
|
if strings.HasPrefix(s, ";") {
|
||||||
|
s = skipSpace(s[1:])
|
||||||
|
if !strings.HasPrefix(s, "q=") {
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
spec.Q, s = expectQuality(s[2:])
|
||||||
|
if spec.Q < 0.0 {
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
specs = append(specs, spec)
|
||||||
|
s = skipSpace(s)
|
||||||
|
if !strings.HasPrefix(s, ",") {
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
s = skipSpace(s[1:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipSpace(s string) (rest string) {
|
||||||
|
i := 0
|
||||||
|
for ; i < len(s); i++ {
|
||||||
|
if octetTypes[s[i]]&isSpace == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s[i:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectTokenSlash(s string) (token, rest string) {
|
||||||
|
i := 0
|
||||||
|
for ; i < len(s); i++ {
|
||||||
|
b := s[i]
|
||||||
|
if (octetTypes[b]&isToken == 0) && b != '/' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s[:i], s[i:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectQuality(s string) (q float64, rest string) {
|
||||||
|
switch {
|
||||||
|
case len(s) == 0:
|
||||||
|
return -1, ""
|
||||||
|
case s[0] == '0':
|
||||||
|
q = 0
|
||||||
|
case s[0] == '1':
|
||||||
|
q = 1
|
||||||
|
default:
|
||||||
|
return -1, ""
|
||||||
|
}
|
||||||
|
s = s[1:]
|
||||||
|
if !strings.HasPrefix(s, ".") {
|
||||||
|
return q, s
|
||||||
|
}
|
||||||
|
s = s[1:]
|
||||||
|
i := 0
|
||||||
|
n := 0
|
||||||
|
d := 1
|
||||||
|
for ; i < len(s); i++ {
|
||||||
|
b := s[i]
|
||||||
|
if b < '0' || b > '9' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n = n*10 + int(b) - '0'
|
||||||
|
d *= 10
|
||||||
|
}
|
||||||
|
return q + float64(n)/float64(d), s[i:]
|
||||||
|
}
|
36
vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/negotiate.go
generated
vendored
Normal file
36
vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/negotiate.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2013 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 or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd.
|
||||||
|
|
||||||
|
package httputil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NegotiateContentEncoding returns the best offered content encoding for the
|
||||||
|
// request's Accept-Encoding header. If two offers match with equal weight and
|
||||||
|
// then the offer earlier in the list is preferred. If no offers are
|
||||||
|
// acceptable, then "" is returned.
|
||||||
|
func NegotiateContentEncoding(r *http.Request, offers []string) string {
|
||||||
|
bestOffer := "identity"
|
||||||
|
bestQ := -1.0
|
||||||
|
specs := header.ParseAccept(r.Header, "Accept-Encoding")
|
||||||
|
for _, offer := range offers {
|
||||||
|
for _, spec := range specs {
|
||||||
|
if spec.Q > bestQ &&
|
||||||
|
(spec.Value == "*" || spec.Value == offer) {
|
||||||
|
bestQ = spec.Q
|
||||||
|
bestOffer = offer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bestQ == 0 {
|
||||||
|
bestOffer = ""
|
||||||
|
}
|
||||||
|
return bestOffer
|
||||||
|
}
|
|
@ -22,13 +22,13 @@ import (
|
||||||
// goRuntimeMemStats provides the metrics initially provided by runtime.ReadMemStats.
|
// goRuntimeMemStats provides the metrics initially provided by runtime.ReadMemStats.
|
||||||
// From Go 1.17 those similar (and better) statistics are provided by runtime/metrics, so
|
// 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
|
// while eval closure works on runtime.MemStats, the struct from Go 1.17+ is
|
||||||
// populated using runtime/metrics.
|
// populated using runtime/metrics. Those are the defaults we can't alter.
|
||||||
func goRuntimeMemStats() memStatsMetrics {
|
func goRuntimeMemStats() memStatsMetrics {
|
||||||
return memStatsMetrics{
|
return memStatsMetrics{
|
||||||
{
|
{
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("alloc_bytes"),
|
memstatNamespace("alloc_bytes"),
|
||||||
"Number of bytes allocated and still in use.",
|
"Number of bytes allocated in heap and currently in use. Equals to /memory/classes/heap/objects:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
|
||||||
|
@ -36,7 +36,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("alloc_bytes_total"),
|
memstatNamespace("alloc_bytes_total"),
|
||||||
"Total number of bytes allocated, even if freed.",
|
"Total number of bytes allocated in heap until now, even if released already. Equals to /gc/heap/allocs:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
|
||||||
|
@ -44,23 +44,16 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("sys_bytes"),
|
memstatNamespace("sys_bytes"),
|
||||||
"Number of bytes obtained from system.",
|
"Number of bytes obtained from system. Equals to /memory/classes/total:byte.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
|
||||||
valType: GaugeValue,
|
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(
|
desc: NewDesc(
|
||||||
memstatNamespace("mallocs_total"),
|
memstatNamespace("mallocs_total"),
|
||||||
"Total number of mallocs.",
|
// TODO(bwplotka): We could add go_memstats_heap_objects, probably useful for discovery. Let's gather more feedback, kind of a waste of bytes for everybody for compatibility reasons to keep both, and we can't really rename/remove useful metric.
|
||||||
|
"Total number of heap objects allocated, both live and gc-ed. Semantically a counter version for go_memstats_heap_objects gauge. Equals to /gc/heap/allocs:objects + /gc/heap/tiny/allocs:objects.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
|
||||||
|
@ -68,7 +61,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("frees_total"),
|
memstatNamespace("frees_total"),
|
||||||
"Total number of frees.",
|
"Total number of heap objects frees. Equals to /gc/heap/frees:objects + /gc/heap/tiny/allocs:objects.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
|
||||||
|
@ -76,7 +69,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("heap_alloc_bytes"),
|
memstatNamespace("heap_alloc_bytes"),
|
||||||
"Number of heap bytes allocated and still in use.",
|
"Number of heap bytes allocated and currently in use, same as go_memstats_alloc_bytes. Equals to /memory/classes/heap/objects:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
|
||||||
|
@ -84,7 +77,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("heap_sys_bytes"),
|
memstatNamespace("heap_sys_bytes"),
|
||||||
"Number of heap bytes obtained from system.",
|
"Number of heap bytes obtained from system. Equals to /memory/classes/heap/objects:bytes + /memory/classes/heap/unused:bytes + /memory/classes/heap/released:bytes + /memory/classes/heap/free:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
|
||||||
|
@ -92,7 +85,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("heap_idle_bytes"),
|
memstatNamespace("heap_idle_bytes"),
|
||||||
"Number of heap bytes waiting to be used.",
|
"Number of heap bytes waiting to be used. Equals to /memory/classes/heap/released:bytes + /memory/classes/heap/free:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
|
||||||
|
@ -100,7 +93,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("heap_inuse_bytes"),
|
memstatNamespace("heap_inuse_bytes"),
|
||||||
"Number of heap bytes that are in use.",
|
"Number of heap bytes that are in use. Equals to /memory/classes/heap/objects:bytes + /memory/classes/heap/unused:bytes",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
|
||||||
|
@ -108,7 +101,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("heap_released_bytes"),
|
memstatNamespace("heap_released_bytes"),
|
||||||
"Number of heap bytes released to OS.",
|
"Number of heap bytes released to OS. Equals to /memory/classes/heap/released:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
|
||||||
|
@ -116,7 +109,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("heap_objects"),
|
memstatNamespace("heap_objects"),
|
||||||
"Number of allocated objects.",
|
"Number of currently allocated objects. Equals to /gc/heap/objects:objects.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
|
||||||
|
@ -124,7 +117,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("stack_inuse_bytes"),
|
memstatNamespace("stack_inuse_bytes"),
|
||||||
"Number of bytes in use by the stack allocator.",
|
"Number of bytes obtained from system for stack allocator in non-CGO environments. Equals to /memory/classes/heap/stacks:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
|
||||||
|
@ -132,7 +125,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("stack_sys_bytes"),
|
memstatNamespace("stack_sys_bytes"),
|
||||||
"Number of bytes obtained from system for stack allocator.",
|
"Number of bytes obtained from system for stack allocator. Equals to /memory/classes/heap/stacks:bytes + /memory/classes/os-stacks:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
|
||||||
|
@ -140,7 +133,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("mspan_inuse_bytes"),
|
memstatNamespace("mspan_inuse_bytes"),
|
||||||
"Number of bytes in use by mspan structures.",
|
"Number of bytes in use by mspan structures. Equals to /memory/classes/metadata/mspan/inuse:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
|
||||||
|
@ -148,7 +141,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("mspan_sys_bytes"),
|
memstatNamespace("mspan_sys_bytes"),
|
||||||
"Number of bytes used for mspan structures obtained from system.",
|
"Number of bytes used for mspan structures obtained from system. Equals to /memory/classes/metadata/mspan/inuse:bytes + /memory/classes/metadata/mspan/free:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
|
||||||
|
@ -156,7 +149,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("mcache_inuse_bytes"),
|
memstatNamespace("mcache_inuse_bytes"),
|
||||||
"Number of bytes in use by mcache structures.",
|
"Number of bytes in use by mcache structures. Equals to /memory/classes/metadata/mcache/inuse:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
|
||||||
|
@ -164,7 +157,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("mcache_sys_bytes"),
|
memstatNamespace("mcache_sys_bytes"),
|
||||||
"Number of bytes used for mcache structures obtained from system.",
|
"Number of bytes used for mcache structures obtained from system. Equals to /memory/classes/metadata/mcache/inuse:bytes + /memory/classes/metadata/mcache/free:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
|
||||||
|
@ -172,7 +165,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("buck_hash_sys_bytes"),
|
memstatNamespace("buck_hash_sys_bytes"),
|
||||||
"Number of bytes used by the profiling bucket hash table.",
|
"Number of bytes used by the profiling bucket hash table. Equals to /memory/classes/profiling/buckets:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
|
||||||
|
@ -180,7 +173,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("gc_sys_bytes"),
|
memstatNamespace("gc_sys_bytes"),
|
||||||
"Number of bytes used for garbage collection system metadata.",
|
"Number of bytes used for garbage collection system metadata. Equals to /memory/classes/metadata/other:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
|
||||||
|
@ -188,7 +181,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("other_sys_bytes"),
|
memstatNamespace("other_sys_bytes"),
|
||||||
"Number of bytes used for other system allocations.",
|
"Number of bytes used for other system allocations. Equals to /memory/classes/other:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
|
||||||
|
@ -196,7 +189,7 @@ func goRuntimeMemStats() memStatsMetrics {
|
||||||
}, {
|
}, {
|
||||||
desc: NewDesc(
|
desc: NewDesc(
|
||||||
memstatNamespace("next_gc_bytes"),
|
memstatNamespace("next_gc_bytes"),
|
||||||
"Number of heap bytes when next garbage collection will take place.",
|
"Number of heap bytes when next garbage collection will take place. Equals to /gc/heap/goal:bytes.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
|
eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
|
||||||
|
@ -225,7 +218,7 @@ func newBaseGoCollector() baseGoCollector {
|
||||||
nil, nil),
|
nil, nil),
|
||||||
gcDesc: NewDesc(
|
gcDesc: NewDesc(
|
||||||
"go_gc_duration_seconds",
|
"go_gc_duration_seconds",
|
||||||
"A summary of the pause duration of garbage collection cycles.",
|
"A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.",
|
||||||
nil, nil),
|
nil, nil),
|
||||||
gcLastTimeDesc: NewDesc(
|
gcLastTimeDesc: NewDesc(
|
||||||
"go_memstats_last_gc_time_seconds",
|
"go_memstats_last_gc_time_seconds",
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/metrics"
|
"runtime/metrics"
|
||||||
|
@ -153,7 +154,8 @@ func defaultGoCollectorOptions() internal.GoCollectorOptions {
|
||||||
"/gc/heap/frees-by-size:bytes": goGCHeapFreesBytes,
|
"/gc/heap/frees-by-size:bytes": goGCHeapFreesBytes,
|
||||||
},
|
},
|
||||||
RuntimeMetricRules: []internal.GoCollectorRule{
|
RuntimeMetricRules: []internal.GoCollectorRule{
|
||||||
//{Matcher: regexp.MustCompile("")},
|
// Recommended metrics we want by default from runtime/metrics.
|
||||||
|
{Matcher: internal.GoCollectorDefaultRuntimeMetrics},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,6 +205,7 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
|
||||||
// to fail here. This condition is tested in TestExpectedRuntimeMetrics.
|
// to fail here. This condition is tested in TestExpectedRuntimeMetrics.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
help := attachOriginalName(d.Description.Description, d.Name)
|
||||||
|
|
||||||
sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name})
|
sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name})
|
||||||
sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1]
|
sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1]
|
||||||
|
@ -214,7 +217,7 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
|
||||||
m = newBatchHistogram(
|
m = newBatchHistogram(
|
||||||
NewDesc(
|
NewDesc(
|
||||||
BuildFQName(namespace, subsystem, name),
|
BuildFQName(namespace, subsystem, name),
|
||||||
d.Description.Description,
|
help,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
|
@ -226,7 +229,7 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Subsystem: subsystem,
|
Subsystem: subsystem,
|
||||||
Name: name,
|
Name: name,
|
||||||
Help: d.Description.Description,
|
Help: help,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -234,7 +237,7 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Subsystem: subsystem,
|
Subsystem: subsystem,
|
||||||
Name: name,
|
Name: name,
|
||||||
Help: d.Description.Description,
|
Help: help,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
metricSet = append(metricSet, m)
|
metricSet = append(metricSet, m)
|
||||||
|
@ -284,6 +287,10 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func attachOriginalName(desc, origName string) string {
|
||||||
|
return fmt.Sprintf("%s Sourced from %s", desc, origName)
|
||||||
|
}
|
||||||
|
|
||||||
// Describe returns all descriptions of the collector.
|
// Describe returns all descriptions of the collector.
|
||||||
func (c *goCollector) Describe(ch chan<- *Desc) {
|
func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||||
c.base.Describe(ch)
|
c.base.Describe(ch)
|
||||||
|
@ -376,13 +383,13 @@ func unwrapScalarRMValue(v metrics.Value) float64 {
|
||||||
//
|
//
|
||||||
// This should never happen because we always populate our metric
|
// This should never happen because we always populate our metric
|
||||||
// set from the runtime/metrics package.
|
// set from the runtime/metrics package.
|
||||||
panic("unexpected unsupported metric")
|
panic("unexpected bad kind metric")
|
||||||
default:
|
default:
|
||||||
// Unsupported metric kind.
|
// Unsupported metric kind.
|
||||||
//
|
//
|
||||||
// This should never happen because we check for this during initialization
|
// This should never happen because we check for this during initialization
|
||||||
// and flag and filter metrics whose kinds we don't understand.
|
// and flag and filter metrics whose kinds we don't understand.
|
||||||
panic("unexpected unsupported metric kind")
|
panic(fmt.Sprintf("unexpected unsupported metric: %v", v.Kind()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -440,7 +440,7 @@ type HistogramOpts struct {
|
||||||
// constant (or any negative float value).
|
// constant (or any negative float value).
|
||||||
NativeHistogramZeroThreshold float64
|
NativeHistogramZeroThreshold float64
|
||||||
|
|
||||||
// The remaining fields define a strategy to limit the number of
|
// The next three fields define a strategy to limit the number of
|
||||||
// populated sparse buckets. If NativeHistogramMaxBucketNumber is left
|
// populated sparse buckets. If NativeHistogramMaxBucketNumber is left
|
||||||
// at zero, the number of buckets is not limited. (Note that this might
|
// at zero, the number of buckets is not limited. (Note that this might
|
||||||
// lead to unbounded memory consumption if the values observed by the
|
// lead to unbounded memory consumption if the values observed by the
|
||||||
|
@ -473,8 +473,27 @@ type HistogramOpts struct {
|
||||||
NativeHistogramMinResetDuration time.Duration
|
NativeHistogramMinResetDuration time.Duration
|
||||||
NativeHistogramMaxZeroThreshold float64
|
NativeHistogramMaxZeroThreshold float64
|
||||||
|
|
||||||
|
// NativeHistogramMaxExemplars limits the number of exemplars
|
||||||
|
// that are kept in memory for each native histogram. If you leave it at
|
||||||
|
// zero, a default value of 10 is used. If no exemplars should be kept specifically
|
||||||
|
// for native histograms, set it to a negative value. (Scrapers can
|
||||||
|
// still use the exemplars exposed for classic buckets, which are managed
|
||||||
|
// independently.)
|
||||||
|
NativeHistogramMaxExemplars int
|
||||||
|
// NativeHistogramExemplarTTL is only checked once
|
||||||
|
// NativeHistogramMaxExemplars is exceeded. In that case, the
|
||||||
|
// oldest exemplar is removed if it is older than NativeHistogramExemplarTTL.
|
||||||
|
// Otherwise, the older exemplar in the pair of exemplars that are closest
|
||||||
|
// together (on an exponential scale) is removed.
|
||||||
|
// If NativeHistogramExemplarTTL is left at its zero value, a default value of
|
||||||
|
// 5m is used. To always delete the oldest exemplar, set it to a negative value.
|
||||||
|
NativeHistogramExemplarTTL time.Duration
|
||||||
|
|
||||||
// now is for testing purposes, by default it's time.Now.
|
// now is for testing purposes, by default it's time.Now.
|
||||||
now func() time.Time
|
now func() time.Time
|
||||||
|
|
||||||
|
// afterFunc is for testing purposes, by default it's time.AfterFunc.
|
||||||
|
afterFunc func(time.Duration, func()) *time.Timer
|
||||||
}
|
}
|
||||||
|
|
||||||
// HistogramVecOpts bundles the options to create a HistogramVec metric.
|
// HistogramVecOpts bundles the options to create a HistogramVec metric.
|
||||||
|
@ -526,6 +545,9 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
||||||
if opts.now == nil {
|
if opts.now == nil {
|
||||||
opts.now = time.Now
|
opts.now = time.Now
|
||||||
}
|
}
|
||||||
|
if opts.afterFunc == nil {
|
||||||
|
opts.afterFunc = time.AfterFunc
|
||||||
|
}
|
||||||
|
|
||||||
h := &histogram{
|
h := &histogram{
|
||||||
desc: desc,
|
desc: desc,
|
||||||
|
@ -536,6 +558,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
||||||
nativeHistogramMinResetDuration: opts.NativeHistogramMinResetDuration,
|
nativeHistogramMinResetDuration: opts.NativeHistogramMinResetDuration,
|
||||||
lastResetTime: opts.now(),
|
lastResetTime: opts.now(),
|
||||||
now: opts.now,
|
now: opts.now,
|
||||||
|
afterFunc: opts.afterFunc,
|
||||||
}
|
}
|
||||||
if len(h.upperBounds) == 0 && opts.NativeHistogramBucketFactor <= 1 {
|
if len(h.upperBounds) == 0 && opts.NativeHistogramBucketFactor <= 1 {
|
||||||
h.upperBounds = DefBuckets
|
h.upperBounds = DefBuckets
|
||||||
|
@ -550,6 +573,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
||||||
h.nativeHistogramZeroThreshold = DefNativeHistogramZeroThreshold
|
h.nativeHistogramZeroThreshold = DefNativeHistogramZeroThreshold
|
||||||
} // Leave h.nativeHistogramZeroThreshold at 0 otherwise.
|
} // Leave h.nativeHistogramZeroThreshold at 0 otherwise.
|
||||||
h.nativeHistogramSchema = pickSchema(opts.NativeHistogramBucketFactor)
|
h.nativeHistogramSchema = pickSchema(opts.NativeHistogramBucketFactor)
|
||||||
|
h.nativeExemplars = makeNativeExemplars(opts.NativeHistogramExemplarTTL, opts.NativeHistogramMaxExemplars)
|
||||||
}
|
}
|
||||||
for i, upperBound := range h.upperBounds {
|
for i, upperBound := range h.upperBounds {
|
||||||
if i < len(h.upperBounds)-1 {
|
if i < len(h.upperBounds)-1 {
|
||||||
|
@ -716,9 +740,17 @@ type histogram struct {
|
||||||
nativeHistogramMinResetDuration time.Duration
|
nativeHistogramMinResetDuration time.Duration
|
||||||
// lastResetTime is protected by mtx. It is also used as created timestamp.
|
// lastResetTime is protected by mtx. It is also used as created timestamp.
|
||||||
lastResetTime time.Time
|
lastResetTime time.Time
|
||||||
|
// resetScheduled is protected by mtx. It is true if a reset is
|
||||||
|
// scheduled for a later time (when nativeHistogramMinResetDuration has
|
||||||
|
// passed).
|
||||||
|
resetScheduled bool
|
||||||
|
nativeExemplars nativeExemplars
|
||||||
|
|
||||||
// now is for testing purposes, by default it's time.Now.
|
// now is for testing purposes, by default it's time.Now.
|
||||||
now func() time.Time
|
now func() time.Time
|
||||||
|
|
||||||
|
// afterFunc is for testing purposes, by default it's time.AfterFunc.
|
||||||
|
afterFunc func(time.Duration, func()) *time.Timer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *histogram) Desc() *Desc {
|
func (h *histogram) Desc() *Desc {
|
||||||
|
@ -729,6 +761,9 @@ func (h *histogram) Observe(v float64) {
|
||||||
h.observe(v, h.findBucket(v))
|
h.observe(v, h.findBucket(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ObserveWithExemplar should not be called in a high-frequency setting
|
||||||
|
// for a native histogram with configured exemplars. For this case,
|
||||||
|
// the implementation isn't lock-free and might suffer from lock contention.
|
||||||
func (h *histogram) ObserveWithExemplar(v float64, e Labels) {
|
func (h *histogram) ObserveWithExemplar(v float64, e Labels) {
|
||||||
i := h.findBucket(v)
|
i := h.findBucket(v)
|
||||||
h.observe(v, i)
|
h.observe(v, i)
|
||||||
|
@ -808,6 +843,13 @@ func (h *histogram) Write(out *dto.Metric) error {
|
||||||
Length: proto.Uint32(0),
|
Length: proto.Uint32(0),
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if h.nativeExemplars.isEnabled() {
|
||||||
|
h.nativeExemplars.Lock()
|
||||||
|
his.Exemplars = append(his.Exemplars, h.nativeExemplars.exemplars...)
|
||||||
|
h.nativeExemplars.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
addAndResetCounts(hotCounts, coldCounts)
|
addAndResetCounts(hotCounts, coldCounts)
|
||||||
return nil
|
return nil
|
||||||
|
@ -874,21 +916,31 @@ func (h *histogram) limitBuckets(counts *histogramCounts, value float64, bucket
|
||||||
if h.maybeReset(hotCounts, coldCounts, coldIdx, value, bucket) {
|
if h.maybeReset(hotCounts, coldCounts, coldIdx, value, bucket) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// One of the other strategies will happen. To undo what they will do as
|
||||||
|
// soon as enough time has passed to satisfy
|
||||||
|
// h.nativeHistogramMinResetDuration, schedule a reset at the right time
|
||||||
|
// if we haven't done so already.
|
||||||
|
if h.nativeHistogramMinResetDuration > 0 && !h.resetScheduled {
|
||||||
|
h.resetScheduled = true
|
||||||
|
h.afterFunc(h.nativeHistogramMinResetDuration-h.now().Sub(h.lastResetTime), h.reset)
|
||||||
|
}
|
||||||
|
|
||||||
if h.maybeWidenZeroBucket(hotCounts, coldCounts) {
|
if h.maybeWidenZeroBucket(hotCounts, coldCounts) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.doubleBucketWidth(hotCounts, coldCounts)
|
h.doubleBucketWidth(hotCounts, coldCounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybeReset resets the whole histogram if at least h.nativeHistogramMinResetDuration
|
// maybeReset resets the whole histogram if at least
|
||||||
// has been passed. It returns true if the histogram has been reset. The caller
|
// h.nativeHistogramMinResetDuration has been passed. It returns true if the
|
||||||
// must have locked h.mtx.
|
// histogram has been reset. The caller must have locked h.mtx.
|
||||||
func (h *histogram) maybeReset(
|
func (h *histogram) maybeReset(
|
||||||
hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int,
|
hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int,
|
||||||
) bool {
|
) bool {
|
||||||
// We are using the possibly mocked h.now() rather than
|
// We are using the possibly mocked h.now() rather than
|
||||||
// time.Since(h.lastResetTime) to enable testing.
|
// time.Since(h.lastResetTime) to enable testing.
|
||||||
if h.nativeHistogramMinResetDuration == 0 ||
|
if h.nativeHistogramMinResetDuration == 0 || // No reset configured.
|
||||||
|
h.resetScheduled || // Do not interefere if a reset is already scheduled.
|
||||||
h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration {
|
h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -906,6 +958,29 @@ func (h *histogram) maybeReset(
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset resets the whole histogram. It locks h.mtx itself, i.e. it has to be
|
||||||
|
// called without having locked h.mtx.
|
||||||
|
func (h *histogram) reset() {
|
||||||
|
h.mtx.Lock()
|
||||||
|
defer h.mtx.Unlock()
|
||||||
|
|
||||||
|
n := atomic.LoadUint64(&h.countAndHotIdx)
|
||||||
|
hotIdx := n >> 63
|
||||||
|
coldIdx := (^n) >> 63
|
||||||
|
hot := h.counts[hotIdx]
|
||||||
|
cold := h.counts[coldIdx]
|
||||||
|
// Completely reset coldCounts.
|
||||||
|
h.resetCounts(cold)
|
||||||
|
// Make coldCounts the new hot counts while resetting countAndHotIdx.
|
||||||
|
n = atomic.SwapUint64(&h.countAndHotIdx, coldIdx<<63)
|
||||||
|
count := n & ((1 << 63) - 1)
|
||||||
|
waitForCooldown(count, hot)
|
||||||
|
// Finally, reset the formerly hot counts, too.
|
||||||
|
h.resetCounts(hot)
|
||||||
|
h.lastResetTime = h.now()
|
||||||
|
h.resetScheduled = false
|
||||||
|
}
|
||||||
|
|
||||||
// maybeWidenZeroBucket widens the zero bucket until it includes the existing
|
// maybeWidenZeroBucket widens the zero bucket until it includes the existing
|
||||||
// buckets closest to the zero bucket (which could be two, if an equidistant
|
// buckets closest to the zero bucket (which could be two, if an equidistant
|
||||||
// negative and a positive bucket exists, but usually it's only one bucket to be
|
// negative and a positive bucket exists, but usually it's only one bucket to be
|
||||||
|
@ -1045,8 +1120,10 @@ func (h *histogram) resetCounts(counts *histogramCounts) {
|
||||||
deleteSyncMap(&counts.nativeHistogramBucketsPositive)
|
deleteSyncMap(&counts.nativeHistogramBucketsPositive)
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateExemplar replaces the exemplar for the provided bucket. With empty
|
// updateExemplar replaces the exemplar for the provided classic bucket.
|
||||||
// labels, it's a no-op. It panics if any of the labels is invalid.
|
// With empty labels, it's a no-op. It panics if any of the labels is invalid.
|
||||||
|
// If histogram is native, the exemplar will be cached into nativeExemplars,
|
||||||
|
// which has a limit, and will remove one exemplar when limit is reached.
|
||||||
func (h *histogram) updateExemplar(v float64, bucket int, l Labels) {
|
func (h *histogram) updateExemplar(v float64, bucket int, l Labels) {
|
||||||
if l == nil {
|
if l == nil {
|
||||||
return
|
return
|
||||||
|
@ -1056,6 +1133,10 @@ func (h *histogram) updateExemplar(v float64, bucket int, l Labels) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
h.exemplars[bucket].Store(e)
|
h.exemplars[bucket].Store(e)
|
||||||
|
doSparse := h.nativeHistogramSchema > math.MinInt32 && !math.IsNaN(v)
|
||||||
|
if doSparse {
|
||||||
|
h.nativeExemplars.addExemplar(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HistogramVec is a Collector that bundles a set of Histograms that all share the
|
// HistogramVec is a Collector that bundles a set of Histograms that all share the
|
||||||
|
@ -1290,6 +1371,48 @@ func MustNewConstHistogram(
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewConstHistogramWithCreatedTimestamp does the same thing as NewConstHistogram but sets the created timestamp.
|
||||||
|
func NewConstHistogramWithCreatedTimestamp(
|
||||||
|
desc *Desc,
|
||||||
|
count uint64,
|
||||||
|
sum float64,
|
||||||
|
buckets map[float64]uint64,
|
||||||
|
ct time.Time,
|
||||||
|
labelValues ...string,
|
||||||
|
) (Metric, error) {
|
||||||
|
if desc.err != nil {
|
||||||
|
return nil, desc.err
|
||||||
|
}
|
||||||
|
if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &constHistogram{
|
||||||
|
desc: desc,
|
||||||
|
count: count,
|
||||||
|
sum: sum,
|
||||||
|
buckets: buckets,
|
||||||
|
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||||
|
createdTs: timestamppb.New(ct),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustNewConstHistogramWithCreatedTimestamp is a version of NewConstHistogramWithCreatedTimestamp that panics where
|
||||||
|
// NewConstHistogramWithCreatedTimestamp would have returned an error.
|
||||||
|
func MustNewConstHistogramWithCreatedTimestamp(
|
||||||
|
desc *Desc,
|
||||||
|
count uint64,
|
||||||
|
sum float64,
|
||||||
|
buckets map[float64]uint64,
|
||||||
|
ct time.Time,
|
||||||
|
labelValues ...string,
|
||||||
|
) Metric {
|
||||||
|
m, err := NewConstHistogramWithCreatedTimestamp(desc, count, sum, buckets, ct, labelValues...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
type buckSort []*dto.Bucket
|
type buckSort []*dto.Bucket
|
||||||
|
|
||||||
func (s buckSort) Len() int {
|
func (s buckSort) Len() int {
|
||||||
|
@ -1529,3 +1652,186 @@ func addAndResetCounts(hot, cold *histogramCounts) {
|
||||||
atomic.AddUint64(&hot.nativeHistogramZeroBucket, atomic.LoadUint64(&cold.nativeHistogramZeroBucket))
|
atomic.AddUint64(&hot.nativeHistogramZeroBucket, atomic.LoadUint64(&cold.nativeHistogramZeroBucket))
|
||||||
atomic.StoreUint64(&cold.nativeHistogramZeroBucket, 0)
|
atomic.StoreUint64(&cold.nativeHistogramZeroBucket, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nativeExemplars struct {
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
|
// Time-to-live for exemplars, it is set to -1 if exemplars are disabled, that is NativeHistogramMaxExemplars is below 0.
|
||||||
|
// The ttl is used on insertion to remove an exemplar that is older than ttl, if present.
|
||||||
|
ttl time.Duration
|
||||||
|
|
||||||
|
exemplars []*dto.Exemplar
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *nativeExemplars) isEnabled() bool {
|
||||||
|
return n.ttl != -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeNativeExemplars(ttl time.Duration, maxCount int) nativeExemplars {
|
||||||
|
if ttl == 0 {
|
||||||
|
ttl = 5 * time.Minute
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxCount == 0 {
|
||||||
|
maxCount = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxCount < 0 {
|
||||||
|
maxCount = 0
|
||||||
|
ttl = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return nativeExemplars{
|
||||||
|
ttl: ttl,
|
||||||
|
exemplars: make([]*dto.Exemplar, 0, maxCount),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *nativeExemplars) addExemplar(e *dto.Exemplar) {
|
||||||
|
if !n.isEnabled() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
n.Lock()
|
||||||
|
defer n.Unlock()
|
||||||
|
|
||||||
|
// When the number of exemplars has not yet exceeded or
|
||||||
|
// is equal to cap(n.exemplars), then
|
||||||
|
// insert the new exemplar directly.
|
||||||
|
if len(n.exemplars) < cap(n.exemplars) {
|
||||||
|
var nIdx int
|
||||||
|
for nIdx = 0; nIdx < len(n.exemplars); nIdx++ {
|
||||||
|
if *e.Value < *n.exemplars[nIdx].Value {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.exemplars = append(n.exemplars[:nIdx], append([]*dto.Exemplar{e}, n.exemplars[nIdx:]...)...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(n.exemplars) == 1 {
|
||||||
|
// When the number of exemplars is 1, then
|
||||||
|
// replace the existing exemplar with the new exemplar.
|
||||||
|
n.exemplars[0] = e
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// From this point on, the number of exemplars is greater than 1.
|
||||||
|
|
||||||
|
// When the number of exemplars exceeds the limit, remove one exemplar.
|
||||||
|
var (
|
||||||
|
ot = time.Time{} // Oldest timestamp seen. Initial value doesn't matter as we replace it due to otIdx == -1 in the loop.
|
||||||
|
otIdx = -1 // Index of the exemplar with the oldest timestamp.
|
||||||
|
|
||||||
|
md = -1.0 // Logarithm of the delta of the closest pair of exemplars.
|
||||||
|
|
||||||
|
// The insertion point of the new exemplar in the exemplars slice after insertion.
|
||||||
|
// This is calculated purely based on the order of the exemplars by value.
|
||||||
|
// nIdx == len(n.exemplars) means the new exemplar is to be inserted after the end.
|
||||||
|
nIdx = -1
|
||||||
|
|
||||||
|
// rIdx is ultimately the index for the exemplar that we are replacing with the new exemplar.
|
||||||
|
// The aim is to keep a good spread of exemplars by value and not let them bunch up too much.
|
||||||
|
// It is calculated in 3 steps:
|
||||||
|
// 1. First we set rIdx to the index of the older exemplar within the closest pair by value.
|
||||||
|
// That is the following will be true (on log scale):
|
||||||
|
// either the exemplar pair on index (rIdx-1, rIdx) or (rIdx, rIdx+1) will have
|
||||||
|
// the closest values to each other from all pairs.
|
||||||
|
// For example, suppose the values are distributed like this:
|
||||||
|
// |-----------x-------------x----------------x----x-----|
|
||||||
|
// ^--rIdx as this is older.
|
||||||
|
// Or like this:
|
||||||
|
// |-----------x-------------x----------------x----x-----|
|
||||||
|
// ^--rIdx as this is older.
|
||||||
|
// 2. If there is an exemplar that expired, then we simple reset rIdx to that index.
|
||||||
|
// 3. We check if by inserting the new exemplar we would create a closer pair at
|
||||||
|
// (nIdx-1, nIdx) or (nIdx, nIdx+1) and set rIdx to nIdx-1 or nIdx accordingly to
|
||||||
|
// keep the spread of exemplars by value; otherwise we keep rIdx as it is.
|
||||||
|
rIdx = -1
|
||||||
|
cLog float64 // Logarithm of the current exemplar.
|
||||||
|
pLog float64 // Logarithm of the previous exemplar.
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, exemplar := range n.exemplars {
|
||||||
|
// Find the exemplar with the oldest timestamp.
|
||||||
|
if otIdx == -1 || exemplar.Timestamp.AsTime().Before(ot) {
|
||||||
|
ot = exemplar.Timestamp.AsTime()
|
||||||
|
otIdx = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the index at which to insert new the exemplar.
|
||||||
|
if nIdx == -1 && *e.Value <= *exemplar.Value {
|
||||||
|
nIdx = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the two closest exemplars and pick the one the with older timestamp.
|
||||||
|
pLog = cLog
|
||||||
|
cLog = math.Log(exemplar.GetValue())
|
||||||
|
if i == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
diff := math.Abs(cLog - pLog)
|
||||||
|
if md == -1 || diff < md {
|
||||||
|
// The closest exemplar pair is at index: i-1, i.
|
||||||
|
// Choose the exemplar with the older timestamp for replacement.
|
||||||
|
md = diff
|
||||||
|
if n.exemplars[i].Timestamp.AsTime().Before(n.exemplars[i-1].Timestamp.AsTime()) {
|
||||||
|
rIdx = i
|
||||||
|
} else {
|
||||||
|
rIdx = i - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all existing exemplar are smaller than new exemplar,
|
||||||
|
// then the exemplar should be inserted at the end.
|
||||||
|
if nIdx == -1 {
|
||||||
|
nIdx = len(n.exemplars)
|
||||||
|
}
|
||||||
|
// Here, we have the following relationships:
|
||||||
|
// n.exemplars[nIdx-1].Value < e.Value (if nIdx > 0)
|
||||||
|
// e.Value <= n.exemplars[nIdx].Value (if nIdx < len(n.exemplars))
|
||||||
|
|
||||||
|
if otIdx != -1 && e.Timestamp.AsTime().Sub(ot) > n.ttl {
|
||||||
|
// If the oldest exemplar has expired, then replace it with the new exemplar.
|
||||||
|
rIdx = otIdx
|
||||||
|
} else {
|
||||||
|
// In the previous for loop, when calculating the closest pair of exemplars,
|
||||||
|
// we did not take into account the newly inserted exemplar.
|
||||||
|
// So we need to calculate with the newly inserted exemplar again.
|
||||||
|
elog := math.Log(e.GetValue())
|
||||||
|
if nIdx > 0 {
|
||||||
|
diff := math.Abs(elog - math.Log(n.exemplars[nIdx-1].GetValue()))
|
||||||
|
if diff < md {
|
||||||
|
// The value we are about to insert is closer to the previous exemplar at the insertion point than what we calculated before in rIdx.
|
||||||
|
// v--rIdx
|
||||||
|
// |-----------x-n-----------x----------------x----x-----|
|
||||||
|
// nIdx-1--^ ^--new exemplar value
|
||||||
|
// Do not make the spread worse, replace nIdx-1 and not rIdx.
|
||||||
|
md = diff
|
||||||
|
rIdx = nIdx - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nIdx < len(n.exemplars) {
|
||||||
|
diff := math.Abs(math.Log(n.exemplars[nIdx].GetValue()) - elog)
|
||||||
|
if diff < md {
|
||||||
|
// The value we are about to insert is closer to the next exemplar at the insertion point than what we calculated before in rIdx.
|
||||||
|
// v--rIdx
|
||||||
|
// |-----------x-----------n-x----------------x----x-----|
|
||||||
|
// new exemplar value--^ ^--nIdx
|
||||||
|
// Do not make the spread worse, replace nIdx-1 and not rIdx.
|
||||||
|
rIdx = nIdx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust the slice according to rIdx and nIdx.
|
||||||
|
switch {
|
||||||
|
case rIdx == nIdx:
|
||||||
|
n.exemplars[nIdx] = e
|
||||||
|
case rIdx < nIdx:
|
||||||
|
n.exemplars = append(n.exemplars[:rIdx], append(n.exemplars[rIdx+1:nIdx], append([]*dto.Exemplar{e}, n.exemplars[nIdx:]...)...)...)
|
||||||
|
case rIdx > nIdx:
|
||||||
|
n.exemplars = append(n.exemplars[:nIdx], append([]*dto.Exemplar{e}, append(n.exemplars[nIdx:rIdx], n.exemplars[rIdx+1:]...)...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,3 +30,5 @@ type GoCollectorOptions struct {
|
||||||
RuntimeMetricSumForHist map[string]string
|
RuntimeMetricSumForHist map[string]string
|
||||||
RuntimeMetricRules []GoCollectorRule
|
RuntimeMetricRules []GoCollectorRule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var GoCollectorDefaultRuntimeMetrics = regexp.MustCompile(`/gc/gogc:percent|/gc/gomemlimit:bytes|/sched/gomaxprocs:threads`)
|
||||||
|
|
|
@ -165,6 +165,8 @@ 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 {
|
||||||
|
// The call below makes vals escape, copy them to avoid that.
|
||||||
|
vals := append([]string(nil), vals...)
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"%w: expected %d label values but got %d in %#v",
|
"%w: expected %d label values but got %d in %#v",
|
||||||
errInconsistentCardinality, expectedNumberOfValues,
|
errInconsistentCardinality, expectedNumberOfValues,
|
||||||
|
|
|
@ -234,7 +234,7 @@ func NewMetricWithExemplars(m Metric, exemplars ...Exemplar) (Metric, error) {
|
||||||
)
|
)
|
||||||
for i, e := range exemplars {
|
for i, e := range exemplars {
|
||||||
ts := e.Timestamp
|
ts := e.Timestamp
|
||||||
if ts == (time.Time{}) {
|
if ts.IsZero() {
|
||||||
ts = now
|
ts = now
|
||||||
}
|
}
|
||||||
exs[i], err = newExemplar(e.Value, ts, e.Labels)
|
exs[i], err = newExemplar(e.Value, ts, e.Labels)
|
||||||
|
|
|
@ -22,14 +22,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type processCollector struct {
|
type processCollector struct {
|
||||||
collectFn func(chan<- Metric)
|
collectFn func(chan<- Metric)
|
||||||
pidFn func() (int, error)
|
pidFn func() (int, error)
|
||||||
reportErrors bool
|
reportErrors bool
|
||||||
cpuTotal *Desc
|
cpuTotal *Desc
|
||||||
openFDs, maxFDs *Desc
|
openFDs, maxFDs *Desc
|
||||||
vsize, maxVsize *Desc
|
vsize, maxVsize *Desc
|
||||||
rss *Desc
|
rss *Desc
|
||||||
startTime *Desc
|
startTime *Desc
|
||||||
|
inBytes, outBytes *Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessCollectorOpts defines the behavior of a process metrics collector
|
// ProcessCollectorOpts defines the behavior of a process metrics collector
|
||||||
|
@ -100,6 +101,16 @@ func NewProcessCollector(opts ProcessCollectorOpts) Collector {
|
||||||
"Start time of the process since unix epoch in seconds.",
|
"Start time of the process since unix epoch in seconds.",
|
||||||
nil, nil,
|
nil, nil,
|
||||||
),
|
),
|
||||||
|
inBytes: NewDesc(
|
||||||
|
ns+"process_network_receive_bytes_total",
|
||||||
|
"Number of bytes received by the process over the network.",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
outBytes: NewDesc(
|
||||||
|
ns+"process_network_transmit_bytes_total",
|
||||||
|
"Number of bytes sent by the process over the network.",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.PidFn == nil {
|
if opts.PidFn == nil {
|
||||||
|
@ -129,6 +140,8 @@ func (c *processCollector) Describe(ch chan<- *Desc) {
|
||||||
ch <- c.maxVsize
|
ch <- c.maxVsize
|
||||||
ch <- c.rss
|
ch <- c.rss
|
||||||
ch <- c.startTime
|
ch <- c.startTime
|
||||||
|
ch <- c.inBytes
|
||||||
|
ch <- c.outBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect returns the current state of all metrics of the collector.
|
// Collect returns the current state of all metrics of the collector.
|
||||||
|
|
18
vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go
generated
vendored
18
vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go
generated
vendored
|
@ -11,8 +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.
|
||||||
|
|
||||||
//go:build !windows && !js
|
//go:build !windows && !js && !wasip1
|
||||||
// +build !windows,!js
|
// +build !windows,!js,!wasip1
|
||||||
|
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
|
@ -63,4 +63,18 @@ func (c *processCollector) processCollect(ch chan<- Metric) {
|
||||||
} else {
|
} else {
|
||||||
c.reportError(ch, nil, err)
|
c.reportError(ch, nil, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if netstat, err := p.Netstat(); err == nil {
|
||||||
|
var inOctets, outOctets float64
|
||||||
|
if netstat.IpExt.InOctets != nil {
|
||||||
|
inOctets = *netstat.IpExt.InOctets
|
||||||
|
}
|
||||||
|
if netstat.IpExt.OutOctets != nil {
|
||||||
|
outOctets = *netstat.IpExt.OutOctets
|
||||||
|
}
|
||||||
|
ch <- MustNewConstMetric(c.inBytes, CounterValue, inOctets)
|
||||||
|
ch <- MustNewConstMetric(c.outBytes, CounterValue, outOctets)
|
||||||
|
} else {
|
||||||
|
c.reportError(ch, nil, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// Copyright The OpenTelemetry Authors
|
// Copyright 2023 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
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@ -12,9 +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.
|
||||||
|
|
||||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.17.0"
|
//go:build wasip1
|
||||||
|
// +build wasip1
|
||||||
|
|
||||||
const (
|
package prometheus
|
||||||
// ExceptionEventName is the name of the Span event representing an exception.
|
|
||||||
ExceptionEventName = "exception"
|
func canCollectProcess() bool {
|
||||||
)
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*processCollector) processCollect(chan<- Metric) {
|
||||||
|
// noop on this platform
|
||||||
|
return
|
||||||
|
}
|
|
@ -76,6 +76,12 @@ func (r *responseWriterDelegator) Write(b []byte) (int, error) {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwrap lets http.ResponseController get the underlying http.ResponseWriter,
|
||||||
|
// by implementing the [rwUnwrapper](https://cs.opensource.google/go/go/+/refs/tags/go1.21.4:src/net/http/responsecontroller.go;l=42-44) interface.
|
||||||
|
func (r *responseWriterDelegator) Unwrap() http.ResponseWriter {
|
||||||
|
return r.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
closeNotifierDelegator struct{ *responseWriterDelegator }
|
closeNotifierDelegator struct{ *responseWriterDelegator }
|
||||||
flusherDelegator struct{ *responseWriterDelegator }
|
flusherDelegator struct{ *responseWriterDelegator }
|
||||||
|
|
|
@ -38,12 +38,13 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/klauspost/compress/zstd"
|
||||||
"github.com/prometheus/common/expfmt"
|
"github.com/prometheus/common/expfmt"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,6 +55,18 @@ const (
|
||||||
processStartTimeHeader = "Process-Start-Time-Unix"
|
processStartTimeHeader = "Process-Start-Time-Unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Compression represents the content encodings handlers support for the HTTP
|
||||||
|
// responses.
|
||||||
|
type Compression string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Identity Compression = "identity"
|
||||||
|
Gzip Compression = "gzip"
|
||||||
|
Zstd Compression = "zstd"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultCompressionFormats = []Compression{Identity, Gzip, Zstd}
|
||||||
|
|
||||||
var gzipPool = sync.Pool{
|
var gzipPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
return gzip.NewWriter(nil)
|
return gzip.NewWriter(nil)
|
||||||
|
@ -122,6 +135,18 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select compression formats to offer based on default or user choice.
|
||||||
|
var compressions []string
|
||||||
|
if !opts.DisableCompression {
|
||||||
|
offers := defaultCompressionFormats
|
||||||
|
if len(opts.OfferedCompressions) > 0 {
|
||||||
|
offers = opts.OfferedCompressions
|
||||||
|
}
|
||||||
|
for _, comp := range offers {
|
||||||
|
compressions = append(compressions, string(comp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) {
|
h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) {
|
||||||
if !opts.ProcessStartTime.IsZero() {
|
if !opts.ProcessStartTime.IsZero() {
|
||||||
rsp.Header().Set(processStartTimeHeader, strconv.FormatInt(opts.ProcessStartTime.Unix(), 10))
|
rsp.Header().Set(processStartTimeHeader, strconv.FormatInt(opts.ProcessStartTime.Unix(), 10))
|
||||||
|
@ -165,21 +190,23 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
|
||||||
} else {
|
} else {
|
||||||
contentType = expfmt.Negotiate(req.Header)
|
contentType = expfmt.Negotiate(req.Header)
|
||||||
}
|
}
|
||||||
header := rsp.Header()
|
rsp.Header().Set(contentTypeHeader, string(contentType))
|
||||||
header.Set(contentTypeHeader, string(contentType))
|
|
||||||
|
|
||||||
w := io.Writer(rsp)
|
w, encodingHeader, closeWriter, err := negotiateEncodingWriter(req, rsp, compressions)
|
||||||
if !opts.DisableCompression && gzipAccepted(req.Header) {
|
if err != nil {
|
||||||
header.Set(contentEncodingHeader, "gzip")
|
if opts.ErrorLog != nil {
|
||||||
gz := gzipPool.Get().(*gzip.Writer)
|
opts.ErrorLog.Println("error getting writer", err)
|
||||||
defer gzipPool.Put(gz)
|
}
|
||||||
|
w = io.Writer(rsp)
|
||||||
gz.Reset(w)
|
encodingHeader = string(Identity)
|
||||||
defer gz.Close()
|
|
||||||
|
|
||||||
w = gz
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer closeWriter()
|
||||||
|
|
||||||
|
// Set Content-Encoding only when data is compressed
|
||||||
|
if encodingHeader != string(Identity) {
|
||||||
|
rsp.Header().Set(contentEncodingHeader, encodingHeader)
|
||||||
|
}
|
||||||
enc := expfmt.NewEncoder(w, contentType)
|
enc := expfmt.NewEncoder(w, contentType)
|
||||||
|
|
||||||
// handleError handles the error according to opts.ErrorHandling
|
// handleError handles the error according to opts.ErrorHandling
|
||||||
|
@ -343,9 +370,19 @@ type HandlerOpts struct {
|
||||||
// no effect on the HTTP status code because ErrorHandling is set to
|
// no effect on the HTTP status code because ErrorHandling is set to
|
||||||
// ContinueOnError.
|
// ContinueOnError.
|
||||||
Registry prometheus.Registerer
|
Registry prometheus.Registerer
|
||||||
// If DisableCompression is true, the handler will never compress the
|
// DisableCompression disables the response encoding (compression) and
|
||||||
// response, even if requested by the client.
|
// encoding negotiation. If true, the handler will
|
||||||
|
// never compress the response, even if requested
|
||||||
|
// by the client and the OfferedCompressions field is set.
|
||||||
DisableCompression bool
|
DisableCompression bool
|
||||||
|
// OfferedCompressions is a set of encodings (compressions) handler will
|
||||||
|
// try to offer when negotiating with the client. This defaults to identity, gzip
|
||||||
|
// and zstd.
|
||||||
|
// NOTE: If handler can't agree with the client on the encodings or
|
||||||
|
// unsupported or empty encodings are set in OfferedCompressions,
|
||||||
|
// handler always fallbacks to no compression (identity), for
|
||||||
|
// compatibility reasons. In such cases ErrorLog will be used if set.
|
||||||
|
OfferedCompressions []Compression
|
||||||
// The number of concurrent HTTP requests is limited to
|
// The number of concurrent HTTP requests is limited to
|
||||||
// MaxRequestsInFlight. Additional requests are responded to with 503
|
// MaxRequestsInFlight. Additional requests are responded to with 503
|
||||||
// Service Unavailable and a suitable message in the body. If
|
// Service Unavailable and a suitable message in the body. If
|
||||||
|
@ -381,19 +418,6 @@ type HandlerOpts struct {
|
||||||
ProcessStartTime time.Time
|
ProcessStartTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// gzipAccepted returns whether the client will accept gzip-encoded content.
|
|
||||||
func gzipAccepted(header http.Header) bool {
|
|
||||||
a := header.Get(acceptEncodingHeader)
|
|
||||||
parts := strings.Split(a, ",")
|
|
||||||
for _, part := range parts {
|
|
||||||
part = strings.TrimSpace(part)
|
|
||||||
if part == "gzip" || strings.HasPrefix(part, "gzip;") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// httpError removes any content-encoding header and then calls http.Error with
|
// httpError removes any content-encoding header and then calls http.Error with
|
||||||
// the provided error and http.StatusInternalServerError. Error contents is
|
// the provided error and http.StatusInternalServerError. Error contents is
|
||||||
// supposed to be uncompressed plain text. Same as with a plain http.Error, this
|
// supposed to be uncompressed plain text. Same as with a plain http.Error, this
|
||||||
|
@ -406,3 +430,38 @@ func httpError(rsp http.ResponseWriter, err error) {
|
||||||
http.StatusInternalServerError,
|
http.StatusInternalServerError,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// negotiateEncodingWriter reads the Accept-Encoding header from a request and
|
||||||
|
// selects the right compression based on an allow-list of supported
|
||||||
|
// compressions. It returns a writer implementing the compression and an the
|
||||||
|
// correct value that the caller can set in the response header.
|
||||||
|
func negotiateEncodingWriter(r *http.Request, rw io.Writer, compressions []string) (_ io.Writer, encodingHeaderValue string, closeWriter func(), _ error) {
|
||||||
|
if len(compressions) == 0 {
|
||||||
|
return rw, string(Identity), func() {}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mrueg): Replace internal/github.com/gddo once https://github.com/golang/go/issues/19307 is implemented.
|
||||||
|
selected := httputil.NegotiateContentEncoding(r, compressions)
|
||||||
|
|
||||||
|
switch selected {
|
||||||
|
case "zstd":
|
||||||
|
// TODO(mrueg): Replace klauspost/compress with stdlib implementation once https://github.com/golang/go/issues/62513 is implemented.
|
||||||
|
z, err := zstd.NewWriter(rw, zstd.WithEncoderLevel(zstd.SpeedFastest))
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", func() {}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
z.Reset(rw)
|
||||||
|
return z, selected, func() { _ = z.Close() }, nil
|
||||||
|
case "gzip":
|
||||||
|
gz := gzipPool.Get().(*gzip.Writer)
|
||||||
|
gz.Reset(rw)
|
||||||
|
return gz, selected, func() { _ = gz.Close(); gzipPool.Put(gz) }, nil
|
||||||
|
case "identity":
|
||||||
|
// This means the content is not compressed.
|
||||||
|
return rw, selected, func() {}, nil
|
||||||
|
default:
|
||||||
|
// The content encoding was not implemented yet.
|
||||||
|
return nil, "", func() {}, fmt.Errorf("content compression format not recognized: %s. Valid formats are: %s", selected, defaultCompressionFormats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -314,16 +314,17 @@ func (r *Registry) Register(c Collector) error {
|
||||||
if dimHash != desc.dimHash {
|
if dimHash != desc.dimHash {
|
||||||
return fmt.Errorf("a previously registered descriptor with the same fully-qualified name as %s has different label names or a different help string", desc)
|
return fmt.Errorf("a previously registered descriptor with the same fully-qualified name as %s has different label names or a different help string", desc)
|
||||||
}
|
}
|
||||||
} else {
|
continue
|
||||||
// ...then check the new descriptors already seen.
|
|
||||||
if dimHash, exists := newDimHashesByName[desc.fqName]; exists {
|
|
||||||
if dimHash != desc.dimHash {
|
|
||||||
return fmt.Errorf("descriptors reported by collector have inconsistent label names or help strings for the same fully-qualified name, offender is %s", desc)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newDimHashesByName[desc.fqName] = desc.dimHash
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ...then check the new descriptors already seen.
|
||||||
|
if dimHash, exists := newDimHashesByName[desc.fqName]; exists {
|
||||||
|
if dimHash != desc.dimHash {
|
||||||
|
return fmt.Errorf("descriptors reported by collector have inconsistent label names or help strings for the same fully-qualified name, offender is %s", desc)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newDimHashesByName[desc.fqName] = desc.dimHash
|
||||||
}
|
}
|
||||||
// A Collector yielding no Desc at all is considered unchecked.
|
// A Collector yielding no Desc at all is considered unchecked.
|
||||||
if len(newDescIDs) == 0 {
|
if len(newDescIDs) == 0 {
|
||||||
|
|
|
@ -783,3 +783,45 @@ func MustNewConstSummary(
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewConstSummaryWithCreatedTimestamp does the same thing as NewConstSummary but sets the created timestamp.
|
||||||
|
func NewConstSummaryWithCreatedTimestamp(
|
||||||
|
desc *Desc,
|
||||||
|
count uint64,
|
||||||
|
sum float64,
|
||||||
|
quantiles map[float64]float64,
|
||||||
|
ct time.Time,
|
||||||
|
labelValues ...string,
|
||||||
|
) (Metric, error) {
|
||||||
|
if desc.err != nil {
|
||||||
|
return nil, desc.err
|
||||||
|
}
|
||||||
|
if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &constSummary{
|
||||||
|
desc: desc,
|
||||||
|
count: count,
|
||||||
|
sum: sum,
|
||||||
|
quantiles: quantiles,
|
||||||
|
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||||
|
createdTs: timestamppb.New(ct),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustNewConstSummaryWithCreatedTimestamp is a version of NewConstSummaryWithCreatedTimestamp that panics where
|
||||||
|
// NewConstSummaryWithCreatedTimestamp would have returned an error.
|
||||||
|
func MustNewConstSummaryWithCreatedTimestamp(
|
||||||
|
desc *Desc,
|
||||||
|
count uint64,
|
||||||
|
sum float64,
|
||||||
|
quantiles map[float64]float64,
|
||||||
|
ct time.Time,
|
||||||
|
labelValues ...string,
|
||||||
|
) Metric {
|
||||||
|
m, err := NewConstSummaryWithCreatedTimestamp(desc, count, sum, quantiles, ct, labelValues...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
|
@ -507,7 +507,7 @@ func (m *metricMap) getOrCreateMetricWithLabelValues(
|
||||||
return metric
|
return metric
|
||||||
}
|
}
|
||||||
|
|
||||||
// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
|
// getOrCreateMetricWithLabels retrieves the metric by hash and label value
|
||||||
// or creates it and returns the new one.
|
// or creates it and returns the new one.
|
||||||
//
|
//
|
||||||
// This function holds the mutex.
|
// This function holds the mutex.
|
||||||
|
|
|
@ -483,6 +483,8 @@ type Histogram struct {
|
||||||
// histograms.
|
// histograms.
|
||||||
PositiveDelta []int64 `protobuf:"zigzag64,13,rep,name=positive_delta,json=positiveDelta" json:"positive_delta,omitempty"` // Count delta of each bucket compared to previous one (or to zero for 1st bucket).
|
PositiveDelta []int64 `protobuf:"zigzag64,13,rep,name=positive_delta,json=positiveDelta" json:"positive_delta,omitempty"` // Count delta of each bucket compared to previous one (or to zero for 1st bucket).
|
||||||
PositiveCount []float64 `protobuf:"fixed64,14,rep,name=positive_count,json=positiveCount" json:"positive_count,omitempty"` // Absolute count of each bucket.
|
PositiveCount []float64 `protobuf:"fixed64,14,rep,name=positive_count,json=positiveCount" json:"positive_count,omitempty"` // Absolute count of each bucket.
|
||||||
|
// Only used for native histograms. These exemplars MUST have a timestamp.
|
||||||
|
Exemplars []*Exemplar `protobuf:"bytes,16,rep,name=exemplars" json:"exemplars,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Histogram) Reset() {
|
func (x *Histogram) Reset() {
|
||||||
|
@ -622,6 +624,13 @@ func (x *Histogram) GetPositiveCount() []float64 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Histogram) GetExemplars() []*Exemplar {
|
||||||
|
if x != nil {
|
||||||
|
return x.Exemplars
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// A Bucket of a conventional histogram, each of which is treated as
|
// A Bucket of a conventional histogram, each of which is treated as
|
||||||
// an individual counter-like time series by Prometheus.
|
// an individual counter-like time series by Prometheus.
|
||||||
type Bucket struct {
|
type Bucket struct {
|
||||||
|
@ -923,6 +932,7 @@ type MetricFamily struct {
|
||||||
Help *string `protobuf:"bytes,2,opt,name=help" json:"help,omitempty"`
|
Help *string `protobuf:"bytes,2,opt,name=help" json:"help,omitempty"`
|
||||||
Type *MetricType `protobuf:"varint,3,opt,name=type,enum=io.prometheus.client.MetricType" json:"type,omitempty"`
|
Type *MetricType `protobuf:"varint,3,opt,name=type,enum=io.prometheus.client.MetricType" json:"type,omitempty"`
|
||||||
Metric []*Metric `protobuf:"bytes,4,rep,name=metric" json:"metric,omitempty"`
|
Metric []*Metric `protobuf:"bytes,4,rep,name=metric" json:"metric,omitempty"`
|
||||||
|
Unit *string `protobuf:"bytes,5,opt,name=unit" json:"unit,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MetricFamily) Reset() {
|
func (x *MetricFamily) Reset() {
|
||||||
|
@ -985,6 +995,13 @@ func (x *MetricFamily) GetMetric() []*Metric {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *MetricFamily) GetUnit() string {
|
||||||
|
if x != nil && x.Unit != nil {
|
||||||
|
return *x.Unit
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
var File_io_prometheus_client_metrics_proto protoreflect.FileDescriptor
|
var File_io_prometheus_client_metrics_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_io_prometheus_client_metrics_proto_rawDesc = []byte{
|
var file_io_prometheus_client_metrics_proto_rawDesc = []byte{
|
||||||
|
@ -1028,7 +1045,7 @@ var file_io_prometheus_client_metrics_proto_rawDesc = []byte{
|
||||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
|
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
|
||||||
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x1f, 0x0a, 0x07, 0x55, 0x6e, 0x74,
|
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x1f, 0x0a, 0x07, 0x55, 0x6e, 0x74,
|
||||||
0x79, 0x70, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20,
|
0x79, 0x70, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20,
|
||||||
0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xac, 0x05, 0x0a, 0x09, 0x48,
|
0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xea, 0x05, 0x0a, 0x09, 0x48,
|
||||||
0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, 0x6d, 0x70,
|
0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, 0x6d, 0x70,
|
||||||
0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
|
0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
|
||||||
0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x73,
|
0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x73,
|
||||||
|
@ -1071,79 +1088,84 @@ var file_io_prometheus_client_metrics_proto_rawDesc = []byte{
|
||||||
0x03, 0x28, 0x12, 0x52, 0x0d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x6c,
|
0x03, 0x28, 0x12, 0x52, 0x0d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x6c,
|
||||||
0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63,
|
0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63,
|
||||||
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x01, 0x52, 0x0d, 0x70, 0x6f, 0x73, 0x69,
|
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x01, 0x52, 0x0d, 0x70, 0x6f, 0x73, 0x69,
|
||||||
0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc6, 0x01, 0x0a, 0x06, 0x42, 0x75,
|
0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x09, 0x65, 0x78, 0x65,
|
||||||
0x63, 0x6b, 0x65, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69,
|
0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69,
|
||||||
0x76, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f,
|
0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69,
|
||||||
0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12,
|
0x65, 0x6e, 0x74, 0x2e, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x09, 0x65, 0x78,
|
||||||
0x34, 0x0a, 0x16, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f,
|
0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x06, 0x42, 0x75, 0x63, 0x6b,
|
||||||
0x75, 0x6e, 0x74, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52,
|
0x65, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65,
|
||||||
0x14, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
|
0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x63, 0x75,
|
||||||
0x46, 0x6c, 0x6f, 0x61, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62,
|
0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x34, 0x0a,
|
||||||
0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x75, 0x70, 0x70, 0x65,
|
0x16, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e,
|
||||||
0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3a, 0x0a, 0x08, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c,
|
0x74, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x14, 0x63,
|
||||||
0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72,
|
0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x46, 0x6c,
|
||||||
0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e,
|
0x6f, 0x61, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x75,
|
||||||
0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x08, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c,
|
0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x75, 0x70, 0x70, 0x65, 0x72, 0x42,
|
||||||
0x61, 0x72, 0x22, 0x3c, 0x0a, 0x0a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x70, 0x61, 0x6e,
|
0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3a, 0x0a, 0x08, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72,
|
||||||
0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x11,
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d,
|
||||||
0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67,
|
0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x78,
|
||||||
0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
|
0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x08, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72,
|
||||||
0x22, 0x91, 0x01, 0x0a, 0x08, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x12, 0x35, 0x0a,
|
0x22, 0x3c, 0x0a, 0x0a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x16,
|
||||||
|
0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x11, 0x52, 0x06,
|
||||||
|
0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
|
||||||
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x91,
|
||||||
|
0x01, 0x0a, 0x08, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x12, 0x35, 0x0a, 0x05, 0x6c,
|
||||||
|
0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x6f, 0x2e,
|
||||||
|
0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
|
0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x62,
|
||||||
|
0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
|
0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
|
||||||
|
0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
|
||||||
|
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
|
||||||
|
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||||
|
0x6d, 0x70, 0x22, 0xff, 0x02, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x35, 0x0a,
|
||||||
0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69,
|
0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69,
|
||||||
0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69,
|
0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69,
|
||||||
0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x6c,
|
0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x6c,
|
||||||
0x61, 0x62, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
|
0x61, 0x62, 0x65, 0x6c, 0x12, 0x31, 0x0a, 0x05, 0x67, 0x61, 0x75, 0x67, 0x65, 0x18, 0x02, 0x20,
|
||||||
0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69,
|
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68,
|
||||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x47, 0x61, 0x75, 0x67, 0x65,
|
||||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
0x52, 0x05, 0x67, 0x61, 0x75, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
||||||
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73,
|
0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72,
|
||||||
0x74, 0x61, 0x6d, 0x70, 0x22, 0xff, 0x02, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12,
|
0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e,
|
||||||
0x35, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f,
|
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
|
||||||
0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63,
|
0x12, 0x37, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52,
|
0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75,
|
||||||
0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x31, 0x0a, 0x05, 0x67, 0x61, 0x75, 0x67, 0x65, 0x18,
|
0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79,
|
||||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65,
|
0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x37, 0x0a, 0x07, 0x75, 0x6e, 0x74,
|
||||||
0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x47, 0x61, 0x75,
|
0x79, 0x70, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6f, 0x2e,
|
||||||
0x67, 0x65, 0x52, 0x05, 0x67, 0x61, 0x75, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x75,
|
|
||||||
0x6e, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6f, 0x2e,
|
|
||||||
0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
0x74, 0x2e, 0x55, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x52, 0x07, 0x75, 0x6e, 0x74, 0x79, 0x70,
|
||||||
0x65, 0x72, 0x12, 0x37, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20,
|
0x65, 0x64, 0x12, 0x3d, 0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x18,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68,
|
0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65,
|
||||||
0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61,
|
0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x69, 0x73,
|
||||||
0x72, 0x79, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x37, 0x0a, 0x07, 0x75,
|
0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61,
|
||||||
0x6e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69,
|
0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x6d,
|
||||||
0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69,
|
0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||||
0x65, 0x6e, 0x74, 0x2e, 0x55, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x52, 0x07, 0x75, 0x6e, 0x74,
|
0x6d, 0x70, 0x4d, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x46,
|
||||||
0x79, 0x70, 0x65, 0x64, 0x12, 0x3d, 0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61,
|
0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
|
||||||
0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
|
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x65, 0x6c,
|
||||||
0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x48,
|
0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x12, 0x34, 0x0a,
|
||||||
0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67,
|
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x69, 0x6f,
|
||||||
0x72, 0x61, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65,
|
||||||
0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x73,
|
0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
|
||||||
0x74, 0x61, 0x6d, 0x70, 0x4d, 0x73, 0x22, 0xa2, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69,
|
0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x04, 0x20,
|
||||||
0x63, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68,
|
0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69,
|
||||||
0x65, 0x6c, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x12,
|
0x63, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69,
|
||||||
0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e,
|
0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x2a, 0x62, 0x0a,
|
||||||
0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c,
|
0x0a, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43,
|
||||||
0x69, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52,
|
0x4f, 0x55, 0x4e, 0x54, 0x45, 0x52, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x41, 0x55, 0x47,
|
||||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18,
|
0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x10, 0x02,
|
||||||
0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65,
|
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x54, 0x59, 0x50, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0d, 0x0a,
|
||||||
0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x74,
|
0x09, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f,
|
||||||
0x72, 0x69, 0x63, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2a, 0x62, 0x0a, 0x0a, 0x4d,
|
0x47, 0x41, 0x55, 0x47, 0x45, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x10,
|
||||||
0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x55,
|
0x05, 0x42, 0x52, 0x0a, 0x14, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65,
|
||||||
0x4e, 0x54, 0x45, 0x52, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x41, 0x55, 0x47, 0x45, 0x10,
|
0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||||
0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x10, 0x02, 0x12, 0x0b,
|
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73,
|
||||||
0x0a, 0x07, 0x55, 0x4e, 0x54, 0x59, 0x50, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x48,
|
0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x67, 0x6f,
|
||||||
0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x47, 0x41,
|
0x3b, 0x69, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x5f, 0x63,
|
||||||
0x55, 0x47, 0x45, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x10, 0x05, 0x42,
|
0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||||
0x52, 0x0a, 0x14, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73,
|
|
||||||
0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
|
||||||
0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2f, 0x63,
|
|
||||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x67, 0x6f, 0x3b, 0x69,
|
|
||||||
0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x5f, 0x63, 0x6c, 0x69,
|
|
||||||
0x65, 0x6e, 0x74,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -1185,22 +1207,23 @@ var file_io_prometheus_client_metrics_proto_depIdxs = []int32{
|
||||||
13, // 5: io.prometheus.client.Histogram.created_timestamp:type_name -> google.protobuf.Timestamp
|
13, // 5: io.prometheus.client.Histogram.created_timestamp:type_name -> google.protobuf.Timestamp
|
||||||
9, // 6: io.prometheus.client.Histogram.negative_span:type_name -> io.prometheus.client.BucketSpan
|
9, // 6: io.prometheus.client.Histogram.negative_span:type_name -> io.prometheus.client.BucketSpan
|
||||||
9, // 7: io.prometheus.client.Histogram.positive_span:type_name -> io.prometheus.client.BucketSpan
|
9, // 7: io.prometheus.client.Histogram.positive_span:type_name -> io.prometheus.client.BucketSpan
|
||||||
10, // 8: io.prometheus.client.Bucket.exemplar:type_name -> io.prometheus.client.Exemplar
|
10, // 8: io.prometheus.client.Histogram.exemplars:type_name -> io.prometheus.client.Exemplar
|
||||||
1, // 9: io.prometheus.client.Exemplar.label:type_name -> io.prometheus.client.LabelPair
|
10, // 9: io.prometheus.client.Bucket.exemplar:type_name -> io.prometheus.client.Exemplar
|
||||||
13, // 10: io.prometheus.client.Exemplar.timestamp:type_name -> google.protobuf.Timestamp
|
1, // 10: io.prometheus.client.Exemplar.label:type_name -> io.prometheus.client.LabelPair
|
||||||
1, // 11: io.prometheus.client.Metric.label:type_name -> io.prometheus.client.LabelPair
|
13, // 11: io.prometheus.client.Exemplar.timestamp:type_name -> google.protobuf.Timestamp
|
||||||
2, // 12: io.prometheus.client.Metric.gauge:type_name -> io.prometheus.client.Gauge
|
1, // 12: io.prometheus.client.Metric.label:type_name -> io.prometheus.client.LabelPair
|
||||||
3, // 13: io.prometheus.client.Metric.counter:type_name -> io.prometheus.client.Counter
|
2, // 13: io.prometheus.client.Metric.gauge:type_name -> io.prometheus.client.Gauge
|
||||||
5, // 14: io.prometheus.client.Metric.summary:type_name -> io.prometheus.client.Summary
|
3, // 14: io.prometheus.client.Metric.counter:type_name -> io.prometheus.client.Counter
|
||||||
6, // 15: io.prometheus.client.Metric.untyped:type_name -> io.prometheus.client.Untyped
|
5, // 15: io.prometheus.client.Metric.summary:type_name -> io.prometheus.client.Summary
|
||||||
7, // 16: io.prometheus.client.Metric.histogram:type_name -> io.prometheus.client.Histogram
|
6, // 16: io.prometheus.client.Metric.untyped:type_name -> io.prometheus.client.Untyped
|
||||||
0, // 17: io.prometheus.client.MetricFamily.type:type_name -> io.prometheus.client.MetricType
|
7, // 17: io.prometheus.client.Metric.histogram:type_name -> io.prometheus.client.Histogram
|
||||||
11, // 18: io.prometheus.client.MetricFamily.metric:type_name -> io.prometheus.client.Metric
|
0, // 18: io.prometheus.client.MetricFamily.type:type_name -> io.prometheus.client.MetricType
|
||||||
19, // [19:19] is the sub-list for method output_type
|
11, // 19: io.prometheus.client.MetricFamily.metric:type_name -> io.prometheus.client.Metric
|
||||||
19, // [19:19] is the sub-list for method input_type
|
20, // [20:20] is the sub-list for method output_type
|
||||||
19, // [19:19] is the sub-list for extension type_name
|
20, // [20:20] is the sub-list for method input_type
|
||||||
19, // [19:19] is the sub-list for extension extendee
|
20, // [20:20] is the sub-list for extension type_name
|
||||||
0, // [0:19] is the sub-list for field type_name
|
20, // [20:20] is the sub-list for extension extendee
|
||||||
|
0, // [0:20] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_io_prometheus_client_metrics_proto_init() }
|
func init() { file_io_prometheus_client_metrics_proto_init() }
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
package expfmt
|
package expfmt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
@ -21,8 +22,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
"google.golang.org/protobuf/encoding/protodelim"
|
||||||
|
|
||||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ func ResponseFormat(h http.Header) Format {
|
||||||
|
|
||||||
mediatype, params, err := mime.ParseMediaType(ct)
|
mediatype, params, err := mime.ParseMediaType(ct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FmtUnknown
|
return fmtUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
const textType = "text/plain"
|
const textType = "text/plain"
|
||||||
|
@ -52,42 +53,44 @@ func ResponseFormat(h http.Header) Format {
|
||||||
switch mediatype {
|
switch mediatype {
|
||||||
case ProtoType:
|
case ProtoType:
|
||||||
if p, ok := params["proto"]; ok && p != ProtoProtocol {
|
if p, ok := params["proto"]; ok && p != ProtoProtocol {
|
||||||
return FmtUnknown
|
return fmtUnknown
|
||||||
}
|
}
|
||||||
if e, ok := params["encoding"]; ok && e != "delimited" {
|
if e, ok := params["encoding"]; ok && e != "delimited" {
|
||||||
return FmtUnknown
|
return fmtUnknown
|
||||||
}
|
}
|
||||||
return FmtProtoDelim
|
return fmtProtoDelim
|
||||||
|
|
||||||
case textType:
|
case textType:
|
||||||
if v, ok := params["version"]; ok && v != TextVersion {
|
if v, ok := params["version"]; ok && v != TextVersion {
|
||||||
return FmtUnknown
|
return fmtUnknown
|
||||||
}
|
}
|
||||||
return FmtText
|
return fmtText
|
||||||
}
|
}
|
||||||
|
|
||||||
return FmtUnknown
|
return fmtUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDecoder returns a new decoder based on the given input format.
|
// NewDecoder returns a new decoder based on the given input format.
|
||||||
// If the input format does not imply otherwise, a text format decoder is returned.
|
// If the input format does not imply otherwise, a text format decoder is returned.
|
||||||
func NewDecoder(r io.Reader, format Format) Decoder {
|
func NewDecoder(r io.Reader, format Format) Decoder {
|
||||||
switch format {
|
switch format.FormatType() {
|
||||||
case FmtProtoDelim:
|
case TypeProtoDelim:
|
||||||
return &protoDecoder{r: r}
|
return &protoDecoder{r: bufio.NewReader(r)}
|
||||||
}
|
}
|
||||||
return &textDecoder{r: r}
|
return &textDecoder{r: r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// protoDecoder implements the Decoder interface for protocol buffers.
|
// protoDecoder implements the Decoder interface for protocol buffers.
|
||||||
type protoDecoder struct {
|
type protoDecoder struct {
|
||||||
r io.Reader
|
r protodelim.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode implements the Decoder interface.
|
// Decode implements the Decoder interface.
|
||||||
func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
|
func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
|
||||||
_, err := pbutil.ReadDelimited(d.r, v)
|
opts := protodelim.UnmarshalOptions{
|
||||||
if err != nil {
|
MaxSize: -1,
|
||||||
|
}
|
||||||
|
if err := opts.UnmarshalFrom(d.r, v); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !model.IsValidMetricName(model.LabelValue(v.GetName())) {
|
if !model.IsValidMetricName(model.LabelValue(v.GetName())) {
|
||||||
|
|
|
@ -18,10 +18,13 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
"google.golang.org/protobuf/encoding/protodelim"
|
||||||
"github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg"
|
|
||||||
"google.golang.org/protobuf/encoding/prototext"
|
"google.golang.org/protobuf/encoding/prototext"
|
||||||
|
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
|
|
||||||
|
"github.com/munnerz/goautoneg"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,23 +63,32 @@ func (ec encoderCloser) Close() error {
|
||||||
// as the support is still experimental. To include the option to negotiate
|
// as the support is still experimental. To include the option to negotiate
|
||||||
// FmtOpenMetrics, use NegotiateOpenMetrics.
|
// FmtOpenMetrics, use NegotiateOpenMetrics.
|
||||||
func Negotiate(h http.Header) Format {
|
func Negotiate(h http.Header) Format {
|
||||||
|
escapingScheme := Format(fmt.Sprintf("; escaping=%s", Format(model.NameEscapingScheme.String())))
|
||||||
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
|
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
|
||||||
|
if escapeParam := ac.Params[model.EscapingKey]; escapeParam != "" {
|
||||||
|
switch Format(escapeParam) {
|
||||||
|
case model.AllowUTF8, model.EscapeUnderscores, model.EscapeDots, model.EscapeValues:
|
||||||
|
escapingScheme = Format(fmt.Sprintf("; escaping=%s", escapeParam))
|
||||||
|
default:
|
||||||
|
// If the escaping parameter is unknown, ignore it.
|
||||||
|
}
|
||||||
|
}
|
||||||
ver := ac.Params["version"]
|
ver := ac.Params["version"]
|
||||||
if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
|
if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
|
||||||
switch ac.Params["encoding"] {
|
switch ac.Params["encoding"] {
|
||||||
case "delimited":
|
case "delimited":
|
||||||
return FmtProtoDelim
|
return fmtProtoDelim + escapingScheme
|
||||||
case "text":
|
case "text":
|
||||||
return FmtProtoText
|
return fmtProtoText + escapingScheme
|
||||||
case "compact-text":
|
case "compact-text":
|
||||||
return FmtProtoCompact
|
return fmtProtoCompact + escapingScheme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
||||||
return FmtText
|
return fmtText + escapingScheme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FmtText
|
return fmtText + escapingScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
// NegotiateIncludingOpenMetrics works like Negotiate but includes
|
// NegotiateIncludingOpenMetrics works like Negotiate but includes
|
||||||
|
@ -84,29 +96,40 @@ func Negotiate(h http.Header) Format {
|
||||||
// temporary and will disappear once FmtOpenMetrics is fully supported and as
|
// temporary and will disappear once FmtOpenMetrics is fully supported and as
|
||||||
// such may be negotiated by the normal Negotiate function.
|
// such may be negotiated by the normal Negotiate function.
|
||||||
func NegotiateIncludingOpenMetrics(h http.Header) Format {
|
func NegotiateIncludingOpenMetrics(h http.Header) Format {
|
||||||
|
escapingScheme := Format(fmt.Sprintf("; escaping=%s", Format(model.NameEscapingScheme.String())))
|
||||||
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
|
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
|
||||||
|
if escapeParam := ac.Params[model.EscapingKey]; escapeParam != "" {
|
||||||
|
switch Format(escapeParam) {
|
||||||
|
case model.AllowUTF8, model.EscapeUnderscores, model.EscapeDots, model.EscapeValues:
|
||||||
|
escapingScheme = Format(fmt.Sprintf("; escaping=%s", escapeParam))
|
||||||
|
default:
|
||||||
|
// If the escaping parameter is unknown, ignore it.
|
||||||
|
}
|
||||||
|
}
|
||||||
ver := ac.Params["version"]
|
ver := ac.Params["version"]
|
||||||
if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
|
if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
|
||||||
switch ac.Params["encoding"] {
|
switch ac.Params["encoding"] {
|
||||||
case "delimited":
|
case "delimited":
|
||||||
return FmtProtoDelim
|
return fmtProtoDelim + escapingScheme
|
||||||
case "text":
|
case "text":
|
||||||
return FmtProtoText
|
return fmtProtoText + escapingScheme
|
||||||
case "compact-text":
|
case "compact-text":
|
||||||
return FmtProtoCompact
|
return fmtProtoCompact + escapingScheme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
||||||
return FmtText
|
return fmtText + escapingScheme
|
||||||
}
|
}
|
||||||
if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion_0_0_1 || ver == OpenMetricsVersion_1_0_0 || ver == "") {
|
if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion_0_0_1 || ver == OpenMetricsVersion_1_0_0 || ver == "") {
|
||||||
if ver == OpenMetricsVersion_1_0_0 {
|
switch ver {
|
||||||
return FmtOpenMetrics_1_0_0
|
case OpenMetricsVersion_1_0_0:
|
||||||
|
return fmtOpenMetrics_1_0_0 + escapingScheme
|
||||||
|
default:
|
||||||
|
return fmtOpenMetrics_0_0_1 + escapingScheme
|
||||||
}
|
}
|
||||||
return FmtOpenMetrics_0_0_1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FmtText
|
return fmtText + escapingScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEncoder returns a new encoder based on content type negotiation. All
|
// NewEncoder returns a new encoder based on content type negotiation. All
|
||||||
|
@ -115,44 +138,54 @@ func NegotiateIncludingOpenMetrics(h http.Header) Format {
|
||||||
// for FmtOpenMetrics, but a future (breaking) release will add the Close method
|
// for FmtOpenMetrics, but a future (breaking) release will add the Close method
|
||||||
// to the Encoder interface directly. The current version of the Encoder
|
// to the Encoder interface directly. The current version of the Encoder
|
||||||
// interface is kept for backwards compatibility.
|
// interface is kept for backwards compatibility.
|
||||||
func NewEncoder(w io.Writer, format Format) Encoder {
|
// In cases where the Format does not allow for UTF-8 names, the global
|
||||||
switch format {
|
// NameEscapingScheme will be applied.
|
||||||
case FmtProtoDelim:
|
//
|
||||||
|
// NewEncoder can be called with additional options to customize the OpenMetrics text output.
|
||||||
|
// For example:
|
||||||
|
// NewEncoder(w, FmtOpenMetrics_1_0_0, WithCreatedLines())
|
||||||
|
//
|
||||||
|
// Extra options are ignored for all other formats.
|
||||||
|
func NewEncoder(w io.Writer, format Format, options ...EncoderOption) Encoder {
|
||||||
|
escapingScheme := format.ToEscapingScheme()
|
||||||
|
|
||||||
|
switch format.FormatType() {
|
||||||
|
case TypeProtoDelim:
|
||||||
return encoderCloser{
|
return encoderCloser{
|
||||||
encode: func(v *dto.MetricFamily) error {
|
encode: func(v *dto.MetricFamily) error {
|
||||||
_, err := pbutil.WriteDelimited(w, v)
|
_, err := protodelim.MarshalTo(w, v)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
close: func() error { return nil },
|
close: func() error { return nil },
|
||||||
}
|
}
|
||||||
case FmtProtoCompact:
|
case TypeProtoCompact:
|
||||||
return encoderCloser{
|
return encoderCloser{
|
||||||
encode: func(v *dto.MetricFamily) error {
|
encode: func(v *dto.MetricFamily) error {
|
||||||
_, err := fmt.Fprintln(w, v.String())
|
_, err := fmt.Fprintln(w, model.EscapeMetricFamily(v, escapingScheme).String())
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
close: func() error { return nil },
|
close: func() error { return nil },
|
||||||
}
|
}
|
||||||
case FmtProtoText:
|
case TypeProtoText:
|
||||||
return encoderCloser{
|
return encoderCloser{
|
||||||
encode: func(v *dto.MetricFamily) error {
|
encode: func(v *dto.MetricFamily) error {
|
||||||
_, err := fmt.Fprintln(w, prototext.Format(v))
|
_, err := fmt.Fprintln(w, prototext.Format(model.EscapeMetricFamily(v, escapingScheme)))
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
close: func() error { return nil },
|
close: func() error { return nil },
|
||||||
}
|
}
|
||||||
case FmtText:
|
case TypeTextPlain:
|
||||||
return encoderCloser{
|
return encoderCloser{
|
||||||
encode: func(v *dto.MetricFamily) error {
|
encode: func(v *dto.MetricFamily) error {
|
||||||
_, err := MetricFamilyToText(w, v)
|
_, err := MetricFamilyToText(w, model.EscapeMetricFamily(v, escapingScheme))
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
close: func() error { return nil },
|
close: func() error { return nil },
|
||||||
}
|
}
|
||||||
case FmtOpenMetrics_0_0_1, FmtOpenMetrics_1_0_0:
|
case TypeOpenMetrics:
|
||||||
return encoderCloser{
|
return encoderCloser{
|
||||||
encode: func(v *dto.MetricFamily) error {
|
encode: func(v *dto.MetricFamily) error {
|
||||||
_, err := MetricFamilyToOpenMetrics(w, v)
|
_, err := MetricFamilyToOpenMetrics(w, model.EscapeMetricFamily(v, escapingScheme), options...)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
close: func() error {
|
close: func() error {
|
||||||
|
|
|
@ -14,30 +14,164 @@
|
||||||
// Package expfmt contains tools for reading and writing Prometheus metrics.
|
// Package expfmt contains tools for reading and writing Prometheus metrics.
|
||||||
package expfmt
|
package expfmt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
|
)
|
||||||
|
|
||||||
// Format specifies the HTTP content type of the different wire protocols.
|
// Format specifies the HTTP content type of the different wire protocols.
|
||||||
type Format string
|
type Format string
|
||||||
|
|
||||||
// Constants to assemble the Content-Type values for the different wire protocols.
|
// Constants to assemble the Content-Type values for the different wire
|
||||||
|
// protocols. The Content-Type strings here are all for the legacy exposition
|
||||||
|
// formats, where valid characters for metric names and label names are limited.
|
||||||
|
// Support for arbitrary UTF-8 characters in those names is already partially
|
||||||
|
// implemented in this module (see model.ValidationScheme), but to actually use
|
||||||
|
// it on the wire, new content-type strings will have to be agreed upon and
|
||||||
|
// added here.
|
||||||
const (
|
const (
|
||||||
TextVersion = "0.0.4"
|
TextVersion = "0.0.4"
|
||||||
ProtoType = `application/vnd.google.protobuf`
|
ProtoType = `application/vnd.google.protobuf`
|
||||||
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
||||||
ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
|
protoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
|
||||||
OpenMetricsType = `application/openmetrics-text`
|
OpenMetricsType = `application/openmetrics-text`
|
||||||
OpenMetricsVersion_0_0_1 = "0.0.1"
|
OpenMetricsVersion_0_0_1 = "0.0.1"
|
||||||
OpenMetricsVersion_1_0_0 = "1.0.0"
|
OpenMetricsVersion_1_0_0 = "1.0.0"
|
||||||
|
|
||||||
// The Content-Type values for the different wire protocols.
|
// The Content-Type values for the different wire protocols. Note that these
|
||||||
FmtUnknown Format = `<unknown>`
|
// values are now unexported. If code was relying on comparisons to these
|
||||||
FmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8`
|
// constants, instead use FormatType().
|
||||||
FmtProtoDelim Format = ProtoFmt + ` encoding=delimited`
|
fmtUnknown Format = `<unknown>`
|
||||||
FmtProtoText Format = ProtoFmt + ` encoding=text`
|
fmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8`
|
||||||
FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
|
fmtProtoDelim Format = protoFmt + ` encoding=delimited`
|
||||||
FmtOpenMetrics_1_0_0 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_1_0_0 + `; charset=utf-8`
|
fmtProtoText Format = protoFmt + ` encoding=text`
|
||||||
FmtOpenMetrics_0_0_1 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_0_0_1 + `; charset=utf-8`
|
fmtProtoCompact Format = protoFmt + ` encoding=compact-text`
|
||||||
|
fmtOpenMetrics_1_0_0 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_1_0_0 + `; charset=utf-8`
|
||||||
|
fmtOpenMetrics_0_0_1 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_0_0_1 + `; charset=utf-8`
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
hdrContentType = "Content-Type"
|
hdrContentType = "Content-Type"
|
||||||
hdrAccept = "Accept"
|
hdrAccept = "Accept"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FormatType is a Go enum representing the overall category for the given
|
||||||
|
// Format. As the number of Format permutations increases, doing basic string
|
||||||
|
// comparisons are not feasible, so this enum captures the most useful
|
||||||
|
// high-level attribute of the Format string.
|
||||||
|
type FormatType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeUnknown FormatType = iota
|
||||||
|
TypeProtoCompact
|
||||||
|
TypeProtoDelim
|
||||||
|
TypeProtoText
|
||||||
|
TypeTextPlain
|
||||||
|
TypeOpenMetrics
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewFormat generates a new Format from the type provided. Mostly used for
|
||||||
|
// tests, most Formats should be generated as part of content negotiation in
|
||||||
|
// encode.go. If a type has more than one version, the latest version will be
|
||||||
|
// returned.
|
||||||
|
func NewFormat(t FormatType) Format {
|
||||||
|
switch t {
|
||||||
|
case TypeProtoCompact:
|
||||||
|
return fmtProtoCompact
|
||||||
|
case TypeProtoDelim:
|
||||||
|
return fmtProtoDelim
|
||||||
|
case TypeProtoText:
|
||||||
|
return fmtProtoText
|
||||||
|
case TypeTextPlain:
|
||||||
|
return fmtText
|
||||||
|
case TypeOpenMetrics:
|
||||||
|
return fmtOpenMetrics_1_0_0
|
||||||
|
default:
|
||||||
|
return fmtUnknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOpenMetricsFormat generates a new OpenMetrics format matching the
|
||||||
|
// specified version number.
|
||||||
|
func NewOpenMetricsFormat(version string) (Format, error) {
|
||||||
|
if version == OpenMetricsVersion_0_0_1 {
|
||||||
|
return fmtOpenMetrics_0_0_1, nil
|
||||||
|
}
|
||||||
|
if version == OpenMetricsVersion_1_0_0 {
|
||||||
|
return fmtOpenMetrics_1_0_0, nil
|
||||||
|
}
|
||||||
|
return fmtUnknown, fmt.Errorf("unknown open metrics version string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatType deduces an overall FormatType for the given format.
|
||||||
|
func (f Format) FormatType() FormatType {
|
||||||
|
toks := strings.Split(string(f), ";")
|
||||||
|
params := make(map[string]string)
|
||||||
|
for i, t := range toks {
|
||||||
|
if i == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
args := strings.Split(t, "=")
|
||||||
|
if len(args) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
params[strings.TrimSpace(args[0])] = strings.TrimSpace(args[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
switch strings.TrimSpace(toks[0]) {
|
||||||
|
case ProtoType:
|
||||||
|
if params["proto"] != ProtoProtocol {
|
||||||
|
return TypeUnknown
|
||||||
|
}
|
||||||
|
switch params["encoding"] {
|
||||||
|
case "delimited":
|
||||||
|
return TypeProtoDelim
|
||||||
|
case "text":
|
||||||
|
return TypeProtoText
|
||||||
|
case "compact-text":
|
||||||
|
return TypeProtoCompact
|
||||||
|
default:
|
||||||
|
return TypeUnknown
|
||||||
|
}
|
||||||
|
case OpenMetricsType:
|
||||||
|
if params["charset"] != "utf-8" {
|
||||||
|
return TypeUnknown
|
||||||
|
}
|
||||||
|
return TypeOpenMetrics
|
||||||
|
case "text/plain":
|
||||||
|
v, ok := params["version"]
|
||||||
|
if !ok {
|
||||||
|
return TypeTextPlain
|
||||||
|
}
|
||||||
|
if v == TextVersion {
|
||||||
|
return TypeTextPlain
|
||||||
|
}
|
||||||
|
return TypeUnknown
|
||||||
|
default:
|
||||||
|
return TypeUnknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToEscapingScheme returns an EscapingScheme depending on the Format. Iff the
|
||||||
|
// Format contains a escaping=allow-utf-8 term, it will select NoEscaping. If a valid
|
||||||
|
// "escaping" term exists, that will be used. Otherwise, the global default will
|
||||||
|
// be returned.
|
||||||
|
func (format Format) ToEscapingScheme() model.EscapingScheme {
|
||||||
|
for _, p := range strings.Split(string(format), ";") {
|
||||||
|
toks := strings.Split(p, "=")
|
||||||
|
if len(toks) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key, value := strings.TrimSpace(toks[0]), strings.TrimSpace(toks[1])
|
||||||
|
if key == model.EscapingKey {
|
||||||
|
scheme, err := model.ToEscapingScheme(value)
|
||||||
|
if err != nil {
|
||||||
|
return model.NameEscapingScheme
|
||||||
|
}
|
||||||
|
return scheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return model.NameEscapingScheme
|
||||||
|
}
|
||||||
|
|
|
@ -22,11 +22,47 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type encoderOption struct {
|
||||||
|
withCreatedLines bool
|
||||||
|
withUnit bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type EncoderOption func(*encoderOption)
|
||||||
|
|
||||||
|
// WithCreatedLines is an EncoderOption that configures the OpenMetrics encoder
|
||||||
|
// to include _created lines (See
|
||||||
|
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#counter-1).
|
||||||
|
// Created timestamps can improve the accuracy of series reset detection, but
|
||||||
|
// come with a bandwidth cost.
|
||||||
|
//
|
||||||
|
// At the time of writing, created timestamp ingestion is still experimental in
|
||||||
|
// Prometheus and need to be enabled with the feature-flag
|
||||||
|
// `--feature-flag=created-timestamp-zero-ingestion`, and breaking changes are
|
||||||
|
// still possible. Therefore, it is recommended to use this feature with caution.
|
||||||
|
func WithCreatedLines() EncoderOption {
|
||||||
|
return func(t *encoderOption) {
|
||||||
|
t.withCreatedLines = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithUnit is an EncoderOption enabling a set unit to be written to the output
|
||||||
|
// and to be added to the metric name, if it's not there already, as a suffix.
|
||||||
|
// Without opting in this way, the unit will not be added to the metric name and,
|
||||||
|
// on top of that, the unit will not be passed onto the output, even if it
|
||||||
|
// were declared in the *dto.MetricFamily struct, i.e. even if in.Unit !=nil.
|
||||||
|
func WithUnit() EncoderOption {
|
||||||
|
return func(t *encoderOption) {
|
||||||
|
t.withUnit = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MetricFamilyToOpenMetrics converts a MetricFamily proto message into the
|
// MetricFamilyToOpenMetrics converts a MetricFamily proto message into the
|
||||||
// OpenMetrics text format and writes the resulting lines to 'out'. It returns
|
// OpenMetrics text format and writes the resulting lines to 'out'. It returns
|
||||||
// the number of bytes written and any error encountered. The output will have
|
// the number of bytes written and any error encountered. The output will have
|
||||||
|
@ -35,6 +71,18 @@ import (
|
||||||
// sanity checks. If the input contains duplicate metrics or invalid metric or
|
// sanity checks. If the input contains duplicate metrics or invalid metric or
|
||||||
// label names, the conversion will result in invalid text format output.
|
// label names, the conversion will result in invalid text format output.
|
||||||
//
|
//
|
||||||
|
// If metric names conform to the legacy validation pattern, they will be placed
|
||||||
|
// outside the brackets in the traditional way, like `foo{}`. If the metric name
|
||||||
|
// fails the legacy validation check, it will be placed quoted inside the
|
||||||
|
// brackets: `{"foo"}`. As stated above, the input is assumed to be santized and
|
||||||
|
// no error will be thrown in this case.
|
||||||
|
//
|
||||||
|
// Similar to metric names, if label names conform to the legacy validation
|
||||||
|
// pattern, they will be unquoted as normal, like `foo{bar="baz"}`. If the label
|
||||||
|
// name fails the legacy validation check, it will be quoted:
|
||||||
|
// `foo{"bar"="baz"}`. As stated above, the input is assumed to be santized and
|
||||||
|
// no error will be thrown in this case.
|
||||||
|
//
|
||||||
// This function fulfills the type 'expfmt.encoder'.
|
// This function fulfills the type 'expfmt.encoder'.
|
||||||
//
|
//
|
||||||
// Note that OpenMetrics requires a final `# EOF` line. Since this function acts
|
// Note that OpenMetrics requires a final `# EOF` line. Since this function acts
|
||||||
|
@ -47,20 +95,34 @@ import (
|
||||||
// Prometheus to OpenMetrics or vice versa:
|
// Prometheus to OpenMetrics or vice versa:
|
||||||
//
|
//
|
||||||
// - Counters are expected to have the `_total` suffix in their metric name. In
|
// - Counters are expected to have the `_total` suffix in their metric name. In
|
||||||
// the output, the suffix will be truncated from the `# TYPE` and `# HELP`
|
// the output, the suffix will be truncated from the `# TYPE`, `# HELP` and `# UNIT`
|
||||||
// line. A counter with a missing `_total` suffix is not an error. However,
|
// lines. A counter with a missing `_total` suffix is not an error. However,
|
||||||
// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
|
// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
|
||||||
// output.
|
// output.
|
||||||
//
|
//
|
||||||
// - No support for the following (optional) features: `# UNIT` line, `_created`
|
// - According to the OM specs, the `# UNIT` line is optional, but if populated,
|
||||||
// line, info type, stateset type, gaugehistogram type.
|
// the unit has to be present in the metric name as its suffix:
|
||||||
|
// (see https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#unit).
|
||||||
|
// However, in order to accommodate any potential scenario where such a change in the
|
||||||
|
// metric name is not desirable, the users are here given the choice of either explicitly
|
||||||
|
// opt in, in case they wish for the unit to be included in the output AND in the metric name
|
||||||
|
// as a suffix (see the description of the WithUnit function above),
|
||||||
|
// or not to opt in, in case they don't want for any of that to happen.
|
||||||
|
//
|
||||||
|
// - No support for the following (optional) features: info type,
|
||||||
|
// stateset type, gaugehistogram type.
|
||||||
//
|
//
|
||||||
// - The size of exemplar labels is not checked (i.e. it's possible to create
|
// - The size of exemplar labels is not checked (i.e. it's possible to create
|
||||||
// exemplars that are larger than allowed by the OpenMetrics specification).
|
// exemplars that are larger than allowed by the OpenMetrics specification).
|
||||||
//
|
//
|
||||||
// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
|
// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
|
||||||
// with a `NaN` value.)
|
// with a `NaN` value.)
|
||||||
func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int, err error) {
|
func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...EncoderOption) (written int, err error) {
|
||||||
|
toOM := encoderOption{}
|
||||||
|
for _, option := range options {
|
||||||
|
option(&toOM)
|
||||||
|
}
|
||||||
|
|
||||||
name := in.GetName()
|
name := in.GetName()
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return 0, fmt.Errorf("MetricFamily has no name: %s", in)
|
return 0, fmt.Errorf("MetricFamily has no name: %s", in)
|
||||||
|
@ -83,12 +145,15 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
n int
|
n int
|
||||||
metricType = in.GetType()
|
metricType = in.GetType()
|
||||||
shortName = name
|
compliantName = name
|
||||||
)
|
)
|
||||||
if metricType == dto.MetricType_COUNTER && strings.HasSuffix(shortName, "_total") {
|
if metricType == dto.MetricType_COUNTER && strings.HasSuffix(compliantName, "_total") {
|
||||||
shortName = name[:len(name)-6]
|
compliantName = name[:len(name)-6]
|
||||||
|
}
|
||||||
|
if toOM.withUnit && in.Unit != nil && !strings.HasSuffix(compliantName, fmt.Sprintf("_%s", *in.Unit)) {
|
||||||
|
compliantName = compliantName + fmt.Sprintf("_%s", *in.Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comments, first HELP, then TYPE.
|
// Comments, first HELP, then TYPE.
|
||||||
|
@ -98,7 +163,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n, err = w.WriteString(shortName)
|
n, err = writeName(w, compliantName)
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -124,7 +189,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n, err = w.WriteString(shortName)
|
n, err = writeName(w, compliantName)
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -151,55 +216,89 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if toOM.withUnit && in.Unit != nil {
|
||||||
|
n, err = w.WriteString("# UNIT ")
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, err = writeName(w, compliantName)
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.WriteByte(' ')
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, err = writeEscapedString(w, *in.Unit, true)
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = w.WriteByte('\n')
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var createdTsBytesWritten int
|
||||||
|
|
||||||
// Finally the samples, one line for each.
|
// Finally the samples, one line for each.
|
||||||
|
if metricType == dto.MetricType_COUNTER && strings.HasSuffix(name, "_total") {
|
||||||
|
compliantName = compliantName + "_total"
|
||||||
|
}
|
||||||
for _, metric := range in.Metric {
|
for _, metric := range in.Metric {
|
||||||
switch metricType {
|
switch metricType {
|
||||||
case dto.MetricType_COUNTER:
|
case dto.MetricType_COUNTER:
|
||||||
if metric.Counter == nil {
|
if metric.Counter == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected counter in metric %s %s", name, metric,
|
"expected counter in metric %s %s", compliantName, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Note that we have ensured above that either the name
|
|
||||||
// ends on `_total` or that the rendered type is
|
|
||||||
// `unknown`. Therefore, no `_total` must be added here.
|
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "", metric, "", 0,
|
w, compliantName, "", metric, "", 0,
|
||||||
metric.Counter.GetValue(), 0, false,
|
metric.Counter.GetValue(), 0, false,
|
||||||
metric.Counter.Exemplar,
|
metric.Counter.Exemplar,
|
||||||
)
|
)
|
||||||
|
if toOM.withCreatedLines && metric.Counter.CreatedTimestamp != nil {
|
||||||
|
createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "_total", metric, "", 0, metric.Counter.GetCreatedTimestamp())
|
||||||
|
n += createdTsBytesWritten
|
||||||
|
}
|
||||||
case dto.MetricType_GAUGE:
|
case dto.MetricType_GAUGE:
|
||||||
if metric.Gauge == nil {
|
if metric.Gauge == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected gauge in metric %s %s", name, metric,
|
"expected gauge in metric %s %s", compliantName, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "", metric, "", 0,
|
w, compliantName, "", metric, "", 0,
|
||||||
metric.Gauge.GetValue(), 0, false,
|
metric.Gauge.GetValue(), 0, false,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
case dto.MetricType_UNTYPED:
|
case dto.MetricType_UNTYPED:
|
||||||
if metric.Untyped == nil {
|
if metric.Untyped == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected untyped in metric %s %s", name, metric,
|
"expected untyped in metric %s %s", compliantName, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "", metric, "", 0,
|
w, compliantName, "", metric, "", 0,
|
||||||
metric.Untyped.GetValue(), 0, false,
|
metric.Untyped.GetValue(), 0, false,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
case dto.MetricType_SUMMARY:
|
case dto.MetricType_SUMMARY:
|
||||||
if metric.Summary == nil {
|
if metric.Summary == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected summary in metric %s %s", name, metric,
|
"expected summary in metric %s %s", compliantName, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
for _, q := range metric.Summary.Quantile {
|
for _, q := range metric.Summary.Quantile {
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "", metric,
|
w, compliantName, "", metric,
|
||||||
model.QuantileLabel, q.GetQuantile(),
|
model.QuantileLabel, q.GetQuantile(),
|
||||||
q.GetValue(), 0, false,
|
q.GetValue(), 0, false,
|
||||||
nil,
|
nil,
|
||||||
|
@ -210,7 +309,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "_sum", metric, "", 0,
|
w, compliantName, "_sum", metric, "", 0,
|
||||||
metric.Summary.GetSampleSum(), 0, false,
|
metric.Summary.GetSampleSum(), 0, false,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
@ -219,20 +318,24 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "_count", metric, "", 0,
|
w, compliantName, "_count", metric, "", 0,
|
||||||
0, metric.Summary.GetSampleCount(), true,
|
0, metric.Summary.GetSampleCount(), true,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
if toOM.withCreatedLines && metric.Summary.CreatedTimestamp != nil {
|
||||||
|
createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "", metric, "", 0, metric.Summary.GetCreatedTimestamp())
|
||||||
|
n += createdTsBytesWritten
|
||||||
|
}
|
||||||
case dto.MetricType_HISTOGRAM:
|
case dto.MetricType_HISTOGRAM:
|
||||||
if metric.Histogram == nil {
|
if metric.Histogram == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected histogram in metric %s %s", name, metric,
|
"expected histogram in metric %s %s", compliantName, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
infSeen := false
|
infSeen := false
|
||||||
for _, b := range metric.Histogram.Bucket {
|
for _, b := range metric.Histogram.Bucket {
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "_bucket", metric,
|
w, compliantName, "_bucket", metric,
|
||||||
model.BucketLabel, b.GetUpperBound(),
|
model.BucketLabel, b.GetUpperBound(),
|
||||||
0, b.GetCumulativeCount(), true,
|
0, b.GetCumulativeCount(), true,
|
||||||
b.Exemplar,
|
b.Exemplar,
|
||||||
|
@ -247,7 +350,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
}
|
}
|
||||||
if !infSeen {
|
if !infSeen {
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "_bucket", metric,
|
w, compliantName, "_bucket", metric,
|
||||||
model.BucketLabel, math.Inf(+1),
|
model.BucketLabel, math.Inf(+1),
|
||||||
0, metric.Histogram.GetSampleCount(), true,
|
0, metric.Histogram.GetSampleCount(), true,
|
||||||
nil,
|
nil,
|
||||||
|
@ -258,7 +361,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "_sum", metric, "", 0,
|
w, compliantName, "_sum", metric, "", 0,
|
||||||
metric.Histogram.GetSampleSum(), 0, false,
|
metric.Histogram.GetSampleSum(), 0, false,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
@ -267,13 +370,17 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n, err = writeOpenMetricsSample(
|
n, err = writeOpenMetricsSample(
|
||||||
w, name, "_count", metric, "", 0,
|
w, compliantName, "_count", metric, "", 0,
|
||||||
0, metric.Histogram.GetSampleCount(), true,
|
0, metric.Histogram.GetSampleCount(), true,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
if toOM.withCreatedLines && metric.Histogram.CreatedTimestamp != nil {
|
||||||
|
createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "", metric, "", 0, metric.Histogram.GetCreatedTimestamp())
|
||||||
|
n += createdTsBytesWritten
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"unexpected type in metric %s %s", name, metric,
|
"unexpected type in metric %s %s", compliantName, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
written += n
|
written += n
|
||||||
|
@ -303,21 +410,9 @@ func writeOpenMetricsSample(
|
||||||
floatValue float64, intValue uint64, useIntValue bool,
|
floatValue float64, intValue uint64, useIntValue bool,
|
||||||
exemplar *dto.Exemplar,
|
exemplar *dto.Exemplar,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
var written int
|
written := 0
|
||||||
n, err := w.WriteString(name)
|
n, err := writeOpenMetricsNameAndLabelPairs(
|
||||||
written += n
|
w, name+suffix, metric.Label, additionalLabelName, additionalLabelValue,
|
||||||
if err != nil {
|
|
||||||
return written, err
|
|
||||||
}
|
|
||||||
if suffix != "" {
|
|
||||||
n, err = w.WriteString(suffix)
|
|
||||||
written += n
|
|
||||||
if err != nil {
|
|
||||||
return written, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n, err = writeOpenMetricsLabelPairs(
|
|
||||||
w, metric.Label, additionalLabelName, additionalLabelValue,
|
|
||||||
)
|
)
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -350,7 +445,7 @@ func writeOpenMetricsSample(
|
||||||
return written, err
|
return written, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if exemplar != nil {
|
if exemplar != nil && len(exemplar.Label) > 0 {
|
||||||
n, err = writeExemplar(w, exemplar)
|
n, err = writeExemplar(w, exemplar)
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -365,27 +460,58 @@ func writeOpenMetricsSample(
|
||||||
return written, nil
|
return written, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeOpenMetricsLabelPairs works like writeOpenMetrics but formats the float
|
// writeOpenMetricsNameAndLabelPairs works like writeOpenMetricsSample but
|
||||||
// in OpenMetrics style.
|
// formats the float in OpenMetrics style.
|
||||||
func writeOpenMetricsLabelPairs(
|
func writeOpenMetricsNameAndLabelPairs(
|
||||||
w enhancedWriter,
|
w enhancedWriter,
|
||||||
|
name string,
|
||||||
in []*dto.LabelPair,
|
in []*dto.LabelPair,
|
||||||
additionalLabelName string, additionalLabelValue float64,
|
additionalLabelName string, additionalLabelValue float64,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
if len(in) == 0 && additionalLabelName == "" {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
written int
|
written int
|
||||||
separator byte = '{'
|
separator byte = '{'
|
||||||
|
metricInsideBraces = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
// If the name does not pass the legacy validity check, we must put the
|
||||||
|
// metric name inside the braces, quoted.
|
||||||
|
if !model.IsValidLegacyMetricName(model.LabelValue(name)) {
|
||||||
|
metricInsideBraces = true
|
||||||
|
err := w.WriteByte(separator)
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
separator = ','
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := writeName(w, name)
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(in) == 0 && additionalLabelName == "" {
|
||||||
|
if metricInsideBraces {
|
||||||
|
err := w.WriteByte('}')
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return written, nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, lp := range in {
|
for _, lp := range in {
|
||||||
err := w.WriteByte(separator)
|
err := w.WriteByte(separator)
|
||||||
written++
|
written++
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return written, err
|
return written, err
|
||||||
}
|
}
|
||||||
n, err := w.WriteString(lp.GetName())
|
n, err := writeName(w, lp.GetName())
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return written, err
|
return written, err
|
||||||
|
@ -442,6 +568,49 @@ func writeOpenMetricsLabelPairs(
|
||||||
return written, nil
|
return written, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeOpenMetricsCreated writes the created timestamp for a single time series
|
||||||
|
// following OpenMetrics text format to w, given the metric name, the metric proto
|
||||||
|
// message itself, optionally a suffix to be removed, e.g. '_total' for counters,
|
||||||
|
// an additional label name with a float64 value (use empty string as label name if
|
||||||
|
// not required) and the timestamp that represents the created timestamp.
|
||||||
|
// The function returns the number of bytes written and any error encountered.
|
||||||
|
func writeOpenMetricsCreated(w enhancedWriter,
|
||||||
|
name, suffixToTrim string, metric *dto.Metric,
|
||||||
|
additionalLabelName string, additionalLabelValue float64,
|
||||||
|
createdTimestamp *timestamppb.Timestamp,
|
||||||
|
) (int, error) {
|
||||||
|
written := 0
|
||||||
|
n, err := writeOpenMetricsNameAndLabelPairs(
|
||||||
|
w, strings.TrimSuffix(name, suffixToTrim)+"_created", metric.Label, additionalLabelName, additionalLabelValue,
|
||||||
|
)
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.WriteByte(' ')
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(beorn7): Format this directly from components of ts to
|
||||||
|
// avoid overflow/underflow and precision issues of the float
|
||||||
|
// conversion.
|
||||||
|
n, err = writeOpenMetricsFloat(w, float64(createdTimestamp.AsTime().UnixNano())/1e9)
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.WriteByte('\n')
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
return written, nil
|
||||||
|
}
|
||||||
|
|
||||||
// writeExemplar writes the provided exemplar in OpenMetrics format to w. The
|
// writeExemplar writes the provided exemplar in OpenMetrics format to w. The
|
||||||
// function returns the number of bytes written and any error encountered.
|
// function returns the number of bytes written and any error encountered.
|
||||||
func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) {
|
func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) {
|
||||||
|
@ -451,7 +620,7 @@ func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return written, err
|
return written, err
|
||||||
}
|
}
|
||||||
n, err = writeOpenMetricsLabelPairs(w, e.Label, "", 0)
|
n, err = writeOpenMetricsNameAndLabelPairs(w, "", e.Label, "", 0)
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return written, err
|
return written, err
|
||||||
|
|
|
@ -62,6 +62,18 @@ var (
|
||||||
// contains duplicate metrics or invalid metric or label names, the conversion
|
// contains duplicate metrics or invalid metric or label names, the conversion
|
||||||
// will result in invalid text format output.
|
// will result in invalid text format output.
|
||||||
//
|
//
|
||||||
|
// If metric names conform to the legacy validation pattern, they will be placed
|
||||||
|
// outside the brackets in the traditional way, like `foo{}`. If the metric name
|
||||||
|
// fails the legacy validation check, it will be placed quoted inside the
|
||||||
|
// brackets: `{"foo"}`. As stated above, the input is assumed to be santized and
|
||||||
|
// no error will be thrown in this case.
|
||||||
|
//
|
||||||
|
// Similar to metric names, if label names conform to the legacy validation
|
||||||
|
// pattern, they will be unquoted as normal, like `foo{bar="baz"}`. If the label
|
||||||
|
// name fails the legacy validation check, it will be quoted:
|
||||||
|
// `foo{"bar"="baz"}`. As stated above, the input is assumed to be santized and
|
||||||
|
// no error will be thrown in this case.
|
||||||
|
//
|
||||||
// This method fulfills the type 'prometheus.encoder'.
|
// This method fulfills the type 'prometheus.encoder'.
|
||||||
func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) {
|
func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) {
|
||||||
// Fail-fast checks.
|
// Fail-fast checks.
|
||||||
|
@ -98,7 +110,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n, err = w.WriteString(name)
|
n, err = writeName(w, name)
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -124,7 +136,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n, err = w.WriteString(name)
|
n, err = writeName(w, name)
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -280,21 +292,9 @@ func writeSample(
|
||||||
additionalLabelName string, additionalLabelValue float64,
|
additionalLabelName string, additionalLabelValue float64,
|
||||||
value float64,
|
value float64,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
var written int
|
written := 0
|
||||||
n, err := w.WriteString(name)
|
n, err := writeNameAndLabelPairs(
|
||||||
written += n
|
w, name+suffix, metric.Label, additionalLabelName, additionalLabelValue,
|
||||||
if err != nil {
|
|
||||||
return written, err
|
|
||||||
}
|
|
||||||
if suffix != "" {
|
|
||||||
n, err = w.WriteString(suffix)
|
|
||||||
written += n
|
|
||||||
if err != nil {
|
|
||||||
return written, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n, err = writeLabelPairs(
|
|
||||||
w, metric.Label, additionalLabelName, additionalLabelValue,
|
|
||||||
)
|
)
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -330,32 +330,64 @@ func writeSample(
|
||||||
return written, nil
|
return written, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeLabelPairs converts a slice of LabelPair proto messages plus the
|
// writeNameAndLabelPairs converts a slice of LabelPair proto messages plus the
|
||||||
// explicitly given additional label pair into text formatted as required by the
|
// explicitly given metric name and additional label pair into text formatted as
|
||||||
// text format and writes it to 'w'. An empty slice in combination with an empty
|
// required by the text format and writes it to 'w'. An empty slice in
|
||||||
// string 'additionalLabelName' results in nothing being written. Otherwise, the
|
// combination with an empty string 'additionalLabelName' results in nothing
|
||||||
// label pairs are written, escaped as required by the text format, and enclosed
|
// being written. Otherwise, the label pairs are written, escaped as required by
|
||||||
// in '{...}'. The function returns the number of bytes written and any error
|
// the text format, and enclosed in '{...}'. The function returns the number of
|
||||||
// encountered.
|
// bytes written and any error encountered. If the metric name is not
|
||||||
func writeLabelPairs(
|
// legacy-valid, it will be put inside the brackets as well. Legacy-invalid
|
||||||
|
// label names will also be quoted.
|
||||||
|
func writeNameAndLabelPairs(
|
||||||
w enhancedWriter,
|
w enhancedWriter,
|
||||||
|
name string,
|
||||||
in []*dto.LabelPair,
|
in []*dto.LabelPair,
|
||||||
additionalLabelName string, additionalLabelValue float64,
|
additionalLabelName string, additionalLabelValue float64,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
if len(in) == 0 && additionalLabelName == "" {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
written int
|
written int
|
||||||
separator byte = '{'
|
separator byte = '{'
|
||||||
|
metricInsideBraces = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
// If the name does not pass the legacy validity check, we must put the
|
||||||
|
// metric name inside the braces.
|
||||||
|
if !model.IsValidLegacyMetricName(model.LabelValue(name)) {
|
||||||
|
metricInsideBraces = true
|
||||||
|
err := w.WriteByte(separator)
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
separator = ','
|
||||||
|
}
|
||||||
|
n, err := writeName(w, name)
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(in) == 0 && additionalLabelName == "" {
|
||||||
|
if metricInsideBraces {
|
||||||
|
err := w.WriteByte('}')
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return written, nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, lp := range in {
|
for _, lp := range in {
|
||||||
err := w.WriteByte(separator)
|
err := w.WriteByte(separator)
|
||||||
written++
|
written++
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return written, err
|
return written, err
|
||||||
}
|
}
|
||||||
n, err := w.WriteString(lp.GetName())
|
n, err := writeName(w, lp.GetName())
|
||||||
written += n
|
written += n
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return written, err
|
return written, err
|
||||||
|
@ -462,3 +494,27 @@ func writeInt(w enhancedWriter, i int64) (int, error) {
|
||||||
numBufPool.Put(bp)
|
numBufPool.Put(bp)
|
||||||
return written, err
|
return written, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeName writes a string as-is if it complies with the legacy naming
|
||||||
|
// scheme, or escapes it in double quotes if not.
|
||||||
|
func writeName(w enhancedWriter, name string) (int, error) {
|
||||||
|
if model.IsValidLegacyMetricName(model.LabelValue(name)) {
|
||||||
|
return w.WriteString(name)
|
||||||
|
}
|
||||||
|
var written int
|
||||||
|
var err error
|
||||||
|
err = w.WriteByte('"')
|
||||||
|
written++
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
var n int
|
||||||
|
n, err = writeEscapedString(w, name, true)
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
err = w.WriteByte('"')
|
||||||
|
written++
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue