diff --git a/go.mod b/go.mod index 9ac57a5cf..8cad7b6f7 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0 github.com/Microsoft/go-winio v0.6.4 - github.com/Microsoft/hcsshim v0.15.0-rc.4 + github.com/Microsoft/hcsshim v0.15.0 github.com/ProtonMail/go-crypto v1.4.1 github.com/agext/levenshtein v1.2.3 github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 @@ -70,8 +70,8 @@ require ( github.com/pkg/errors v0.9.1 github.com/pkg/profile v1.7.0 github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 - github.com/prometheus/client_golang v1.24.1 - github.com/prometheus/procfs v0.21.1 + github.com/prometheus/client_golang v1.25.0 + github.com/prometheus/procfs v0.22.0 github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b github.com/sigstore/sigstore-go v1.2.2 github.com/sirupsen/logrus v1.10.2 @@ -88,31 +88,31 @@ require ( github.com/vishvananda/netlink v1.3.1 github.com/vishvananda/netns v0.0.5 go.etcd.io/bbolt v1.5.0 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0 - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.71.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 - go.opentelemetry.io/otel v1.46.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0 + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.72.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0 + go.opentelemetry.io/otel v1.47.0 go.opentelemetry.io/otel/exporters/jaeger v1.17.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0 - go.opentelemetry.io/otel/exporters/prometheus v0.68.0 - go.opentelemetry.io/otel/metric v1.46.0 - go.opentelemetry.io/otel/sdk v1.46.0 - go.opentelemetry.io/otel/sdk/metric v1.46.0 - go.opentelemetry.io/otel/trace v1.46.0 - go.opentelemetry.io/proto/otlp v1.11.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.47.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.47.0 + go.opentelemetry.io/otel/exporters/prometheus v0.69.0 + go.opentelemetry.io/otel/metric v1.47.0 + go.opentelemetry.io/otel/sdk v1.47.0 + go.opentelemetry.io/otel/sdk/metric v1.47.0 + go.opentelemetry.io/otel/trace v1.47.0 + go.opentelemetry.io/proto/otlp v1.11.1 golang.org/x/crypto v0.58.0 - golang.org/x/exp v0.0.0-20260603202125-055de637280b + golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba golang.org/x/mod v0.42.0 - golang.org/x/net v0.61.0 + golang.org/x/net v0.62.0 golang.org/x/sync v0.24.0 golang.org/x/sys v0.49.0 golang.org/x/time v0.16.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 - google.golang.org/grpc v1.84.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20261012220534-4341edf3f941 + google.golang.org/grpc v1.85.0 google.golang.org/protobuf v1.36.12 kernel.org/pub/linux/libs/security/libcap/cap v1.2.78 tags.cncf.io/container-device-interface v1.1.1 @@ -124,7 +124,7 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.7.0 // indirect github.com/anchore/go-struct-converter v0.1.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.20 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.25 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.20.5 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.8 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.8 // indirect @@ -159,36 +159,36 @@ require ( github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.25.5 // indirect - github.com/go-openapi/errors v0.22.8 // indirect - github.com/go-openapi/jsonpointer v1.0.0 // indirect - github.com/go-openapi/jsonreference v1.0.0 // indirect - github.com/go-openapi/loads v0.25.0 // indirect - github.com/go-openapi/runtime v0.33.0 // indirect - github.com/go-openapi/runtime/server-middleware v0.30.0 // indirect - github.com/go-openapi/spec v0.22.9 // indirect - github.com/go-openapi/strfmt v0.27.0 // indirect - github.com/go-openapi/swag v0.28.0 // indirect - github.com/go-openapi/swag/cmdutils v0.28.0 // indirect - github.com/go-openapi/swag/conv v0.28.0 // indirect - github.com/go-openapi/swag/fileutils v0.28.0 // indirect - github.com/go-openapi/swag/jsonutils v0.28.0 // indirect - github.com/go-openapi/swag/loading v0.28.0 // indirect - github.com/go-openapi/swag/mangling v0.28.0 // indirect - github.com/go-openapi/swag/netutils v0.28.0 // indirect - github.com/go-openapi/swag/pools v0.28.0 // indirect - github.com/go-openapi/swag/stringutils v0.28.0 // indirect - github.com/go-openapi/swag/typeutils v0.28.0 // indirect - github.com/go-openapi/swag/yamlutils v0.28.0 // indirect - github.com/go-openapi/validate v0.26.1 // indirect + github.com/go-openapi/analysis v1.0.0 // indirect + github.com/go-openapi/errors v0.22.9 // indirect + github.com/go-openapi/jsonpointer v1.0.1 // indirect + github.com/go-openapi/jsonreference v1.0.1 // indirect + github.com/go-openapi/loads v0.25.2 // indirect + github.com/go-openapi/runtime v0.33.2 // indirect + github.com/go-openapi/runtime/server-middleware v0.33.2 // indirect + github.com/go-openapi/spec v1.0.0 // indirect + github.com/go-openapi/strfmt v0.27.2 // indirect + github.com/go-openapi/swag v0.29.2 // indirect + github.com/go-openapi/swag/cmdutils v0.29.2 // indirect + github.com/go-openapi/swag/conv v0.29.2 // indirect + github.com/go-openapi/swag/fileutils v0.29.2 // indirect + github.com/go-openapi/swag/jsonutils v0.29.2 // indirect + github.com/go-openapi/swag/loading v0.29.2 // indirect + github.com/go-openapi/swag/mangling v0.29.2 // indirect + github.com/go-openapi/swag/netutils v0.29.2 // indirect + github.com/go-openapi/swag/pools v0.29.2 // indirect + github.com/go-openapi/swag/stringutils v0.29.2 // indirect + github.com/go-openapi/swag/typeutils v0.29.2 // indirect + github.com/go-openapi/swag/yamlutils v0.29.2 // indirect + github.com/go-openapi/validate v1.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/certificate-transparency-go v1.3.3 // indirect - github.com/google/go-containerregistry v0.21.7 // indirect + github.com/google/go-containerregistry v0.22.0 // indirect github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0 // indirect github.com/hanwen/go-fuse/v2 v2.11.0 // indirect github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/in-toto/attestation v1.2.0 // indirect @@ -196,11 +196,11 @@ require ( github.com/moby/sys/mount v0.3.5 // indirect github.com/moby/sys/sequential v0.7.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/oklog/ulid/v2 v2.1.1 // indirect + github.com/oklog/ulid/v2 v2.1.2 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/prometheus/client_model v0.6.3 // indirect - github.com/prometheus/common v0.71.0 // indirect + github.com/prometheus/common v0.72.0 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/secure-systems-lab/go-securesystemslib v0.11.0 // indirect @@ -216,10 +216,11 @@ require ( github.com/vbatts/tar-split v0.12.3 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.yaml.in/yaml/v3 v3.0.5 // indirect + go.opentelemetry.io/otel/log v1.47.0 // indirect + go.yaml.in/yaml/v3 v3.0.6 // indirect golang.org/x/term v0.47.0 // indirect golang.org/x/text v0.43.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941 // indirect google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2 // indirect k8s.io/klog/v2 v2.140.0 // indirect kernel.org/pub/linux/libs/security/libcap/psx v1.2.78 // indirect diff --git a/go.sum b/go.sum index 0f36198ea..9a5be81b7 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.4 h1:kJF2pamtYCWXf0xAT8sAkwKC0pMl2HYBrRPHAqyUc+g= github.com/Microsoft/go-winio v0.6.4/go.mod h1:1xl5JXG4ze/m74GH6Dc4Mwxfc3VL5siRVQjIAlHH07U= -github.com/Microsoft/hcsshim v0.15.0-rc.4 h1:aZFX4LH0S20Lgjq0wG61StIClj7im4yzrxIClkaR8Z8= -github.com/Microsoft/hcsshim v0.15.0-rc.4/go.mod h1:BA9CBztgu4h/6Jsvo1O1M4qjWw09PoYpaEYgexPE578= +github.com/Microsoft/hcsshim v0.15.0 h1:AWiHGf0+9f7cDcfhuU3zXORCAPmIOWzTYfHhcrMcx3U= +github.com/Microsoft/hcsshim v0.15.0/go.mod h1:eStXUkML1Fmkgmwr6XHbYkBC1j7p2FA8ZtA9dyRMbts= github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM= github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= @@ -63,8 +63,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go-v2 v1.47.5 h1:5yA+A+BiXbDq1ZLbYwPViwhEGDMdR0MEhL8Jh2LnLS4= github.com/aws/aws-sdk-go-v2 v1.47.5/go.mod h1:iNIkogrRvFwm+1OQIUOP2lPBtlXZboOIUWiCa+pHEMw= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.20 h1:GPRlPwz40I2B2VrBEASOA3Bi77NyeqejNLkifosX0rs= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.20/go.mod h1:g7PNzKcsOKWb4fkSRBA7BZVAS6Y8IcxzN+nRohhQ1Q8= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.25 h1:MW0Iql1SOTgQPj8mCxrU/eH/K/AIDWi08ItOsXaWRLU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.25/go.mod h1:+ucVYmHYB3JqVueY0E1RHahdXAnKQbIHqybSbvOUbOM= github.com/aws/aws-sdk-go-v2/config v1.33.13 h1:u52x6ISQOx172tpwM0VRxhJzEsTJYpMcEYUGM2A1wrw= github.com/aws/aws-sdk-go-v2/config v1.33.13/go.mod h1:/ixtz6XPHb42zekjQ0LqD9XjTpTysNWhIGwufY1OzI4= github.com/aws/aws-sdk-go-v2/credentials v1.20.13 h1:j4z41OtspmQ3ftQycaDunJ26b69a9SHfaSVUPqgRv8k= @@ -212,56 +212,56 @@ github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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-openapi/analysis v0.25.5 h1:xPYEvTb90o1y0epuiOPAoG4QqahjP3cdp5xNlHeKJRI= -github.com/go-openapi/analysis v0.25.5/go.mod h1:d3UGtQC5uq5Kqqqis2VH09Km/v3vwsWrYkbp4gdm+Rc= -github.com/go-openapi/errors v0.22.8 h1:oP7sW7TWc3wFFjrzzj0nI83H2qMBkNjNfSd+XRejk/I= -github.com/go-openapi/errors v0.22.8/go.mod h1:BuUoHcYrU6E7V9gfj1I5wLQqgtIHnup/alXZ8KdgQ0w= -github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s= -github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= -github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= -github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= -github.com/go-openapi/loads v0.25.0 h1:74Bc2snfaVlsHzwdQj/3gsA9XJz3daXTJVs+4ZaK7jI= -github.com/go-openapi/loads v0.25.0/go.mod h1:JFBw4SIB9+PTIFHDfcXuSSy5h6aWzjtUCrPYyx3qWU8= -github.com/go-openapi/runtime v0.33.0 h1:Dd3Oj2ig+WH8ckK95l0Wn2V8a4bH/UqWPRZVT0vc8yU= -github.com/go-openapi/runtime v0.33.0/go.mod h1:+rsupH3+TFKqmFysqkmgBOTxpVJV8eV+j9myvvea2Xw= -github.com/go-openapi/runtime/server-middleware v0.30.0 h1:8rPoJ/xv7JL8BsovaqboKETlpWBArVh8n+0L/GyePog= -github.com/go-openapi/runtime/server-middleware v0.30.0/go.mod h1:OYNT/TxNvB/VK5oe4htM2jDTwlEXuejVJmu0DVZfAMs= -github.com/go-openapi/spec v0.22.9 h1:/vKIFDcGKp0ktZWGbym/tJEWbk6/XOEmAVU0kqKMH+w= -github.com/go-openapi/spec v0.22.9/go.mod h1:b/mNUYIOQOyIiUzUzXEE8xzyZqf93KvM9hQGP91yfl0= -github.com/go-openapi/strfmt v0.27.0 h1:kbcTeaD9TXuXD0hhMXzuYa1sdTo6+dWGvwjW93E80IM= -github.com/go-openapi/strfmt v0.27.0/go.mod h1:s/qhDqfY72irigXUGJmtgid2Rm+3tnz3k8hZaRmvWYc= -github.com/go-openapi/swag v0.28.0 h1:xkgbOSKj6DZziNpyqRRAOt3GJGtgjgsd2RoyT30VWuw= -github.com/go-openapi/swag v0.28.0/go.mod h1:4qYnT3Cqr1p1VknOdPo70evN4rgQnAg6jwApHyxSGIg= -github.com/go-openapi/swag/cmdutils v0.28.0 h1:7TOeNtkYru1SG8Y34tDh9WBbLsMqGnptuxWiHREPZ4Q= -github.com/go-openapi/swag/cmdutils v0.28.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= -github.com/go-openapi/swag/conv v0.28.0 h1:GtqqbyFe7vR5Y7ehxG9W6/OvrSFdf1OLeTGp40TqxH8= -github.com/go-openapi/swag/conv v0.28.0/go.mod h1:mbUE+mzctnhxi864m0Q07SpN8OowD9JhxmxuYvZZD/k= -github.com/go-openapi/swag/fileutils v0.28.0 h1:Z04XWQD7R8Eq+7GnOrjovBxPPmZzsS4gt2H2GPGIViU= -github.com/go-openapi/swag/fileutils v0.28.0/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8= -github.com/go-openapi/swag/jsonutils v0.28.0 h1:YIch6FwO7RXzeAnbO8Tu7dWBZeUEH+4nA0HXltVTnv4= -github.com/go-openapi/swag/jsonutils v0.28.0/go.mod h1:CYM3WlTUcagR2ZoHdz54di/cbBqt82tuxuXgAjxw+mg= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.28.0 h1:qV+VVUAx5Oro8WjVWpZeql7YReTKhT4smR4zhcOQZr0= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.28.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= -github.com/go-openapi/swag/loading v0.28.0 h1:td8QZdZC9MIYGGSnSPKShKiK22I2tU5UQvuUhIBPRLU= -github.com/go-openapi/swag/loading v0.28.0/go.mod h1:rXB0QiQX5mMveXEA7ouM4KiiM9jVJe4K6BVbwhD1M4k= -github.com/go-openapi/swag/mangling v0.28.0 h1:pH8eyeNO9SLYsTMWJrurnNfKmDa28XrlA+HePVD53VM= -github.com/go-openapi/swag/mangling v0.28.0/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w= -github.com/go-openapi/swag/netutils v0.28.0 h1:YXN6TALEi2pzts8/8GNm6T61HTAZsieukGZidap989k= -github.com/go-openapi/swag/netutils v0.28.0/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ= -github.com/go-openapi/swag/pools v0.28.0 h1:HPMZWSAfce3rdVTFcjFiCIBtDg9h4x2QlRrHipwhxeU= -github.com/go-openapi/swag/pools v0.28.0/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= -github.com/go-openapi/swag/stringutils v0.28.0 h1:ixsc9iYgDPubHL/8nSkbnryEHpD2VRlBMLKpQyPXcDU= -github.com/go-openapi/swag/stringutils v0.28.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= -github.com/go-openapi/swag/typeutils v0.28.0 h1:nRBKSBXjDgf01VDPB3fWeD9nQuhCOVeIYAkUx2tbkyY= -github.com/go-openapi/swag/typeutils v0.28.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= -github.com/go-openapi/swag/yamlutils v0.28.0 h1:TV3JXH6DS46KUroDtMLAYHGkdWf5VDq3wVWFirmzROY= -github.com/go-openapi/swag/yamlutils v0.28.0/go.mod h1:x0q/yndZHEgk9Rx3DyDqzFUmHy55KTvIZldvF2dTJXs= -github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= -github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= -github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= -github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= -github.com/go-openapi/validate v0.26.1 h1:pZSbvtRO8G2R2FpWTYRn3w8LrsNwbtaVhP2dWiBa0Us= -github.com/go-openapi/validate v0.26.1/go.mod h1:B8UMgXiQiwwQWIbmuROlwJZDPGlikPuh7iHV1vPX9Oo= +github.com/go-openapi/analysis v1.0.0 h1:sNvbAGCJqUTqIAodr9IVqJMmuZas3YS9ms1dGK9yiJ4= +github.com/go-openapi/analysis v1.0.0/go.mod h1:NhYjJ57fnE+bcE7UwrJyMkhWA3Dfz7TdiBfTVAnos4Y= +github.com/go-openapi/errors v0.22.9 h1:HI9+SyVYiRzyeBQGv0CbWbQa+u2S0nny7G7AhY+UMiM= +github.com/go-openapi/errors v0.22.9/go.mod h1:R73q66sXP2smzAGgFOI4nqtusRK2xN5pYCjsij+KX58= +github.com/go-openapi/jsonpointer v1.0.1 h1:2KxywRmNwJkT/FMBa3iRNHEaAxSJvjqoufQZy3au1Mg= +github.com/go-openapi/jsonpointer v1.0.1/go.mod h1:wI7ZYsFmbIi9nBXOZqgDaS/bqOchRGZjqxFli7FBYxY= +github.com/go-openapi/jsonreference v1.0.1 h1:4zJ7AmYDKNmD3aSpfPnFNCFA5E80/xMHUNKgydaLh38= +github.com/go-openapi/jsonreference v1.0.1/go.mod h1:dYplQXa6p5lXprLcJ8LE2iU7vNpXsAHDQ5ZAgL+Qx3A= +github.com/go-openapi/loads v0.25.2 h1:+uNsDlRQfYtZTrh+3pdwampcAqZVPuBJW0IA82aZHII= +github.com/go-openapi/loads v0.25.2/go.mod h1:RXsfJEQGGNv4uw8u/KdmF8Vh8OR4fTfs9ZO4QrzNohA= +github.com/go-openapi/runtime v0.33.2 h1:HSxskMs0WmpCdQvBWVxHt2t2mXMwn8DDav3VtVidwig= +github.com/go-openapi/runtime v0.33.2/go.mod h1:NQpSLiIsEAIpZDEs6xUrhjm6ZiQh85X8bHKlqLPgNP8= +github.com/go-openapi/runtime/server-middleware v0.33.2 h1:BVFjAaW4Jh/kZ4QSsgDrGzLuSuaKzSiyvappUFKxgUk= +github.com/go-openapi/runtime/server-middleware v0.33.2/go.mod h1:E3mWY61/UgBJ5EUmKh+h6A1oQQdD1U4raowVMmPmQug= +github.com/go-openapi/spec v1.0.0 h1:JtB/GHOj+eetjse6YvxqLze88oEekl/4uPBethvzRrA= +github.com/go-openapi/spec v1.0.0/go.mod h1:boj1PRhqS0x5jylgcNp9BRWxenphrh7vVNYZ90IRCoo= +github.com/go-openapi/strfmt v0.27.2 h1:SG32SlbwNy92s0KJiVxt2joJeFdqIYHvwrA0OU6HqzQ= +github.com/go-openapi/strfmt v0.27.2/go.mod h1:M4CKsMO0Fb8qR10+1Ra75wCKNNquy+Vj+4LWZrhTo2E= +github.com/go-openapi/swag v0.29.2 h1:9n8frkcsuQRA0INU31VbxNxt1zBaHxrHYGEf5BUjFi4= +github.com/go-openapi/swag v0.29.2/go.mod h1:RkCiX1gCVXWgLOavDXE3ALJrQ/VO2ziiIzOUs3z10xo= +github.com/go-openapi/swag/cmdutils v0.29.2 h1:cXEzX/nWCODon251f+1HgL75/R4XXML5IZxgLCWMoro= +github.com/go-openapi/swag/cmdutils v0.29.2/go.mod h1:XziaSVzYqkDvpWXzASfWajw2YvJrLscq610O2XiyqJw= +github.com/go-openapi/swag/conv v0.29.2 h1:8c9shoB8l0QRSR6ymq1llHdBWDqpIgJfjTGHx3Vuhm0= +github.com/go-openapi/swag/conv v0.29.2/go.mod h1:AZS0YigTNf8qNtD6WqJz/N4RUNmpr76SyjFGkq4+p6Q= +github.com/go-openapi/swag/fileutils v0.29.2 h1:mdUL+Vw5ah1fO1AvFCoHeIyv7YZsCz2MN3KNqd/lLVI= +github.com/go-openapi/swag/fileutils v0.29.2/go.mod h1:7QKmmodjAebaq61lGVJa8ldLdGeMF4DSgYv8tXOGGo0= +github.com/go-openapi/swag/jsonutils v0.29.2 h1:uZNSD2/rJDYAfvsLYkykTzXuyxM3QpDKV9jhRHrMu6k= +github.com/go-openapi/swag/jsonutils v0.29.2/go.mod h1:ONTdNvj3Y+IXRzfa17E+Rgt2ns/qiSOYjIo2K7v2yDs= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.2 h1:w+Fd6EBOMGlC74GYGHqCLGyb3Bpams8TtNrgM/SG4jo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.2/go.mod h1:HC2egPORFzbj/gf05Zrfgz8Mgplx3oW7hgGi7pjZVhM= +github.com/go-openapi/swag/loading v0.29.2 h1:QU1ry24e6r6Shoxe380Nx0X5iKkpRO+hJffsyJ2dVlY= +github.com/go-openapi/swag/loading v0.29.2/go.mod h1:DqilDjuiJKETecsS4TRopWG1acUDsfqN39ZmQhPu6uI= +github.com/go-openapi/swag/mangling v0.29.2 h1:ltdo3K0tTP4P6zWhVVWDU9D37/YYBuMJRdZxiS2Dtog= +github.com/go-openapi/swag/mangling v0.29.2/go.mod h1:RjDi4TnItAenS3cgCXSpIl1kKbjG7il6pnmQVl/8bp8= +github.com/go-openapi/swag/netutils v0.29.2 h1:dBli6jyUa93sDS/XYWShJzf4+nnVfFKfvY9SLUaUzB8= +github.com/go-openapi/swag/netutils v0.29.2/go.mod h1:1pM6Xg/Um8E1eps3umWl8Hme3ByWXOtHsvFC0CULHUE= +github.com/go-openapi/swag/pools v0.29.2 h1:PlGoDRF8WtSyXkedZZkpW3f9wDhFf3u8KtaBcmgmh8c= +github.com/go-openapi/swag/pools v0.29.2/go.mod h1:V3lhxVT4qDYRqc2MRSSbLsTYIYV/2HlHafhyEkmzLIc= +github.com/go-openapi/swag/stringutils v0.29.2 h1:lcnBxwAaysT3bMUVBfn9V/PkfVqkurpqufKU6rTUMGk= +github.com/go-openapi/swag/stringutils v0.29.2/go.mod h1:i9cdh7sGaa0nm3CqIvH5IM5h2QClk1wns2ktKeILvRI= +github.com/go-openapi/swag/typeutils v0.29.2 h1:O7aVvkTs3pXwikgtrPLenigEMdQFgONKRooQA9pgf2I= +github.com/go-openapi/swag/typeutils v0.29.2/go.mod h1:7+GDG+uz9Ke+eVt4rClZg7wklSDp8hT/mKNh/pC26TE= +github.com/go-openapi/swag/yamlutils v0.29.2 h1:IFKFFeDnuIwzfsuWRQU+rI8iL3g4XyAYjV/RlnlxPLM= +github.com/go-openapi/swag/yamlutils v0.29.2/go.mod h1:7MGqtcrK73sxQ4ceiyIf8qiXS/s09JLMdR5esK5euYQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.7.0 h1:wPW6YRgx3+SID1yUy/Xwa17L8kFEaEKod2VRbJDZNUs= +github.com/go-openapi/testify/enable/yaml/v2 v2.7.0/go.mod h1:mI1M88etYbc3PhgHsWQK2kwvNwW5aGFqMPbmib+SGIs= +github.com/go-openapi/testify/v2 v2.8.0 h1:19QDx5b57p8KjO2E4sgs/woL4Akp+FGLRlVm2xn0Rho= +github.com/go-openapi/testify/v2 v2.8.0/go.mod h1:4gUN8jC+RqOE2qjW/vDmfyTvl5BCht4qL7oca0odrak= +github.com/go-openapi/validate v1.0.0 h1:dFsYCLVUQUL6Vi2lQSexgwmCXDuHe7eWRDhQxkE+xYA= +github.com/go-openapi/validate v1.0.0/go.mod h1:wwXGRqMQzOZ7PCqBcgNk+DD9+Cacnxv7we5T0M/eA3Y= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= @@ -284,8 +284,8 @@ github.com/google/certificate-transparency-go v1.3.3 h1:hq/rSxztSkXN2tx/3jQqF6Xc github.com/google/certificate-transparency-go v1.3.3/go.mod h1:iR17ZgSaXRzSa5qvjFl8TnVD5h8ky2JMVio+dzoKMgA= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-containerregistry v0.21.7 h1:/vPFuVXDjtFREsVArW+0h1CIl5urnOhzei4X2DMW9IU= -github.com/google/go-containerregistry v0.21.7/go.mod h1:kjSbt7/zMsKLWfnHrIvKvhXHUw91jbe9DNjPPJ32gXE= +github.com/google/go-containerregistry v0.22.0 h1:eGbCiPeYxAH/7WLLq6zTBALP0tUIFsoyRauhxXDJ53I= +github.com/google/go-containerregistry v0.22.0/go.mod h1:bJR35SK8XgisYmhg/FMQ/5RK0S/XrOAqLBV5/LR2XE0= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg= github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= @@ -303,8 +303,8 @@ github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0 h1:Bd7KaOxzULLxtZ/K5s1aLbWhR0+5RToO65TXHsf3bqQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0/go.mod h1:nN7ts3dFXKtCZWc//yfkpcQNKJABg16/uDVAZpLDalo= github.com/hanwen/go-fuse/v2 v2.11.0 h1:CGVkJh9gRz0pTRMADNcqdFl3ec/5QbE/Vx1Gl7ESozM= github.com/hanwen/go-fuse/v2 v2.11.0/go.mod h1:aU7NkGYZUmuJrZapoI3mEcNve7PZTySUOLBuch/vR6U= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -398,8 +398,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= -github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= -github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= +github.com/oklog/ulid/v2 v2.1.2 h1:IEclFb9JNvzYA6MW2SCxbLzcHTVsfqm3PrqGQJH5zec= +github.com/oklog/ulid/v2 v2.1.2/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/onsi/ginkgo/v2 v2.25.1 h1:Fwp6crTREKM+oA6Cz4MsO8RhKQzs2/gOIVOUscMAfZY= github.com/onsi/ginkgo/v2 v2.25.1/go.mod h1:ppTWQ1dh9KM/F1XgpeRqelR+zHVwV81DGRSDnFxK7Sk= github.com/onsi/gomega v1.38.1 h1:FaLA8GlcpXDwsb7m0h2A9ew2aTk3vnZMlzFgg5tz/pk= @@ -428,16 +428,16 @@ github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDj github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU= -github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE= +github.com/prometheus/client_golang v1.25.0 h1:cDtW1TcFsMi1RJc8khwCKB4VhzwV04aKqbYtNOXuiK0= +github.com/prometheus/client_golang v1.25.0/go.mod h1:j2X/4/kaQHLPnmyEU8zjmkndo1T317VpCIQEml8LTKk= github.com/prometheus/client_model v0.6.3 h1:O0jaTVAYNxTHYInEPFJt5I3+sN8zqBtVMPTB1qyxiEo= github.com/prometheus/client_model v0.6.3/go.mod h1:gpN5P9S7Rr6Yr92PiQ+Ixvhf6JZEkF1dnxsYL2aPBEM= -github.com/prometheus/common v0.71.0 h1:9KDAKb7Mj3HEVKyFCK6Dc/HIwlBzZIN2l7/lrHl3KK8= -github.com/prometheus/common v0.71.0/go.mod h1:CLJ5H8TEsGX8bl31BdMkfhIZ+QmZ9tBPPotUxUbfcmk= +github.com/prometheus/common v0.72.0 h1:tAYsE+sPJxIncDAobm4H5aQjmox9ZxEIIqPbiffa8G4= +github.com/prometheus/common v0.72.0/go.mod h1:77NWqAQ2tXT7BIK40qjJdw5Acrsrg1TlHAnsQi3i6mk= github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos= github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= -github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI= -github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY= +github.com/prometheus/procfs v0.22.0 h1:6q9+/JL9IKAPbCmBrv9n5O5Ty3NKnciV5X7YGw0oics= +github.com/prometheus/procfs v0.22.0/go.mod h1:CvmFr/GVhIjIvWJZW3tgkODBQMRIf0EyWMQLHCHab58= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= @@ -539,40 +539,42 @@ go.etcd.io/bbolt v1.5.0 h1:S7GAl7Fxv12yohbwFfIbQCGDWbQbtDGPET4P/bD4lxU= go.etcd.io/bbolt v1.5.0/go.mod h1:mkltfYE5aUHQxUct9N9V+Kp7aSjFqjgrhcXIS70Lrdk= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0 h1:B2h3uqicet1CT2N5TOFhS+Gq++9i0/CLmaxvhmhtP5s= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0/go.mod h1:dylvB+ZiiwMvsDij9O84Uy7SijLgHMX4mbkncds+4Sw= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.71.0 h1:oFNJW32h2SXnET7XXstgT7pVh4vN+jW+GfiIaBguIZE= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.71.0/go.mod h1:+H3sPOFwag14eMHTPMElZtV0e4YfVZ/85KgrKUCB5FI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90UzBltIDKq1/5mrTGxTnOFDV0ICOhLoxiZ8jlg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU= -go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc= -go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0 h1:Tq+E65HaNbZTeqcLw6QUhsV+/EIWdkfUH2CQzcrlE5M= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0/go.mod h1:A+EVhDakAj1waJBPhmTszZaSr08ww8MRRKy1nB1rqck= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.72.0 h1:jva1c3z2ZFEQ5sTvnLG2tBALNehO+QvdXKQii6eKRoo= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.72.0/go.mod h1:3pjFS5EnOVfjvYO6/NMdtJFHFQR+8uiGtrZ965nZP4w= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0 h1:LxwW/9ctSCv+QkE/cLR7M91ZIkXNMqJtEMi1vCw9U8s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0/go.mod h1:tOsftB4SslBwwErVEPaenU2RpThXWPIU8DoJHEC4dyw= +go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM= +go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU= go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0 h1:qkDYCAFiZXLcs1L4aY+tP2wguQ4kURANqHOQMA2et2s= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0/go.mod h1:tkipS4DRzmpAmvg+Gw4++O1IdDq6TVDnvnYU6cmbQVs= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0 h1:AP23h/mFgb/lc7tdck1Kfn9qxsM8TAeNPCU5C3pzaps= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0/go.mod h1:K4EqCe1b4kGk5WR690ntg9LaBfsPoV32FwthbyoptuA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 h1:OFnwLJr+pF3iHrlGSzbxyuo6/6HyBlnlN1CWEJmBVcw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0/go.mod h1:716wFneO0ov19A2beH5hjfh9AK5z/VWNAtDijp1Y0/g= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0 h1:w53CDeOA/Kurp7yRsegSr6pbbr759dOvJ+yNmWM6Hxs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0/go.mod h1:BOmGMCbAtvcJiSJ+hLuhgPLdDbimnraSl8irz3iY8sY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0 h1:KrC1YrQeSt46ITMWAbgQx1M1eV1/1TKzttrBzymPmss= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0/go.mod h1:zDSEzoEqsOrgBeGvH66KRgxh90VonFyJqBHA0Pk3+rM= -go.opentelemetry.io/otel/exporters/prometheus v0.68.0 h1:QOf2IftqQwITVRJpnn0M7M9ZCbgWfxz4P7i9C9yc2N4= -go.opentelemetry.io/otel/exporters/prometheus v0.68.0/go.mod h1:bgSvqu2TWGXiz7yr5UTMfObH8oqxJWHTnubQ3ef9BO4= -go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8= -go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o= -go.opentelemetry.io/otel/metric/x v0.68.0 h1:TA/cBT23D3MnxYPwHL7YFOdYGdx0A0v+s7Mzotpd1dU= -go.opentelemetry.io/otel/metric/x v0.68.0/go.mod h1:agudOmvWhwUTjgibWDzxD2PoWYnpw5Ht5jISYOD2Hd4= -go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI= -go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM= -go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE= -go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4= -go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c= -go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI= -go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk= -go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0 h1:LaLVGJtIzHcvHjVs2OftmKcc+M9mdOqS8vZ1fBD1Yes= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0/go.mod h1:vF6H5sNDuQBJWgSX00iZgbIqk2MZZoVMH0ar5t5bOpw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.47.0 h1:7kszRN4Ze5GeAkUnBjBSUIunVBMA+mZIG04auueqguM= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.47.0/go.mod h1:CLzakYy8jOdkBfcveCWYkeKJxujcF4xPhh2Z7IfE98U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0 h1:julhjPeUH/q/7hinbSdDdqt5h7Zw9YWmRlWRhI0jd54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0/go.mod h1:Ao2mz688LH/tFf0yMAenidq6k2YNSx6SIY2q6jDACck= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0 h1:UFpxOpYPmMNUtOWhdb+nC1WELIgVf8z9higURrbzYU4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0/go.mod h1:YBGjxe3lt0jtXoEXxGrGhv/jM7oUBUDVK7zhAvNyEjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.47.0 h1:aXZXsZ012wOgVkqaiQv+Z/d8V0xKjmg70F6m4CE94lc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.47.0/go.mod h1:ziu1gUIJhAaxM3EV1e3Ralk5AAyL1UOYz3lJJ4VSI38= +go.opentelemetry.io/otel/exporters/prometheus v0.69.0 h1:LQVBTGnHvzrfGJpDoCSVTY7eaLZArvaTSq5l84Skxew= +go.opentelemetry.io/otel/exporters/prometheus v0.69.0/go.mod h1:moif0nlgj/M16NRT8lDZVt8MC52+EOAJfR8EKRJ8LyU= +go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI= +go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw= +go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY= +go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU= +go.opentelemetry.io/otel/metric/x v0.69.0 h1:DjRLr15H83v+hCW7JA9NoJvOkYTtmq5YoDRbe9deYpM= +go.opentelemetry.io/otel/metric/x v0.69.0/go.mod h1:uVvsMPMFFyj/HUQfrUnH3JjnOQ1dwFDorgFLRBasM0k= +go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I= +go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0= +go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw= +go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw= +go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM= +go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0= +go.opentelemetry.io/proto/otlp v1.11.1 h1:SCrPqH9NE5CmBrOqpjNCiT0X5mGwMyGERXdogfR7Yjw= +go.opentelemetry.io/proto/otlp v1.11.1/go.mod h1:wq8W4aSf6bOy8RZyESOeQFr9Pu7wydWX/TY4sgvrTPg= go.step.sm/crypto v0.77.7 h1:6azC+pD678Vjju8yXnMDHCZJ+HzFaEmL3sCryiezTIA= go.step.sm/crypto v0.77.7/go.mod h1:OW/2sEHwTtDKq70PvSQ5B0JGy/CrLyDKOiVy3YvZMTQ= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= @@ -585,18 +587,18 @@ go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= -go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= -go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +go.yaml.in/yaml/v3 v3.0.6 h1:zcDfvjXEqTQmpjniUBLc91xYJMB2c4QOFxEF/LCEckM= +go.yaml.in/yaml/v3 v3.0.6/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54= golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w= -golang.org/x/exp v0.0.0-20260603202125-055de637280b h1:v1uXiEBHo8QA0LiGCo7UgHMzHT4Kdfpl2zmtH5vaP1Q= -golang.org/x/exp v0.0.0-20260603202125-055de637280b/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= +golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba h1:Ck8QetSgk912qxWLMCKxd0in+aiyBQyDSMae6e/xmpU= +golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba/go.mod h1:50RgIsmK7OwqzTTeqcSXQW8SswW0o8fRcDxmqGluJ8E= golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg= golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs= -golang.org/x/net v0.61.0 h1:RR+6j/BTBCrggOLugxa+66R8FvoN6MHlzDlZIbN9YFw= -golang.org/x/net v0.61.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI= -golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= -golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/net v0.62.0 h1:18ELalfM5+XNRwzM2nYqXsZQ9ByS1uhj2O/U7+5jqRY= +golang.org/x/net v0.62.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI= +golang.org/x/oauth2 v0.37.0 h1:JUlcxA8oAtauLfiH8FX2/FkAWHAdi0QtGCGc+hofE98= +golang.org/x/oauth2 v0.37.0/go.mod h1:IxwZNxUULJmpBFf9K/9NTMSIfZZuvuTy1gGxhigP/58= golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA= golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -619,12 +621,12 @@ google.golang.org/api v0.283.0 h1:0lkp8u0MPwJVHqRL+nJlMAoZVVzbmiXmFHXMOTmSPik= google.golang.org/api v0.283.0/go.mod h1:6Wssta4c5n9qHq5CBhmlai5h/PUa1djdDAIhYEHyvcM= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= -google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 h1:izFU9hz7aeLI/Mi1J0991ae+xcwRLr7hTqWnB/9aIIU= -google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5/go.mod h1:3LhxRw4YYkf+ylAfgaY9JlVLFKhokkCV8duhLLe7+t0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 h1:1VUiZAXyC+zmiFYi+WLtBzr68Cj8wOofHjjrA/kkizc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA= -google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0= -google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0= +google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941 h1:DS/w3N8rsfrwxwgGSj6WhMsPo7aNQGmDx74J81zd0NQ= +google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941/go.mod h1:AuGAdi9KnXss7xbLxIKhCvk+Ro/SxpET/iS45DNYN+M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20261012220534-4341edf3f941 h1:QG6hS4zFplRZvOQedzei4t2pT/zkQc3VR1u+S9/rcAw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20261012220534-4341edf3f941/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc= +google.golang.org/grpc v1.85.0 h1:BPBCfuVRQ1qvBhKDOq9uvQllMvO59rKsYhXpp7Dd8vw= +google.golang.org/grpc v1.85.0/go.mod h1:0rQrOD58yjal/0EaVbGBANindixsCZNQPDV3VKtaKuQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2 h1:rgSNvqscFZ1JgV/4wH5GOsZFSFkR2Eua9As3KIr2LlM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2/go.mod h1:iMEtFwDlAhjDU9L5mY6U1XLwlIId/G3h+QcBHDIvrJ8= google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= diff --git a/vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go index 9f697beca..589cc2073 100644 --- a/vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/hcn/zsyscall_windows.go index cb5bee5f5..e0a005e52 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hns/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/hns/zsyscall_windows.go index 11c7e97e3..fd44ca9b6 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hns/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hns/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go index 14c750bd8..b3afbe3fc 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/internal/regstate/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/regstate/zsyscall_windows.go index f7bb0f551..4f96607df 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/regstate/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/regstate/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/internal/security/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/security/zsyscall_windows.go index 395f54687..cce973394 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/security/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/security/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go index 67779de50..43888c8a2 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/vmcompute/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go index e73de48b0..499e8ae99 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go @@ -194,16 +194,30 @@ func (r *legacyLayerReader) reset() { func findBackupStreamSize(r io.Reader) (int64, error) { br := winio.NewBackupStreamReader(r) + var size int64 for { hdr, err := br.Next() if err != nil { if errors.Is(err, io.EOF) { - err = nil + // With no inline data, sparse blocks provide the logical size. + return size, nil } return 0, err } - if hdr.Id == winio.BackupData { - return hdr.Size, nil + switch hdr.Id { + case winio.BackupData: + // Non-sparse files and sparse files with inline data carry their + // logical size in BackupData. + if hdr.Size > 0 || hdr.Attributes&winio.StreamSparseAttributes == 0 { + return hdr.Size, nil + } + // A sparse BackupData stream without inline data is followed by + // sparse blocks that describe its logical size. + case winio.BackupSparseBlock: + // The terminal zero-length block has an offset at logical EOF. + if end := hdr.Offset + hdr.Size; end > size { + size = end + } } } } diff --git a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/zsyscall_windows.go index 403b94fc5..a57fcfba4 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/wclayer/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/wclayer/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs.go index 3e3c15412..e7222a1c8 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs.go @@ -154,6 +154,20 @@ func CimGetVerificationInformation(blockCimPath string, isSealed *uint32, hashSi )(blockCimPath, isSealed, hashSize, signatureSize, fixedHeaderSize, hash, signature) } +func CimGetVerificationInformation2(blockCimPath string, flags types.CimGetVerificationInfoFlags, isSealed *uint32, hashSize *uint64, signatureOffset *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte, signatureType *types.CimSignatureType, hashAlgorithm *types.CimHashAlgorithm) (hr error) { + return pickSupported( + cimwriter.CimGetVerificationInformation2, + cimfs.CimGetVerificationInformation2, + )(blockCimPath, flags, isSealed, hashSize, signatureOffset, signatureSize, fixedHeaderSize, hash, signature, signatureType, hashAlgorithm) +} + +func CimQueryBlockInfo(blockCimPath string, cimInfoBufferSize uint32, cimInfoBuffer *types.CimFsCimInfo, requiredBufferSize *uint32, cimCount *uint32) (hr error) { + return pickSupported( + cimwriter.CimQueryBlockInfo, + cimfs.CimQueryBlockInfo, + )(blockCimPath, cimInfoBufferSize, cimInfoBuffer, requiredBufferSize, cimCount) +} + func CimMountVerifiedImage(imagePath string, fsName string, flags uint32, volumeID *guid.GUID, hashSize uint16, hash *byte) error { return cimfs.CimMountVerifiedImage(imagePath, fsName, flags, volumeID, hashSize, hash) } diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs/cimfs.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs/cimfs.go index 0317c73a7..9fc7e3964 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs/cimfs.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs/cimfs.go @@ -19,6 +19,10 @@ type FsHandle = types.FsHandle type StreamHandle = types.StreamHandle type FileMetadata = types.CimFsFileMetadata type ImagePath = types.CimFsImagePath +type CimInfo = types.CimFsCimInfo +type VerificationInfoFlags = types.CimGetVerificationInfoFlags +type SignatureType = types.CimSignatureType +type HashAlgorithm = types.CimHashAlgorithm //sys CimMountImage(imagePath string, fsName string, flags uint32, volumeID *GUID) (hr error) = cimfs.CimMountImage? //sys CimDismountImage(volumeID *GUID) (hr error) = cimfs.CimDismountImage? @@ -29,7 +33,7 @@ type ImagePath = types.CimFsImagePath //sys CimCommitImage(cimFSHandle FsHandle) (hr error) = cimfs.CimCommitImage? //sys CimCreateFile(cimFSHandle FsHandle, path string, file *FileMetadata, cimStreamHandle *StreamHandle) (hr error) = cimfs.CimCreateFile? -//sys CimCloseStream(cimStreamHandle StreamHandle) (hr error) = cimfs.CimCloseStream? +//sys CimCloseStream(cimStreamHandle StreamHandle) = cimfs.CimCloseStream? //sys CimWriteStream(cimStreamHandle StreamHandle, buffer uintptr, bufferSize uint32) (hr error) = cimfs.CimWriteStream? //sys CimDeletePath(cimFSHandle FsHandle, path string) (hr error) = cimfs.CimDeletePath? //sys CimCreateHardLink(cimFSHandle FsHandle, newPath string, oldPath string) (hr error) = cimfs.CimCreateHardLink? @@ -41,6 +45,8 @@ type ImagePath = types.CimFsImagePath //sys CimCreateMergeLink(cimFSHandle FsHandle, newPath string, oldPath string) (hr error) = cimfs.CimCreateMergeLink? //sys CimSealImage(blockCimPath string, hashSize *uint64, fixedHeaderSize *uint64, hash *byte) (hr error) = cimfs.CimSealImage? //sys CimGetVerificationInformation(blockCimPath string, isSealed *uint32, hashSize *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte) (hr error) = cimfs.CimGetVerificationInformation? +//sys CimGetVerificationInformation2(blockCimPath string, flags VerificationInfoFlags, isSealed *uint32, hashSize *uint64, signatureOffset *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte, signatureType *SignatureType, hashAlgorithm *HashAlgorithm) (hr error) = cimfs.CimGetVerificationInformation2? +//sys CimQueryBlockInfo(blockCimPath string, cimInfoBufferSize uint32, cimInfoBuffer *CimInfo, requiredBufferSize *uint32, cimCount *uint32) (hr error) = cimfs.CimQueryBlockInfo? //sys CimMountVerifiedImage(imagePath string, fsName string, flags uint32, volumeID *GUID, hashSize uint16, hash *byte) (hr error) = cimfs.CimMountVerifiedImage? //sys CimMergeMountVerifiedImage(numCimPaths uint32, backingImagePaths *ImagePath, flags uint32, volumeID *GUID, hashSize uint16, hash *byte) (hr error) = cimfs.CimMergeMountVerifiedImage? diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs/zsyscall_windows.go index d1c36868b..1ee40e9fd 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e @@ -39,27 +35,29 @@ func errnoErr(e syscall.Errno) error { var ( modcimfs = windows.NewLazySystemDLL("cimfs.dll") - procCimAddFsToMergedImage = modcimfs.NewProc("CimAddFsToMergedImage") - procCimAddFsToMergedImage2 = modcimfs.NewProc("CimAddFsToMergedImage2") - procCimCloseImage = modcimfs.NewProc("CimCloseImage") - procCimCloseStream = modcimfs.NewProc("CimCloseStream") - procCimCommitImage = modcimfs.NewProc("CimCommitImage") - procCimCreateAlternateStream = modcimfs.NewProc("CimCreateAlternateStream") - procCimCreateFile = modcimfs.NewProc("CimCreateFile") - procCimCreateHardLink = modcimfs.NewProc("CimCreateHardLink") - procCimCreateImage = modcimfs.NewProc("CimCreateImage") - procCimCreateImage2 = modcimfs.NewProc("CimCreateImage2") - procCimCreateMergeLink = modcimfs.NewProc("CimCreateMergeLink") - procCimDeletePath = modcimfs.NewProc("CimDeletePath") - procCimDismountImage = modcimfs.NewProc("CimDismountImage") - procCimGetVerificationInformation = modcimfs.NewProc("CimGetVerificationInformation") - procCimMergeMountImage = modcimfs.NewProc("CimMergeMountImage") - procCimMergeMountVerifiedImage = modcimfs.NewProc("CimMergeMountVerifiedImage") - procCimMountImage = modcimfs.NewProc("CimMountImage") - procCimMountVerifiedImage = modcimfs.NewProc("CimMountVerifiedImage") - procCimSealImage = modcimfs.NewProc("CimSealImage") - procCimTombstoneFile = modcimfs.NewProc("CimTombstoneFile") - procCimWriteStream = modcimfs.NewProc("CimWriteStream") + procCimAddFsToMergedImage = modcimfs.NewProc("CimAddFsToMergedImage") + procCimAddFsToMergedImage2 = modcimfs.NewProc("CimAddFsToMergedImage2") + procCimCloseImage = modcimfs.NewProc("CimCloseImage") + procCimCloseStream = modcimfs.NewProc("CimCloseStream") + procCimCommitImage = modcimfs.NewProc("CimCommitImage") + procCimCreateAlternateStream = modcimfs.NewProc("CimCreateAlternateStream") + procCimCreateFile = modcimfs.NewProc("CimCreateFile") + procCimCreateHardLink = modcimfs.NewProc("CimCreateHardLink") + procCimCreateImage = modcimfs.NewProc("CimCreateImage") + procCimCreateImage2 = modcimfs.NewProc("CimCreateImage2") + procCimCreateMergeLink = modcimfs.NewProc("CimCreateMergeLink") + procCimDeletePath = modcimfs.NewProc("CimDeletePath") + procCimDismountImage = modcimfs.NewProc("CimDismountImage") + procCimGetVerificationInformation = modcimfs.NewProc("CimGetVerificationInformation") + procCimGetVerificationInformation2 = modcimfs.NewProc("CimGetVerificationInformation2") + procCimMergeMountImage = modcimfs.NewProc("CimMergeMountImage") + procCimMergeMountVerifiedImage = modcimfs.NewProc("CimMergeMountVerifiedImage") + procCimMountImage = modcimfs.NewProc("CimMountImage") + procCimMountVerifiedImage = modcimfs.NewProc("CimMountVerifiedImage") + procCimQueryBlockInfo = modcimfs.NewProc("CimQueryBlockInfo") + procCimSealImage = modcimfs.NewProc("CimSealImage") + procCimTombstoneFile = modcimfs.NewProc("CimTombstoneFile") + procCimWriteStream = modcimfs.NewProc("CimWriteStream") ) func CimAddFsToMergedImage(cimFSHandle FsHandle, path string) (hr error) { @@ -119,18 +117,12 @@ func CimCloseImage(cimFSHandle FsHandle) (err error) { return } -func CimCloseStream(cimStreamHandle StreamHandle) (hr error) { - hr = procCimCloseStream.Find() - if hr != nil { +func CimCloseStream(cimStreamHandle StreamHandle) (err error) { + err = procCimCloseStream.Find() + if err != nil { return } - r0, _, _ := syscall.SyscallN(procCimCloseStream.Addr(), uintptr(cimStreamHandle)) - if int32(r0) < 0 { - if r0&0x1fff0000 == 0x00070000 { - r0 &= 0xffff - } - hr = syscall.Errno(r0) - } + syscall.SyscallN(procCimCloseStream.Addr(), uintptr(cimStreamHandle)) return } @@ -366,6 +358,30 @@ func _CimGetVerificationInformation(blockCimPath *uint16, isSealed *uint32, hash return } +func CimGetVerificationInformation2(blockCimPath string, flags VerificationInfoFlags, isSealed *uint32, hashSize *uint64, signatureOffset *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte, signatureType *SignatureType, hashAlgorithm *HashAlgorithm) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(blockCimPath) + if hr != nil { + return + } + return _CimGetVerificationInformation2(_p0, flags, isSealed, hashSize, signatureOffset, signatureSize, fixedHeaderSize, hash, signature, signatureType, hashAlgorithm) +} + +func _CimGetVerificationInformation2(blockCimPath *uint16, flags VerificationInfoFlags, isSealed *uint32, hashSize *uint64, signatureOffset *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte, signatureType *SignatureType, hashAlgorithm *HashAlgorithm) (hr error) { + hr = procCimGetVerificationInformation2.Find() + if hr != nil { + return + } + r0, _, _ := syscall.SyscallN(procCimGetVerificationInformation2.Addr(), uintptr(unsafe.Pointer(blockCimPath)), uintptr(flags), uintptr(unsafe.Pointer(isSealed)), uintptr(unsafe.Pointer(hashSize)), uintptr(unsafe.Pointer(signatureOffset)), uintptr(unsafe.Pointer(signatureSize)), uintptr(unsafe.Pointer(fixedHeaderSize)), uintptr(unsafe.Pointer(hash)), uintptr(unsafe.Pointer(signature)), uintptr(unsafe.Pointer(signatureType)), uintptr(unsafe.Pointer(hashAlgorithm))) + if int32(r0) < 0 { + if r0&0x1fff0000 == 0x00070000 { + r0 &= 0xffff + } + hr = syscall.Errno(r0) + } + return +} + func CimMergeMountImage(numCimPaths uint32, backingImagePaths *ImagePath, flags uint32, volumeID *GUID) (hr error) { hr = procCimMergeMountImage.Find() if hr != nil { @@ -454,6 +470,30 @@ func _CimMountVerifiedImage(imagePath *uint16, fsName *uint16, flags uint32, vol return } +func CimQueryBlockInfo(blockCimPath string, cimInfoBufferSize uint32, cimInfoBuffer *CimInfo, requiredBufferSize *uint32, cimCount *uint32) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(blockCimPath) + if hr != nil { + return + } + return _CimQueryBlockInfo(_p0, cimInfoBufferSize, cimInfoBuffer, requiredBufferSize, cimCount) +} + +func _CimQueryBlockInfo(blockCimPath *uint16, cimInfoBufferSize uint32, cimInfoBuffer *CimInfo, requiredBufferSize *uint32, cimCount *uint32) (hr error) { + hr = procCimQueryBlockInfo.Find() + if hr != nil { + return + } + r0, _, _ := syscall.SyscallN(procCimQueryBlockInfo.Addr(), uintptr(unsafe.Pointer(blockCimPath)), uintptr(cimInfoBufferSize), uintptr(unsafe.Pointer(cimInfoBuffer)), uintptr(unsafe.Pointer(requiredBufferSize)), uintptr(unsafe.Pointer(cimCount))) + if int32(r0) < 0 { + if r0&0x1fff0000 == 0x00070000 { + r0 &= 0xffff + } + hr = syscall.Errno(r0) + } + return +} + func CimSealImage(blockCimPath string, hashSize *uint64, fixedHeaderSize *uint64, hash *byte) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(blockCimPath) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimwriter/cimwriter.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimwriter/cimwriter.go index d8f4d4dc1..1c4aac7cc 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimwriter/cimwriter.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimwriter/cimwriter.go @@ -17,6 +17,10 @@ type FsHandle = types.FsHandle type StreamHandle = types.StreamHandle type FileMetadata = types.CimFsFileMetadata type ImagePath = types.CimFsImagePath +type CimInfo = types.CimFsCimInfo +type VerificationInfoFlags = types.CimGetVerificationInfoFlags +type SignatureType = types.CimSignatureType +type HashAlgorithm = types.CimHashAlgorithm //sys CimCreateImage(imagePath string, oldFSName *uint16, newFSName *uint16, cimFSHandle *FsHandle) (hr error) = cimwriter.CimCreateImage? //sys CimCreateImage2(imagePath string, flags uint32, oldFSName *uint16, newFSName *uint16, cimFSHandle *FsHandle) (hr error) = cimwriter.CimCreateImage2? @@ -24,7 +28,7 @@ type ImagePath = types.CimFsImagePath //sys CimCommitImage(cimFSHandle FsHandle) (hr error) = cimwriter.CimCommitImage? //sys CimCreateFile(cimFSHandle FsHandle, path string, file *FileMetadata, cimStreamHandle *StreamHandle) (hr error) = cimwriter.CimCreateFile? -//sys CimCloseStream(cimStreamHandle StreamHandle) (hr error) = cimwriter.CimCloseStream? +//sys CimCloseStream(cimStreamHandle StreamHandle) = cimwriter.CimCloseStream? //sys CimWriteStream(cimStreamHandle StreamHandle, buffer uintptr, bufferSize uint32) (hr error) = cimwriter.CimWriteStream? //sys CimDeletePath(cimFSHandle FsHandle, path string) (hr error) = cimwriter.CimDeletePath? //sys CimCreateHardLink(cimFSHandle FsHandle, newPath string, oldPath string) (hr error) = cimwriter.CimCreateHardLink? @@ -37,6 +41,8 @@ type ImagePath = types.CimFsImagePath //sys CimSealImage(blockCimPath string, hashSize *uint64, fixedHeaderSize *uint64, hash *byte) (hr error) = cimwriter.CimSealImage? //sys CimGetVerificationInformation(blockCimPath string, isSealed *uint32, hashSize *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte) (hr error) = cimwriter.CimGetVerificationInformation? +//sys CimGetVerificationInformation2(blockCimPath string, flags VerificationInfoFlags, isSealed *uint32, hashSize *uint64, signatureOffset *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte, signatureType *SignatureType, hashAlgorithm *HashAlgorithm) (hr error) = cimwriter.CimGetVerificationInformation2? +//sys CimQueryBlockInfo(blockCimPath string, cimInfoBufferSize uint32, cimInfoBuffer *CimInfo, requiredBufferSize *uint32, cimCount *uint32) (hr error) = cimwriter.CimQueryBlockInfo? var load = sync.OnceValue(func() error { // Pre-load the DLL with a restricted search path (System32 + application directory only) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimwriter/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimwriter/zsyscall_windows.go index 3dbafa1a2..0bde95a1d 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimwriter/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/cimwriter/zsyscall_windows.go @@ -7,18 +7,16 @@ package cimwriter import ( "syscall" "unsafe" + + "golang.org/x/sys/windows" ) var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -28,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e @@ -37,22 +35,24 @@ func errnoErr(e syscall.Errno) error { var ( modcimwriter = syscall.NewLazyDLL("cimwriter.dll") - procCimAddFsToMergedImage = modcimwriter.NewProc("CimAddFsToMergedImage") - procCimAddFsToMergedImage2 = modcimwriter.NewProc("CimAddFsToMergedImage2") - procCimCloseImage = modcimwriter.NewProc("CimCloseImage") - procCimCloseStream = modcimwriter.NewProc("CimCloseStream") - procCimCommitImage = modcimwriter.NewProc("CimCommitImage") - procCimCreateAlternateStream = modcimwriter.NewProc("CimCreateAlternateStream") - procCimCreateFile = modcimwriter.NewProc("CimCreateFile") - procCimCreateHardLink = modcimwriter.NewProc("CimCreateHardLink") - procCimCreateImage = modcimwriter.NewProc("CimCreateImage") - procCimCreateImage2 = modcimwriter.NewProc("CimCreateImage2") - procCimCreateMergeLink = modcimwriter.NewProc("CimCreateMergeLink") - procCimDeletePath = modcimwriter.NewProc("CimDeletePath") - procCimGetVerificationInformation = modcimwriter.NewProc("CimGetVerificationInformation") - procCimSealImage = modcimwriter.NewProc("CimSealImage") - procCimTombstoneFile = modcimwriter.NewProc("CimTombstoneFile") - procCimWriteStream = modcimwriter.NewProc("CimWriteStream") + procCimAddFsToMergedImage = modcimwriter.NewProc("CimAddFsToMergedImage") + procCimAddFsToMergedImage2 = modcimwriter.NewProc("CimAddFsToMergedImage2") + procCimCloseImage = modcimwriter.NewProc("CimCloseImage") + procCimCloseStream = modcimwriter.NewProc("CimCloseStream") + procCimCommitImage = modcimwriter.NewProc("CimCommitImage") + procCimCreateAlternateStream = modcimwriter.NewProc("CimCreateAlternateStream") + procCimCreateFile = modcimwriter.NewProc("CimCreateFile") + procCimCreateHardLink = modcimwriter.NewProc("CimCreateHardLink") + procCimCreateImage = modcimwriter.NewProc("CimCreateImage") + procCimCreateImage2 = modcimwriter.NewProc("CimCreateImage2") + procCimCreateMergeLink = modcimwriter.NewProc("CimCreateMergeLink") + procCimDeletePath = modcimwriter.NewProc("CimDeletePath") + procCimGetVerificationInformation = modcimwriter.NewProc("CimGetVerificationInformation") + procCimGetVerificationInformation2 = modcimwriter.NewProc("CimGetVerificationInformation2") + procCimQueryBlockInfo = modcimwriter.NewProc("CimQueryBlockInfo") + procCimSealImage = modcimwriter.NewProc("CimSealImage") + procCimTombstoneFile = modcimwriter.NewProc("CimTombstoneFile") + procCimWriteStream = modcimwriter.NewProc("CimWriteStream") ) func CimAddFsToMergedImage(cimFSHandle FsHandle, path string) (hr error) { @@ -112,18 +112,12 @@ func CimCloseImage(cimFSHandle FsHandle) (err error) { return } -func CimCloseStream(cimStreamHandle StreamHandle) (hr error) { - hr = procCimCloseStream.Find() - if hr != nil { +func CimCloseStream(cimStreamHandle StreamHandle) (err error) { + err = procCimCloseStream.Find() + if err != nil { return } - r0, _, _ := syscall.SyscallN(procCimCloseStream.Addr(), uintptr(cimStreamHandle)) - if int32(r0) < 0 { - if r0&0x1fff0000 == 0x00070000 { - r0 &= 0xffff - } - hr = syscall.Errno(r0) - } + syscall.SyscallN(procCimCloseStream.Addr(), uintptr(cimStreamHandle)) return } @@ -344,6 +338,54 @@ func _CimGetVerificationInformation(blockCimPath *uint16, isSealed *uint32, hash return } +func CimGetVerificationInformation2(blockCimPath string, flags VerificationInfoFlags, isSealed *uint32, hashSize *uint64, signatureOffset *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte, signatureType *SignatureType, hashAlgorithm *HashAlgorithm) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(blockCimPath) + if hr != nil { + return + } + return _CimGetVerificationInformation2(_p0, flags, isSealed, hashSize, signatureOffset, signatureSize, fixedHeaderSize, hash, signature, signatureType, hashAlgorithm) +} + +func _CimGetVerificationInformation2(blockCimPath *uint16, flags VerificationInfoFlags, isSealed *uint32, hashSize *uint64, signatureOffset *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte, signatureType *SignatureType, hashAlgorithm *HashAlgorithm) (hr error) { + hr = procCimGetVerificationInformation2.Find() + if hr != nil { + return + } + r0, _, _ := syscall.SyscallN(procCimGetVerificationInformation2.Addr(), uintptr(unsafe.Pointer(blockCimPath)), uintptr(flags), uintptr(unsafe.Pointer(isSealed)), uintptr(unsafe.Pointer(hashSize)), uintptr(unsafe.Pointer(signatureOffset)), uintptr(unsafe.Pointer(signatureSize)), uintptr(unsafe.Pointer(fixedHeaderSize)), uintptr(unsafe.Pointer(hash)), uintptr(unsafe.Pointer(signature)), uintptr(unsafe.Pointer(signatureType)), uintptr(unsafe.Pointer(hashAlgorithm))) + if int32(r0) < 0 { + if r0&0x1fff0000 == 0x00070000 { + r0 &= 0xffff + } + hr = syscall.Errno(r0) + } + return +} + +func CimQueryBlockInfo(blockCimPath string, cimInfoBufferSize uint32, cimInfoBuffer *CimInfo, requiredBufferSize *uint32, cimCount *uint32) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(blockCimPath) + if hr != nil { + return + } + return _CimQueryBlockInfo(_p0, cimInfoBufferSize, cimInfoBuffer, requiredBufferSize, cimCount) +} + +func _CimQueryBlockInfo(blockCimPath *uint16, cimInfoBufferSize uint32, cimInfoBuffer *CimInfo, requiredBufferSize *uint32, cimCount *uint32) (hr error) { + hr = procCimQueryBlockInfo.Find() + if hr != nil { + return + } + r0, _, _ := syscall.SyscallN(procCimQueryBlockInfo.Addr(), uintptr(unsafe.Pointer(blockCimPath)), uintptr(cimInfoBufferSize), uintptr(unsafe.Pointer(cimInfoBuffer)), uintptr(unsafe.Pointer(requiredBufferSize)), uintptr(unsafe.Pointer(cimCount))) + if int32(r0) < 0 { + if r0&0x1fff0000 == 0x00070000 { + r0 &= 0xffff + } + hr = syscall.Errno(r0) + } + return +} + func CimSealImage(blockCimPath string, hashSize *uint64, fixedHeaderSize *uint64, hash *byte) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(blockCimPath) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/types/cimfs.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/types/cimfs.go index 2fa8cfc71..b8f77bd00 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/types/cimfs.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/types/cimfs.go @@ -11,6 +11,27 @@ import ( type FsHandle uintptr type StreamHandle uintptr +type CimGetVerificationInfoFlags uint32 + +const ( + CimGetVerificationInfoNone CimGetVerificationInfoFlags = 0 + CimGetVerificationInfoFromSkeletonCim CimGetVerificationInfoFlags = 1 +) + +type CimSignatureType uint32 + +const ( + CimSignatureNone CimSignatureType = 0 + CimSignaturePKCS7 CimSignatureType = 1 +) + +type CimHashAlgorithm uint32 + +const ( + CimHashAlgorithmSHA256 CimHashAlgorithm = 0 + CimHashAlgorithmSHA512 CimHashAlgorithm = 1 +) + type CimFsFileMetadata struct { Attributes uint32 FileSize int64 @@ -34,3 +55,9 @@ type CimFsImagePath struct { ImageDir *uint16 ImageName *uint16 } + +type CimFsCimInfo struct { + NextEntryOffset uint32 + CimNameLength uint16 + CimName [1]uint16 +} diff --git a/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go index 4a32bcacd..b7b2b61bf 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/Microsoft/hcsshim/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/zsyscall_windows.go index e43d59a40..05a1ecca6 100644 --- a/vendor/github.com/Microsoft/hcsshim/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/zsyscall_windows.go @@ -15,12 +15,8 @@ var _ unsafe.Pointer // Do the interface allocations only once for common // Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_IO_PENDING error = windows.ERROR_IO_PENDING errERROR_EINVAL error = syscall.EINVAL ) @@ -30,7 +26,7 @@ func errnoErr(e syscall.Errno) error { switch e { case 0: return errERROR_EINVAL - case errnoERROR_IO_PENDING: + case windows.ERROR_IO_PENDING: return errERROR_IO_PENDING } return e diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md index 321c572f7..e5a8a79f2 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md @@ -1,3 +1,23 @@ +# v1.7.25 (2026-10-27) + +* **Dependency Update**: Update to smithy-go v1.28.7. + +# v1.7.24 (2026-10-22) + +* **Bug Fix**: Update smithy-go to v1.28.6 + +# v1.7.23 (2026-10-21) + +* **Bug Fix**: Enforce event stream header key value length limit instead of truncating + +# v1.7.22 (2026-10-09.2) + +* **Dependency Update**: Update to smithy-go v1.28.5. + +# v1.7.21 (2026-10-08) + +* **Dependency Update**: Update to smithy-go v1.28.4. + # v1.7.20 (2026-08-26) * **Dependency Update**: Update to smithy-go v1.28.0. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/encode.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/encode.go index 61cf7238d..f2e37c8b3 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/encode.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/encode.go @@ -141,6 +141,13 @@ func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) // stream format. Returns an error if a header fails to encode. func EncodeHeaders(w io.Writer, headers Headers) error { for _, h := range headers { + if len(h.Name) > maxHeaderNameLen { + return LengthError{ + Part: "header name", + Want: maxHeaderNameLen, Have: len(h.Name), + Value: h.Name, + } + } hn := headerName{ Len: uint8(len(h.Name)), } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go index d52e6b34d..860e8f477 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go @@ -3,4 +3,4 @@ package eventstream // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.7.20" +const goModuleVersion = "1.7.25" diff --git a/vendor/github.com/go-openapi/analysis/.codecov.yml b/vendor/github.com/go-openapi/analysis/.codecov.yml index a5ba8e96d..75d4a08f9 100644 --- a/vendor/github.com/go-openapi/analysis/.codecov.yml +++ b/vendor/github.com/go-openapi/analysis/.codecov.yml @@ -7,3 +7,8 @@ coverage: patch: default: target: 80% + +ignore: + - "testdata" + - "internal/antest" + - "internal/testintegration" diff --git a/vendor/github.com/go-openapi/analysis/.golangci.yml b/vendor/github.com/go-openapi/analysis/.golangci.yml index 0d7baa1d7..8488e9771 100644 --- a/vendor/github.com/go-openapi/analysis/.golangci.yml +++ b/vendor/github.com/go-openapi/analysis/.golangci.yml @@ -10,6 +10,7 @@ linters: - gomodguard - gomodguard_v2 - exhaustruct + - exhaustruct_v5 - nlreturn - nonamedreturns - noinlineerr diff --git a/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md b/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md index a89274cdb..f18413611 100644 --- a/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/analysis/CONTRIBUTORS.md @@ -4,31 +4,32 @@ | Total Contributors | Total Contributions | | --- | --- | -| 22 | 273 | +| 23 | 298 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @fredbi | 133 | | +| @fredbi | 149 | | | @casualjim | 91 | | +| @amoudani | 9 | | | @keramix | 9 | | | @youyuanwu | 8 | | | @wjase | 7 | | -| @kul-amr | 3 | | -| @schafle | 3 | | | @msample | 3 | | -| @mbohlool | 2 | | +| @schafle | 3 | | +| @kul-amr | 3 | | | @zmay2030 | 2 | | -| @ujjwalsh | 1 | | -| @itengfei | 1 | | -| @nrnrk | 1 | | -| @cuishuang | 1 | | -| @tklauser | 1 | | -| @Shimizu1111 | 1 | | -| @thaJeztah | 1 | | -| @knweiss | 1 | | -| @guillemj | 1 | | -| @gregmarr | 1 | | -| @danielfbm | 1 | | +| @mbohlool | 2 | | | @Copilot | 1 | | +| @danielfbm | 1 | | +| @gregmarr | 1 | | +| @guillemj | 1 | | +| @knweiss | 1 | | +| @thaJeztah | 1 | | +| @Shimizu1111 | 1 | | +| @tklauser | 1 | | +| @cuishuang | 1 | | +| @nrnrk | 1 | | +| @itengfei | 1 | | +| @ujjwalsh | 1 | | _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_ diff --git a/vendor/github.com/go-openapi/analysis/README.md b/vendor/github.com/go-openapi/analysis/README.md index 2a9046297..abb0de930 100644 --- a/vendor/github.com/go-openapi/analysis/README.md +++ b/vendor/github.com/go-openapi/analysis/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -102,8 +102,6 @@ Maintainers can cut a new release by either: [release-badge]: https://badge.fury.io/gh/go-openapi%2Fanalysis.svg [release-url]: https://badge.fury.io/gh/go-openapi%2Fanalysis -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/analysis -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/analysis [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/analysis [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/analysis diff --git a/vendor/github.com/go-openapi/analysis/analyzer.go b/vendor/github.com/go-openapi/analysis/analyzer.go index c24811aae..63245a182 100644 --- a/vendor/github.com/go-openapi/analysis/analyzer.go +++ b/vendor/github.com/go-openapi/analysis/analyzer.go @@ -30,6 +30,15 @@ type referenceAnalysis struct { parameterItems map[string]spec.Ref allRefs map[string]spec.Ref pathItems map[string]spec.Ref + + // unmappedRefs holds the $ref found under keywords the Swagger 2.0 model does not map, which + // land in [spec.Schema.ExtraProps] as raw JSON: propertyNames, contains, if/then/else, $defs. + // + // They are kept apart from allRefs and schemas on purpose. Flatten needs them to import their + // target and rewrite the pointer; every other consumer of this analysis - AllRefs, + // AllReferences, AllDefinitionReferences and what go-swagger builds on them - addresses schemas + // through the model, and a key naming a raw JSON node is of no use there. + unmappedRefs map[string]spec.Ref } func (r *referenceAnalysis) addRef(key string, ref spec.Ref) { @@ -48,6 +57,11 @@ func (r *referenceAnalysis) addItemsRef(key string, items *spec.Items, location } } +// addUnmappedRef records a $ref held by a keyword the model does not map. +func (r *referenceAnalysis) addUnmappedRef(key string, ref spec.Ref) { + r.unmappedRefs["#"+key] = ref +} + func (r *referenceAnalysis) addSchemaRef(key string, ref SchemaRef) { r.schemas["#"+key] = ref.Schema.Ref r.addRef(key, ref.Schema.Ref) @@ -585,6 +599,20 @@ func (s *Spec) AllRefs() (result []spec.Ref) { return } +// AllRefsByLocation returns all the references found in the document, keyed by +// where each one is declared. +// +// Keys are local JSON references into the analyzed document, with tokens +// escaped as per RFC 6901, e.g. "#/paths/~1pets/get/responses/200/schema". +// +// Unlike [Spec.AllRefs], the result is not deduplicated: the same reference +// declared in several places appears under each of its locations. +// +// The map is cloned to avoid accidental changes. +func (s *Spec) AllRefsByLocation() map[string]spec.Ref { + return cloneRefMap(s.references.allRefs) +} + // ParameterPatterns returns all the patterns found in parameters // the map is cloned to avoid accidental changes. func (s *Spec) ParameterPatterns() map[string]string { @@ -725,6 +753,7 @@ func (s *Spec) reset() { s.references.headerItems = make(map[string]spec.Ref, allocLargeMap) s.references.parameterItems = make(map[string]spec.Ref, allocLargeMap) s.references.allRefs = make(map[string]spec.Ref, allocLargeMap) + s.references.unmappedRefs = make(map[string]spec.Ref, allocSmallMap) s.patterns.parameters = make(map[string]string, allocLargeMap) s.patterns.headers = make(map[string]string, allocLargeMap) s.patterns.items = make(map[string]string, allocLargeMap) @@ -958,6 +987,42 @@ func (s *Spec) analyzeResponse(prefix string, k int, res spec.Response) { } } +// analyzeUnmapped records the $ref held by the keywords of a schema that the Swagger 2.0 model +// does not map, which json.Unmarshal leaves in ExtraProps as raw JSON. +// +// The keys it produces address the node holding the $ref, so "#/definitions/deep/propertyNames" +// or "#/definitions/deep/if/anyOf/0". [replace.UpdateRef] writes to them through the same +// jsonpointer call every other key goes through. +func (s *Spec) analyzeUnmapped(prefix string, extra map[string]any) { + for key := range extra { + s.analyzeUnmappedNode(slashpath.Join(prefix, jsonpointer.Escape(key)), extra[key]) + } +} + +func (s *Spec) analyzeUnmappedNode(refURI string, node any) { + switch value := node.(type) { + case map[string]any: + if raw, ok := value["$ref"].(string); ok { + ref, err := spec.NewRef(raw) + if err != nil { + return // a string under a "$ref" key is not necessarily a reference + } + + s.references.addUnmappedRef(refURI, ref) + + return // a $ref makes its siblings irrelevant + } + + for key := range value { + s.analyzeUnmappedNode(slashpath.Join(refURI, jsonpointer.Escape(key)), value[key]) + } + case []any: + for i := range value { + s.analyzeUnmappedNode(slashpath.Join(refURI, strconv.Itoa(i)), value[i]) + } + } +} + func (s *Spec) analyzeSchema(name string, schema *spec.Schema, prefix string) { refURI := slashpath.Join(prefix, jsonpointer.Escape(name)) schRef := SchemaRef{ @@ -981,6 +1046,8 @@ func (s *Spec) analyzeSchema(name string, schema *spec.Schema, prefix string) { s.enums.addSchemaEnum(refURI, schema.Enum) } + s.analyzeUnmapped(refURI, schema.ExtraProps) + for k, v := range schema.Definitions { s.analyzeSchema(k, &v, slashpath.Join(refURI, "definitions")) } @@ -1053,6 +1120,13 @@ func cloneStringMap(source map[string]string) map[string]string { return res } +func cloneRefMap(source map[string]spec.Ref) map[string]spec.Ref { + res := make(map[string]spec.Ref, len(source)) + maps.Copy(res, source) + + return res +} + func cloneEnumMap(source map[string][]any) map[string][]any { res := make(map[string][]any, len(source)) maps.Copy(res, source) diff --git a/vendor/github.com/go-openapi/analysis/flatten.go b/vendor/github.com/go-openapi/analysis/flatten.go index c90456f6a..2b7371f54 100644 --- a/vendor/github.com/go-openapi/analysis/flatten.go +++ b/vendor/github.com/go-openapi/analysis/flatten.go @@ -5,6 +5,7 @@ package analysis import ( "log" + "maps" "path" "slices" "sort" @@ -179,18 +180,20 @@ func normalizeRef(opts *FlattenOpts) error { debugLog("normalizeRef") altered := false - for k, w := range opts.Spec.references.allRefs { - if !strings.HasPrefix(w.String(), opts.BasePath+definitionsPath) { // may be a mix of / and \, depending on OS - continue - } + for _, refs := range []map[string]spec.Ref{opts.Spec.references.allRefs, opts.Spec.references.unmappedRefs} { + for k, w := range refs { + if !strings.HasPrefix(w.String(), opts.BasePath+definitionsPath) { // may be a mix of / and \, depending on OS + continue + } - altered = true - debugLog("stripping absolute path for: %s", w.String()) + altered = true + debugLog("stripping absolute path for: %s", w.String()) - // strip the base path from definition - if err := replace.UpdateRef(opts.Swagger(), k, - spec.MustCreateRef(path.Join(definitionsPath, path.Base(w.String())))); err != nil { - return err + // strip the base path from definition + if err := replace.UpdateRef(opts.Swagger(), k, + spec.MustCreateRef(path.Join(definitionsPath, path.Base(w.String())))); err != nil { + return err + } } } @@ -276,6 +279,10 @@ func removeUnusedSinglePass(opts *FlattenOpts) (hasRemoved bool) { delete(expected, k) } + for _, ref := range opts.Spec.references.unmappedRefs { + delete(expected, ref.String()) + } + for k := range expected { hasRemoved = true debugLog("removing unused definition %s", path.Base(k)) @@ -327,9 +334,11 @@ func importNewRef(entry sortref.RefRevIdx, refStr string, opts *FlattenOpts) err partialAnalyzer.analyzeSchema("", sch, "/") // now rewrite those refs with rebase - for key, ref := range partialAnalyzer.references.allRefs { - if err := replace.UpdateRef(sch, key, spec.MustCreateRef(normalize.RebaseRef(entry.Ref.String(), ref.String()))); err != nil { - return ErrRewriteRef(key, entry.Ref.String(), err) + for _, refs := range []map[string]spec.Ref{partialAnalyzer.references.allRefs, partialAnalyzer.references.unmappedRefs} { + for key, ref := range refs { + if err := replace.UpdateRef(sch, key, spec.MustCreateRef(normalize.RebaseRef(entry.Ref.String(), ref.String()))); err != nil { + return ErrRewriteRef(key, entry.Ref.String(), err) + } } } @@ -374,10 +383,20 @@ func importNewRef(entry sortref.RefRevIdx, refStr string, opts *FlattenOpts) err // At every iteration, new remotes may be found when digging deeper: they are rebased to the current schema before being imported. // // This returns true when no more remote references can be found. +// importableRefs returns every $ref that flatten has to bring into the root document: the ones the +// model maps, and the ones held by keywords it does not. +func importableRefs(sp *Spec) map[string]spec.Ref { + refs := make(map[string]spec.Ref, len(sp.references.schemas)+len(sp.references.unmappedRefs)) + maps.Copy(refs, sp.references.schemas) + maps.Copy(refs, sp.references.unmappedRefs) + + return refs +} + func importExternalReferences(opts *FlattenOpts) (bool, error) { debugLog("importExternalReferences") - groupedRefs := sortref.ReverseIndex(opts.Spec.references.schemas, opts.BasePath) + groupedRefs := sortref.ReverseIndex(importableRefs(opts.Spec), opts.BasePath) sortedRefStr := make([]string, 0, len(groupedRefs)) if opts.flattenContext == nil { opts.flattenContext = newContext() diff --git a/vendor/github.com/go-openapi/analysis/go.work b/vendor/github.com/go-openapi/analysis/go.work index c0f02a78f..fc8fd598e 100644 --- a/vendor/github.com/go-openapi/analysis/go.work +++ b/vendor/github.com/go-openapi/analysis/go.work @@ -1,4 +1,4 @@ -go 1.25.0 +go 1.26.0 use ( . diff --git a/vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go b/vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go index b4c0fdd44..66cad8f39 100644 --- a/vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go +++ b/vendor/github.com/go-openapi/analysis/internal/flatten/replace/replace.go @@ -19,6 +19,7 @@ import ( const ( definitionsPath = "#/definitions" + jsonRef = "$ref" allocMediumMap = 64 ) @@ -217,6 +218,17 @@ func UpdateRef(sp any, key string, ref spec.Ref) error { switch refable := value.(type) { case *spec.Schema: refable.Ref = ref + case map[string]any: + // a keyword the Swagger 2.0 model does not map: the node is raw JSON, and the map it + // holds is the one in the document - writing to it reaches the document + refable[jsonRef] = ref.String() + case *any: + raw, ok := (*refable).(map[string]any) + if !ok { + return ErrNoSchemaWithRef(key, value) + } + + raw[jsonRef] = ref.String() case *spec.SchemaOrArray: if refable.Schema != nil { refable.Schema.Ref = ref diff --git a/vendor/github.com/go-openapi/analysis/revive.toml b/vendor/github.com/go-openapi/analysis/revive.toml new file mode 100644 index 000000000..eef9c1712 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/revive.toml @@ -0,0 +1,18 @@ +# revive configuration used by codefactor.io. +# +# This is redundant with .golangci.yml, since revive is part of golangci-lint, +# but we need to configure it to remain consistent across reporting tools. + +ignore-generated-header = false +severity = "warning" +confidence = 0.8 +error-code = 0 +warning-code = 0 +enable-default-rules = true + +[rule.exported] +disabled = true +[rule.cyclomatic] +arguments = [25] +[rule.cognitive-complexity] +arguments = [25] diff --git a/vendor/github.com/go-openapi/errors/CONTRIBUTORS.md b/vendor/github.com/go-openapi/errors/CONTRIBUTORS.md index 68b716b56..94064c3f7 100644 --- a/vendor/github.com/go-openapi/errors/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/errors/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 13 | 115 | +| 13 | 121 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 58 | | -| @fredbi | 41 | | +| @fredbi | 47 | | | @youyuanwu | 5 | | | @alexandear | 2 | | | @fiorix | 1 | | diff --git a/vendor/github.com/go-openapi/errors/README.md b/vendor/github.com/go-openapi/errors/README.md index 35e6b69ba..db87dfde1 100644 --- a/vendor/github.com/go-openapi/errors/README.md +++ b/vendor/github.com/go-openapi/errors/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -18,12 +18,9 @@ Shared errors and error interface used throughout the various libraries found in * **2025-12-19** : new community chat on discord * a new discord community channel is available to be notified of changes and support users - * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31** You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url] -Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url] - ## Status API is stable. @@ -69,9 +66,9 @@ This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE). ## Other documentation * [All-time contributors](./CONTRIBUTORS.md) -* [Contributing guidelines](.github/CONTRIBUTING.md) -* [Maintainers documentation](docs/MAINTAINERS.md) -* [Code style](docs/STYLE.md) +* [Contributing guidelines][contributing-doc-site] +* [Maintainers documentation][maintainers-doc-site] +* [Code style][style-doc-site] ## Cutting a new release @@ -95,16 +92,11 @@ Maintainers can cut a new release by either: [release-badge]: https://badge.fury.io/gh/go-openapi%2Ferrors.svg [release-url]: https://badge.fury.io/gh/go-openapi%2Ferrors -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/errors -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/errors [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/errors [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/errors [godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/errors [godoc-url]: http://pkg.go.dev/github.com/go-openapi/errors -[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png -[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM -[slack-url]: https://goswagger.slack.com/archives/C04R30YMU [discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue [discord-url]: https://discord.gg/FfnFYaC3k5 @@ -116,3 +108,7 @@ Maintainers can cut a new release by either: [goversion-url]: https://github.com/go-openapi/errors/blob/master/go.mod [top-badge]: https://img.shields.io/github/languages/top/go-openapi/errors [commits-badge]: https://img.shields.io/github/commits-since/go-openapi/errors/latest + +[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html +[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html +[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html diff --git a/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md b/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md index de0bf5c04..6941823e6 100644 --- a/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md @@ -4,11 +4,11 @@ | Total Contributors | Total Contributions | | --- | --- | -| 13 | 132 | +| 13 | 136 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @fredbi | 83 | | +| @fredbi | 87 | | | @casualjim | 33 | | | @magodo | 3 | | | @youyuanwu | 3 | | diff --git a/vendor/github.com/go-openapi/jsonpointer/README.md b/vendor/github.com/go-openapi/jsonpointer/README.md index 6e7929c64..e563fac77 100644 --- a/vendor/github.com/go-openapi/jsonpointer/README.md +++ b/vendor/github.com/go-openapi/jsonpointer/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -152,8 +152,6 @@ Maintainers can cut a new release by either: [release-badge]: https://badge.fury.io/gh/go-openapi%2Fjsonpointer.svg [release-url]: https://badge.fury.io/gh/go-openapi%2Fjsonpointer -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/jsonpointer -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/jsonpointer [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/jsonpointer [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/jsonpointer diff --git a/vendor/github.com/go-openapi/jsonpointer/pointer.go b/vendor/github.com/go-openapi/jsonpointer/pointer.go index 05fc863ee..d6ee165f6 100644 --- a/vendor/github.com/go-openapi/jsonpointer/pointer.go +++ b/vendor/github.com/go-openapi/jsonpointer/pointer.go @@ -284,7 +284,7 @@ func (p *Pointer) set(node, data any, nameProvider NameProvider) (any, error) { // new child reference (e.g. a slice header returned by an "-" append) into its parent on the way // back up. // -// Returning the (possibly new) node at each level is what makes append work at any depth without +// Returning the (possibly new) node at each level makes append work at any depth without // requiring the caller to pass a pointer to the containing slice: the new slice header propagates // up and each parent rebinds it via the appropriate kind-specific setter. func (p *Pointer) setAt(node any, tokens []string, data any, nameProvider NameProvider) (any, error) { diff --git a/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md b/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md index d20737c94..605e03795 100644 --- a/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md @@ -4,11 +4,11 @@ | Total Contributors | Total Contributions | | --- | --- | -| 9 | 83 | +| 9 | 84 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @fredbi | 46 | | +| @fredbi | 47 | | | @casualjim | 25 | | | @youyuanwu | 5 | | | @olivierlemasle | 2 | | diff --git a/vendor/github.com/go-openapi/jsonreference/README.md b/vendor/github.com/go-openapi/jsonreference/README.md index fbd16cf89..000a1feb5 100644 --- a/vendor/github.com/go-openapi/jsonreference/README.md +++ b/vendor/github.com/go-openapi/jsonreference/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -97,8 +97,6 @@ Maintainers can cut a new release by either: [gomod-badge]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fjsonreference.svg [gomod-url]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fjsonreference -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/jsonreference -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/jsonreference [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/jsonreference [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/jsonreference diff --git a/vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go b/vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go index a08b47320..6ef640e3b 100644 --- a/vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go +++ b/vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go @@ -5,19 +5,12 @@ package internal import ( "net/url" - "regexp" "strings" ) const ( - defaultHTTPPort = ":80" - defaultHTTPSPort = ":443" -) - -// Regular expressions used by the normalizations. -var ( - rxPort = regexp.MustCompile(`(:\d+)/?$`) - rxDupSlashes = regexp.MustCompile(`/{2,}`) + defaultHTTPPort = "80" + defaultHTTPSPort = "443" ) // NormalizeURL will normalize the specified URL @@ -55,20 +48,66 @@ func lowercaseHost(u *url.URL) { } } +// removeDefaultPort drops :80 from an http URL and :443 from an https one. +// +// The port stays when dropping it would leave an authority url.Parse no longer accepts, so the +// shortened host is parsed before being kept. url.Parse reads "https://:a:443" as the host ":a" +// on port 443, and ":a" on its own is an invalid port, so "https://:a" no longer parses. +// +// A degenerate authority can spell a default port twice - url.Parse reads "http://:80:80" as the +// host ":80" on port 80 - so removal repeats until nothing more comes off. Each pass shortens the +// host, so the loop ends, and normalizing the result again changes nothing. func removeDefaultPort(u *url.URL) { - if len(u.Host) > 0 { - scheme := strings.ToLower(u.Scheme) - u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string { - if (scheme == "http" && val == defaultHTTPPort) || (scheme == "https" && val == defaultHTTPSPort) { - return "" - } - return val - }) + for { + port := u.Port() + if port == "" || port != defaultPortForScheme(strings.ToLower(u.Scheme)) { + return + } + + host := strings.TrimSuffix(u.Host, ":"+port) + if _, err := url.Parse("//" + host); err != nil { + return + } + + u.Host = host } } -func removeDuplicateSlashes(u *url.URL) { - if len(u.Path) > 0 { - u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/") +func defaultPortForScheme(scheme string) string { + switch scheme { + case "http": + return defaultHTTPPort + case "https": + return defaultHTTPSPort + default: + return "" } } + +// removeDuplicateSlashes collapses every run of slashes in the path to a single one, however +// long the run is: "/a//b///c" becomes "/a/b/c". +// +// A path holding no "//" is left as it is, which is the common case and costs one scan and no +// allocation. +func removeDuplicateSlashes(u *url.URL) { + const doubleSlash = "//" + + start := strings.Index(u.Path, doubleSlash) + if start < 0 { + return + } + + var collapsed strings.Builder + collapsed.Grow(len(u.Path)) + collapsed.WriteString(u.Path[:start+1]) // everything up to and including the first slash of the run + + for i := start + 1; i < len(u.Path); i++ { + c := u.Path[i] + if c == '/' && u.Path[i-1] == '/' { + continue + } + collapsed.WriteByte(c) + } + + u.Path = collapsed.String() +} diff --git a/vendor/github.com/go-openapi/loads/CONTRIBUTORS.md b/vendor/github.com/go-openapi/loads/CONTRIBUTORS.md index ff3fd3508..b13f2b8d2 100644 --- a/vendor/github.com/go-openapi/loads/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/loads/CONTRIBUTORS.md @@ -4,11 +4,11 @@ | Total Contributors | Total Contributions | | --- | --- | -| 14 | 136 | +| 14 | 139 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @fredbi | 58 | | +| @fredbi | 61 | | | @casualjim | 48 | | | @youyuanwu | 6 | | | @vburenin | 4 | | diff --git a/vendor/github.com/go-openapi/loads/README.md b/vendor/github.com/go-openapi/loads/README.md index 293f79bb6..8fa5b4bc7 100644 --- a/vendor/github.com/go-openapi/loads/README.md +++ b/vendor/github.com/go-openapi/loads/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -127,8 +127,6 @@ Maintainers can cut a new release by either: [release-badge]: https://badge.fury.io/gh/go-openapi%2Floads.svg [release-url]: https://badge.fury.io/gh/go-openapi%2Floads -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/loads -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/loads [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/loads [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/loads diff --git a/vendor/github.com/go-openapi/loads/errors.go b/vendor/github.com/go-openapi/loads/errors.go index e94f038f9..f1df4e38a 100644 --- a/vendor/github.com/go-openapi/loads/errors.go +++ b/vendor/github.com/go-openapi/loads/errors.go @@ -3,6 +3,11 @@ package loads +import ( + "errors" + "fmt" +) + type loaderError string func (e loaderError) Error() string { @@ -11,7 +16,7 @@ func (e loaderError) Error() string { const ( // ErrLoads is an error returned by the loads package. - ErrLoads loaderError = "loaderrs error" + ErrLoads loaderError = "cannot load spec" // ErrNoLoader indicates that no configured loader matched the input. ErrNoLoader loaderError = "no loader matched" @@ -20,3 +25,17 @@ const ( // to a non-public address (loopback, private, link-local, or unspecified). ErrForbiddenAddress loaderError = "blocked dial to a non-public address" ) + +// errLoads marks err as an error from this package, so callers may test it with +// [errors.Is] against [ErrLoads]. +// +// The cause is reported on a single line, after the sentinel. An error that already +// carries the sentinel is returned unchanged: loaders are chained, and reporting +// "cannot load spec" once per link in the chain would tell the caller nothing. +func errLoads(err error) error { + if err == nil || errors.Is(err, ErrLoads) { + return err + } + + return fmt.Errorf("%w: %w", ErrLoads, err) +} diff --git a/vendor/github.com/go-openapi/loads/loaders.go b/vendor/github.com/go-openapi/loads/loaders.go index ba5c48b65..dc5f22fe1 100644 --- a/vendor/github.com/go-openapi/loads/loaders.go +++ b/vendor/github.com/go-openapi/loads/loaders.go @@ -5,7 +5,6 @@ package loads import ( "encoding/json" - "errors" "net/url" "slices" @@ -162,7 +161,7 @@ func (l *loader) WithNext(next *loader) *loader { func (l *loader) Load(path string) (json.RawMessage, error) { _, erp := url.Parse(path) if erp != nil { - return nil, errors.Join(erp, ErrLoads) + return nil, errLoads(erp) } var lastErr error = ErrNoLoader // default error if no match was found @@ -180,7 +179,7 @@ func (l *loader) Load(path string) (json.RawMessage, error) { lastErr = err } - return nil, errors.Join(lastErr, ErrLoads) + return nil, errLoads(lastErr) } func (l *loader) clone() *loader { @@ -202,7 +201,7 @@ func (l *loader) clone() *loader { func JSONDoc(path string, opts ...loading.Option) (json.RawMessage, error) { data, err := loading.LoadFromFileOrHTTP(path, opts...) if err != nil { - return nil, errors.Join(err, ErrLoads) + return nil, errLoads(err) } return json.RawMessage(data), nil } diff --git a/vendor/github.com/go-openapi/loads/spec.go b/vendor/github.com/go-openapi/loads/spec.go index 40eaff2c7..ea64717cf 100644 --- a/vendor/github.com/go-openapi/loads/spec.go +++ b/vendor/github.com/go-openapi/loads/spec.go @@ -5,22 +5,16 @@ package loads import ( "bytes" - "encoding/gob" "encoding/json" - "errors" "fmt" "maps" "github.com/go-openapi/analysis" "github.com/go-openapi/spec" + "github.com/go-openapi/swag/jsonutils" "github.com/go-openapi/swag/yamlutils" ) -func init() { - gob.Register(map[string]any{}) - gob.Register([]any{}) -} - // Document represents a swagger spec document. type Document struct { // specAnalyzer @@ -110,7 +104,7 @@ func Analyzed(data json.RawMessage, version string, options ...LoaderOption) (*D version = "2.0" } if version != "2.0" { - return nil, fmt.Errorf("spec version %q is not supported: %w", version, ErrLoads) + return nil, fmt.Errorf("%w: spec version %q is not supported", ErrLoads, version) } raw, err := trimData(data) // trim blanks, then convert yaml docs into json @@ -120,12 +114,12 @@ func Analyzed(data json.RawMessage, version string, options ...LoaderOption) (*D swspec := new(spec.Swagger) if err = json.Unmarshal(raw, swspec); err != nil { - return nil, errors.Join(err, ErrLoads) + return nil, errLoads(err) } origsqspec, err := cloneSpec(swspec) if err != nil { - return nil, errors.Join(err, ErrLoads) + return nil, errLoads(err) } d := &Document{ @@ -153,12 +147,12 @@ func trimData(in json.RawMessage) (json.RawMessage, error) { // assume yaml doc: convert it to json yml, err := yamlutils.BytesToYAMLDoc(trimmed) if err != nil { - return nil, fmt.Errorf("analyzed: %w: %w", err, ErrLoads) + return nil, fmt.Errorf("analyzed: %w", errLoads(err)) } d, err := yamlutils.YAMLToJSON(yml) if err != nil { - return nil, fmt.Errorf("analyzed: %w: %w", err, ErrLoads) + return nil, fmt.Errorf("analyzed: %w", errLoads(err)) } return d, nil @@ -277,14 +271,16 @@ func (d *Document) SpecFilePath() string { return d.specFilePath } +// cloneSpec deep-copies a specification through its JSON representation. +// +// It used to go through gob, which omits a field holding the zero value for its type and +// flattens a pointer to what it points at, so an optional number that was present and zero came +// back nil: "minimum": 0, "maximum": 0, "maxLength": 0, "maxItems": 0 and "maxProperties": 0 were +// dropped from the copy, at any depth and with no error. That copy is what OrigSpec returns and +// what ResetDefinitions writes back over the live definitions. func cloneSpec(src *spec.Swagger) (*spec.Swagger, error) { - var b bytes.Buffer - if err := gob.NewEncoder(&b).Encode(src); err != nil { - return nil, err - } - var dst spec.Swagger - if err := gob.NewDecoder(&b).Decode(&dst); err != nil { + if err := jsonutils.FromDynamicJSON(src, &dst); err != nil { return nil, err } diff --git a/vendor/github.com/go-openapi/runtime/.golangci.yml b/vendor/github.com/go-openapi/runtime/.golangci.yml index affd69c88..3e917ed30 100644 --- a/vendor/github.com/go-openapi/runtime/.golangci.yml +++ b/vendor/github.com/go-openapi/runtime/.golangci.yml @@ -5,6 +5,7 @@ linters: - depguard - err113 # disabled temporarily: there are just too many issues to address - exhaustruct + - exhaustruct_v5 - funlen - gochecknoglobals - gochecknoinits diff --git a/vendor/github.com/go-openapi/runtime/CONTRIBUTORS.md b/vendor/github.com/go-openapi/runtime/CONTRIBUTORS.md index 9c959ef48..5d212799b 100644 --- a/vendor/github.com/go-openapi/runtime/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/runtime/CONTRIBUTORS.md @@ -4,21 +4,21 @@ | Total Contributors | Total Contributions | | --- | --- | -| 71 | 570 | +| 73 | 581 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 268 | | -| @fredbi | 144 | | +| @fredbi | 152 | | | @youyuanwu | 19 | | | @josephwoodward | 13 | | | @kenjones-cisco | 12 | | | @GlenDC | 7 | | -| @moenning | 6 | | | @mstoykov | 6 | | +| @moenning | 6 | | | @elakito | 6 | | +| @Copilot | 5 | | | @ifraixedes | 5 | | -| @Copilot | 4 | | | @zeitlinger | 4 | | | @jkawamoto | 3 | | | @stoyanr | 3 | | @@ -40,12 +40,13 @@ | @tschaub | 1 | | | @pytlesk4 | 1 | | | @tgraf | 1 | | +| @delthas | 1 | | | @seanprince | 1 | | | @rodriguise | 1 | | | @petrkotas | 1 | | +| @fpawel | 1 | | | @maxatome | 1 | | | @maxkarelov | 1 | | -| @tooolbox | 1 | | | @akutz | 1 | | | @yabberyabber | 1 | | | @elv-gilles | 1 | | @@ -79,5 +80,6 @@ | @KuaaMU | 1 | | | @germanhs | 1 | | | @pracucci | 1 | | +| @tooolbox | 1 | | _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_ diff --git a/vendor/github.com/go-openapi/runtime/README.md b/vendor/github.com/go-openapi/runtime/README.md index 134d930cd..270200eaa 100644 --- a/vendor/github.com/go-openapi/runtime/README.md +++ b/vendor/github.com/go-openapi/runtime/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![Doc][doc-badge]][doc-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -123,8 +123,6 @@ Maintainers can cut a new release by either: [release-badge]: https://badge.fury.io/gh/go-openapi%2Fruntime.svg [release-url]: https://badge.fury.io/gh/go-openapi%2Fruntime -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/runtime -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/runtime [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/runtime [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/runtime diff --git a/vendor/github.com/go-openapi/runtime/client/keepalive.go b/vendor/github.com/go-openapi/runtime/client/keepalive.go index 6b6097d20..da66f355d 100644 --- a/vendor/github.com/go-openapi/runtime/client/keepalive.go +++ b/vendor/github.com/go-openapi/runtime/client/keepalive.go @@ -35,6 +35,7 @@ func (k *keepAliveTransport) RoundTrip(r *http.Request) (*http.Response, error) type drainingReadCloser struct { rdr io.ReadCloser seenEOF atomic.Uint32 + discard io.Writer } func (d *drainingReadCloser) Read(p []byte) (n int, err error) { @@ -51,7 +52,11 @@ func (d *drainingReadCloser) Close() error { // If the reader side (a HTTP server) is misbehaving, it still may send // some bytes, but the closer ignores them to keep the underling // connection open. - _, _ = io.Copy(io.Discard, d.rdr) + discard := d.discard + if discard == nil { + discard = io.Discard + } + _, _ = io.Copy(discard, d.rdr) } return d.rdr.Close() } diff --git a/vendor/github.com/go-openapi/runtime/go.work b/vendor/github.com/go-openapi/runtime/go.work index 73479f9ad..5cf12c175 100644 --- a/vendor/github.com/go-openapi/runtime/go.work +++ b/vendor/github.com/go-openapi/runtime/go.work @@ -5,4 +5,4 @@ use ( ./server-middleware ) -go 1.25.0 +go 1.26.0 diff --git a/vendor/github.com/go-openapi/runtime/multipart_stream.go b/vendor/github.com/go-openapi/runtime/multipart_stream.go index 76e1bf460..78bc97559 100644 --- a/vendor/github.com/go-openapi/runtime/multipart_stream.go +++ b/vendor/github.com/go-openapi/runtime/multipart_stream.go @@ -342,6 +342,10 @@ func (s *MultipartFormStream) Drain() error { // particular, a net/http server request body may discard a limited amount of // unread data to allow connection reuse, so Close is not guaranteed to return // immediately. Call Drain when trailing form fields must be collected. +// +// Close returns the error reported by the request body, except io.EOF: a +// net/http server body reports io.EOF once it discards that unread remainder, +// which tells us the body ended, not that closing it failed. func (s *MultipartFormStream) Close() error { if s == nil || s.closed { return nil @@ -357,7 +361,14 @@ func (s *MultipartFormStream) Close() error { return nil } - return s.request.Body.Close() + // Since go1.27.0, net/http (*body).Close returns io.EOF when it discards + // the unread remainder of the request itself. Reaching the end of the body + // is not a close failure. + if err := s.request.Body.Close(); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil } func supportsMultipartFormStream(method string) bool { diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/mediatype.go b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/mediatype.go index 2138b8266..41a32a160 100644 --- a/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/mediatype.go +++ b/vendor/github.com/go-openapi/runtime/server-middleware/mediatype/mediatype.go @@ -197,18 +197,14 @@ func Parse(s string) (MediaType, error) { if plus := strings.LastIndexByte(mt.Subtype, '+'); plus >= 0 && plus < len(mt.Subtype)-1 { mt.Suffix = mt.Subtype[plus+1:] } + if q, ok := params["q"]; ok { - if qf, perr := strconv.ParseFloat(q, 64); perr == nil { - if qf < 0 { - qf = 0 - } - if qf > 1 { - qf = 1 - } + if qf, isFloat := boundedQ(q); isFloat { mt.Q = qf } delete(params, "q") } + if len(params) > 0 { mt.Params = params } @@ -267,6 +263,23 @@ func (m MediaType) Specificity() int { return SpecificityExactWithParams } +func boundedQ(q string) (float64, bool) { + qf, err := strconv.ParseFloat(q, 64) + if err != nil { + return 0, false + } + + if qf < 0 { + qf = 0 + } + + if qf > 1 { + qf = 1 + } + + return qf, true +} + // typeAgrees reports whether two top-level types match, allowing "*" on // either side. A type of "*" without a "*" subtype is rejected per RFC // 7231 §5.3.2 ("*/sub" is not valid), but Parse never produces such a diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/header/header.go b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/header/header.go index 6ce870d89..6f3c3f003 100644 --- a/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/header/header.go +++ b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/header/header.go @@ -300,7 +300,13 @@ func expectQuality(s string) (q float64, rest string) { n = n*10 + int(b) - '0' d *= 10 } - return q + float64(n)/float64(d), s[i:] + result := q + float64(n)/float64(d) + // RFC 7231 §5.3.1: qvalue is in [0, 1]. Inputs like "1.1" + // would otherwise yield > 1; reject as malformed. + if result > 1 { + return -1, s[i:] + } + return result, s[i:] } func expectTokenOrQuoted(s string) (value string, rest string) { diff --git a/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/negotiate.go b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/negotiate.go index c36ad5ada..3c932a196 100644 --- a/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/negotiate.go +++ b/vendor/github.com/go-openapi/runtime/server-middleware/negotiate/negotiate.go @@ -89,6 +89,16 @@ func WithMatchSuffix(enable bool) Option { // // Encoding tokens have no parameters, so this function is unaffected by // the v0.30 parameter-honouring change to [ContentType]. +// +// Deprecated: ContentEncoding negotiation is not used by the components +// of this project. +// +// This historical addition has never been associated with proper +// compression middleware and is thus half a feature. +// The runtime does not ship compression. +// Use github.com/CAFxX/httpcompression or github.com/klauspost/compress/gzhttp +// at the http.Handler level, or github.com/klauspost/compress/* for client +// transport wrapping. See docs/examples/middleware for a recipe. func ContentEncoding(r *http.Request, offers []string) string { bestOffer := "identity" bestQ := -1.0 diff --git a/vendor/github.com/go-openapi/spec/.golangci.yml b/vendor/github.com/go-openapi/spec/.golangci.yml index 9d2733176..3f3b5af8d 100644 --- a/vendor/github.com/go-openapi/spec/.golangci.yml +++ b/vendor/github.com/go-openapi/spec/.golangci.yml @@ -9,6 +9,7 @@ linters: - gomodguard - gomodguard_v2 - exhaustruct + - exhaustruct_v5 - nlreturn - nonamedreturns - noinlineerr diff --git a/vendor/github.com/go-openapi/spec/CONTRIBUTORS.md b/vendor/github.com/go-openapi/spec/CONTRIBUTORS.md index 12fd069b0..3e1620230 100644 --- a/vendor/github.com/go-openapi/spec/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/spec/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 38 | 403 | +| 39 | 439 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 191 | | -| @fredbi | 101 | | +| @fredbi | 136 | | | @pytlesk4 | 26 | | | @kul-amr | 10 | | | @keramix | 10 | | @@ -46,5 +46,6 @@ | @sttts | 1 | | | @ChandanChainani | 1 | | | @bvwells | 1 | | +| @amoudani | 1 | | _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_ diff --git a/vendor/github.com/go-openapi/spec/README.md b/vendor/github.com/go-openapi/spec/README.md index 7c96eb9a5..9188f8308 100644 --- a/vendor/github.com/go-openapi/spec/README.md +++ b/vendor/github.com/go-openapi/spec/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -120,8 +120,6 @@ Maintainers can cut a new release by either: [gomod-badge]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fspec.svg [gomod-url]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fspec -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/spec -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/spec [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/spec [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/spec diff --git a/vendor/github.com/go-openapi/spec/expander.go b/vendor/github.com/go-openapi/spec/expander.go index 00eb5b53a..2922fccb5 100644 --- a/vendor/github.com/go-openapi/spec/expander.go +++ b/vendor/github.com/go-openapi/spec/expander.go @@ -4,8 +4,12 @@ package spec import ( + "cmp" "encoding/json" "fmt" + "iter" + "maps" + "slices" "github.com/go-openapi/swag/loading" ) @@ -109,7 +113,8 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error { specBasePath := options.RelativeBase if !options.SkipSchemas { - for key, definition := range spec.Definitions { + for key := range sortedKeys(spec.Definitions) { + definition := spec.Definitions[key] parentRefs := make([]string, 0, smallPrealloc) parentRefs = append(parentRefs, "#/definitions/"+key) @@ -123,7 +128,7 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error { } } - for key := range spec.Parameters { + for key := range sortedKeys(spec.Parameters) { parameter := spec.Parameters[key] if err := expandParameterOrResponse(¶meter, resolver, specBasePath); resolver.shouldStopOnError(err) { return err @@ -131,7 +136,7 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error { spec.Parameters[key] = parameter } - for key := range spec.Responses { + for key := range sortedKeys(spec.Responses) { response := spec.Responses[key] if err := expandParameterOrResponse(&response, resolver, specBasePath); resolver.shouldStopOnError(err) { return err @@ -140,7 +145,7 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error { } if spec.Paths != nil { - for key := range spec.Paths.Paths { + for key := range sortedKeys(spec.Paths.Paths) { pth := spec.Paths.Paths[key] if err := expandPathItem(&pth, resolver, specBasePath); resolver.shouldStopOnError(err) { return err @@ -278,6 +283,38 @@ func expandItems(target Schema, parentRefs []string, resolver *schemaLoader, bas return &target, nil } +// sortedKeys walks the keys of a map in a fixed order. +// +// Expansion inlines the first branch that reaches a cycle and leaves a $ref on the others, so +// the order the walk visits siblings in decides which node ends up holding the $ref. Ranging a +// map straight gives that decision to Go's map iteration, and the same document then expands +// differently from one run to the next - see go-openapi/spec#93. +// +// A map of fewer than two keys has only one order, so it is yielded without sorting: schemata +// with a single property or definition are most of what a walk of a large document visits, and +// the slice this would otherwise allocate is paid at every node. +func sortedKeys[K cmp.Ordered, V any](m map[K]V) iter.Seq[K] { + const alreadyOrdered = 2 // a map of fewer keys than this has only one order + + return func(yield func(K) bool) { + if len(m) < alreadyOrdered { + for key := range m { + yield(key) + + return + } + + return + } + + for _, key := range slices.Sorted(maps.Keys(m)) { + if !yield(key) { + return + } + } + } +} + //nolint:gocognit,gocyclo,cyclop // complex but well-tested $ref expansion logic; refactoring deferred to dedicated PR func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { if err := resolver.context.countNode(); err != nil { @@ -312,7 +349,9 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba return &target, nil } - for k := range target.Definitions { + rebaseExtraRefs(target.ExtraProps, resolver, basePath) + + for k := range sortedKeys(target.Definitions) { tt, err := expandSchema(target.Definitions[k], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err @@ -370,7 +409,7 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba } } - for k := range target.Properties { + for k := range sortedKeys(target.Properties) { t, err := expandSchema(target.Properties[k], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err @@ -390,7 +429,7 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba } } - for k := range target.PatternProperties { + for k := range sortedKeys(target.PatternProperties) { t, err := expandSchema(target.PatternProperties[k], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err @@ -400,7 +439,7 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba } } - for k := range target.Dependencies { + for k := range sortedKeys(target.Dependencies) { if target.Dependencies[k].Schema != nil { t, err := expandSchema(*target.Dependencies[k].Schema, parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { @@ -424,6 +463,67 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba return &target, nil } +// rebaseExtraRefs rewrites the $ref held by keywords this model does not map, so that +// they still point at their target once the schema is inlined into another document. +// +// expandSchema walks the fields of [Schema] and stops there. A keyword the Swagger 2.0 +// model predates - propertyNames, contains, if/then/else, $defs - lands in ExtraProps as +// raw JSON, and a $ref inside it is copied into the root verbatim: "#/definitions/leaf" +// then names a definition of the root document instead of the one it came from. +// +// Rebasing makes the pointer correct. It does not expand it, and it does not make the +// expanded document self-contained: a $ref that came from another document keeps pointing +// there. +func rebaseExtraRefs(extra map[string]any, resolver *schemaLoader, basePath string) { + for key := range extra { + rebaseRawRefs(extra[key], resolver, basePath) + } +} + +// rebaseRawRefs walks raw JSON and rebases every "$ref" string value it finds. +func rebaseRawRefs(node any, resolver *schemaLoader, basePath string) { + switch value := node.(type) { + case map[string]any: + for key := range value { + if key == jsonRef { + if ref, ok := value[key].(string); ok { + if rebased, ok := rebaseRawRef(ref, resolver, basePath); ok { + value[key] = rebased + } + + continue + } + } + + rebaseRawRefs(value[key], resolver, basePath) + } + case []any: + for i := range value { + rebaseRawRefs(value[i], resolver, basePath) + } + } +} + +// rebaseRawRef resolves a $ref against basePath, then spells it relative to the document +// being expanded, like the SkipSchemas branch of [expandSchema] does for a mapped $ref. +// +// It reports false when the $ref is empty or does not parse: an unmapped keyword may hold +// any JSON, and a string under a "$ref" key is not necessarily a reference. +func rebaseRawRef(ref string, resolver *schemaLoader, basePath string) (string, bool) { + if ref == "" { + return "", false + } + + rebased, err := NewRef(normalizeURI(ref, basePath)) + if err != nil { + return "", false + } + + denormalized := denormalizeRef(&rebased, resolver.context.basePath, resolver.context.rootID) + + return denormalized.String(), true +} + func expandSchemaRef(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { // if a Ref is found, all sibling fields are skipped // Ref also changes the resolution scope of children expandSchema @@ -483,7 +583,7 @@ func expandPathItem(pathItem *PathItem, resolver *schemaLoader, basePath string) pathItem.Ref = Ref{} for i := range pathItem.Parameters { - if err := expandParameterOrResponse(&(pathItem.Parameters[i]), resolver, basePath); resolver.shouldStopOnError(err) { + if err := expandParameterOrResponse(&pathItem.Parameters[i], resolver, basePath); resolver.shouldStopOnError(err) { return err } } @@ -528,7 +628,7 @@ func expandOperation(op *Operation, resolver *schemaLoader, basePath string) err return err } - for code := range responses.StatusCodeResponses { + for code := range sortedKeys(responses.StatusCodeResponses) { response := responses.StatusCodeResponses[code] if err := expandParameterOrResponse(&response, resolver, basePath); resolver.shouldStopOnError(err) { return err diff --git a/vendor/github.com/go-openapi/spec/gob.go b/vendor/github.com/go-openapi/spec/gob.go new file mode 100644 index 000000000..dad749229 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/gob.go @@ -0,0 +1,230 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package spec + +import ( + "bytes" + "encoding/gob" +) + +// Optional numbers and gob. +// +// gob omits any struct field that holds the zero value for its type, and flattens a pointer to +// the value it points at. An optional number that is present and zero - "minimum": 0, which the +// JSON Schema meta-schema spells for every positiveInteger, or "maximum": 0 on a parameter - +// therefore travels as the zero value, is omitted, and comes back as a nil pointer. The bound is +// dropped and nothing reports it. +// +// [Schema], [Parameter], [Header] and [Items] are the types that carry those numbers, so each +// sends which of them were present-and-zero alongside the struct, and puts the zero back on the +// way in. The encoders sit on the outer types rather than on CommonValidations or SchemaProps +// because a method on an embedded type is promoted to the type embedding it: gob would then call +// it for the whole value and drop everything the embedded type does not hold. [Swagger] and +// [Operation] already carry their own encoders for the same reason. + +// zeroBounds records which optional numbers of a value were present and zero. +type zeroBounds uint16 + +const ( + zeroMaximum zeroBounds = 1 << iota + zeroMinimum + zeroMaxLength + zeroMinLength + zeroMaxItems + zeroMinItems + zeroMultipleOf + zeroMaxProperties + zeroMinProperties +) + +func floatBound(value *float64, bit zeroBounds) zeroBounds { + if value != nil && *value == 0 { + return bit + } + + return 0 +} + +func intBound(value *int64, bit zeroBounds) zeroBounds { + if value != nil && *value == 0 { + return bit + } + + return 0 +} + +func restoreFloat(value **float64, bounds, bit zeroBounds) { + if bounds&bit != 0 && *value == nil { + *value = new(float64) + } +} + +func restoreInt(value **int64, bounds, bit zeroBounds) { + if bounds&bit != 0 && *value == nil { + *value = new(int64) + } +} + +func commonBounds(v CommonValidations) zeroBounds { + return floatBound(v.Maximum, zeroMaximum) | + floatBound(v.Minimum, zeroMinimum) | + floatBound(v.MultipleOf, zeroMultipleOf) | + intBound(v.MaxLength, zeroMaxLength) | + intBound(v.MinLength, zeroMinLength) | + intBound(v.MaxItems, zeroMaxItems) | + intBound(v.MinItems, zeroMinItems) +} + +func restoreCommon(v *CommonValidations, bounds zeroBounds) { + restoreFloat(&v.Maximum, bounds, zeroMaximum) + restoreFloat(&v.Minimum, bounds, zeroMinimum) + restoreFloat(&v.MultipleOf, bounds, zeroMultipleOf) + restoreInt(&v.MaxLength, bounds, zeroMaxLength) + restoreInt(&v.MinLength, bounds, zeroMinLength) + restoreInt(&v.MaxItems, bounds, zeroMaxItems) + restoreInt(&v.MinItems, bounds, zeroMinItems) +} + +// GobEncode provides a gob encoder for Schema that keeps its zero-valued bounds. +func (s Schema) GobEncode() ([]byte, error) { + type plain Schema + + p := s.SchemaProps + bounds := floatBound(p.Maximum, zeroMaximum) | + floatBound(p.Minimum, zeroMinimum) | + floatBound(p.MultipleOf, zeroMultipleOf) | + intBound(p.MaxLength, zeroMaxLength) | + intBound(p.MinLength, zeroMinLength) | + intBound(p.MaxItems, zeroMaxItems) | + intBound(p.MinItems, zeroMinItems) | + intBound(p.MaxProperties, zeroMaxProperties) | + intBound(p.MinProperties, zeroMinProperties) + + var b bytes.Buffer + err := gob.NewEncoder(&b).Encode(struct { + Plain plain + Bounds zeroBounds + }{Plain: plain(s), Bounds: bounds}) + + return b.Bytes(), err +} + +// GobDecode provides a gob decoder for Schema that keeps its zero-valued bounds. +func (s *Schema) GobDecode(b []byte) error { + type plain Schema + + var raw struct { + Plain plain + Bounds zeroBounds + } + if err := gob.NewDecoder(bytes.NewBuffer(b)).Decode(&raw); err != nil { + return err + } + + *s = Schema(raw.Plain) + restoreFloat(&s.Maximum, raw.Bounds, zeroMaximum) + restoreFloat(&s.Minimum, raw.Bounds, zeroMinimum) + restoreFloat(&s.MultipleOf, raw.Bounds, zeroMultipleOf) + restoreInt(&s.MaxLength, raw.Bounds, zeroMaxLength) + restoreInt(&s.MinLength, raw.Bounds, zeroMinLength) + restoreInt(&s.MaxItems, raw.Bounds, zeroMaxItems) + restoreInt(&s.MinItems, raw.Bounds, zeroMinItems) + restoreInt(&s.MaxProperties, raw.Bounds, zeroMaxProperties) + restoreInt(&s.MinProperties, raw.Bounds, zeroMinProperties) + + return nil +} + +// GobEncode provides a gob encoder for Parameter that keeps its zero-valued bounds. +func (p Parameter) GobEncode() ([]byte, error) { + type plain Parameter + + var b bytes.Buffer + err := gob.NewEncoder(&b).Encode(struct { + Plain plain + Bounds zeroBounds + }{Plain: plain(p), Bounds: commonBounds(p.CommonValidations)}) + + return b.Bytes(), err +} + +// GobDecode provides a gob decoder for Parameter that keeps its zero-valued bounds. +func (p *Parameter) GobDecode(b []byte) error { + type plain Parameter + + var raw struct { + Plain plain + Bounds zeroBounds + } + if err := gob.NewDecoder(bytes.NewBuffer(b)).Decode(&raw); err != nil { + return err + } + + *p = Parameter(raw.Plain) + restoreCommon(&p.CommonValidations, raw.Bounds) + + return nil +} + +// GobEncode provides a gob encoder for Header that keeps its zero-valued bounds. +func (h Header) GobEncode() ([]byte, error) { + type plain Header + + var b bytes.Buffer + err := gob.NewEncoder(&b).Encode(struct { + Plain plain + Bounds zeroBounds + }{Plain: plain(h), Bounds: commonBounds(h.CommonValidations)}) + + return b.Bytes(), err +} + +// GobDecode provides a gob decoder for Header that keeps its zero-valued bounds. +func (h *Header) GobDecode(b []byte) error { + type plain Header + + var raw struct { + Plain plain + Bounds zeroBounds + } + if err := gob.NewDecoder(bytes.NewBuffer(b)).Decode(&raw); err != nil { + return err + } + + *h = Header(raw.Plain) + restoreCommon(&h.CommonValidations, raw.Bounds) + + return nil +} + +// GobEncode provides a gob encoder for Items that keeps its zero-valued bounds. +func (i Items) GobEncode() ([]byte, error) { + type plain Items + + var b bytes.Buffer + err := gob.NewEncoder(&b).Encode(struct { + Plain plain + Bounds zeroBounds + }{Plain: plain(i), Bounds: commonBounds(i.CommonValidations)}) + + return b.Bytes(), err +} + +// GobDecode provides a gob decoder for Items that keeps its zero-valued bounds. +func (i *Items) GobDecode(b []byte) error { + type plain Items + + var raw struct { + Plain plain + Bounds zeroBounds + } + if err := gob.NewDecoder(bytes.NewBuffer(b)).Decode(&raw); err != nil { + return err + } + + *i = Items(raw.Plain) + restoreCommon(&i.CommonValidations, raw.Bounds) + + return nil +} diff --git a/vendor/github.com/go-openapi/spec/normalizer.go b/vendor/github.com/go-openapi/spec/normalizer.go index 68252dc30..ced7f9935 100644 --- a/vendor/github.com/go-openapi/spec/normalizer.go +++ b/vendor/github.com/go-openapi/spec/normalizer.go @@ -41,10 +41,11 @@ func normalizeURI(refPath, base string) string { if refURL.Path == "." { refURL.Path = "" } + forgetSpelling(refURL) r := MustCreateRef(refURL.String()) if r.IsCanonical() { - return refURL.String() + return r.String() } baseURL, _ := parseURL(base) @@ -56,6 +57,14 @@ func normalizeURI(refPath, base string) string { // copying fragment from ref to base baseURL.Fragment = refURL.Fragment + if baseURL.Scheme != "" && baseURL.Path != "" && !path.IsAbs(baseURL.Path) { + // a base that carries no path of its own (e.g. "smb://host") leaves the join relative. + // Anchor it, because a relative path under a scheme does not survive rendering: it is + // either promoted to a host component, which is not even guaranteed to be a legal one + // ("a://some file.json" no longer parses), or read back as absolute anyway. + baseURL.Path = path.Join("/", baseURL.Path) + } + return baseURL.String() } @@ -82,23 +91,45 @@ func denormalizeRef(ref *Ref, originalRelativeBase, id string) Ref { } if id != "" { - idBaseURL, err := parseURL(id) - if err == nil { // if the schema id is not usable as a URI, ignore it - if ref, ok := rebase(ref, idBaseURL, true); ok { // rebase, but keep references to root unchanged (do not want $ref: "") + if _, err := parseURL(id); err == nil { // if the schema id is not usable as a URI, ignore it + // rebase, but keep references to root unchanged (do not want $ref: "") + if ref, ok := rebase(ref, canonicalURL(id), true); ok { // $ref relative to the ID of the schema in the root document return ref } } } - originalRelativeBaseURL, _ := parseURL(originalRelativeBase) - - r, _ := rebase(ref, originalRelativeBaseURL, false) + r, _ := rebase(ref, canonicalURL(originalRelativeBase), false) return r } -func rebase(ref *Ref, v *url.URL, notEqual bool) (Ref, bool) { +// canonicalURL parses a URI the way a Ref does, so that rebase compares authorities that are +// spelled alike. +// +// Turning a URI into a Ref lower-cases the host and drops a default port, whereas the normalizer +// keeps the spelling it was handed: comparing the two spellings directly makes a $ref look like +// it belongs to another host, and leaves it absolute when it should have been rebased. +func canonicalURL(in string) *url.URL { + if ref, err := NewRef(in); err == nil { + return ref.GetURL() + } + + if u, err := parseURL(in); err == nil { + return u + } + + return &url.URL{} +} + +// rebase expresses a $ref relative to v, which is either the URI of the base document or +// the "id" that anchors the root schema. +// +// The two differ in what v stands for. An "id" anchors a namespace, so a $ref below it is +// expressed relative to the id itself. A base is a document, so a $ref is expressed relative +// to the folder that holds it, and only a $ref to that very document collapses to an empty $ref. +func rebase(ref *Ref, v *url.URL, isID bool) (Ref, bool) { var newBase url.URL u := ref.GetURL() @@ -118,26 +149,78 @@ func rebase(ref *Ref, v *url.URL, notEqual bool) (Ref, bool) { newBase.Fragment = u.Fragment - if after, ok := strings.CutPrefix(u.Path, docPath); ok { - newBase.Path = after - } else { - newBase.Path = strings.TrimPrefix(u.Path, v.Path) - } + switch { + case isID: + if after, ok := cutPathPrefix(u.Path, docPath); ok { + newBase.Path = after + } else { + newBase.Path = strings.TrimPrefix(u.Path, v.Path) + } - if notEqual && newBase.Path == "" && newBase.Fragment == "" { - // do not want rebasing to end up in an empty $ref - return *ref, false + if newBase.Path == "" && newBase.Fragment == "" { + // do not want rebasing to end up in an empty $ref + return *ref, false + } + + case u.Path == docPath: + // the $ref points to the base document itself + newBase.Path = "" + + default: + newBase.Path = strings.TrimPrefix(u.Path, v.Path) + + if newBase.Path == "" { + // the $ref points to the folder that holds the base, not to a document: + // a $ref with no path of its own would denote the base document instead + return *ref, false + } } if path.IsAbs(newBase.Path) { - // whenever we end up with an absolute path, specify the scheme and host + // whenever we end up with an absolute path, we render a whole URI newBase.Scheme = v.Scheme newBase.Host = v.Host + newBase.User = u.User + newBase.RawQuery = u.RawQuery + newBase.ForceQuery = u.ForceQuery + } else if u.RawQuery != v.RawQuery || u.ForceQuery != v.ForceQuery || !sameUserinfo(u.User, v.User) { + // a relative $ref carries neither credentials nor query of its own: normalizing one + // applies those of the base. Leave the $ref absolute rather than have it resolve + // against a different query or different credentials. + return *ref, false } return MustCreateRef(newBase.String()), true } +// sameUserinfo compares the userinfo components of two URIs. +// +// An absent userinfo differs from an empty one: "file:///x" and "file://@/x" do not render alike. +func sameUserinfo(a, b *url.Userinfo) bool { + if a == nil || b == nil { + return a == b + } + + return a.String() == b.String() +} + +// cutPathPrefix is strings.CutPrefix, cutting on path separators only. +// +// "/base/spec.json" is a prefix of "/base/spec.json/x" but not of "/base/spec.json.orig": +// cutting the latter would leave ".orig" to be rebased against the wrong folder. +func cutPathPrefix(pth, prefix string) (string, bool) { + after, ok := strings.CutPrefix(pth, prefix) + if !ok { + return "", false + } + + if after == "" || strings.HasPrefix(after, "/") || strings.HasSuffix(prefix, "/") { + return after, true + } + + return "", false +} + // normalizeRef canonicalize a Ref, using a canonical relativeBase as its absolute anchor. func normalizeRef(ref *Ref, relativeBase string) *Ref { r := MustCreateRef(normalizeURI(ref.String(), relativeBase)) @@ -170,11 +253,12 @@ func normalizeBase(in string) string { if u.Path == "." { // empty after Clean() u.Path = "" } + forgetSpelling(u) if u.Scheme != "" { if path.IsAbs(u.Path) || u.Scheme != fileScheme { // this is absolute or explicitly not a local file: we're good - return u.String() + return canonicalString(u) } } @@ -187,5 +271,41 @@ func normalizeBase(in string) string { u.Scheme = fileScheme u.Path = absPath(u.Path) // platform-dependent u.RawQuery = "" // any query component is irrelevant for a base - return u.String() + return canonicalString(u) +} + +// forgetSpelling drops the escaped spelling url.Parse recorded, so that rendering the URL +// derives it from Path and Fragment again. +// +// url.URL.String returns RawPath whenever it still decodes to Path, and the normalizer rewrites +// Path - path.Clean, then a join onto the base. A RawPath describing the path as it was written +// no longer describes the path we now hold, and rendering it can produce a URI that does not +// parse: normalizeBase("%2F") used to return "file://%2F", where the escaped form lost the +// leading slash that Path carries and what is left reads as an authority. +func forgetSpelling(u *url.URL) { + u.RawPath = "" + u.RawFragment = "" +} + +// canonicalString renders a URL the way jsonreference does. +// +// The normalizer and jsonreference each canonicalize a URI, and they used to disagree: the +// normalizer kept the spelling it was handed while a Ref lower-cases the host, drops a default +// port and re-escapes path and fragment. Everything the expander stores - cache keys, the +// parentRefs chain, a $ref written back into the document - goes through both, so the two must +// agree or one document splits into two spellings of itself. +// +// A URI that jsonreference cannot parse is returned as it stands, rather than panicking through +// MustCreateRef. Such a URI is a defect in the normalizer, and the fuzz target reports it as one. +func canonicalString(u *url.URL) string { + rendered := u.String() + + r, err := NewRef(rendered) + if err != nil { + specLogger.Printf("warning: the normalizer produced an unparseable URI %q: %v", rendered, err) + + return rendered + } + + return r.String() } diff --git a/vendor/github.com/go-openapi/spec/normalizer_windows.go b/vendor/github.com/go-openapi/spec/normalizer_windows.go index 61515c9a1..a439f432a 100644 --- a/vendor/github.com/go-openapi/spec/normalizer_windows.go +++ b/vendor/github.com/go-openapi/spec/normalizer_windows.go @@ -1,4 +1,4 @@ -// -build windows +//go:build windows // SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers // SPDX-License-Identifier: Apache-2.0 diff --git a/vendor/github.com/go-openapi/spec/swagger.go b/vendor/github.com/go-openapi/spec/swagger.go index dbe32db8a..61a278e2d 100644 --- a/vendor/github.com/go-openapi/spec/swagger.go +++ b/vendor/github.com/go-openapi/spec/swagger.go @@ -403,7 +403,9 @@ func (s *SchemaOrArray) ContainsType(name string) bool { // MarshalJSON converts this schema object or array into JSON structure. func (s SchemaOrArray) MarshalJSON() ([]byte, error) { - if len(s.Schemas) > 0 { + if s.Schemas != nil { + // an empty array is still the array form: marshalling it as the single form + // would yield "null", which is not a schema return json.Marshal(s.Schemas) } return json.Marshal(s.Schema) diff --git a/vendor/github.com/go-openapi/strfmt/.golangci.yml b/vendor/github.com/go-openapi/strfmt/.golangci.yml index 31480c713..ce7a6ae47 100644 --- a/vendor/github.com/go-openapi/strfmt/.golangci.yml +++ b/vendor/github.com/go-openapi/strfmt/.golangci.yml @@ -10,6 +10,7 @@ linters: - gomodguard_v2 - godox - exhaustruct + - exhaustruct_v5 - nlreturn - nonamedreturns - noinlineerr diff --git a/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md b/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md index fa17ff311..72a176c76 100644 --- a/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/strfmt/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 41 | 243 | +| 41 | 254 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 88 | | -| @fredbi | 74 | | +| @fredbi | 85 | | | @youyuanwu | 13 | | | @jlambatl | 9 | | | @GlenDC | 5 | | diff --git a/vendor/github.com/go-openapi/strfmt/README.md b/vendor/github.com/go-openapi/strfmt/README.md index 15ee0e582..939fba7d2 100644 --- a/vendor/github.com/go-openapi/strfmt/README.md +++ b/vendor/github.com/go-openapi/strfmt/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -213,8 +213,6 @@ Maintainers can cut a new release by either: [gomod-badge]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fstrfmt.svg [gomod-url]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fstrfmt -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/strfmt -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/strfmt [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/strfmt [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/strfmt diff --git a/vendor/github.com/go-openapi/strfmt/default.go b/vendor/github.com/go-openapi/strfmt/default.go index bcc57e6fa..9168d053c 100644 --- a/vendor/github.com/go-openapi/strfmt/default.go +++ b/vendor/github.com/go-openapi/strfmt/default.go @@ -119,6 +119,7 @@ func IsHostname(str string) bool { } // IDNA check + str, _ = strings.CutSuffix(str, ".") // tolerates trailing ".", whereas IDNA ValidateLabel rule does not res, err := idnaHostChecker.ToASCII(strings.ToLower(str)) if err != nil || res == "" { return false @@ -1976,7 +1977,7 @@ func isISBN(str string, version int) bool { for i = range isbnVersion13 - 1 { checksum += factor[i%2] * int32(sanitized[i]-'0') } - return (int32(sanitized[isbnVersion13-1]-'0'))-((decimalBase-(checksum%decimalBase))%decimalBase) == 0 + return int32(sanitized[isbnVersion13-1]-'0')-((decimalBase-(checksum%decimalBase))%decimalBase) == 0 default: return isISBN(str, isbnVersion10) || isISBN(str, isbnVersion13) } diff --git a/vendor/github.com/go-openapi/strfmt/format.go b/vendor/github.com/go-openapi/strfmt/format.go index 09c375425..7ec785661 100644 --- a/vendor/github.com/go-openapi/strfmt/format.go +++ b/vendor/github.com/go-openapi/strfmt/format.go @@ -122,7 +122,7 @@ func (f *defaultFormats) Add(name string, strfmt Format, validator Validator) bo nme := f.normalizeName(name) tpe := reflect.TypeOf(strfmt) - if tpe.Kind() == reflect.Ptr { + if tpe.Kind() == reflect.Pointer { tpe = tpe.Elem() } @@ -176,7 +176,7 @@ func (f *defaultFormats) DelByFormat(strfmt Format) bool { defer f.Unlock() tpe := reflect.TypeOf(strfmt) - if tpe.Kind() == reflect.Ptr { + if tpe.Kind() == reflect.Pointer { tpe = tpe.Elem() } @@ -208,7 +208,7 @@ func (f *defaultFormats) ContainsFormat(strfmt Format) bool { f.Lock() defer f.Unlock() tpe := reflect.TypeOf(strfmt) - if tpe.Kind() == reflect.Ptr { + if tpe.Kind() == reflect.Pointer { tpe = tpe.Elem() } diff --git a/vendor/github.com/go-openapi/strfmt/go.work b/vendor/github.com/go-openapi/strfmt/go.work index f233e74cf..432c541d6 100644 --- a/vendor/github.com/go-openapi/strfmt/go.work +++ b/vendor/github.com/go-openapi/strfmt/go.work @@ -4,4 +4,4 @@ use ( ./internal/testintegration ) -go 1.25.0 +go 1.26.0 diff --git a/vendor/github.com/go-openapi/swag/.golangci.yml b/vendor/github.com/go-openapi/swag/.golangci.yml index 099c0a78c..e0932d0a6 100644 --- a/vendor/github.com/go-openapi/swag/.golangci.yml +++ b/vendor/github.com/go-openapi/swag/.golangci.yml @@ -7,6 +7,7 @@ linters: - errchkjson - errorlint - exhaustruct + - exhaustruct_v5 - forcetypeassert - funlen - gochecknoglobals @@ -48,7 +49,7 @@ linters: min-len: 2 min-occurrences: 3 gocyclo: - min-complexity: 45 + min-complexity: 25 exclusions: generated: lax presets: diff --git a/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md b/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md index 0f0711cd5..1ff92bc1c 100644 --- a/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/swag/CONTRIBUTORS.md @@ -4,11 +4,11 @@ | Total Contributors | Total Contributions | | --- | --- | -| 24 | 251 | +| 24 | 272 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @fredbi | 121 | | +| @fredbi | 142 | | | @casualjim | 98 | | | @alexandear | 4 | | | @orisano | 3 | | diff --git a/vendor/github.com/go-openapi/swag/README.md b/vendor/github.com/go-openapi/swag/README.md index c6c2d21e9..f56801e43 100644 --- a/vendor/github.com/go-openapi/swag/README.md +++ b/vendor/github.com/go-openapi/swag/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -197,8 +197,6 @@ Maintainers can cut a new release by either: [gomod-badge]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fswag.svg [gomod-url]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fswag -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/swag -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/swag [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/swag [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/swag diff --git a/vendor/github.com/go-openapi/swag/fileutils/doc.go b/vendor/github.com/go-openapi/swag/fileutils/doc.go index 859a200d8..d5ca57b96 100644 --- a/vendor/github.com/go-openapi/swag/fileutils/doc.go +++ b/vendor/github.com/go-openapi/swag/fileutils/doc.go @@ -3,8 +3,14 @@ // Package fileutils exposes utilities to deal with files and paths. // -// Currently, there is: -// - [File] to represent an abstraction of an uploaded file. -// For instance, this is used by [github.com/go-openapi/runtime.File]. -// - path search utilities (e.g. finding packages in the GO search path) +// It provides: +// +// - [File], an abstraction of an uploaded file. +// It is used by [github.com/go-openapi/runtime.File]. +// - Implementations of [fs.FS]: [OsFS] and [GlobOsFS] wrap the os package, +// [MapFS] serves files held in memory, [OverlayFS] stacks file systems on top of one another, +// [OpaqueFS] lets a layer claim a directory for itself, and [FileReaderFS] adds a ReadFile +// method to any [fs.FS]. +// - [MustSub], to re-root a file system inline when the directory is a constant of the program. +// - path search utilities, to locate a package in the go search path. package fileutils diff --git a/vendor/github.com/go-openapi/swag/fileutils/file.go b/vendor/github.com/go-openapi/swag/fileutils/file.go index 5ad4cfaea..a5ff03c75 100644 --- a/vendor/github.com/go-openapi/swag/fileutils/file.go +++ b/vendor/github.com/go-openapi/swag/fileutils/file.go @@ -6,17 +6,22 @@ package fileutils import "mime/multipart" // File represents an uploaded file. +// +// Data holds the payload, and Header the multipart metadata. +// File implements [io.ReadCloser] by delegating both methods to Data. +// +// The zero File is not usable: [File.Read] and [File.Close] both panic when Data is nil. type File struct { Data multipart.File Header *multipart.FileHeader } -// Read bytes from the file +// Read reads bytes from the payload. func (f *File) Read(p []byte) (n int, err error) { return f.Data.Read(p) } -// Close the file +// Close closes the payload. func (f *File) Close() error { return f.Data.Close() } diff --git a/vendor/github.com/go-openapi/swag/fileutils/fs.go b/vendor/github.com/go-openapi/swag/fileutils/fs.go new file mode 100644 index 000000000..56b0a1f53 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/fileutils/fs.go @@ -0,0 +1,106 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package fileutils + +import ( + "fmt" + "io/fs" + "os" +) + +// OsFS exposes package os features as an [fs.FS], without having to use [os.Root]. +// +// Existing alternatives from the standard library are [os.DirFS], which requires a base directory, +// and [os.Root.FS], which requires a root. +// [OsFS] is intended to be used when none of these alternatives are workable, +// that is when the caller does not know which root it should run in. +// +// Names are passed to the os package unchanged, +// so [OsFS] accepts absolute and relative paths, which a conforming [fs.FS] rejects. +// It offers no containment: every file that the process may read is reachable. +// +// [OsFS] implements [fs.FS], [fs.ReadFileFS] and [fs.ReadDirFS]. +type OsFS struct { +} + +// NewReadOnlyOsFS builds an [OsFS], a read-only view of the os file system. +func NewReadOnlyOsFS() *OsFS { + return &OsFS{} +} + +// Open opens the named file for reading. +func (f *OsFS) Open(name string) (fs.File, error) { + return os.Open(name) +} + +// ReadFile reads the named file and returns its content. +func (f *OsFS) ReadFile(name string) ([]byte, error) { + return os.ReadFile(name) +} + +// ReadDir reads the named directory and returns its entries sorted by file name. +func (f *OsFS) ReadDir(name string) ([]fs.DirEntry, error) { + return os.ReadDir(name) +} + +// FileReaderFS makes a [fs.FS] into a [fs.ReadFileFS], with a [FileReaderFS.ReadFile] method. +type FileReaderFS struct { + fs.FS +} + +// NewFileReaderFS transforms a [fs.FS] into a [fs.ReadFileFS]. +func NewFileReaderFS(base fs.FS) *FileReaderFS { + return &FileReaderFS{ + FS: base, + } +} + +// ReadFile reads the named file from the base file system and returns its content. +func (f *FileReaderFS) ReadFile(name string) ([]byte, error) { + return fs.ReadFile(f.FS, name) +} + +// GlobOsFS is an [OsFS] that also implements [fs.GlobFS], with a [GlobOsFS.Glob] method. +type GlobOsFS struct { + *OsFS +} + +// NewGlobOsFS is like [NewReadOnlyOsFS], augmented to match the [fs.GlobFS] interface. +func NewGlobOsFS() *GlobOsFS { + return &GlobOsFS{ + OsFS: NewReadOnlyOsFS(), + } +} + +// Glob returns the names matching pattern, sorted in lexical order. +// +// It returns a nil slice and no error when nothing matches, +// and [path.ErrBadPattern] when the pattern is malformed. +func (f *GlobOsFS) Glob(pattern string) ([]string, error) { + return fs.Glob(f.OsFS, pattern) +} + +// MustSub re-roots a file system at one of its directories, and panics when it cannot. +// +// It is [fs.Sub] for the cases where the directory is a constant of the program, such as a folder +// of an [embed.FS] assembled at initialization time: there, a failure means the program is wrong, +// not that its input is. +// +// Use [fs.Sub] itself whenever the directory comes from the outside, such as a flag, +// a configuration file or a request, so that an invalid one is reported rather than fatal. +// +// It is meant to be composed inline: +// +// assets := NewOverlayFS( +// MustSub(embedded, "templates"), +// MustSub(embedded, "templates/contrib/mine"), +// ) +func MustSub(fsys fs.FS, dir string) fs.FS { + subFS, err := fs.Sub(fsys, dir) + if err != nil { + panic(fmt.Errorf("fileutils.MustSub: cannot re-root at %q: %w", dir, err)) + } + + return subFS +} diff --git a/vendor/github.com/go-openapi/swag/fileutils/mapfs.go b/vendor/github.com/go-openapi/swag/fileutils/mapfs.go new file mode 100644 index 000000000..5a81879f6 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/fileutils/mapfs.go @@ -0,0 +1,366 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package fileutils + +import ( + "bytes" + "errors" + "io" + "io/fs" + "path" + "slices" + "strings" + "time" +) + +// Default modes of the entries of a [MapFS]. +// +// A [MapFS] is read-only, so its files and directories are readable and never writable. +const ( + // DefaultFileMode is the mode reported by a file with no [MapFile.Mode] of its own. + DefaultFileMode fs.FileMode = 0o444 + + // DefaultDirMode is the mode reported by the directories of a [MapFS]. + DefaultDirMode fs.FileMode = fs.ModeDir | 0o555 +) + +var ( + // errNameIsFileAndDir is reported when the same name is held as a file and as a parent directory. + errNameIsFileAndDir = errors.New("name is held both as a file and as a directory") + + // errNotDir is reported when a regular file is listed as a directory. + errNotDir = errors.New("not a directory") +) + +// MapFile is a file held by a [MapFS]. +// +// Only [MapFile.Data] is required. [NewMapFS] fills the remaining fields with presets when they +// are left to their zero value. +type MapFile struct { + // Data is the content of the file. + Data []byte + + // Mode is the file mode reported by [fs.FileInfo.Mode]. Zero means [DefaultFileMode]. + Mode fs.FileMode + + // ModTime is the modification time reported by [fs.FileInfo.ModTime]. + // + // The zero value is left as is, so that a [MapFS] built from the same input twice + // reports the same metadata. + ModTime time.Time + + // Sys is the opaque value reported by [fs.FileInfo.Sys]. + Sys any +} + +// MapFS is a read-only in-memory [fs.FS], built from a map of file names to content. +// +// It is intended for the cases where the files to serve are held in memory rather than on disk: +// an overlay assembled from raw bytes, assets that a configuration provides, or a fixture in a test. +// +// Names are slash-separated paths, as accepted by [fs.ValidPath]. [NewMapFS] cleans them, +// so a name may be given with a leading "./" or "/", or with redundant elements. +// A name that remains invalid once cleaned, such as one climbing above the root, is reported +// as an error rather than dropped. +// +// Separators are never translated, so that the same input yields the same file system on every +// platform: a caller holding os paths converts them with [path/filepath.ToSlash] beforehand. +// +// Directories are implied by the names of the files, and are indexed once, when the file system +// is built: a name holds a file, and every one of its parents holds a directory. +// The root "." always exists, even when the file system holds no file at all. +// +// [MapFS] implements [fs.FS], [fs.ReadFileFS], [fs.StatFS] and [fs.ReadDirFS], but not [fs.GlobFS]: +// [fs.Glob] resolves against it all the same, through [MapFS.ReadDir]. +type MapFS struct { + files map[string]MapFile + dirs map[string][]fs.DirEntry +} + +// NewMapFS builds an in-memory file system from a map of file names to content. +// +// Names are normalized, and reported as an error when they remain invalid, or when the same name +// is held both as a file and as the parent directory of another one. +// A [MapFile] left with a zero [MapFile.Mode] reports [DefaultFileMode]. +// +// The map is copied, so adding or removing an entry afterwards leaves the file system alone. +// The contents are not: a caller that writes to a [MapFile.Data] slice it still holds changes +// what the file system serves. Hand over a slice nothing else keeps, or copy it first. +func NewMapFS(files map[string]MapFile) (*MapFS, error) { + normalized := make(map[string]MapFile, len(files)) + + for name, file := range files { + clean, err := normalizeMapName(name) + if err != nil { + return nil, err + } + + if _, isDuplicate := normalized[clean]; isDuplicate { + return nil, &fs.PathError{Op: "newmapfs", Path: clean, Err: fs.ErrExist} + } + + if file.Mode == 0 { + file.Mode = DefaultFileMode + } + + normalized[clean] = file + } + + dirs, err := indexMapDirs(normalized) + if err != nil { + return nil, err + } + + return &MapFS{ + files: normalized, + dirs: dirs, + }, nil +} + +// FromRawMap builds the files of a [MapFS] from raw contents, leaving every metadata field to its preset. +// +// It is the shortest way to a [MapFS] when all the caller holds is bytes: +// +// mapFS, err := NewMapFS(FromRawMap(map[string][]byte{ +// "folder/file1": raw1, +// "folder/file2": raw2, +// })) +func FromRawMap(raw map[string][]byte) map[string]MapFile { + files := make(map[string]MapFile, len(raw)) + for name, data := range raw { + files[name] = MapFile{Data: data} + } + + return files +} + +// Open opens the named file or directory. +// +// Opening a directory yields a [fs.ReadDirFile] reporting the same entries as [MapFS.ReadDir]. +func (f *MapFS) Open(name string) (fs.File, error) { + if !fs.ValidPath(name) { + return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid} + } + + if file, isFile := f.files[name]; isFile { + return &openMapFile{ + info: mapFileInfo{name: path.Base(name), file: file}, + reader: bytes.NewReader(file.Data), + }, nil + } + + entries, isDir := f.dirs[name] + if !isDir { + return nil, notFound("open", name) + } + + return &openMapDir{info: mapDirInfo{name: path.Base(name)}, entries: entries}, nil +} + +// ReadFile reads the named file and returns a copy of its content. +func (f *MapFS) ReadFile(name string) ([]byte, error) { + if !fs.ValidPath(name) { + return nil, &fs.PathError{Op: "read", Path: name, Err: fs.ErrInvalid} + } + + file, isFile := f.files[name] + if !isFile { + if _, isDir := f.dirs[name]; isDir { + return nil, &fs.PathError{Op: "read", Path: name, Err: errIsDir} + } + + return nil, notFound("read", name) + } + + // a caller mutating the result would otherwise mutate what the file system serves + return slices.Clone(file.Data), nil +} + +// Stat returns the [fs.FileInfo] of the named file or directory. +func (f *MapFS) Stat(name string) (fs.FileInfo, error) { + if !fs.ValidPath(name) { + return nil, &fs.PathError{Op: "stat", Path: name, Err: fs.ErrInvalid} + } + + if file, isFile := f.files[name]; isFile { + return mapFileInfo{name: path.Base(name), file: file}, nil + } + + if _, isDir := f.dirs[name]; isDir { + return mapDirInfo{name: path.Base(name)}, nil + } + + return nil, notFound("stat", name) +} + +// ReadDir lists the named directory, with its entries sorted by file name. +func (f *MapFS) ReadDir(name string) ([]fs.DirEntry, error) { + if !fs.ValidPath(name) { + return nil, &fs.PathError{Op: "readdir", Path: name, Err: fs.ErrInvalid} + } + + entries, isDir := f.dirs[name] + if !isDir { + if _, isFile := f.files[name]; isFile { + return nil, &fs.PathError{Op: "readdir", Path: name, Err: errNotDir} + } + + return nil, notFound("readdir", name) + } + + // the index is shared by every caller, so it must not escape + return slices.Clone(entries), nil +} + +// normalizeMapName turns the name of a file into the cleaned form that [fs.ValidPath] accepts. +// +// Separators are left alone: an [fs.FS] name is slash-separated by definition, and translating +// them here would resolve the same input differently depending on the platform. +func normalizeMapName(name string) (string, error) { + clean := path.Clean(strings.TrimPrefix(name, "/")) + + if !fs.ValidPath(clean) || clean == "." { + return "", &fs.PathError{Op: "newmapfs", Path: name, Err: fs.ErrInvalid} + } + + return clean, nil +} + +// indexMapDirs builds the directory index of a [MapFS], once, from the names of its files. +// +// Every parent of a file name holds a directory, up to the root, which always exists. +func indexMapDirs(files map[string]MapFile) (map[string][]fs.DirEntry, error) { + children := map[string]map[string]bool{".": {}} // directory -> child base name -> is a directory + + for name := range files { + dir := path.Dir(name) + addMapChild(children, dir, path.Base(name), false) + + // every ancestor of the file holds a directory + for dir != "." { + parent := path.Dir(dir) + addMapChild(children, parent, path.Base(dir), true) + dir = parent + } + } + + dirs := make(map[string][]fs.DirEntry, len(children)) + for dir, names := range children { + if _, isFile := files[dir]; isFile { + return nil, &fs.PathError{Op: "newmapfs", Path: dir, Err: errNameIsFileAndDir} + } + + entries := make([]fs.DirEntry, 0, len(names)) + for base, isDir := range names { + if isDir { + entries = append(entries, mapDirInfo{name: base}) + + continue + } + + entries = append(entries, mapFileInfo{name: base, file: files[path.Join(dir, base)]}) + } + + slices.SortFunc(entries, func(a, b fs.DirEntry) int { + return strings.Compare(a.Name(), b.Name()) + }) + dirs[dir] = entries + } + + return dirs, nil +} + +// addMapChild records that a directory holds an entry. +func addMapChild(children map[string]map[string]bool, dir, base string, isDir bool) { + entries, exists := children[dir] + if !exists { + entries = make(map[string]bool) + children[dir] = entries + } + + entries[base] = isDir +} + +// mapFileInfo reports the metadata of a file of a [MapFS]. It is both a [fs.FileInfo] and a [fs.DirEntry]. +type mapFileInfo struct { + name string + file MapFile +} + +func (i mapFileInfo) Name() string { return i.name } +func (i mapFileInfo) Size() int64 { return int64(len(i.file.Data)) } +func (i mapFileInfo) Mode() fs.FileMode { return i.file.Mode } +func (i mapFileInfo) Type() fs.FileMode { return i.file.Mode.Type() } +func (i mapFileInfo) ModTime() time.Time { return i.file.ModTime } +func (i mapFileInfo) IsDir() bool { return false } +func (i mapFileInfo) Sys() any { return i.file.Sys } +func (i mapFileInfo) Info() (fs.FileInfo, error) { return i, nil } + +// mapDirInfo reports the metadata of a directory of a [MapFS]. It is both a [fs.FileInfo] and a [fs.DirEntry]. +// +// Directories are implied by the names of the files, so they carry no metadata of their own. +type mapDirInfo struct { + name string +} + +func (i mapDirInfo) Name() string { return i.name } +func (i mapDirInfo) Size() int64 { return 0 } +func (i mapDirInfo) Mode() fs.FileMode { return DefaultDirMode } +func (i mapDirInfo) Type() fs.FileMode { return fs.ModeDir } +func (i mapDirInfo) ModTime() time.Time { return time.Time{} } +func (i mapDirInfo) IsDir() bool { return true } +func (i mapDirInfo) Sys() any { return nil } +func (i mapDirInfo) Info() (fs.FileInfo, error) { return i, nil } + +// openMapFile is the [fs.File] returned when opening a file of a [MapFS]. +type openMapFile struct { + info mapFileInfo + reader *bytes.Reader +} + +func (f *openMapFile) Stat() (fs.FileInfo, error) { return f.info, nil } + +func (f *openMapFile) Close() error { return nil } + +func (f *openMapFile) Read(p []byte) (int, error) { return f.reader.Read(p) } + +func (f *openMapFile) Seek(offset int64, whence int) (int64, error) { + return f.reader.Seek(offset, whence) +} + +// openMapDir is the [fs.ReadDirFile] returned when opening a directory of a [MapFS]. +type openMapDir struct { + info mapDirInfo + entries []fs.DirEntry + offset int +} + +func (d *openMapDir) Stat() (fs.FileInfo, error) { return d.info, nil } + +func (d *openMapDir) Close() error { return nil } + +func (d *openMapDir) Read([]byte) (int, error) { + return 0, &fs.PathError{Op: "read", Path: d.info.name, Err: errIsDir} +} + +// ReadDir returns the next n entries, or all the remaining ones when n is not positive. +func (d *openMapDir) ReadDir(n int) ([]fs.DirEntry, error) { + remaining := len(d.entries) - d.offset + if n <= 0 { + entries := slices.Clone(d.entries[d.offset:]) + d.offset = len(d.entries) + + return entries, nil + } + + if remaining == 0 { + return nil, io.EOF + } + + n = min(n, remaining) + entries := slices.Clone(d.entries[d.offset : d.offset+n]) + d.offset += n + + return entries, nil +} diff --git a/vendor/github.com/go-openapi/swag/fileutils/opaque.go b/vendor/github.com/go-openapi/swag/fileutils/opaque.go new file mode 100644 index 000000000..526e86736 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/fileutils/opaque.go @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package fileutils + +import ( + "io/fs" + "path" +) + +// OpaqueDirFS is a file system that entirely owns some of its directories. +// +// [OverlayFS] neither merges an opaque directory with the layers below it, +// nor resolves any name under it against them: +// what the owning layer holds replaces what they hold under the same name. +// +// [OpaqueFS] is the implementation provided by this package. +type OpaqueDirFS interface { + fs.FS + + // IsOpaqueDir reports whether a directory was declared as entirely owned by this file system. + // + // It answers from the declarations given to [NewOpaqueFS], and does not check that the file + // system holds the directory: a name declared opaque reports true either way. + // [OverlayFS] consults it only for a layer that holds the directory. + IsOpaqueDir(name string) bool +} + +// OpaqueDirsAll declares that a file system owns every directory it holds, except its root. +// +// It is the only pattern recognized by [NewOpaqueFS]: directories are otherwise matched +// by their exact name. +const OpaqueDirsAll = "*" + +// OpaqueFS makes a [fs.FS] into an [OpaqueDirFS], by declaring the directories that it owns. +type OpaqueFS struct { + fs.FS + + opaqueDirs map[string]struct{} +} + +// NewOpaqueFS declares the directories that a file system entirely owns, +// so that they shadow the layers below when it is stacked in an [OverlayFS]. +// +// Directories are slash-separated paths, as accepted by [fs.ValidPath], and are cleaned. +// Declaring "." makes the whole file system opaque, down from its root. +// Declaring [OpaqueDirsAll] makes every directory opaque but the root, +// so that the root still merges and the layers below keep contributing what they hold beside it. +// +// Declaring a directory that this file system does not hold changes nothing once it is stacked. +// [OverlayFS] skips a layer that does not hold the directory before it consults opacity, +// so the layers below keep resolving that directory and everything under it. +func NewOpaqueFS(base fs.FS, dirs ...string) *OpaqueFS { + opaqueDirs := make(map[string]struct{}, len(dirs)) + for _, dir := range dirs { + opaqueDirs[path.Clean(dir)] = struct{}{} + } + + return &OpaqueFS{ + FS: base, + opaqueDirs: opaqueDirs, + } +} + +// IsOpaqueDir reports whether a directory was declared as entirely owned by this file system. +// +// It answers from the declarations given to [NewOpaqueFS], and does not check that the file +// system holds the directory: a name declared opaque reports true either way. +// [OverlayFS] consults it only for a layer that holds the directory. +func (f *OpaqueFS) IsOpaqueDir(name string) bool { + if _, isOpaque := f.opaqueDirs[name]; isOpaque { + return true + } + + if name == "." { + // the root is owned only when it is declared explicitly + return false + } + + _, ownsAll := f.opaqueDirs[OpaqueDirsAll] + + return ownsAll +} + +// ReadFile reads a file from the wrapped file system. +func (f *OpaqueFS) ReadFile(name string) ([]byte, error) { + return fs.ReadFile(f.FS, name) +} + +// Stat returns the [fs.FileInfo] of a name in the wrapped file system. +func (f *OpaqueFS) Stat(name string) (fs.FileInfo, error) { + return fs.Stat(f.FS, name) +} + +// ReadDir lists a directory of the wrapped file system. +func (f *OpaqueFS) ReadDir(name string) ([]fs.DirEntry, error) { + return fs.ReadDir(f.FS, name) +} diff --git a/vendor/github.com/go-openapi/swag/fileutils/overlay.go b/vendor/github.com/go-openapi/swag/fileutils/overlay.go new file mode 100644 index 000000000..d67ab6a5f --- /dev/null +++ b/vendor/github.com/go-openapi/swag/fileutils/overlay.go @@ -0,0 +1,345 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package fileutils + +import ( + "errors" + "io" + "io/fs" + "path" + "slices" + "strings" + "syscall" +) + +// OverlayFS is a read-only [fs.FS] that stacks overlays on top of a base file system. +// +// A name is resolved in the topmost layer that holds it, then down to the base. +// See [NewOverlayFS] for the order in which layers are stacked. +// When the name is absent from all layers, every method returns a [fs.PathError] that reports +// the name and matches [fs.ErrNotExist]. +// +// [OverlayFS] implements [fs.FS], [fs.ReadFileFS], [fs.StatFS] and [fs.ReadDirFS], but not [fs.GlobFS]. +// A directory returns an error when the resolved layer does not support reading directories. +// +// Directories are merged: a directory reports the union of the entries held by every layer, +// and the topmost layer wins whenever the same name is held by several of them. +// A layer may claim a directory for itself with [NewOpaqueFS], which stops the merge +// and hides everything the lower layers hold under that directory. +type OverlayFS struct { + layers []fs.FS +} + +// NewOverlayFS builds an overlay file system from a base file system and a list of overlays. +// +// Overlays are stacked in the order in which they are provided: +// the last one sits on top and is resolved first, then the preceding ones in reverse order. +// The base is always resolved last. +// +// An empty list of overlays yields a file system that resolves against the base alone. +func NewOverlayFS(base fs.FS, overlays ...fs.FS) *OverlayFS { + layers := make([]fs.FS, 0, len(overlays)+1) + for _, overlay := range slices.Backward(overlays) { + layers = append(layers, overlay) + } + layers = append(layers, base) + + return &OverlayFS{ + layers: layers, + } +} + +// Open opens a file, resolving layers from the topmost overlay down to the base. +// +// Opening a directory yields a [fs.ReadDirFile] that reports the same entries as +// [OverlayFS.ReadDir], so that a merged directory reads alike either way. +func (f *OverlayFS) Open(name string) (fs.File, error) { + file, err := f.openInLayers(name) + if err != nil { + return nil, err + } + + info, err := file.Stat() + if err != nil { + _ = file.Close() + + return nil, err + } + + if !info.IsDir() { + return file, nil + } + + // the entries of a directory come from every layer, not from the one that resolved it + _ = file.Close() + + entries, err := f.readMergedDir(name) + if err != nil { + return nil, err + } + + return &mergedDir{name: name, info: info, entries: entries}, nil +} + +// ReadFile reads a file, resolving layers from the topmost overlay down to the base. +func (f *OverlayFS) ReadFile(name string) ([]byte, error) { + layer, err := f.findInLayers("open", name) + if err != nil { + return nil, err + } + + return fs.ReadFile(layer, name) +} + +// Stat returns the [fs.FileInfo] of a file, resolving layers from the topmost overlay down to the base. +func (f *OverlayFS) Stat(name string) (fs.FileInfo, error) { + layer, err := f.findInLayers("stat", name) + if err != nil { + return nil, err + } + + return fs.Stat(layer, name) +} + +// ReadDir lists a directory, resolving layers from the topmost overlay down to the base. +// +// The entries of every layer holding the directory are merged, sorted by file name, +// and a name held by several layers is reported by the topmost of them. +// The merge stops at the topmost layer that owns the directory, as declared by [NewOpaqueFS]. +func (f *OverlayFS) ReadDir(name string) ([]fs.DirEntry, error) { + return f.readMergedDir(name) +} + +// readMergedDir collects the entries of every layer that holds a directory. +// +// A name that is not a directory in some layer shadows the layers below it, +// just like a regular file does. +func (f *OverlayFS) readMergedDir(name string) ([]fs.DirEntry, error) { + var ( + merged []fs.DirEntry + found bool + ) + seen := make(map[string]struct{}) + + for _, layer := range f.layers { + info, err := fs.Stat(layer, name) + if err != nil { + if !isNotFound(err) { + return nil, err + } + + if ownsSubtreeOf(layer, name) { + break + } + + continue + } + + if !info.IsDir() { + if found { + // a directory held by an upper layer shadows this entry + break + } + + // let the layer report why the name cannot be listed + return fs.ReadDir(layer, name) + } + + entries, err := fs.ReadDir(layer, name) + if err != nil { + return nil, err + } + + found = true + for _, entry := range entries { + if _, isShadowed := seen[entry.Name()]; isShadowed { + continue + } + + seen[entry.Name()] = struct{}{} + merged = append(merged, entry) + } + + if declaresOpaqueDir(layer, name) || ownsSubtreeOf(layer, name) { + // this layer owns the directory, or one of its parents: + // the layers below it contribute nothing + break + } + } + + if !found { + return nil, notFound("readdir", name) + } + + slices.SortFunc(merged, func(a, b fs.DirEntry) int { + return strings.Compare(a.Name(), b.Name()) + }) + + return merged, nil +} + +// openInLayers opens a name in the topmost layer that holds it. +func (f *OverlayFS) openInLayers(name string) (fs.File, error) { + for _, layer := range f.layers { + file, err := layer.Open(name) + if err == nil { + return file, nil + } + + if !isNotFound(err) { + return nil, err + } + + if ownsSubtreeOf(layer, name) { + break + } + } + + return nil, notFound("open", name) +} + +// findInLayers returns the topmost layer that holds a name. +// +// op names the operation reported by the [fs.PathError] raised when no layer holds the name. +func (f *OverlayFS) findInLayers(op, name string) (fs.FS, error) { + for _, layer := range f.layers { + err := probeInLayer(layer, name) + if err == nil { + return layer, nil + } + + if !isNotFound(err) { + return nil, err + } + + if ownsSubtreeOf(layer, name) { + break + } + } + + return nil, notFound(op, name) +} + +// probeInLayer reports the error raised by a layer when looking a name up. +// +// A layer implementing [fs.StatFS] is probed with Stat. +// Otherwise the name is opened, then closed again. +func probeInLayer(layer fs.FS, name string) error { + if statFS, supportsStat := layer.(fs.StatFS); supportsStat { + _, err := statFS.Stat(name) + + return err + } + + file, err := layer.Open(name) + if err == nil { + _ = file.Close() + } + + return err +} + +// declaresOpaqueDir tells whether a layer marks a directory as entirely owned. +func declaresOpaqueDir(layer fs.FS, name string) bool { + opaque, isOpaqueFS := layer.(OpaqueDirFS) + + return isOpaqueFS && opaque.IsOpaqueDir(name) +} + +// ownsDir tells whether a layer marks a directory as entirely owned, and holds it. +func ownsDir(layer fs.FS, name string) bool { + if !declaresOpaqueDir(layer, name) { + return false + } + + info, err := fs.Stat(layer, name) + + return err == nil && info.IsDir() +} + +// ownsSubtreeOf tells whether a layer owns one of the parent directories of a name. +// +// The layers below such a layer hold nothing that is reachable under that name. +func ownsSubtreeOf(layer fs.FS, name string) bool { + if _, isOpaqueFS := layer.(OpaqueDirFS); !isOpaqueFS { + return false + } + + for dir := path.Dir(name); ; { + if ownsDir(layer, dir) { + return true + } + + // "." and "/" are their own parent, so this is where the walk up ends + parent := path.Dir(dir) + if parent == dir { + return false + } + + dir = parent + } +} + +// errIsDir is reported when a merged directory is read as a regular file. +var errIsDir = errors.New("is a directory") + +// mergedDir is the [fs.ReadDirFile] returned when opening a directory with merged layers. +// +// Its [fs.FileInfo] is the one of the topmost layer holding the directory, +// while its entries come from all the layers holding it. +type mergedDir struct { + name string + info fs.FileInfo + entries []fs.DirEntry + offset int +} + +func (d *mergedDir) Stat() (fs.FileInfo, error) { return d.info, nil } + +func (d *mergedDir) Close() error { return nil } + +func (d *mergedDir) Read([]byte) (int, error) { + return 0, &fs.PathError{Op: "read", Path: d.name, Err: errIsDir} +} + +// ReadDir returns the next n entries, or all the remaining ones when n is not positive. +func (d *mergedDir) ReadDir(n int) ([]fs.DirEntry, error) { + remaining := len(d.entries) - d.offset + if n <= 0 { + entries := d.entries[d.offset:] + d.offset = len(d.entries) + + return entries, nil + } + + if remaining == 0 { + return nil, io.EOF + } + + n = min(n, remaining) + entries := d.entries[d.offset : d.offset+n] + d.offset += n + + return entries, nil +} + +// notFound builds the error reported when a name is absent from all layers. +// +// It mirrors what the os package raises for a missing file, +// so that a caller may retrieve the name from the error alone. +func notFound(op, name string) error { + return &fs.PathError{Op: op, Path: name, Err: fs.ErrNotExist} +} + +// isNotFound tells whether an error raised by a layer means that the name is absent from that layer. +// +// The whole error chain is inspected, so a layer that wraps its errors resolves like any other, +// and so does a layer that is itself an [OverlayFS]. +// +// [syscall.ENOTDIR] is matched explicitly, because a path traversing a regular file +// does not report [fs.ErrNotExist] on all platforms. +// Any other error stops the resolution and is reported to the caller. +func isNotFound(err error) bool { + return errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) +} diff --git a/vendor/github.com/go-openapi/swag/fileutils/path.go b/vendor/github.com/go-openapi/swag/fileutils/path.go index dd09f690b..647df7609 100644 --- a/vendor/github.com/go-openapi/swag/fileutils/path.go +++ b/vendor/github.com/go-openapi/swag/fileutils/path.go @@ -10,10 +10,17 @@ import ( "strings" ) -// GOPATHKey represents the env key for gopath +// GOPATHKey is the name of the environment variable that holds the go search path. const GOPATHKey = "GOPATH" -// FindInSearchPath finds a package in a provided lists of paths +// FindInSearchPath finds a package in a list of search paths. +// +// searchPath lists directories separated by the OS path separator, +// in the form accepted by [filepath.SplitList]. +// Each directory is probed for a src/pkg subdirectory. +// +// It returns the first match, with symlinks resolved, +// or an empty string when the package is not found in any of the directories. func FindInSearchPath(searchPath, pkg string) string { pathsList := filepath.SplitList(searchPath) for _, path := range pathsList { @@ -26,7 +33,9 @@ func FindInSearchPath(searchPath, pkg string) string { return "" } -// FindInGoSearchPath finds a package in the $GOPATH:$GOROOT +// FindInGoSearchPath finds a package in $GOPATH and $GOROOT. +// +// It returns an empty string when the package is not found. // // Deprecated: this function is no longer relevant with modern go. // It uses [runtime.GOROOT] under the hood, which is deprecated as of go1.24. @@ -34,7 +43,10 @@ func FindInGoSearchPath(pkg string) string { return FindInSearchPath(FullGoSearchPath(), pkg) } -// FullGoSearchPath gets the search paths for finding packages +// FullGoSearchPath returns the search paths in which a package may be found. +// +// It joins $GOPATH, which defaults to $HOME/go when unset, with [runtime.GOROOT]. +// The two are separated by a colon, so the result is not usable on windows. // // Deprecated: this function is no longer relevant with modern go. // It uses [runtime.GOROOT] under the hood, which is deprecated as of go1.24. diff --git a/vendor/github.com/go-openapi/swag/go.work b/vendor/github.com/go-openapi/swag/go.work index f1dddc436..bb5810650 100644 --- a/vendor/github.com/go-openapi/swag/go.work +++ b/vendor/github.com/go-openapi/swag/go.work @@ -18,4 +18,4 @@ use ( ./yamlutils ) -go 1.25.0 +go 1.26.0 diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/options.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/options.go index f114f1f1a..cfcd42685 100644 --- a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/options.go +++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/options.go @@ -10,6 +10,11 @@ package json // It mirrors the limit enforced by the standard library's [encoding/json] decoder // (see encoding/json's internal maxNestingDepth), which this adapter would otherwise // not benefit from since it drives [encoding/json.Decoder.Token] directly. +// +// With encoding/json v2 (GOEXPERIMENT=jsonv2, the default from go1.27), Token applies +// that same limit itself and reports "exceeded max depth" before this counter fires. +// Set a lower limit with [WithMaxNestingDepth] to be rejected earlier than the stdlib; +// a higher one does not lift the stdlib's own 10,000-level ceiling on the decode path. const defaultMaxNestingDepth = 10000 // Option selects options for the stdlib adapter. diff --git a/vendor/github.com/go-openapi/swag/revive.toml b/vendor/github.com/go-openapi/swag/revive.toml new file mode 100644 index 000000000..eef9c1712 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/revive.toml @@ -0,0 +1,18 @@ +# revive configuration used by codefactor.io. +# +# This is redundant with .golangci.yml, since revive is part of golangci-lint, +# but we need to configure it to remain consistent across reporting tools. + +ignore-generated-header = false +severity = "warning" +confidence = 0.8 +error-code = 0 +warning-code = 0 +enable-default-rules = true + +[rule.exported] +disabled = true +[rule.cyclomatic] +arguments = [25] +[rule.cognitive-complexity] +arguments = [25] diff --git a/vendor/github.com/go-openapi/swag/yamlutils/yaml.go b/vendor/github.com/go-openapi/swag/yamlutils/yaml.go index d4b5335f6..01ce324ae 100644 --- a/vendor/github.com/go-openapi/swag/yamlutils/yaml.go +++ b/vendor/github.com/go-openapi/swag/yamlutils/yaml.go @@ -248,7 +248,7 @@ func yamlScalar(node *yaml.Node) (any, error) { func yamlStringScalarC(node *yaml.Node) (string, error) { if node.Kind != yaml.ScalarNode { - return "", fmt.Errorf("expecting a string scalar but got %q: %w", node.Kind, ErrYAML) + return "", fmt.Errorf("expecting a string scalar but got node.Kind(%d): %w", node.Kind, ErrYAML) } switch node.LongTag() { case yamlStringScalar, yamlIntScalar, yamlFloatScalar: diff --git a/vendor/github.com/go-openapi/validate/.gitignore b/vendor/github.com/go-openapi/validate/.gitignore index d8f4186fe..fbb78de2c 100644 --- a/vendor/github.com/go-openapi/validate/.gitignore +++ b/vendor/github.com/go-openapi/validate/.gitignore @@ -3,3 +3,4 @@ .idea .env .mcp.json +.worktrees diff --git a/vendor/github.com/go-openapi/validate/.golangci.yml b/vendor/github.com/go-openapi/validate/.golangci.yml index 4d6b36e47..c05f38e9d 100644 --- a/vendor/github.com/go-openapi/validate/.golangci.yml +++ b/vendor/github.com/go-openapi/validate/.golangci.yml @@ -7,7 +7,10 @@ linters: - gochecknoglobals - gochecknoinits - godox + - gomodguard + - gomodguard_v2 - exhaustruct + - exhaustruct_v5 - ireturn - nlreturn - nestif diff --git a/vendor/github.com/go-openapi/validate/BENCHMARK.md b/vendor/github.com/go-openapi/validate/BENCHMARK.md deleted file mode 100644 index 0353eae5b..000000000 --- a/vendor/github.com/go-openapi/validate/BENCHMARK.md +++ /dev/null @@ -1,34 +0,0 @@ -# Benchmark - -Validating the Kubernetes Swagger API - -## v0.22.6: 60,000,000 allocs - -``` -goos: linux -goarch: amd64 -pkg: github.com/go-openapi/validate -cpu: AMD Ryzen 7 5800X 8-Core Processor -Benchmark_KubernetesSpec/validating_kubernetes_API-16 1 8549863982 ns/op 7067424936 B/op 59583275 allocs/op -``` - -## After refact PR: minor but noticeable improvements: 25,000,000 allocs - -``` -go test -bench Spec -goos: linux -goarch: amd64 -pkg: github.com/go-openapi/validate -cpu: AMD Ryzen 7 5800X 8-Core Processor -Benchmark_KubernetesSpec/validating_kubernetes_API-16 1 4064535557 ns/op 3379715592 B/op 25320330 allocs/op -``` - -## After reduce GC pressure PR: 17,000,000 allocs - -``` -goos: linux -goarch: amd64 -pkg: github.com/go-openapi/validate -cpu: AMD Ryzen 7 5800X 8-Core Processor -Benchmark_KubernetesSpec/validating_kubernetes_API-16 1 3758414145 ns/op 2593881496 B/op 17111373 allocs/op -``` diff --git a/vendor/github.com/go-openapi/validate/CONTRIBUTORS.md b/vendor/github.com/go-openapi/validate/CONTRIBUTORS.md index 40d877a11..d0906ed08 100644 --- a/vendor/github.com/go-openapi/validate/CONTRIBUTORS.md +++ b/vendor/github.com/go-openapi/validate/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 31 | 310 | +| 32 | 351 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 169 | | -| @fredbi | 73 | | +| @fredbi | 113 | | | @sttts | 11 | | | @youyuanwu | 9 | | | @keramix | 8 | | @@ -32,6 +32,7 @@ | @liggitt | 1 | | | @ilyakaznacheev | 1 | | | @hypnoglow | 1 | | +| @HNO3Miracle | 1 | | | @gautierdelorme | 1 | | | @flavioribeiro | 1 | | | @pheepi | 1 | | diff --git a/vendor/github.com/go-openapi/validate/README.md b/vendor/github.com/go-openapi/validate/README.md index b814a2ef1..aa8eea563 100644 --- a/vendor/github.com/go-openapi/validate/README.md +++ b/vendor/github.com/go-openapi/validate/README.md @@ -5,7 +5,7 @@ -[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] +[![Release][release-badge]][release-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] [![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] @@ -98,8 +98,6 @@ Maintainers can cut a new release by either: [release-badge]: https://badge.fury.io/gh/go-openapi%2Fvalidate.svg [release-url]: https://badge.fury.io/gh/go-openapi%2Fvalidate -[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/validate -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/validate [codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/validate [codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/validate diff --git a/vendor/github.com/go-openapi/validate/collection_format.go b/vendor/github.com/go-openapi/validate/collection_format.go new file mode 100644 index 000000000..a77ba564d --- /dev/null +++ b/vendor/github.com/go-openapi/validate/collection_format.go @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "fmt" + "strconv" + + "github.com/go-openapi/spec" +) + +// validateCollectionFormats warns about a collectionFormat that has no effect. +// +// collectionFormat says how to join the members of an array into one value on the wire — csv, ssv, +// tsv, pipes, or multi for a parameter repeated once per member: +// +// parameters: +// - name: tags +// in: query +// type: array +// items: { type: string } +// collectionFormat: pipes +// +// There is nothing to join when the type is not array, so a collectionFormat written on a string or +// an integer does nothing. Swagger 2.0 says the member "determines the format of the array if type +// array is used" and stops there — it never forbids writing it elsewhere, so this is a warning and +// the specification stays valid. +// +// The meta-schema already covers the rest of the collectionFormat rules, and covers them at every +// location: the value must be one of csv, ssv, tsv or pipes, widened with multi for a query or +// formData parameter, where repeating the parameter is possible. A body parameter cannot carry the +// member at all. None of that needs a rule here. +// +// Only a parameter, a header and an items carry a collectionFormat — [spec.SimpleSchema] holds it, +// and [spec.Schema] has no such member. So this walks what the operations of the document declare, +// the way [SpecValidator.validateItems] does, and never looks at a schema. A JSON schema validated +// on its own is untouched by this rule. +func (s *SpecValidator) validateCollectionFormats() *Result { + res := validatorPools.results.Borrow() + + operations := s.analyzer.Operations() + for _, method := range sortedKeys(operations) { + byPath := operations[method] + for _, path := range sortedKeys(byPath) { + op := byPath[path] + + for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { + if param.In == swaggerBody { + // a body parameter describes itself with a schema, and the meta-schema + // forbids it a collectionFormat outright + continue + } + + at := s.parameterPath(path, method, param.In, param.Name) + in := fmt.Sprintf("parameter %q", param.Name) + checkCollectionFormat(at, param.CollectionFormat, param.Type, in, res) + checkItemsCollectionFormats(at, param.Items, in, res) + } + + for _, response := range responsesOf(op) { + at := responsePath(path, method, response.code) + for _, name := range sortedKeys(response.resp.Headers) { + header := response.resp.Headers[name] + headerAt := at.children(swaggerHeaders, name) + in := fmt.Sprintf("header %q", name) + checkCollectionFormat(headerAt, header.CollectionFormat, header.Type, in, res) + checkItemsCollectionFormats(headerAt, header.Items, in, res) + } + } + } + } + + return res +} + +// codedResponse is a response together with the code the operation files it under, "default" +// included. +type codedResponse struct { + code string + resp spec.Response +} + +// responsesOf lists the responses an operation declares, in a settled order: the default response +// first, then the status codes in ascending order. +func responsesOf(op *spec.Operation) []codedResponse { + if op == nil || op.Responses == nil { + return nil + } + + var responses []codedResponse + if op.Responses.Default != nil { + responses = append(responses, codedResponse{code: jsonDefault, resp: *op.Responses.Default}) + } + + for _, code := range sortedKeys(op.Responses.StatusCodeResponses) { + responses = append(responses, codedResponse{ + code: strconv.Itoa(code), + resp: op.Responses.StatusCodeResponses[code], + }) + } + + return responses +} + +// checkItemsCollectionFormats checks the items of a parameter or header, then the items of those +// items, as deep as the document nests them. +// +// Every level is named the same way in a message: an array of arrays that writes a pointless +// collectionFormat twice is one thing to fix, and the deeper location is reported only when the +// shallower one is sound. +func checkItemsCollectionFormats(at pathSegments, items *spec.Items, in string, res *Result) { + for items != nil { + at = at.child(jsonItems) + checkCollectionFormat(at, items.CollectionFormat, items.Type, "items of "+in, res) + items = items.Items + } +} + +// checkCollectionFormat warns when a collectionFormat is written on something that is not an array. +// +// A missing collectionFormat has nothing to answer for, and neither has a missing type: a document +// that leaves the type out is already reported by the meta-schema, and guessing what it meant here +// would only add noise. +func checkCollectionFormat(at pathSegments, collectionFormat, typ, in string, res *Result) { + if collectionFormat == "" || typ == "" || typ == arrayType { + return + } + + res.addWarningsAt(at.child(swaggerCollectionFormat), collectionFormatIgnoredMsg(collectionFormat, in, typ)) +} diff --git a/vendor/github.com/go-openapi/validate/default_validator.go b/vendor/github.com/go-openapi/validate/default_validator.go index ebcd80713..5902cee5c 100644 --- a/vendor/github.com/go-openapi/validate/default_validator.go +++ b/vendor/github.com/go-openapi/validate/default_validator.go @@ -4,9 +4,6 @@ package validate import ( - "fmt" - "strings" - "github.com/go-openapi/spec" ) @@ -20,7 +17,7 @@ type defaultValidator struct { // Validate validates the default values declared in the swagger spec. func (d *defaultValidator) Validate() *Result { - errs := pools.poolOfResults.BorrowResult() // will redeem when merged + errs := validatorPools.results.Borrow() // will redeem when merged if d == nil || d.SpecValidator == nil { return errs @@ -44,28 +41,16 @@ func (d *defaultValidator) resetVisited() { } } -func isVisited(path string, visitedSchemas map[string]struct{}) bool { - _, found := visitedSchemas[path] +func isVisited(path pathSegments, visitedSchemas map[string]struct{}) bool { + _, found := visitedSchemas[path.pointer()] if found { return true } - // search for overlapping paths - var ( - parent string - suffix string - ) - const backtrackFromEnd = 2 - for i := len(path) - backtrackFromEnd; i >= 0; i-- { - r := path[i] - if r != '.' { - continue - } - - parent = path[0:i] - suffix = path[i+1:] - - if strings.HasSuffix(parent, suffix) { + // search for overlapping paths: a trailing run of tokens that already + // appears at the end of what leads to it means we are going in circles. + for i := 1; i < len(path); i++ { + if path[:i].hasSuffix(path[i:]) { return true } } @@ -74,12 +59,12 @@ func isVisited(path string, visitedSchemas map[string]struct{}) bool { } // beingVisited asserts a schema is being visited. -func (d *defaultValidator) beingVisited(path string) { - d.visitedSchemas[path] = struct{}{} +func (d *defaultValidator) beingVisited(path pathSegments) { + d.visitedSchemas[path.pointer()] = struct{}{} } // isVisited tells if a path has already been visited. -func (d *defaultValidator) isVisited(path string) bool { +func (d *defaultValidator) isVisited(path pathSegments) bool { return isVisited(path, d.visitedSchemas) } @@ -88,15 +73,18 @@ func (d *defaultValidator) validateDefaultValueValidAgainstSchema() *Result { // every default value that is specified must validate against the schema for that property // headers, items, parameters, schema - res := pools.poolOfResults.BorrowResult() // will redeem when merged + res := validatorPools.results.Borrow() // will redeem when merged s := d.SpecValidator - for method, pathItem := range s.expandedAnalyzer().Operations() { - for path, op := range pathItem { + operations := s.expandedAnalyzer().Operations() + for _, method := range sortedKeys(operations) { + pathItem := operations[method] + for _, path := range sortedKeys(pathItem) { + op := pathItem[path] // parameters for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { if param.Default != nil && param.Required { - res.AddWarnings(requiredHasDefaultMsg(param.Name, param.In)) + res.addWarningsAt(s.parameterPath(path, method, param.In, param.Name), requiredHasDefaultMsg(param.Name, param.In)) } // reset explored schemas to get depth-first recursive-proof exploration @@ -107,33 +95,34 @@ func (d *defaultValidator) validateDefaultValueValidAgainstSchema() *Result { if param.Default != nil && param.Schema == nil { // check param default value is valid red := newParamValidator(¶m, s.KnownFormats, d.schemaOptions).Validate(param.Default) //#nosec + red.relocate(s.parameterPath(path, method, param.In, param.Name).child(jsonDefault)) if red.HasErrorsOrWarnings() { - res.AddErrors(defaultValueDoesNotValidateMsg(param.Name, param.In)) + res.addErrorsAt(s.parameterPath(path, method, param.In, param.Name), defaultValueDoesNotValidateMsg(param.Name, param.In)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } // Recursively follows Items and Schemas if param.Items != nil { - red := d.validateDefaultValueItemsAgainstSchema(param.Name, param.In, ¶m, param.Items) //#nosec + red := d.validateDefaultValueItemsAgainstSchema(s.parameterPath(path, method, param.In, param.Name), param.In, ¶m, param.Items) //#nosec if red.HasErrorsOrWarnings() { - res.AddErrors(defaultValueItemsDoesNotValidateMsg(param.Name, param.In)) + res.addErrorsAt(s.parameterPath(path, method, param.In, param.Name), defaultValueItemsDoesNotValidateMsg(param.Name, param.In)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } if param.Schema != nil { // Validate default value against schema - red := d.validateDefaultValueSchemaAgainstSchema(param.Name, param.In, param.Schema) + red := d.validateDefaultValueSchemaAgainstSchema(s.parameterPath(path, method, param.In, param.Name).structuralChild(jsonSchema), param.In, param.Schema) if red.HasErrorsOrWarnings() { - res.AddErrors(defaultValueDoesNotValidateMsg(param.Name, param.In)) + res.addErrorsAt(s.parameterPath(path, method, param.In, param.Name), defaultValueDoesNotValidateMsg(param.Name, param.In)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } } @@ -141,68 +130,74 @@ func (d *defaultValidator) validateDefaultValueValidAgainstSchema() *Result { if op.Responses != nil { if op.Responses.Default != nil { // Same constraint on default Response - res.Merge(d.validateDefaultInResponse(op.Responses.Default, jsonDefault, path, 0, op.ID)) + res.Merge(d.validateDefaultInResponse(op.Responses.Default, jsonDefault, path, method, 0, op.ID)) } // Same constraint on regular Responses if op.Responses.StatusCodeResponses != nil { // Safeguard - for code, r := range op.Responses.StatusCodeResponses { - res.Merge(d.validateDefaultInResponse(&r, "response", path, code, op.ID)) //#nosec + for _, code := range sortedKeys(op.Responses.StatusCodeResponses) { + r := op.Responses.StatusCodeResponses[code] + res.Merge(d.validateDefaultInResponse(&r, "response", path, method, code, op.ID)) } } } else if op.ID != "" { // Empty op.ID means there is no meaningful operation: no need to report a specific message - res.AddErrors(noValidResponseMsg(op.ID)) + res.addErrorsAt(operationPath(path, method), noValidResponseMsg(op.ID)) } } } if s.spec.Spec().Definitions != nil { // Safeguard // reset explored schemas to get depth-first recursive-proof exploration d.resetVisited() - for nm, sch := range s.spec.Spec().Definitions { - res.Merge(d.validateDefaultValueSchemaAgainstSchema("definitions."+nm, "body", &sch)) //#nosec + definitions := s.spec.Spec().Definitions + for _, nm := range sortedKeys(definitions) { + sch := definitions[nm] + res.Merge(d.validateDefaultValueSchemaAgainstSchema(newPathSegments(swaggerDefinitions, nm), "body", &sch)) } } return res } -func (d *defaultValidator) validateDefaultInResponse(resp *spec.Response, responseType, path string, responseCode int, operationID string) *Result { +func (d *defaultValidator) validateDefaultInResponse( + resp *spec.Response, responseType, path, method string, responseCode int, operationID string, +) *Result { s := d.SpecValidator - response, res := responseHelp.expandResponseRef(resp, path, s) + responseName, responseCodeAsStr := responseHelp.responseMsgVariants(responseType, responseCode) + response, res := responseHelp.expandResponseRef(resp, path, responsePath(path, method, responseCodeAsStr), s) if !res.IsValid() { return res } - responseName, responseCodeAsStr := responseHelp.responseMsgVariants(responseType, responseCode) - if response.Headers != nil { // Safeguard - for nm, h := range response.Headers { + for _, nm := range sortedKeys(response.Headers) { + h := response.Headers[nm] // reset explored schemas to get depth-first recursive-proof exploration d.resetVisited() if h.Default != nil { red := newHeaderValidator(nm, &h, s.KnownFormats, d.schemaOptions).Validate(h.Default) //#nosec + red.relocate(responseHeaderPath(path, method, responseCodeAsStr, nm).child(jsonDefault)) if red.HasErrorsOrWarnings() { - res.AddErrors(defaultValueHeaderDoesNotValidateMsg(operationID, nm, responseName)) + res.addErrorsAt(responseHeaderPath(path, method, responseCodeAsStr, nm), defaultValueHeaderDoesNotValidateMsg(operationID, nm, responseName)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } // Headers have inline definition, like params if h.Items != nil { - red := d.validateDefaultValueItemsAgainstSchema(nm, "header", &h, h.Items) //#nosec + red := d.validateDefaultValueItemsAgainstSchema(responseHeaderPath(path, method, responseCodeAsStr, nm), "header", &h, h.Items) //#nosec if red.HasErrorsOrWarnings() { - res.AddErrors(defaultValueHeaderItemsDoesNotValidateMsg(operationID, nm, responseName)) + res.addErrorsAt(responseHeaderPath(path, method, responseCodeAsStr, nm), defaultValueHeaderItemsDoesNotValidateMsg(operationID, nm, responseName)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } if _, err := compileRegexp(h.Pattern); err != nil { - res.AddErrors(invalidPatternInHeaderMsg(operationID, nm, responseName, h.Pattern, err)) + res.addErrorsAt(responseHeaderPath(path, method, responseCodeAsStr, nm), invalidPatternInHeaderMsg(operationID, nm, responseName, h.Pattern, err)) } // Headers don't have schema @@ -212,62 +207,65 @@ func (d *defaultValidator) validateDefaultInResponse(resp *spec.Response, respon // reset explored schemas to get depth-first recursive-proof exploration d.resetVisited() - red := d.validateDefaultValueSchemaAgainstSchema(responseCodeAsStr, "response", response.Schema) + red := d.validateDefaultValueSchemaAgainstSchema( + responsePath(path, method, responseCodeAsStr).structuralChild(jsonSchema), "response", response.Schema) if red.HasErrorsOrWarnings() { // Additional message to make sure the context of the error is not lost - res.AddErrors(defaultValueInDoesNotValidateMsg(operationID, responseName)) + res.addErrorsAt(responsePath(path, method, responseCodeAsStr), defaultValueInDoesNotValidateMsg(operationID, responseName)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } return res } -func (d *defaultValidator) validateDefaultValueSchemaAgainstSchema(path, in string, schema *spec.Schema) *Result { +func (d *defaultValidator) validateDefaultValueSchemaAgainstSchema(path pathSegments, in string, schema *spec.Schema) *Result { if schema == nil || d.isVisited(path) { // Avoids recursing if we are already done with that check return nil } d.beingVisited(path) - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() s := d.SpecValidator if schema.Default != nil { res.Merge( - newSchemaValidator(schema, s.spec.Spec(), path+".default", s.KnownFormats, d.schemaOptions).Validate(schema.Default), + newSchemaValidator(schema, s.spec.Spec(), path.child(jsonDefault), s.KnownFormats, d.schemaOptions).Validate(schema.Default), ) } if schema.Items != nil { if schema.Items.Schema != nil { - res.Merge(d.validateDefaultValueSchemaAgainstSchema(path+".items.default", in, schema.Items.Schema)) + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path.child(jsonItems), in, schema.Items.Schema)) } // Multiple schemas in items if schema.Items.Schemas != nil { // Safeguard for i, sch := range schema.Items.Schemas { - res.Merge(d.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.items[%d].default", path, i), in, &sch)) //#nosec + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path.child(jsonItems).item(i), in, &sch)) //#nosec } } } if _, err := compileRegexp(schema.Pattern); err != nil { - res.AddErrors(invalidPatternInMsg(path, in, schema.Pattern)) + res.addErrorsAt(path, invalidPatternInMsg(path.dotted(), in, schema.Pattern)) } if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { // NOTE: we keep validating values, even though additionalItems is not supported by Swagger 2.0 (and 3.0 as well) - res.Merge(d.validateDefaultValueSchemaAgainstSchema(path+".additionalItems", in, schema.AdditionalItems.Schema)) + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path.child(jsonAdditionalItems), in, schema.AdditionalItems.Schema)) } - for propName, prop := range schema.Properties { - res.Merge(d.validateDefaultValueSchemaAgainstSchema(path+"."+propName, in, &prop)) //#nosec + for _, propName := range sortedKeys(schema.Properties) { + prop := schema.Properties[propName] + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path.structuralChild(jsonProperties).child(propName), in, &prop)) } - for propName, prop := range schema.PatternProperties { - res.Merge(d.validateDefaultValueSchemaAgainstSchema(path+"."+propName, in, &prop)) //#nosec + for _, propName := range sortedKeys(schema.PatternProperties) { + prop := schema.PatternProperties[propName] + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path.structuralChild(jsonPatternProperties).child(propName), in, &prop)) } if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { - res.Merge(d.validateDefaultValueSchemaAgainstSchema(path+".additionalProperties", in, schema.AdditionalProperties.Schema)) + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path.child(jsonAdditionalProperties), in, schema.AdditionalProperties.Schema)) } if schema.AllOf != nil { for i, aoSch := range schema.AllOf { - res.Merge(d.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.allOf[%d]", path, i), in, &aoSch)) //#nosec + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path.child(jsonAllOf).item(i), in, &aoSch)) //#nosec } } return res @@ -275,8 +273,8 @@ func (d *defaultValidator) validateDefaultValueSchemaAgainstSchema(path, in stri // NOTE: Temporary duplicated code. Need to refactor with examples -func (d *defaultValidator) validateDefaultValueItemsAgainstSchema(path, in string, root any, items *spec.Items) *Result { - res := pools.poolOfResults.BorrowResult() +func (d *defaultValidator) validateDefaultValueItemsAgainstSchema(path pathSegments, in string, root any, items *spec.Items) *Result { + res := validatorPools.results.Borrow() s := d.SpecValidator if items != nil { if items.Default != nil { @@ -285,10 +283,10 @@ func (d *defaultValidator) validateDefaultValueItemsAgainstSchema(path, in strin ) } if items.Items != nil { - res.Merge(d.validateDefaultValueItemsAgainstSchema(path+"[0].default", in, root, items.Items)) + res.Merge(d.validateDefaultValueItemsAgainstSchema(path.item(0), in, root, items.Items)) } if _, err := compileRegexp(items.Pattern); err != nil { - res.AddErrors(invalidPatternInMsg(path, in, items.Pattern)) + res.addErrorsAt(path, invalidPatternInMsg(path.dotted(), in, items.Pattern)) } } return res diff --git a/vendor/github.com/go-openapi/validate/discriminator.go b/vendor/github.com/go-openapi/validate/discriminator.go new file mode 100644 index 000000000..7a4ab4167 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/discriminator.go @@ -0,0 +1,156 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "slices" + + "github.com/go-openapi/spec" +) + +// validateDiscriminators checks the discriminator of every definition, and of every schema a +// definition holds inline. +// +// A discriminator names the property that tells subtypes apart: +// +// Pet: +// discriminator: petType +// required: [ petType ] +// properties: +// petType: { type: string } +// +// Swagger 2.0 asks two things of that property: the schema must define it, and must list it as +// required. Both matter for the same reason — an instance carries its subtype in that property, +// so a subtype cannot be resolved from an instance that has nowhere to put the value, or that is +// free to leave it out. +// +// The JSON meta-schema types discriminator as a plain string and never compares it against +// properties or required, so it can express neither check. +// +// A property contributed by an allOf member counts as defined, and one that member requires counts +// as required: [SpecValidator.declaresProperty] already reads a composed definition that way for +// the required rule, and a discriminator resolves against the instance the whole composition +// describes. +// +// The third clause of the rule — the value must name this schema or one that inherits it — +// constrains the data, not the document, so it belongs to schema validation rather than here. +func (s *SpecValidator) validateDiscriminators() *Result { + res := validatorPools.results.Borrow() + definitions := s.spec.Spec().Definitions + + for _, name := range sortedKeys(definitions) { + schema := definitions[name] + s.walkDiscriminators(newPathSegments(swaggerDefinitions, name), &schema, res) + } + + return res +} + +// walkDiscriminators checks the discriminator of a schema, then of every schema it holds inline. +// +// A schema written as a $ref is left alone: it is checked where it is defined, and following it +// here would report the same fault twice and, for a recursive definition, would not terminate. +// This mirrors [SpecValidator.walkRequired]. +func (s *SpecValidator) walkDiscriminators(at pathSegments, v *spec.Schema, res *Result) { + if v == nil || v.Ref.String() != "" { + return + } + + s.checkDiscriminator(at, v, res) + + for _, name := range sortedKeys(v.Properties) { + held := v.Properties[name] + s.walkDiscriminators(at.structuralChild(jsonProperties).child(name), &held, res) + } + + for _, pattern := range sortedKeys(v.PatternProperties) { + held := v.PatternProperties[pattern] + s.walkDiscriminators(at.structuralChild(jsonPatternProperties).child(pattern), &held, res) + } + + if v.Items != nil { + if v.Items.Schema != nil { + s.walkDiscriminators(at.child(jsonItems), v.Items.Schema, res) + } + for i := range v.Items.Schemas { + s.walkDiscriminators(at.child(jsonItems).item(i), &v.Items.Schemas[i], res) + } + } + + if v.AdditionalProperties != nil && v.AdditionalProperties.Schema != nil { + s.walkDiscriminators(at.child(jsonAdditionalProperties), v.AdditionalProperties.Schema, res) + } + + for _, composition := range []struct { + keyword string + members []spec.Schema + }{ + {jsonAllOf, v.AllOf}, + {jsonAnyOf, v.AnyOf}, + {jsonOneOf, v.OneOf}, + } { + for i := range composition.members { + s.walkDiscriminators(at.child(composition.keyword).item(i), &composition.members[i], res) + } + } + + if v.Not != nil { + s.walkDiscriminators(at.child(jsonNot), v.Not, res) + } +} + +// checkDiscriminator checks the discriminator a single schema declares. A schema without one has +// nothing to answer for. +// +// Both findings are reported against the discriminator itself, which is the entry a reader has to +// go and amend, and both are reported when they apply: a discriminator naming a property that is +// neither defined nor required is two separate slips to fix. +func (s *SpecValidator) checkDiscriminator(at pathSegments, v *spec.Schema, res *Result) { + if v.Discriminator == "" { + return + } + + of := identify(at).name + discriminatorAt := at.child(jsonDiscriminator) + + if _, declared := s.declaresProperty(v, v.Discriminator, maxCompositionHops); !declared { + res.addErrorsAt(discriminatorAt, discriminatorNotDefinedMsg(v.Discriminator, of)) + } + + if !s.requiresProperty(v, v.Discriminator, maxCompositionHops) { + res.addErrorsAt(discriminatorAt, discriminatorNotRequiredMsg(v.Discriminator, of)) + } +} + +// requiresProperty reports whether a schema, or any schema composed into it by allOf, lists the +// named property as required. +// +// It is the required-list counterpart of [SpecValidator.declaresProperty], and follows allOf the +// same way, including the local $ref an allOf member may be written as. +func (s *SpecValidator) requiresProperty(v *spec.Schema, name string, hops int) bool { + if v == nil || hops <= 0 { + return false + } + + if slices.Contains(v.Required, name) { + return true + } + + for i := range v.AllOf { + member := &v.AllOf[i] + if member.Ref.String() != "" { + resolved, err := s.resolveRef(&member.Ref) + if err != nil { + continue + } + member = resolved + } + + if s.requiresProperty(member, name, hops-1) { + return true + } + } + + return false +} diff --git a/vendor/github.com/go-openapi/validate/doc.go b/vendor/github.com/go-openapi/validate/doc.go index 5218ec85c..f2d02d1a3 100644 --- a/vendor/github.com/go-openapi/validate/doc.go +++ b/vendor/github.com/go-openapi/validate/doc.go @@ -12,6 +12,11 @@ // Validates a spec document (from JSON or YAML) against the JSON schema for swagger, // then checks a number of extra rules that can't be expressed in JSON schema. // +// The lists below hold the extra rules only. The meta-schema already settles a great deal on its +// own, and where it does, no rule is repeated here: collectionFormat, say, must be one of csv, ssv, +// tsv or pipes, widened with multi for a query or formData parameter, and a body parameter may not +// carry one at all — all of that comes out of the meta-schema, at every location it applies to. +// // Entry points: // // - Spec() @@ -25,6 +30,9 @@ // [x] path uniqueness: each api path should be non-verbatim (account for path param names) unique per method. Validation can be laxed by disabling StrictPathParamUniqueness. // [x] each security reference should contain only unique scopes // [x] each security scope in a security definition should be unique +// [x] a discriminator must name a property the schema defines and lists as required +// [x] each security requirement must name a scheme declared in securityDefinitions +// [x] only an oauth2 security requirement may list scopes: every other scheme type must list none // [x] parameters in path must be unique // [x] each path parameter must correspond to a parameter placeholder and vice versa // [x] each referenceable definition must have references @@ -47,6 +55,8 @@ // [x] unsupported validation of examples on non-JSON media types // [x] examples in response without schema // [x] readOnly properties should not be required +// [x] an oauth2 security requirement names a scope its security scheme does not declare +// [x] collectionFormat is written on a parameter, header or items whose type is not array // // # Validating a schema // @@ -69,8 +79,11 @@ // [ ] errors and warnings are not reported with key/line number in spec // [ ] default values and examples on responses only support application/json producer type // [ ] invalid numeric constraints (such as Minimum, etc..) are not checked except for default and example values -// [ ] rules for collectionFormat are not implemented -// [ ] no validation rule for polymorphism support (discriminator) [not done here] // [ ] valid js ECMA regexp not supported by Go regexp engine are considered invalid // [ ] arbitrary large numbers are not supported: max is math.MaxFloat64 +// +// Left out by design, rather than pending: a discriminator value is not checked against the schema +// names it may take. That clause of the swagger rule constrains an instance rather than the +// document, so there is nothing in a specification for [SpecValidator] to read, and checking it +// would mean resolving polymorphic payloads, which this package does not do. package validate diff --git a/vendor/github.com/go-openapi/validate/example_validator.go b/vendor/github.com/go-openapi/validate/example_validator.go index eb6b5ee5c..0e193d523 100644 --- a/vendor/github.com/go-openapi/validate/example_validator.go +++ b/vendor/github.com/go-openapi/validate/example_validator.go @@ -4,8 +4,6 @@ package validate import ( - "fmt" - "github.com/go-openapi/spec" ) @@ -24,7 +22,7 @@ type exampleValidator struct { // - individual property // - responses func (ex *exampleValidator) Validate() *Result { - errs := pools.poolOfResults.BorrowResult() + errs := validatorPools.results.Borrow() if ex == nil || ex.SpecValidator == nil { return errs @@ -50,12 +48,12 @@ func (ex *exampleValidator) resetVisited() { } // beingVisited asserts a schema is being visited. -func (ex *exampleValidator) beingVisited(path string) { - ex.visitedSchemas[path] = struct{}{} +func (ex *exampleValidator) beingVisited(path pathSegments) { + ex.visitedSchemas[path.pointer()] = struct{}{} } // isVisited tells if a path has already been visited. -func (ex *exampleValidator) isVisited(path string) bool { +func (ex *exampleValidator) isVisited(path pathSegments) bool { return isVisited(path, ex.visitedSchemas) } @@ -65,11 +63,14 @@ func (ex *exampleValidator) validateExampleValueValidAgainstSchema() *Result { // in: schemas, properties, object, items // not in: headers, parameters without schema - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() s := ex.SpecValidator - for method, pathItem := range s.expandedAnalyzer().Operations() { - for path, op := range pathItem { + operations := s.expandedAnalyzer().Operations() + for _, method := range sortedKeys(operations) { + pathItem := operations[method] + for _, path := range sortedKeys(pathItem) { + op := pathItem[path] // parameters for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { @@ -84,33 +85,34 @@ func (ex *exampleValidator) validateExampleValueValidAgainstSchema() *Result { if param.Example != nil && param.Schema == nil { // check param default value is valid red := newParamValidator(¶m, s.KnownFormats, ex.schemaOptions).Validate(param.Example) //#nosec + red.relocate(s.parameterPath(path, method, param.In, param.Name).child(swaggerExample)) if red.HasErrorsOrWarnings() { - res.AddWarnings(exampleValueDoesNotValidateMsg(param.Name, param.In)) + res.addWarningsAt(s.parameterPath(path, method, param.In, param.Name), exampleValueDoesNotValidateMsg(param.Name, param.In)) res.MergeAsWarnings(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } // Recursively follows Items and Schemas if param.Items != nil { - red := ex.validateExampleValueItemsAgainstSchema(param.Name, param.In, ¶m, param.Items) //#nosec + red := ex.validateExampleValueItemsAgainstSchema(s.parameterPath(path, method, param.In, param.Name), param.In, ¶m, param.Items) //#nosec if red.HasErrorsOrWarnings() { - res.AddWarnings(exampleValueItemsDoesNotValidateMsg(param.Name, param.In)) + res.addWarningsAt(s.parameterPath(path, method, param.In, param.Name), exampleValueItemsDoesNotValidateMsg(param.Name, param.In)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } if param.Schema != nil { // Validate example value against schema - red := ex.validateExampleValueSchemaAgainstSchema(param.Name, param.In, param.Schema) + red := ex.validateExampleValueSchemaAgainstSchema(s.parameterPath(path, method, param.In, param.Name).structuralChild(jsonSchema), param.In, param.Schema) if red.HasErrorsOrWarnings() { - res.AddWarnings(exampleValueDoesNotValidateMsg(param.Name, param.In)) + res.addWarningsAt(s.parameterPath(path, method, param.In, param.Name), exampleValueDoesNotValidateMsg(param.Name, param.In)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } } @@ -118,68 +120,74 @@ func (ex *exampleValidator) validateExampleValueValidAgainstSchema() *Result { if op.Responses != nil { if op.Responses.Default != nil { // Same constraint on default Response - res.Merge(ex.validateExampleInResponse(op.Responses.Default, jsonDefault, path, 0, op.ID)) + res.Merge(ex.validateExampleInResponse(op.Responses.Default, jsonDefault, path, method, 0, op.ID)) } // Same constraint on regular Responses if op.Responses.StatusCodeResponses != nil { // Safeguard - for code, r := range op.Responses.StatusCodeResponses { - res.Merge(ex.validateExampleInResponse(&r, "response", path, code, op.ID)) //#nosec + for _, code := range sortedKeys(op.Responses.StatusCodeResponses) { + r := op.Responses.StatusCodeResponses[code] + res.Merge(ex.validateExampleInResponse(&r, "response", path, method, code, op.ID)) } } } else if op.ID != "" { // Empty op.ID means there is no meaningful operation: no need to report a specific message - res.AddErrors(noValidResponseMsg(op.ID)) + res.addErrorsAt(operationPath(path, method), noValidResponseMsg(op.ID)) } } } if s.spec.Spec().Definitions != nil { // Safeguard // reset explored schemas to get depth-first recursive-proof exploration ex.resetVisited() - for nm, sch := range s.spec.Spec().Definitions { - res.Merge(ex.validateExampleValueSchemaAgainstSchema("definitions."+nm, "body", &sch)) //#nosec + definitions := s.spec.Spec().Definitions + for _, nm := range sortedKeys(definitions) { + sch := definitions[nm] + res.Merge(ex.validateExampleValueSchemaAgainstSchema(newPathSegments(swaggerDefinitions, nm), "body", &sch)) } } return res } -func (ex *exampleValidator) validateExampleInResponse(resp *spec.Response, responseType, path string, responseCode int, operationID string) *Result { +func (ex *exampleValidator) validateExampleInResponse( + resp *spec.Response, responseType, path, method string, responseCode int, operationID string, +) *Result { s := ex.SpecValidator - response, res := responseHelp.expandResponseRef(resp, path, s) + responseName, responseCodeAsStr := responseHelp.responseMsgVariants(responseType, responseCode) + response, res := responseHelp.expandResponseRef(resp, path, responsePath(path, method, responseCodeAsStr), s) if !res.IsValid() { // Safeguard return res } - responseName, responseCodeAsStr := responseHelp.responseMsgVariants(responseType, responseCode) - if response.Headers != nil { // Safeguard - for nm, h := range response.Headers { + for _, nm := range sortedKeys(response.Headers) { + h := response.Headers[nm] // reset explored schemas to get depth-first recursive-proof exploration ex.resetVisited() if h.Example != nil { red := newHeaderValidator(nm, &h, s.KnownFormats, ex.schemaOptions).Validate(h.Example) //#nosec + red.relocate(responseHeaderPath(path, method, responseCodeAsStr, nm).child(swaggerExample)) if red.HasErrorsOrWarnings() { - res.AddWarnings(exampleValueHeaderDoesNotValidateMsg(operationID, nm, responseName)) + res.addWarningsAt(responseHeaderPath(path, method, responseCodeAsStr, nm), exampleValueHeaderDoesNotValidateMsg(operationID, nm, responseName)) res.MergeAsWarnings(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } // Headers have inline definition, like params if h.Items != nil { - red := ex.validateExampleValueItemsAgainstSchema(nm, "header", &h, h.Items) //#nosec + red := ex.validateExampleValueItemsAgainstSchema(responseHeaderPath(path, method, responseCodeAsStr, nm), "header", &h, h.Items) //#nosec if red.HasErrorsOrWarnings() { - res.AddWarnings(exampleValueHeaderItemsDoesNotValidateMsg(operationID, nm, responseName)) + res.addWarningsAt(responseHeaderPath(path, method, responseCodeAsStr, nm), exampleValueHeaderItemsDoesNotValidateMsg(operationID, nm, responseName)) res.MergeAsWarnings(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } if _, err := compileRegexp(h.Pattern); err != nil { - res.AddErrors(invalidPatternInHeaderMsg(operationID, nm, responseName, h.Pattern, err)) + res.addErrorsAt(responseHeaderPath(path, method, responseCodeAsStr, nm), invalidPatternInHeaderMsg(operationID, nm, responseName, h.Pattern, err)) } // Headers don't have schema @@ -189,77 +197,84 @@ func (ex *exampleValidator) validateExampleInResponse(resp *spec.Response, respo // reset explored schemas to get depth-first recursive-proof exploration ex.resetVisited() - red := ex.validateExampleValueSchemaAgainstSchema(responseCodeAsStr, "response", response.Schema) + red := ex.validateExampleValueSchemaAgainstSchema( + responsePath(path, method, responseCodeAsStr).structuralChild(jsonSchema), "response", response.Schema) if red.HasErrorsOrWarnings() { // Additional message to make sure the context of the error is not lost - res.AddWarnings(exampleValueInDoesNotValidateMsg(operationID, responseName)) + res.addWarningsAt(responsePath(path, method, responseCodeAsStr), exampleValueInDoesNotValidateMsg(operationID, responseName)) res.Merge(red) } else if red.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(red) + redeemResult(red) } } if response.Examples != nil { if response.Schema != nil { - if example, ok := response.Examples["application/json"]; ok { + if example, ok := response.Examples[jsonMimeApplicationJSON]; ok { + exampleAt := responsePath(path, method, responseCodeAsStr). + child(swaggerExamples). + structuralChild(jsonMimeApplicationJSON) res.MergeAsWarnings( - newSchemaValidator(response.Schema, s.spec.Spec(), path+".examples", s.KnownFormats, s.schemaOptions).Validate(example), + newSchemaValidator(response.Schema, s.spec.Spec(), + exampleAt, s.KnownFormats, s.schemaOptions).Validate(example), ) } else { // Proposal for enhancement: validate other media types too - res.AddWarnings(examplesMimeNotSupportedMsg(operationID, responseName)) + res.addWarningsAt(responsePath(path, method, responseCodeAsStr).child(swaggerExamples), examplesMimeNotSupportedMsg(operationID, responseName)) } } else { - res.AddWarnings(examplesWithoutSchemaMsg(operationID, responseName)) + res.addWarningsAt(responsePath(path, method, responseCodeAsStr).child(swaggerExamples), examplesWithoutSchemaMsg(operationID, responseName)) } } return res } -func (ex *exampleValidator) validateExampleValueSchemaAgainstSchema(path, in string, schema *spec.Schema) *Result { +func (ex *exampleValidator) validateExampleValueSchemaAgainstSchema(path pathSegments, in string, schema *spec.Schema) *Result { if schema == nil || ex.isVisited(path) { // Avoids recursing if we are already done with that check return nil } ex.beingVisited(path) s := ex.SpecValidator - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() if schema.Example != nil { res.MergeAsWarnings( - newSchemaValidator(schema, s.spec.Spec(), path+".example", s.KnownFormats, ex.schemaOptions).Validate(schema.Example), + newSchemaValidator(schema, s.spec.Spec(), path.child(swaggerExample), s.KnownFormats, ex.schemaOptions).Validate(schema.Example), ) } if schema.Items != nil { if schema.Items.Schema != nil { - res.Merge(ex.validateExampleValueSchemaAgainstSchema(path+".items.example", in, schema.Items.Schema)) + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path.child(jsonItems), in, schema.Items.Schema)) } // Multiple schemas in items if schema.Items.Schemas != nil { // Safeguard for i, sch := range schema.Items.Schemas { - res.Merge(ex.validateExampleValueSchemaAgainstSchema(fmt.Sprintf("%s.items[%d].example", path, i), in, &sch)) //#nosec + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path.child(jsonItems).item(i), in, &sch)) //#nosec } } } if _, err := compileRegexp(schema.Pattern); err != nil { - res.AddErrors(invalidPatternInMsg(path, in, schema.Pattern)) + res.addErrorsAt(path, invalidPatternInMsg(path.dotted(), in, schema.Pattern)) } if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { // NOTE: we keep validating values, even though additionalItems is unsupported in Swagger 2.0 (and 3.0 as well) - res.Merge(ex.validateExampleValueSchemaAgainstSchema(path+".additionalItems", in, schema.AdditionalItems.Schema)) + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path.child(jsonAdditionalItems), in, schema.AdditionalItems.Schema)) } - for propName, prop := range schema.Properties { - res.Merge(ex.validateExampleValueSchemaAgainstSchema(path+"."+propName, in, &prop)) //#nosec + for _, propName := range sortedKeys(schema.Properties) { + prop := schema.Properties[propName] + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path.structuralChild(jsonProperties).child(propName), in, &prop)) } - for propName, prop := range schema.PatternProperties { - res.Merge(ex.validateExampleValueSchemaAgainstSchema(path+"."+propName, in, &prop)) //#nosec + for _, propName := range sortedKeys(schema.PatternProperties) { + prop := schema.PatternProperties[propName] + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path.structuralChild(jsonPatternProperties).child(propName), in, &prop)) } if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { - res.Merge(ex.validateExampleValueSchemaAgainstSchema(path+".additionalProperties", in, schema.AdditionalProperties.Schema)) + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path.child(jsonAdditionalProperties), in, schema.AdditionalProperties.Schema)) } if schema.AllOf != nil { for i, aoSch := range schema.AllOf { - res.Merge(ex.validateExampleValueSchemaAgainstSchema(fmt.Sprintf("%s.allOf[%d]", path, i), in, &aoSch)) //#nosec + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path.child(jsonAllOf).item(i), in, &aoSch)) //#nosec } } return res @@ -268,8 +283,8 @@ func (ex *exampleValidator) validateExampleValueSchemaAgainstSchema(path, in str // NOTE: Temporary duplicated code. Need to refactor with examples // -func (ex *exampleValidator) validateExampleValueItemsAgainstSchema(path, in string, root any, items *spec.Items) *Result { - res := pools.poolOfResults.BorrowResult() +func (ex *exampleValidator) validateExampleValueItemsAgainstSchema(path pathSegments, in string, root any, items *spec.Items) *Result { + res := validatorPools.results.Borrow() s := ex.SpecValidator if items != nil { if items.Example != nil { @@ -278,10 +293,10 @@ func (ex *exampleValidator) validateExampleValueItemsAgainstSchema(path, in stri ) } if items.Items != nil { - res.Merge(ex.validateExampleValueItemsAgainstSchema(path+"[0].example", in, root, items.Items)) + res.Merge(ex.validateExampleValueItemsAgainstSchema(path.item(0), in, root, items.Items)) } if _, err := compileRegexp(items.Pattern); err != nil { - res.AddErrors(invalidPatternInMsg(path, in, items.Pattern)) + res.addErrorsAt(path, invalidPatternInMsg(path.dotted(), in, items.Pattern)) } } diff --git a/vendor/github.com/go-openapi/validate/formats.go b/vendor/github.com/go-openapi/validate/formats.go index eab261537..23359e35d 100644 --- a/vendor/github.com/go-openapi/validate/formats.go +++ b/vendor/github.com/go-openapi/validate/formats.go @@ -11,21 +11,21 @@ import ( ) type formatValidator struct { - Path string + Path pathSegments In string Format string KnownFormats strfmt.Registry Options *SchemaValidatorOptions } -func newFormatValidator(path, in, format string, formats strfmt.Registry, opts *SchemaValidatorOptions) *formatValidator { +func newFormatValidator(path pathSegments, in, format string, formats strfmt.Registry, opts *SchemaValidatorOptions) *formatValidator { if opts == nil { opts = new(SchemaValidatorOptions) } var f *formatValidator if opts.recycleValidators { - f = pools.poolOfFormatValidators.BorrowValidator() + f = validatorPools.formatValidators.Borrow() } else { f = new(formatValidator) } @@ -39,10 +39,6 @@ func newFormatValidator(path, in, format string, formats strfmt.Registry, opts * return f } -func (f *formatValidator) SetPath(path string) { - f.Path = path -} - func (f *formatValidator) Applies(source any, kind reflect.Kind) bool { if source == nil || f.KnownFormats == nil { return false @@ -71,7 +67,7 @@ func (f *formatValidator) Validate(val any) *Result { var result *Result if f.Options.recycleResult { - result = pools.poolOfResults.BorrowResult() + result = validatorPools.results.Borrow() } else { result = new(Result) } @@ -81,13 +77,17 @@ func (f *formatValidator) Validate(val any) *Result { return result } - if err := FormatOf(f.Path, f.In, f.Format, str, f.KnownFormats); err != nil { - result.AddErrors(err) + if err := FormatOf(f.Path.dotted(), f.In, f.Format, str, f.KnownFormats); err != nil { + result.addErrorsAt(f.Path, err) } return result } +func (f *formatValidator) setPath(path pathSegments) { + f.Path = path +} + func (f *formatValidator) redeem() { - pools.poolOfFormatValidators.RedeemValidator(f) + validatorPools.formatValidators.Redeem(f) } diff --git a/vendor/github.com/go-openapi/validate/helpers.go b/vendor/github.com/go-openapi/validate/helpers.go index 7cc254e02..ea7143607 100644 --- a/vendor/github.com/go-openapi/validate/helpers.go +++ b/vendor/github.com/go-openapi/validate/helpers.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/go-openapi/errors" + "github.com/go-openapi/jsonpointer" "github.com/go-openapi/spec" ) @@ -33,13 +34,84 @@ const ( ) const ( - jsonProperties = "properties" - jsonItems = "items" - jsonType = "type" - // jsonSchema = "schema". - jsonDefault = "default" + jsonProperties = "properties" + jsonPatternProperties = "patternProperties" + jsonItems = "items" + jsonType = "type" + jsonSchema = "schema" + jsonRequired = "required" + jsonRef = "$ref" + jsonDefault = "default" + jsonDiscriminator = "discriminator" + + jsonAllOf = "allOf" + jsonAnyOf = "anyOf" + jsonOneOf = "oneOf" + jsonNot = "not" + jsonAdditionalItems = "additionalItems" + jsonAdditionalProperties = "additionalProperties" + + swaggerPaths = "paths" + swaggerDefinitions = "definitions" + swaggerResponses = "responses" + swaggerParameters = "parameters" + swaggerHeaders = "headers" + swaggerOperationID = "operationId" + swaggerSecurity = "security" + swaggerCollectionFormat = "collectionFormat" + + // securitySchemeOAuth2 is the only security scheme type whose requirements carry scopes. + securitySchemeOAuth2 = "oauth2" + + jsonMimeApplicationJSON = "application/json" ) +// operationPath locates an operation in the spec document. +func operationPath(path, method string) pathSegments { + return newPathSegments(swaggerPaths, path, methodToken(method)) +} + +// parameterPath locates a parameter of an operation in the spec document. +func (s *SpecValidator) parameterPath(path, method, in, name string) pathSegments { + return s.paramLocations.at(path, method, in, name) +} + +// responsePath locates a response of an operation in the spec document. +func responsePath(path, method, responseCode string) pathSegments { + return operationPath(path, method).children(swaggerResponses, responseCode) +} + +// responseHeaderPath locates a header declared by a response. +func responseHeaderPath(path, method, responseCode, header string) pathSegments { + return responsePath(path, method, responseCode).children(swaggerHeaders, header) +} + +// methodToken normalizes an HTTP method into the key under which the operation +// is found in the document: the analyzer hands them over in upper case, but a +// path item spells them in lower case. +func methodToken(method string) string { + return strings.ToLower(method) +} + +// localRefPath turns a local JSON reference such as "#/definitions/Pet" into +// the location of what it points to. +// +// It yields the document root for anything that does not address a local +// fragment, a remote reference in particular. +func localRefPath(ref string) pathSegments { + rest, isLocal := strings.CutPrefix(ref, "#/") + if !isLocal { + return rootPath() + } + + tokens := strings.Split(rest, "/") + for i, token := range tokens { + tokens[i] = jsonpointer.Unescape(token) + } + + return newPathSegments(tokens...) +} + const ( stringFormatDate = "date" stringFormatDateTime = "date-time" @@ -91,24 +163,33 @@ type errorHelper struct { } func (h *errorHelper) sErr(err errors.Error, recycle bool) *Result { - // Builds a Result from standard errors.Error + return h.sErrAt(nil, err, recycle) +} + +// sErrAt builds a Result from a standard errors.Error reported at a known location. +func (h *errorHelper) sErrAt(at pathSegments, err errors.Error, recycle bool) *Result { var result *Result if recycle { - result = pools.poolOfResults.BorrowResult() + result = validatorPools.results.Borrow() } else { result = new(Result) } - result.Errors = []error{err} + result.addErrorsAt(at, err) return result } func (h *errorHelper) addPointerError(res *Result, err error, ref string, fromPath string) *Result { - // Provides more context on error messages - // reported by the jsoinpointer package by altering the passed Result + return h.addPointerErrorAt(res, nil, err, ref, fromPath) +} + +// addPointerErrorAt provides more context on error messages reported by the +// jsonpointer package, by altering the passed Result. +func (h *errorHelper) addPointerErrorAt(res *Result, at pathSegments, err error, ref string, fromPath string) *Result { if err != nil { - res.AddErrors(cannotResolveRefMsg(fromPath, ref, err)) + res.addErrorsAt(at, cannotResolveRefMsg(fromPath, ref, err)) } + return res } @@ -222,15 +303,19 @@ func (h *paramHelper) safeExpandedParamsFor(path, method, operationID string, re // remove params with invalid expansion from Slice operation.Parameters = resolvedParams - for _, ppr := range s.expandedAnalyzer().SafeParamsFor(method, path, + // the analyzer keys parameters by name and location: walk those keys in + // order, so that findings about an operation's parameters come out the + // same way on every run + safeParams := s.expandedAnalyzer().SafeParamsFor(method, path, func(_ spec.Parameter, err error) bool { // since params have already been expanded, there are few causes for error - res.AddErrors(someParametersBrokenMsg(path, method, operationID)) + res.addErrorsAt(operationPath(path, method), someParametersBrokenMsg(path, method, operationID)) // original error from analyzer - res.AddErrors(err) + res.addErrorsAt(operationPath(path, method), err) return true - }) { - params = append(params, ppr) + }) + for _, k := range sortedKeys(safeParams) { + params = append(params, safeParams[k]) } } return @@ -249,14 +334,16 @@ func (h *paramHelper) resolveParam(path, method, operationID string, param *spec if err != nil { // Safeguard // NOTE: we may enter here when the whole parameter is an unresolved $ref refPath := strings.Join([]string{"\"" + path + "\"", method}, ".") - errorHelp.addPointerError(res, err, param.Ref.String(), refPath) + errorHelp.addPointerErrorAt(res, s.parameterPath(path, method, param.In, param.Name), err, param.Ref.String(), refPath) return nil, res } - res.Merge(h.checkExpandedParam(param, param.Name, param.In, operationID, isRef)) + res.Merge(h.checkExpandedParam(param, param.Name, param.In, operationID, s.parameterPath(path, method, param.In, param.Name), isRef)) return param, res } -func (h *paramHelper) checkExpandedParam(pr *spec.Parameter, path, in, operation string, isRef bool) *Result { +func (h *paramHelper) checkExpandedParam( + pr *spec.Parameter, path, in, operation string, at pathSegments, isRef bool, +) *Result { // Secure parameter structure after $ref resolution res := new(Result) simpleZero := spec.SimpleSchema{} @@ -267,17 +354,17 @@ func (h *paramHelper) checkExpandedParam(pr *spec.Parameter, path, in, operation // Most likely, a $ref with a sibling is an unwanted situation: in itself this is a warning... // but we detect it because of the following error: // schema took over Parameter for an unexplained reason - res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation)) + res.addWarningsAt(at, refShouldNotHaveSiblingsMsg(path, operation)) } - res.AddErrors(invalidParameterDefinitionMsg(path, in, operation)) + res.addErrorsAt(at, invalidParameterDefinitionMsg(path, in, operation)) case pr.In != swaggerBody && pr.Schema != nil: if isRef { - res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation)) + res.addWarningsAt(at, refShouldNotHaveSiblingsMsg(path, operation)) } - res.AddErrors(invalidParameterDefinitionAsSchemaMsg(path, in, operation)) + res.addErrorsAt(at, invalidParameterDefinitionAsSchemaMsg(path, in, operation)) case (pr.In == swaggerBody && pr.Schema == nil) || (pr.In != swaggerBody && pr.SimpleSchema == simpleZero): // Other unexpected mishaps - res.AddErrors(invalidParameterDefinitionMsg(path, in, operation)) + res.addErrorsAt(at, invalidParameterDefinitionMsg(path, in, operation)) } return res } @@ -288,7 +375,7 @@ type responseHelper struct { func (r *responseHelper) expandResponseRef( response *spec.Response, - path string, s *SpecValidator, + path string, at pathSegments, s *SpecValidator, ) (*spec.Response, *Result) { // Ensure response is expanded var err error @@ -301,7 +388,7 @@ func (r *responseHelper) expandResponseRef( } if err != nil { // Safeguard // NOTE: we may enter here when the whole response is an unresolved $ref. - errorHelp.addPointerError(res, err, response.Ref.String(), path) + errorHelp.addPointerErrorAt(res, at, err, response.Ref.String(), path) return nil, res } diff --git a/vendor/github.com/go-openapi/validate/object_validator.go b/vendor/github.com/go-openapi/validate/object_validator.go index e651b3f70..cac243ece 100644 --- a/vendor/github.com/go-openapi/validate/object_validator.go +++ b/vendor/github.com/go-openapi/validate/object_validator.go @@ -4,7 +4,6 @@ package validate import ( - "fmt" "reflect" "strings" @@ -14,7 +13,7 @@ import ( ) type objectValidator struct { - Path string + Path pathSegments In string MaxProperties *int64 MinProperties *int64 @@ -25,10 +24,9 @@ type objectValidator struct { Root any KnownFormats strfmt.Registry Options *SchemaValidatorOptions - splitPath []string } -func newObjectValidator(path, in string, +func newObjectValidator(path pathSegments, in string, maxProperties, minProperties *int64, required []string, properties spec.SchemaProperties, additionalProperties *spec.SchemaOrBool, patternProperties spec.SchemaProperties, root any, formats strfmt.Registry, opts *SchemaValidatorOptions, @@ -39,7 +37,7 @@ func newObjectValidator(path, in string, var v *objectValidator if opts.recycleValidators { - v = pools.poolOfObjectValidators.BorrowValidator() + v = validatorPools.objectValidators.Borrow() } else { v = new(objectValidator) } @@ -55,7 +53,6 @@ func newObjectValidator(path, in string, v.Root = root v.KnownFormats = formats v.Options = opts - v.splitPath = strings.Split(v.Path, ".") return v } @@ -72,21 +69,21 @@ func (o *objectValidator) Validate(data any) *Result { var ok bool val, ok = data.(map[string]any) if !ok { - return errorHelp.sErr(invalidObjectMsg(o.Path, o.In), o.Options.recycleResult) + return errorHelp.sErrAt(o.Path, invalidObjectMsg(o.Path.dotted(), o.In), o.Options.recycleResult) } } numKeys := int64(len(val)) if o.MinProperties != nil && numKeys < *o.MinProperties { - return errorHelp.sErr(errors.TooFewProperties(o.Path, o.In, *o.MinProperties), o.Options.recycleResult) + return errorHelp.sErrAt(o.Path, errors.TooFewProperties(o.Path.dotted(), o.In, *o.MinProperties), o.Options.recycleResult) } if o.MaxProperties != nil && numKeys > *o.MaxProperties { - return errorHelp.sErr(errors.TooManyProperties(o.Path, o.In, *o.MaxProperties), o.Options.recycleResult) + return errorHelp.sErrAt(o.Path, errors.TooManyProperties(o.Path.dotted(), o.In, *o.MaxProperties), o.Options.recycleResult) } var res *Result if o.Options.recycleResult { - res = pools.poolOfResults.BorrowResult() + res = validatorPools.results.Borrow() } else { res = new(Result) } @@ -106,7 +103,8 @@ func (o *objectValidator) Validate(data any) *Result { // Check patternProperties // NOTE: it looks like we have done that twice in many cases - for key, value := range val { + for _, key := range sortedKeys(val) { + value := val[key] _, regularProperty := o.Properties[key] matched, _, patterns := o.validatePatternProperty(key, value, res) // applies to regular properties as well if regularProperty || !matched { @@ -115,7 +113,7 @@ func (o *objectValidator) Validate(data any) *Result { for _, pName := range patterns { if v, ok := o.PatternProperties[pName]; ok { - r := newSchemaValidator(&v, o.Root, o.Path+"."+key, o.KnownFormats, o.Options).Validate(value) + r := newSchemaValidator(&v, o.Root, o.Path.child(key), o.KnownFormats, o.Options).Validate(value) res.mergeForField(data.(map[string]any), key, r) //nolint:forcetypeassert // data is always map[string]any at this point } } @@ -124,11 +122,6 @@ func (o *objectValidator) Validate(data any) *Result { return res } -func (o *objectValidator) SetPath(path string) { - o.Path = path - o.splitPath = strings.Split(path, ".") -} - func (o *objectValidator) Applies(source any, kind reflect.Kind) bool { // NOTE: this should also work for structs // there is a problem in the type validator where it will be unhappy about null values @@ -137,19 +130,29 @@ func (o *objectValidator) Applies(source any, kind reflect.Kind) bool { return isSchema && (kind == reflect.Map || kind == reflect.Struct) } +// The three predicates below tell what kind of content the validated object +// is, so that schema-only checks are not run against plain data. +// +// Array indices are trimmed first: an element of an example is example data +// just as much as the example itself. + func (o *objectValidator) isProperties() bool { - p := o.splitPath - return len(p) > 1 && p[len(p)-1] == jsonProperties && p[len(p)-2] != jsonProperties + p := o.Path.trimIndexes() + + return p.last() == jsonProperties && p.beforeLast() != jsonProperties } func (o *objectValidator) isDefault() bool { - p := o.splitPath - return len(p) > 1 && p[len(p)-1] == jsonDefault && p[len(p)-2] != jsonDefault + p := o.Path.trimIndexes() + + return p.last() == jsonDefault && p.beforeLast() != jsonDefault } func (o *objectValidator) isExample() bool { - p := o.splitPath - return len(p) > 1 && (p[len(p)-1] == swaggerExample || p[len(p)-1] == swaggerExamples) && p[len(p)-2] != swaggerExample + p := o.Path.trimIndexes() + last := p.last() + + return (last == swaggerExample || last == swaggerExamples) && p.beforeLast() != swaggerExample } func (o *objectValidator) checkArrayMustHaveItems(res *Result, val map[string]any) { @@ -174,7 +177,7 @@ func (o *objectValidator) checkArrayMustHaveItems(res *Result, val map[string]an return } - res.AddErrors(errors.Required(jsonItems, o.Path, item)) + res.addErrorsAt(o.Path, errors.Required(jsonItems, o.Path.dotted(), item)) } func (o *objectValidator) checkItemsMustBeTypeArray(res *Result, val map[string]any) { @@ -194,11 +197,11 @@ func (o *objectValidator) checkItemsMustBeTypeArray(res *Result, val map[string] t, typeFound := val[jsonType] if !typeFound { // there is no type - res.AddErrors(errors.Required(jsonType, o.Path, t)) + res.addErrorsAt(o.Path, errors.Required(jsonType, o.Path.dotted(), t)) } if tpe, isString := t.(string); !isString || tpe != arrayType { - res.AddErrors(errors.InvalidType(o.Path, o.In, arrayType, nil)) + res.addErrorsAt(o.Path, errors.InvalidType(o.Path.dotted(), o.In, arrayType, nil)) } } @@ -212,7 +215,7 @@ func (o *objectValidator) precheck(res *Result, val map[string]any) { } func (o *objectValidator) validateNoAdditionalProperties(val map[string]any, res *Result) { - for k := range val { + for _, k := range sortedKeys(val) { if k == "$schema" || k == "id" { // special properties "$schema" and "id" are ignored continue @@ -238,7 +241,7 @@ func (o *objectValidator) validateNoAdditionalProperties(val map[string]any, res continue } - res.AddErrors(errors.PropertyNotAllowed(o.Path, o.In, k)) + res.addErrorsAt(o.Path.child(k), errors.PropertyNotAllowed(o.Path.dotted(), o.In, k)) // BUG(fredbi): This section should move to a part dedicated to spec validation as // it will conflict with regular schemas where a property "headers" is defined. @@ -261,7 +264,8 @@ func (o *objectValidator) validateNoAdditionalProperties(val map[string]any, res continue } - for headerKey, headerBody := range headers { + for _, headerKey := range sortedKeys(headers) { + headerBody := headers[headerKey] if headerBody == nil { continue } @@ -282,7 +286,7 @@ func (o *objectValidator) validateNoAdditionalProperties(val map[string]any, res } msg := strings.Join([]string{", one may not use $ref=\":", refString, "\""}, "") - res.AddErrors(refNotAllowedInHeaderMsg(o.Path, headerKey, msg)) + res.addErrorsAt(o.Path, refNotAllowedInHeaderMsg(o.Path.dotted(), headerKey, msg)) /* case "$ref": if val[k] != nil { @@ -294,7 +298,8 @@ func (o *objectValidator) validateNoAdditionalProperties(val map[string]any, res } func (o *objectValidator) validateAdditionalProperties(val map[string]any, res *Result) { - for key, value := range val { + for _, key := range sortedKeys(val) { + value := val[key] _, regularProperty := o.Properties[key] if regularProperty { continue @@ -315,7 +320,7 @@ func (o *objectValidator) validateAdditionalProperties(val map[string]any, res * // Cases: properties which are not regular properties and have not been matched by the PatternProperties validator // AdditionalProperties as Schema - r := newSchemaValidator(o.AdditionalProperties.Schema, o.Root, o.Path+"."+key, o.KnownFormats, o.Options).Validate(value) + r := newSchemaValidator(o.AdditionalProperties.Schema, o.Root, o.Path.child(key), o.KnownFormats, o.Options).Validate(value) res.mergeForField(val, key, r) } // Valid cases: additionalProperties: true or undefined @@ -326,19 +331,14 @@ func (o *objectValidator) validatePropertiesSchema(val map[string]any, res *Resu // Property types: // - regular Property - pSchema := pools.poolOfSchemas.BorrowSchema() // recycle a spec.Schema object which lifespan extends only to the validation of properties + pSchema := validatorPools.schemas.Borrow() // recycle a spec.Schema object which lifespan extends only to the validation of properties defer func() { - pools.poolOfSchemas.RedeemSchema(pSchema) + validatorPools.schemas.Redeem(pSchema) }() - for pName := range o.Properties { + for _, pName := range sortedKeys(o.Properties) { *pSchema = o.Properties[pName] - var rName string - if o.Path == "" { - rName = pName - } else { - rName = o.Path + "." + pName - } + rName := o.Path.child(pName) // Recursively validates each property against its schema v, ok := val[pName] @@ -374,7 +374,9 @@ func (o *objectValidator) validatePropertiesSchema(val map[string]any, res *Resu continue } - res.AddErrors(errors.Required(fmt.Sprintf("%s.%s", o.Path, k), o.In, v)) + // located on the object that lacks the property: the property itself + // has no node to point at, and the object has to be amended + res.addErrorsAt(o.Path, errors.Required(o.Path.child(k).dotted(), o.In, v)) } } @@ -388,12 +390,12 @@ func (o *objectValidator) validatePatternProperty(key string, value any, result succeededOnce := false patterns := make([]string, 0, len(o.PatternProperties)) - schema := pools.poolOfSchemas.BorrowSchema() + schema := validatorPools.schemas.Borrow() defer func() { - pools.poolOfSchemas.RedeemSchema(schema) + validatorPools.schemas.Redeem(schema) }() - for k := range o.PatternProperties { + for _, k := range sortedKeys(o.PatternProperties) { re, err := compileRegexp(k) if err != nil { continue @@ -407,7 +409,7 @@ func (o *objectValidator) validatePatternProperty(key string, value any, result *schema = o.PatternProperties[k] patterns = append(patterns, k) matched = true - validator := newSchemaValidator(schema, o.Root, fmt.Sprintf("%s.%s", o.Path, key), o.KnownFormats, o.Options) + validator := newSchemaValidator(schema, o.Root, o.Path.child(key), o.KnownFormats, o.Options) res := validator.Validate(value) result.Merge(res) @@ -416,6 +418,10 @@ func (o *objectValidator) validatePatternProperty(key string, value any, result return matched, succeededOnce, patterns } +func (o *objectValidator) setPath(path pathSegments) { + o.Path = path +} + func (o *objectValidator) redeem() { - pools.poolOfObjectValidators.RedeemValidator(o) + validatorPools.objectValidators.Redeem(o) } diff --git a/vendor/github.com/go-openapi/validate/param_locations.go b/vendor/github.com/go-openapi/validate/param_locations.go new file mode 100644 index 000000000..703d6ca17 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/param_locations.go @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "strconv" + + "github.com/go-openapi/spec" +) + +// paramLocations tells where an operation declares a parameter. +// +// Parameters are held in an array, so a name is not how a document addresses +// one: only its index is. The index is not something a validator can work out +// from an expanded parameter either, because expansion merges the parameters +// an operation declares with those its path item declares, and resolves the +// ones written as a $ref. So the unexpanded document is indexed once, and +// looked up by what a validator does know: the operation, and the name and +// location of the parameter it is reporting on. +type paramLocations map[paramKey]pathSegments + +// paramKey identifies a parameter the way the swagger specification does: +// a name is unique only within an "in". +type paramKey struct { + path string + method string + in string + name string +} + +// newParamLocations indexes the parameters declared by an unexpanded document. +func newParamLocations(sp *spec.Swagger) paramLocations { + locations := make(paramLocations) + if sp == nil || sp.Paths == nil { + return locations + } + + for path, pathItem := range sp.Paths.Paths { + at := newPathSegments(swaggerPaths, path) + + // parameters declared by the path item are shared by all its + // operations: recorded once, without a method + locations.collect(sp, paramKey{path: path}, at, pathItem.Parameters) + + for method, op := range operationsOf(&pathItem) { //#nosec + if op == nil { + continue + } + + locations.collect(sp, paramKey{path: path, method: method}, at.child(method), op.Parameters) + } + } + + return locations +} + +// at returns where an operation declares a parameter. +// +// A parameter the operation does not declare itself may come from its path +// item. When neither knows it, which happens for a parameter too broken to be +// identified, the pointer stops on the array holding it and the name is kept +// for the message alone: an index no one could work out would be a guess. +func (l paramLocations) at(path, method, in, name string) pathSegments { + if found, isDeclared := l[paramKey{path: path, method: methodToken(method), in: in, name: name}]; isDeclared { + return found + } + + if found, isDeclared := l[paramKey{path: path, in: in, name: name}]; isDeclared { + return found + } + + return operationPath(path, method).child(swaggerParameters).cosmeticChild(name) +} + +func (l paramLocations) collect(sp *spec.Swagger, key paramKey, at pathSegments, params []spec.Parameter) { + for i := range params { + name, in, ok := parameterIdentity(sp, ¶ms[i]) + if !ok { + continue + } + + key.name = name + key.in = in + l[key] = at.child(swaggerParameters).childAs(strconv.Itoa(i), name) + } +} + +// parameterIdentity names a parameter as declared, resolving the one indirection +// a document may put in the way: an entry written as a local $ref. +func parameterIdentity(sp *spec.Swagger, param *spec.Parameter) (name, in string, ok bool) { + if param.Ref.String() == "" { + return param.Name, param.In, param.Name != "" + } + + shared := localRefPath(param.Ref.String()) + const sharedParameterDepth = 2 + if len(shared) != sharedParameterDepth || shared.beforeLast() != swaggerParameters { + return "", "", false + } + + declared, isDeclared := sp.Parameters[shared.last()] + if !isDeclared { + return "", "", false + } + + return declared.Name, declared.In, declared.Name != "" +} + +// operationsOf yields the operations of a path item, keyed as the document +// spells them. +func operationsOf(pathItem *spec.PathItem) map[string]*spec.Operation { + return map[string]*spec.Operation{ + "get": pathItem.Get, + "put": pathItem.Put, + "post": pathItem.Post, + "delete": pathItem.Delete, + "options": pathItem.Options, + "head": pathItem.Head, + "patch": pathItem.Patch, + } +} diff --git a/vendor/github.com/go-openapi/validate/path.go b/vendor/github.com/go-openapi/validate/path.go new file mode 100644 index 000000000..4b2da2535 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/path.go @@ -0,0 +1,269 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "slices" + "strconv" + "strings" + + "github.com/go-openapi/jsonpointer" +) + +// pathSegments is the location of a validated value inside a document, +// held as an ordered list of unescaped JSON pointer reference tokens. +// +// Validators build a location by appending tokens as they descend into +// properties and array items, then render it only when they report an error. +// Keeping the tokens apart until then makes it possible to produce a +// valid [RFC 6901] JSON pointer: a token is escaped when it is rendered, and +// the separator can never be confused with a token that contains one. +// +// The zero value is the location of the document root. +// +// [RFC 6901]: https://datatracker.ietf.org/doc/html/rfc6901 +type pathSegments []pathToken + +// pathToken is one step of a location. +// +// A token addresses a member the way the document does, which is not always +// the way a reader recognizes it: an operation addresses its parameters by +// index, while a message is far more useful naming them. When the two differ, +// display carries the readable form and only the message uses it. +type pathToken struct { + token string + display string + + // structural marks a token a document needs to address the value, but + // that messages have never shown: a "properties" between a schema and one + // of its members, say. It is part of the pointer and absent from the + // dotted form. + structural bool + + // cosmetic is the converse: a token messages name but that the document + // does not address, such as a parameter too broken to be found by name in + // the array holding it. It is part of the dotted form and absent from the + // pointer, which then stops at the deepest node the document does contain. + cosmetic bool +} + +// readable renders a token the way a message should spell it. +func (t pathToken) readable() string { + if t.display != "" { + return t.display + } + + return t.token +} + +// newPathSegments builds a location from a list of unescaped tokens. +func newPathSegments(tokens ...string) pathSegments { + if len(tokens) == 0 { + return nil + } + + segments := make(pathSegments, len(tokens)) + for i, token := range tokens { + segments[i] = pathToken{token: token} + } + + return segments +} + +// rootPath is the location of the document root. +func rootPath() pathSegments { return nil } + +// String implements [fmt.Stringer] with the legacy dotted notation, so that a +// location interpolated into a message reads as it always has. +func (p pathSegments) String() string { return p.dotted() } + +// child returns the location of a named member of the value at p. +// +// The receiver is never modified: sibling children may be derived from the +// same parent without aliasing one another. +func (p pathSegments) child(token string) pathSegments { + return p.appendToken(pathToken{token: token}) +} + +// childAs returns the location of a member the document addresses as token, +// which messages should spell as display instead. +func (p pathSegments) childAs(token, display string) pathSegments { + return p.appendToken(pathToken{token: token, display: display}) +} + +// structuralChild returns the location of a member a document addresses but +// messages do not name. +func (p pathSegments) structuralChild(token string) pathSegments { + return p.appendToken(pathToken{token: token, structural: true}) +} + +// cosmeticChild returns a location that messages spell as a member named token, +// while the pointer stays on p. +func (p pathSegments) cosmeticChild(token string) pathSegments { + return p.appendToken(pathToken{token: token, cosmetic: true}) +} + +func (p pathSegments) appendToken(token pathToken) pathSegments { + child := make(pathSegments, len(p)+1) + copy(child, p) + child[len(p)] = p.inherit(token) + + return child +} + +// inherit passes down what a parent token says about addressability: nothing +// below a token the document does not address is addressable either, so the +// pointer has to stop at the same place. +func (p pathSegments) inherit(token pathToken) pathToken { + if len(p) > 0 && p[len(p)-1].cosmetic { + token.cosmetic = true + } + + return token +} + +// children returns the location of a chain of named members below p. +func (p pathSegments) children(tokens ...string) pathSegments { + child := make(pathSegments, len(p)+len(tokens)) + copy(child, p) + for i, token := range tokens { + child[len(p)+i] = child[:len(p)+i].inherit(pathToken{token: token}) + } + + return child +} + +// item returns the location of the index'th element of the array at p. +func (p pathSegments) item(index int) pathSegments { + return p.child(strconv.Itoa(index)) +} + +// isEmpty tells if p locates the document root. +func (p pathSegments) isEmpty() bool { return len(p) == 0 } + +// last returns the trailing meaningful token, or an empty string at the +// document root. +// +// Structural tokens are skipped: they say how a document addresses the value, +// not what the value is, and the callers here are asking the latter. +func (p pathSegments) last() string { + if token, ok := p.meaningfulAt(0); ok { + return token + } + + return "" +} + +// beforeLast returns the meaningful token before the trailing one, or an empty +// string when p holds fewer than two of them. +func (p pathSegments) beforeLast() string { + if token, ok := p.meaningfulAt(1); ok { + return token + } + + return "" +} + +// meaningfulAt returns the nth token from the end, counting only the tokens a +// message would show. +func (p pathSegments) meaningfulAt(n int) (string, bool) { + seen := 0 + for _, token := range slices.Backward(p) { + if token.structural { + continue + } + + if seen == n { + return token.token, true + } + + seen++ + } + + return "", false +} + +// trimIndexes returns p without its trailing array index tokens. +// +// It answers "what is this value inside of", disregarding how deep into an +// array it sits: the items of an example are still an example. +func (p pathSegments) trimIndexes() pathSegments { + end := len(p) + for end > 0 && isIndexToken(p[end-1].token) { + end-- + } + + return p[:end] +} + +// isIndexToken tells if a token addresses an array element rather than a member. +func isIndexToken(token string) bool { + if token == "" { + return false + } + + for _, r := range token { + if r < '0' || r > '9' { + return false + } + } + + return true +} + +// hasSuffix tells if p ends with the given sequence of tokens. +func (p pathSegments) hasSuffix(suffix pathSegments) bool { + if len(suffix) > len(p) { + return false + } + + offset := len(p) - len(suffix) + for i, token := range suffix { + if p[offset+i].token != token.token { + return false + } + } + + return true +} + +// dotted renders the location in the legacy dot-separated notation, e.g. +// "definitions.Pet.friends.0.name". +// +// Tokens are emitted verbatim: a token containing a dot is indistinguishable +// from a separator. This notation is kept because it is what surfaces as the +// name of a validation error, and API consumers of go-swagger servers see it. +// Use [pathSegments.pointer] whenever the location needs to be unambiguous. +func (p pathSegments) dotted() string { + readable := make([]string, 0, len(p)) + for _, token := range p { + if token.structural { + continue + } + + readable = append(readable, token.readable()) + } + + return strings.Join(readable, ".") +} + +// pointer renders the location as an RFC 6901 JSON pointer, e.g. +// "/definitions/Pet/friends/0/name". The document root renders as "". +func (p pathSegments) pointer() string { + if len(p) == 0 { + return "" + } + + var w strings.Builder + for _, token := range p { + if token.cosmetic { + continue + } + + w.WriteByte('/') + w.WriteString(jsonpointer.Escape(token.token)) + } + + return w.String() +} diff --git a/vendor/github.com/go-openapi/validate/pools.go b/vendor/github.com/go-openapi/validate/pools.go index c8936bd10..24fde6e9c 100644 --- a/vendor/github.com/go-openapi/validate/pools.go +++ b/vendor/github.com/go-openapi/validate/pools.go @@ -1,369 +1,87 @@ // SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers // SPDX-License-Identifier: Apache-2.0 -//go:build !validatedebug - package validate import ( - "sync" - "github.com/go-openapi/spec" + "github.com/go-openapi/swag/pools" ) -var pools allPools +// validatorPools recycles the objects allocated while validating. +// +// Validation allocates a validator per schema node and a result per check, so +// the same handful of types are built and thrown away constantly. Recycling +// them keeps validating a large specification affordable. +// +// Build with the "poolsdebug" tag to have every borrow and redeem tracked: +// misuse then panics where it happens rather than corrupting a pool, and +// [pools.AssertNoLeaks] reports what was borrowed and never given back. +var validatorPools allPools func init() { resetPools() } +// resetPools builds a fresh set of pools. +// +// Recycling an object twice leaves a pool holding it twice, and it would then +// be handed to two borrowers at once. A test that provokes such misuse has to +// start the next one from clean pools. func resetPools() { - // NOTE: for testing purpose, we might want to reset pools after calling Validate twice. - // The pool is corrupted in that case: calling Put twice inserts a duplicate in the pool - // and further calls to Get are mishandled. - - pools = allPools{ - poolOfSchemaValidators: schemaValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &SchemaValidator{} - - return s - }, - }, - }, - poolOfObjectValidators: objectValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &objectValidator{} - - return s - }, - }, - }, - poolOfSliceValidators: sliceValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &schemaSliceValidator{} - - return s - }, - }, - }, - poolOfItemsValidators: itemsValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &itemsValidator{} - - return s - }, - }, - }, - poolOfBasicCommonValidators: basicCommonValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &basicCommonValidator{} - - return s - }, - }, - }, - poolOfHeaderValidators: headerValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &HeaderValidator{} - - return s - }, - }, - }, - poolOfParamValidators: paramValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &ParamValidator{} - - return s - }, - }, - }, - poolOfBasicSliceValidators: basicSliceValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &basicSliceValidator{} - - return s - }, - }, - }, - poolOfNumberValidators: numberValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &numberValidator{} - - return s - }, - }, - }, - poolOfStringValidators: stringValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &stringValidator{} - - return s - }, - }, - }, - poolOfSchemaPropsValidators: schemaPropsValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &schemaPropsValidator{} - - return s - }, - }, - }, - poolOfFormatValidators: formatValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &formatValidator{} - - return s - }, - }, - }, - poolOfTypeValidators: typeValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &typeValidator{} - - return s - }, - }, - }, - poolOfSchemas: schemasPool{ - Pool: &sync.Pool{ - New: func() any { - s := &spec.Schema{} - - return s - }, - }, - }, - poolOfResults: resultsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &Result{} - - return s - }, - }, - }, + validatorPools = allPools{ + schemaValidators: pools.New[SchemaValidator](), + objectValidators: pools.New[objectValidator](), + sliceValidators: pools.New[schemaSliceValidator](), + itemsValidators: pools.New[itemsValidator](), + basicCommonValidators: pools.New[basicCommonValidator](), + headerValidators: pools.New[HeaderValidator](), + paramValidators: pools.New[ParamValidator](), + basicSliceValidators: pools.New[basicSliceValidator](), + numberValidators: pools.New[numberValidator](), + stringValidators: pools.New[stringValidator](), + schemaPropsValidators: pools.New[schemaPropsValidator](), + formatValidators: pools.New[formatValidator](), + typeValidators: pools.New[typeValidator](), + schemas: pools.New[spec.Schema](), + results: pools.New[Result](), } } -type ( - allPools struct { - // memory pools for all validator objects. - // - // Each pool can be borrowed from and redeemed to. - poolOfSchemaValidators schemaValidatorsPool - poolOfObjectValidators objectValidatorsPool - poolOfSliceValidators sliceValidatorsPool - poolOfItemsValidators itemsValidatorsPool - poolOfBasicCommonValidators basicCommonValidatorsPool - poolOfHeaderValidators headerValidatorsPool - poolOfParamValidators paramValidatorsPool - poolOfBasicSliceValidators basicSliceValidatorsPool - poolOfNumberValidators numberValidatorsPool - poolOfStringValidators stringValidatorsPool - poolOfSchemaPropsValidators schemaPropsValidatorsPool - poolOfFormatValidators formatValidatorsPool - poolOfTypeValidators typeValidatorsPool - poolOfSchemas schemasPool - poolOfResults resultsPool - } - - schemaValidatorsPool struct { - *sync.Pool - } - - objectValidatorsPool struct { - *sync.Pool - } - - sliceValidatorsPool struct { - *sync.Pool - } - - itemsValidatorsPool struct { - *sync.Pool - } - - basicCommonValidatorsPool struct { - *sync.Pool - } - - headerValidatorsPool struct { - *sync.Pool - } - - paramValidatorsPool struct { - *sync.Pool - } - - basicSliceValidatorsPool struct { - *sync.Pool - } - - numberValidatorsPool struct { - *sync.Pool - } - - stringValidatorsPool struct { - *sync.Pool - } - - schemaPropsValidatorsPool struct { - *sync.Pool - } - - formatValidatorsPool struct { - *sync.Pool - } - - typeValidatorsPool struct { - *sync.Pool - } - - schemasPool struct { - *sync.Pool - } - - resultsPool struct { - *sync.Pool - } -) - -func (p schemaValidatorsPool) BorrowValidator() *SchemaValidator { - return p.Get().(*SchemaValidator) //nolint:forcetypeassert // pool New always returns this type +// allPools is the set of pools shared by the validators of this package. +type allPools struct { + schemaValidators *pools.Pool[SchemaValidator] + objectValidators *pools.Pool[objectValidator] + sliceValidators *pools.Pool[schemaSliceValidator] + itemsValidators *pools.Pool[itemsValidator] + basicCommonValidators *pools.Pool[basicCommonValidator] + headerValidators *pools.Pool[HeaderValidator] + paramValidators *pools.Pool[ParamValidator] + basicSliceValidators *pools.Pool[basicSliceValidator] + numberValidators *pools.Pool[numberValidator] + stringValidators *pools.Pool[stringValidator] + schemaPropsValidators *pools.Pool[schemaPropsValidator] + formatValidators *pools.Pool[formatValidator] + typeValidators *pools.Pool[typeValidator] + schemas *pools.Pool[spec.Schema] + results *pools.Pool[Result] } -func (p schemaValidatorsPool) RedeemValidator(s *SchemaValidator) { - // NOTE: s might be nil. In that case, Put is a noop. - p.Put(s) -} - -func (p objectValidatorsPool) BorrowValidator() *objectValidator { - return p.Get().(*objectValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p objectValidatorsPool) RedeemValidator(s *objectValidator) { - p.Put(s) -} - -func (p sliceValidatorsPool) BorrowValidator() *schemaSliceValidator { - return p.Get().(*schemaSliceValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p sliceValidatorsPool) RedeemValidator(s *schemaSliceValidator) { - p.Put(s) -} - -func (p itemsValidatorsPool) BorrowValidator() *itemsValidator { - return p.Get().(*itemsValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p itemsValidatorsPool) RedeemValidator(s *itemsValidator) { - p.Put(s) -} - -func (p basicCommonValidatorsPool) BorrowValidator() *basicCommonValidator { - return p.Get().(*basicCommonValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p basicCommonValidatorsPool) RedeemValidator(s *basicCommonValidator) { - p.Put(s) -} - -func (p headerValidatorsPool) BorrowValidator() *HeaderValidator { - return p.Get().(*HeaderValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p headerValidatorsPool) RedeemValidator(s *HeaderValidator) { - p.Put(s) -} - -func (p paramValidatorsPool) BorrowValidator() *ParamValidator { - return p.Get().(*ParamValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p paramValidatorsPool) RedeemValidator(s *ParamValidator) { - p.Put(s) -} - -func (p basicSliceValidatorsPool) BorrowValidator() *basicSliceValidator { - return p.Get().(*basicSliceValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p basicSliceValidatorsPool) RedeemValidator(s *basicSliceValidator) { - p.Put(s) -} - -func (p numberValidatorsPool) BorrowValidator() *numberValidator { - return p.Get().(*numberValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p numberValidatorsPool) RedeemValidator(s *numberValidator) { - p.Put(s) -} - -func (p stringValidatorsPool) BorrowValidator() *stringValidator { - return p.Get().(*stringValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p stringValidatorsPool) RedeemValidator(s *stringValidator) { - p.Put(s) -} - -func (p schemaPropsValidatorsPool) BorrowValidator() *schemaPropsValidator { - return p.Get().(*schemaPropsValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p schemaPropsValidatorsPool) RedeemValidator(s *schemaPropsValidator) { - p.Put(s) -} - -func (p formatValidatorsPool) BorrowValidator() *formatValidator { - return p.Get().(*formatValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p formatValidatorsPool) RedeemValidator(s *formatValidator) { - p.Put(s) -} - -func (p typeValidatorsPool) BorrowValidator() *typeValidator { - return p.Get().(*typeValidator) //nolint:forcetypeassert // pool New always returns this type -} - -func (p typeValidatorsPool) RedeemValidator(s *typeValidator) { - p.Put(s) -} - -func (p schemasPool) BorrowSchema() *spec.Schema { - return p.Get().(*spec.Schema) //nolint:forcetypeassert // pool New always returns this type -} - -func (p schemasPool) RedeemSchema(s *spec.Schema) { - p.Put(s) -} - -func (p resultsPool) BorrowResult() *Result { - return p.Get().(*Result).cleared() //nolint:forcetypeassert // pool New always returns *Result -} - -func (p resultsPool) RedeemResult(s *Result) { - if s == emptyResult { +// redeemResult returns a result to the pool. +// +// emptyResult is a shared value that was never borrowed, so it is not the +// pool's to take back: handing it over would be reported as a foreign redeem, +// rightly. +// +// Results are borrowed straight from the pool rather than through a helper, +// so that the instrumented build attributes a leak to the code that borrowed it. +// +// This wrapper costs that attribution on redeem, where a double redeem still +// names the offending call site in the panic it raises. +func redeemResult(r *Result) { + if r == emptyResult { return } - p.Put(s) + + validatorPools.results.Redeem(r) } diff --git a/vendor/github.com/go-openapi/validate/pools_debug.go b/vendor/github.com/go-openapi/validate/pools_debug.go deleted file mode 100644 index d123ed409..000000000 --- a/vendor/github.com/go-openapi/validate/pools_debug.go +++ /dev/null @@ -1,1015 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers -// SPDX-License-Identifier: Apache-2.0 - -//go:build validatedebug - -package validate - -import ( - "fmt" - "runtime" - "sync" - "testing" - - "github.com/go-openapi/spec" -) - -// This version of the pools is to be used for debugging and testing, with build tag "validatedebug". -// -// In this mode, the pools are tracked for allocation and redemption of borrowed objects, so we can -// verify a few behaviors of the validators. The debug pools panic when an invalid usage pattern is detected. - -var pools allPools - -func init() { - resetPools() -} - -func resetPools() { - // NOTE: for testing purpose, we might want to reset pools after calling Validate twice. - // The pool is corrupted in that case: calling Put twice inserts a duplicate in the pool - // and further calls to Get are mishandled. - - pools = allPools{ - poolOfSchemaValidators: schemaValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &SchemaValidator{} - - return s - }, - }, - debugMap: make(map[*SchemaValidator]status), - allocMap: make(map[*SchemaValidator]string), - redeemMap: make(map[*SchemaValidator]string), - }, - poolOfObjectValidators: objectValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &objectValidator{} - - return s - }, - }, - debugMap: make(map[*objectValidator]status), - allocMap: make(map[*objectValidator]string), - redeemMap: make(map[*objectValidator]string), - }, - poolOfSliceValidators: sliceValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &schemaSliceValidator{} - - return s - }, - }, - debugMap: make(map[*schemaSliceValidator]status), - allocMap: make(map[*schemaSliceValidator]string), - redeemMap: make(map[*schemaSliceValidator]string), - }, - poolOfItemsValidators: itemsValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &itemsValidator{} - - return s - }, - }, - debugMap: make(map[*itemsValidator]status), - allocMap: make(map[*itemsValidator]string), - redeemMap: make(map[*itemsValidator]string), - }, - poolOfBasicCommonValidators: basicCommonValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &basicCommonValidator{} - - return s - }, - }, - debugMap: make(map[*basicCommonValidator]status), - allocMap: make(map[*basicCommonValidator]string), - redeemMap: make(map[*basicCommonValidator]string), - }, - poolOfHeaderValidators: headerValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &HeaderValidator{} - - return s - }, - }, - debugMap: make(map[*HeaderValidator]status), - allocMap: make(map[*HeaderValidator]string), - redeemMap: make(map[*HeaderValidator]string), - }, - poolOfParamValidators: paramValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &ParamValidator{} - - return s - }, - }, - debugMap: make(map[*ParamValidator]status), - allocMap: make(map[*ParamValidator]string), - redeemMap: make(map[*ParamValidator]string), - }, - poolOfBasicSliceValidators: basicSliceValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &basicSliceValidator{} - - return s - }, - }, - debugMap: make(map[*basicSliceValidator]status), - allocMap: make(map[*basicSliceValidator]string), - redeemMap: make(map[*basicSliceValidator]string), - }, - poolOfNumberValidators: numberValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &numberValidator{} - - return s - }, - }, - debugMap: make(map[*numberValidator]status), - allocMap: make(map[*numberValidator]string), - redeemMap: make(map[*numberValidator]string), - }, - poolOfStringValidators: stringValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &stringValidator{} - - return s - }, - }, - debugMap: make(map[*stringValidator]status), - allocMap: make(map[*stringValidator]string), - redeemMap: make(map[*stringValidator]string), - }, - poolOfSchemaPropsValidators: schemaPropsValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &schemaPropsValidator{} - - return s - }, - }, - debugMap: make(map[*schemaPropsValidator]status), - allocMap: make(map[*schemaPropsValidator]string), - redeemMap: make(map[*schemaPropsValidator]string), - }, - poolOfFormatValidators: formatValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &formatValidator{} - - return s - }, - }, - debugMap: make(map[*formatValidator]status), - allocMap: make(map[*formatValidator]string), - redeemMap: make(map[*formatValidator]string), - }, - poolOfTypeValidators: typeValidatorsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &typeValidator{} - - return s - }, - }, - debugMap: make(map[*typeValidator]status), - allocMap: make(map[*typeValidator]string), - redeemMap: make(map[*typeValidator]string), - }, - poolOfSchemas: schemasPool{ - Pool: &sync.Pool{ - New: func() any { - s := &spec.Schema{} - - return s - }, - }, - debugMap: make(map[*spec.Schema]status), - allocMap: make(map[*spec.Schema]string), - redeemMap: make(map[*spec.Schema]string), - }, - poolOfResults: resultsPool{ - Pool: &sync.Pool{ - New: func() any { - s := &Result{} - - return s - }, - }, - debugMap: make(map[*Result]status), - allocMap: make(map[*Result]string), - redeemMap: make(map[*Result]string), - }, - } -} - -const ( - statusFresh status = iota + 1 - statusRecycled - statusRedeemed -) - -func (s status) String() string { - switch s { - case statusFresh: - return "fresh" - case statusRecycled: - return "recycled" - case statusRedeemed: - return "redeemed" - default: - panic(fmt.Errorf("invalid status: %d", s)) - } -} - -type ( - // Debug - status uint8 - - allPools struct { - // memory pools for all validator objects. - // - // Each pool can be borrowed from and redeemed to. - poolOfSchemaValidators schemaValidatorsPool - poolOfObjectValidators objectValidatorsPool - poolOfSliceValidators sliceValidatorsPool - poolOfItemsValidators itemsValidatorsPool - poolOfBasicCommonValidators basicCommonValidatorsPool - poolOfHeaderValidators headerValidatorsPool - poolOfParamValidators paramValidatorsPool - poolOfBasicSliceValidators basicSliceValidatorsPool - poolOfNumberValidators numberValidatorsPool - poolOfStringValidators stringValidatorsPool - poolOfSchemaPropsValidators schemaPropsValidatorsPool - poolOfFormatValidators formatValidatorsPool - poolOfTypeValidators typeValidatorsPool - poolOfSchemas schemasPool - poolOfResults resultsPool - } - - schemaValidatorsPool struct { - *sync.Pool - debugMap map[*SchemaValidator]status - allocMap map[*SchemaValidator]string - redeemMap map[*SchemaValidator]string - mx sync.Mutex - } - - objectValidatorsPool struct { - *sync.Pool - debugMap map[*objectValidator]status - allocMap map[*objectValidator]string - redeemMap map[*objectValidator]string - mx sync.Mutex - } - - sliceValidatorsPool struct { - *sync.Pool - debugMap map[*schemaSliceValidator]status - allocMap map[*schemaSliceValidator]string - redeemMap map[*schemaSliceValidator]string - mx sync.Mutex - } - - itemsValidatorsPool struct { - *sync.Pool - debugMap map[*itemsValidator]status - allocMap map[*itemsValidator]string - redeemMap map[*itemsValidator]string - mx sync.Mutex - } - - basicCommonValidatorsPool struct { - *sync.Pool - debugMap map[*basicCommonValidator]status - allocMap map[*basicCommonValidator]string - redeemMap map[*basicCommonValidator]string - mx sync.Mutex - } - - headerValidatorsPool struct { - *sync.Pool - debugMap map[*HeaderValidator]status - allocMap map[*HeaderValidator]string - redeemMap map[*HeaderValidator]string - mx sync.Mutex - } - - paramValidatorsPool struct { - *sync.Pool - debugMap map[*ParamValidator]status - allocMap map[*ParamValidator]string - redeemMap map[*ParamValidator]string - mx sync.Mutex - } - - basicSliceValidatorsPool struct { - *sync.Pool - debugMap map[*basicSliceValidator]status - allocMap map[*basicSliceValidator]string - redeemMap map[*basicSliceValidator]string - mx sync.Mutex - } - - numberValidatorsPool struct { - *sync.Pool - debugMap map[*numberValidator]status - allocMap map[*numberValidator]string - redeemMap map[*numberValidator]string - mx sync.Mutex - } - - stringValidatorsPool struct { - *sync.Pool - debugMap map[*stringValidator]status - allocMap map[*stringValidator]string - redeemMap map[*stringValidator]string - mx sync.Mutex - } - - schemaPropsValidatorsPool struct { - *sync.Pool - debugMap map[*schemaPropsValidator]status - allocMap map[*schemaPropsValidator]string - redeemMap map[*schemaPropsValidator]string - mx sync.Mutex - } - - formatValidatorsPool struct { - *sync.Pool - debugMap map[*formatValidator]status - allocMap map[*formatValidator]string - redeemMap map[*formatValidator]string - mx sync.Mutex - } - - typeValidatorsPool struct { - *sync.Pool - debugMap map[*typeValidator]status - allocMap map[*typeValidator]string - redeemMap map[*typeValidator]string - mx sync.Mutex - } - - schemasPool struct { - *sync.Pool - debugMap map[*spec.Schema]status - allocMap map[*spec.Schema]string - redeemMap map[*spec.Schema]string - mx sync.Mutex - } - - resultsPool struct { - *sync.Pool - debugMap map[*Result]status - allocMap map[*Result]string - redeemMap map[*Result]string - mx sync.Mutex - } -) - -func (p *schemaValidatorsPool) BorrowValidator() *SchemaValidator { - s := p.Get().(*SchemaValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled schema should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *schemaValidatorsPool) RedeemValidator(s *SchemaValidator) { - // NOTE: s might be nil. In that case, Put is a noop. - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed schema should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed schema should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *objectValidatorsPool) BorrowValidator() *objectValidator { - s := p.Get().(*objectValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled object should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *objectValidatorsPool) RedeemValidator(s *objectValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed object should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed object should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *sliceValidatorsPool) BorrowValidator() *schemaSliceValidator { - s := p.Get().(*schemaSliceValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled schemaSliceValidator should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *sliceValidatorsPool) RedeemValidator(s *schemaSliceValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed schemaSliceValidator should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed schemaSliceValidator should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *itemsValidatorsPool) BorrowValidator() *itemsValidator { - s := p.Get().(*itemsValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled itemsValidator should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *itemsValidatorsPool) RedeemValidator(s *itemsValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed itemsValidator should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed itemsValidator should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *basicCommonValidatorsPool) BorrowValidator() *basicCommonValidator { - s := p.Get().(*basicCommonValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled basicCommonValidator should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *basicCommonValidatorsPool) RedeemValidator(s *basicCommonValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed basicCommonValidator should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed basicCommonValidator should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *headerValidatorsPool) BorrowValidator() *HeaderValidator { - s := p.Get().(*HeaderValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled HeaderValidator should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *headerValidatorsPool) RedeemValidator(s *HeaderValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed header should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed header should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *paramValidatorsPool) BorrowValidator() *ParamValidator { - s := p.Get().(*ParamValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled param should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *paramValidatorsPool) RedeemValidator(s *ParamValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed param should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed param should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *basicSliceValidatorsPool) BorrowValidator() *basicSliceValidator { - s := p.Get().(*basicSliceValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled basicSliceValidator should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *basicSliceValidatorsPool) RedeemValidator(s *basicSliceValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed basicSliceValidator should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed basicSliceValidator should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *numberValidatorsPool) BorrowValidator() *numberValidator { - s := p.Get().(*numberValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled number should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *numberValidatorsPool) RedeemValidator(s *numberValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed number should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed number should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *stringValidatorsPool) BorrowValidator() *stringValidator { - s := p.Get().(*stringValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled string should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *stringValidatorsPool) RedeemValidator(s *stringValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed string should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed string should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *schemaPropsValidatorsPool) BorrowValidator() *schemaPropsValidator { - s := p.Get().(*schemaPropsValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled param should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *schemaPropsValidatorsPool) RedeemValidator(s *schemaPropsValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed schemaProps should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed schemaProps should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *formatValidatorsPool) BorrowValidator() *formatValidator { - s := p.Get().(*formatValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled format should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *formatValidatorsPool) RedeemValidator(s *formatValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed format should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed format should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *typeValidatorsPool) BorrowValidator() *typeValidator { - s := p.Get().(*typeValidator) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled type should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *typeValidatorsPool) RedeemValidator(s *typeValidator) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed type should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic(fmt.Errorf("redeemed type should have been allocated from a fresh or recycled pointer. Got status %s, already redeamed at: %s", x, p.redeemMap[s])) - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *schemasPool) BorrowSchema() *spec.Schema { - s := p.Get().(*spec.Schema) - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled spec.Schema should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *schemasPool) RedeemSchema(s *spec.Schema) { - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed spec.Schema should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed spec.Schema should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *resultsPool) BorrowResult() *Result { - s := p.Get().(*Result).cleared() - - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - p.debugMap[s] = statusFresh - } else { - if x != statusRedeemed { - panic("recycled result should have been redeemed") - } - p.debugMap[s] = statusRecycled - } - p.allocMap[s] = caller() - - return s -} - -func (p *resultsPool) RedeemResult(s *Result) { - if s == emptyResult { - if len(s.Errors) > 0 || len(s.Warnings) > 0 { - panic("empty result should not mutate") - } - return - } - p.mx.Lock() - defer p.mx.Unlock() - x, ok := p.debugMap[s] - if !ok { - panic("redeemed Result should have been allocated") - } - if x != statusRecycled && x != statusFresh { - panic("redeemed Result should have been allocated from a fresh or recycled pointer") - } - p.debugMap[s] = statusRedeemed - p.redeemMap[s] = caller() - p.Put(s) -} - -func (p *allPools) allIsRedeemed(t testing.TB) bool { - outcome := true - for k, v := range p.poolOfSchemaValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("schemaValidator should be redeemed. Allocated by: %s", p.poolOfSchemaValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfObjectValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("objectValidator should be redeemed. Allocated by: %s", p.poolOfObjectValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfSliceValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("sliceValidator should be redeemed. Allocated by: %s", p.poolOfSliceValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfItemsValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("itemsValidator should be redeemed. Allocated by: %s", p.poolOfItemsValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfBasicCommonValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("basicCommonValidator should be redeemed. Allocated by: %s", p.poolOfBasicCommonValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfHeaderValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("headerValidator should be redeemed. Allocated by: %s", p.poolOfHeaderValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfParamValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("paramValidator should be redeemed. Allocated by: %s", p.poolOfParamValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfBasicSliceValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("basicSliceValidator should be redeemed. Allocated by: %s", p.poolOfBasicSliceValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfNumberValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("numberValidator should be redeemed. Allocated by: %s", p.poolOfNumberValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfStringValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("stringValidator should be redeemed. Allocated by: %s", p.poolOfStringValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfSchemaPropsValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("schemaPropsValidator should be redeemed. Allocated by: %s", p.poolOfSchemaPropsValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfFormatValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("formatValidator should be redeemed. Allocated by: %s", p.poolOfFormatValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfTypeValidators.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("typeValidator should be redeemed. Allocated by: %s", p.poolOfTypeValidators.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfSchemas.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("schemas should be redeemed. Allocated by: %s", p.poolOfSchemas.allocMap[k]) - outcome = false - } - for k, v := range p.poolOfResults.debugMap { - if v == statusRedeemed { - continue - } - t.Logf("result should be redeemed. Allocated by: %s", p.poolOfResults.allocMap[k]) - outcome = false - } - - return outcome -} - -func caller() string { - pc, _, _, _ := runtime.Caller(3) //nolint:dogsled - from, line := runtime.FuncForPC(pc).FileLine(pc) - - return fmt.Sprintf("%s:%d", from, line) -} diff --git a/vendor/github.com/go-openapi/validate/ref_locations.go b/vendor/github.com/go-openapi/validate/ref_locations.go new file mode 100644 index 000000000..1853340d2 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/ref_locations.go @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "github.com/go-openapi/analysis" +) + +// refLocations tells where a $ref value is declared in a document. +// +// The analyzer indexes references the other way around, by the location each +// was found at, so the index is inverted here. Only declarations are indexed: +// a "$ref" member sitting in an example or in a default value is data, and the +// analyzer never walks into it. +type refLocations map[string]pathSegments + +// newRefLocations inverts the analyzer's reference index. +// +// A reference declared in several places keeps the smallest declaration, so +// that the answer does not depend on map iteration order. +func newRefLocations(analyzer *analysis.Spec) refLocations { + declarations := make(map[string]string) + for location, ref := range analyzer.AllRefsByLocation() { + value := ref.String() + if value == "" { + continue + } + + if known, isKnown := declarations[value]; isKnown && known <= location { + continue + } + + declarations[value] = location + } + + locations := make(refLocations, len(declarations)) + for value, location := range declarations { + locations[value] = localRefPath(location) + } + + return locations +} + +// at returns where a reference is declared, or the document root when the +// reference is not one the analyzer indexed. +func (l refLocations) at(ref string) pathSegments { + return l[ref] +} diff --git a/vendor/github.com/go-openapi/validate/ref_redirects.go b/vendor/github.com/go-openapi/validate/ref_redirects.go new file mode 100644 index 000000000..95fe96c22 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/ref_redirects.go @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "strings" + + "github.com/go-openapi/analysis" +) + +// maxRefHops bounds how many $ref a pointer may be followed through, so that a +// document referring to itself cannot spin here. +const maxRefHops = 10 + +// refRedirects maps the location of a $ref to the location it points at, for +// the local references of a document. +// +// Checks walk the expanded document, so a finding below a $ref comes out with a +// pointer that descends into a node the authored document does not contain: a +// bare "$ref" member has nothing under it. Following the reference turns such a +// pointer back into one the document addresses. +type refRedirects map[string]string + +func newRefRedirects(analyzer *analysis.Spec) refRedirects { + redirects := make(refRedirects) + for location, ref := range analyzer.AllRefsByLocation() { + target := ref.String() + if !strings.HasPrefix(target, "#/") { + // only a local reference has a location in this document + continue + } + + redirects[strings.TrimPrefix(location, "#")] = strings.TrimPrefix(target, "#") + } + + return redirects +} + +// through rewrites a pointer that descends below a $ref. +// +// A pointer that stops at the $ref itself is left alone: that node exists, and +// it is where a reader has to go to amend the reference. +func (r refRedirects) through(pointer string) string { + if len(r) == 0 { + return pointer + } + + for range maxRefHops { + prefix, rest, ok := r.crossing(pointer) + if !ok { + return pointer + } + + pointer = prefix + rest + } + + return pointer +} + +// crossing finds the longest prefix of pointer that holds a $ref, and returns +// the location that reference points at together with what is left below it. +func (r refRedirects) crossing(pointer string) (target, rest string, ok bool) { + for at := strings.LastIndex(pointer, "/"); at > 0; at = strings.LastIndex(pointer[:at], "/") { + if target, isRef := r[pointer[:at]]; isRef { + return target, pointer[at:], true + } + } + + return "", "", false +} diff --git a/vendor/github.com/go-openapi/validate/required_walk.go b/vendor/github.com/go-openapi/validate/required_walk.go new file mode 100644 index 000000000..b3fd3cdf4 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/required_walk.go @@ -0,0 +1,179 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "strings" + + "github.com/go-openapi/errors" + "github.com/go-openapi/spec" +) + +// schemaIdentity is how a message refers to the schema a required entry +// belongs to. +// +// A definition is named on its own, the way it always has been. A schema the +// definition holds is named by the way down to it, relative to the definition: +// "A.inner" rather than "A", which would send a reader to the wrong place. +type schemaIdentity struct { + name string + nested bool +} + +// identify names the schema a location leads to. +func identify(at pathSegments) schemaIdentity { + const definitionDepth = 2 // "definitions", then the name of one + + return schemaIdentity{ + name: strings.TrimPrefix(at.dotted(), swaggerDefinitions+"."), + nested: len(at) > definitionDepth, + } +} + +func (i schemaIdentity) requiredButNotDefined(property string) errors.Error { + if i.nested { + return requiredButNotDefinedInSchemaMsg(property, i.name) + } + + return requiredButNotDefinedMsg(property, i.name) +} + +// maxCompositionHops bounds how far the search for a declared property follows +// allOf members and the local $ref they may be written as. +const maxCompositionHops = 20 + +// walkRequired checks the required entries of a schema, then those of every +// schema it holds inline. +// +// A definition is not the only place a document says an object must hold a +// property: so does the schema of a property, of an array item, of an +// additionalProperties. Each of those is a self-contained object definition, +// and a required entry naming something it never declares is the same slip +// wherever it sits. +// +// A schema written as a $ref is left alone: it is checked where it is defined, +// and following it here would report the same slip twice and, for a recursive +// definition, would not terminate. +// +// It reports whether the walk should carry on, which is how the caller stops on +// the first fault unless it was asked for everything. +func (s *SpecValidator) walkRequired(at pathSegments, v *spec.Schema, res *Result) bool { + if v == nil || v.Ref.String() != "" { + return true + } + + for i, pn := range v.Required { + // the offending entry of the required array, not the schema holding + // it: that is what a reader has to go and amend + red := s.validateRequiredProperties(pn, identify(at), at, at.child(jsonRequired).item(i), v) + // NOTE: capture validity before merging: Merge may redeem `red` to the + // pool (wantsRedeemOnMerge), after which reading it races with a + // concurrent BorrowResult().cleared() in another goroutine. + isValid := red.IsValid() + res.Merge(red) + if !isValid && !s.Options.ContinueOnErrors { + return false + } + } + + return s.walkInlineSchemas(at, v, res) +} + +// walkInlineSchemas descends into every schema a schema holds, without checking +// the required entries of a composition member. +// +// Inside allOf, anyOf, oneOf or not, a member is a fragment of a constraint +// rather than a complete definition: its required entries speak of the instance +// the whole composition describes, and are legitimately met by a sibling member +// or by no declaration at all. Those are honoured when data is validated, and +// saying anything about them here would be wrong. Their own members are still +// walked, because a property schema nested in one of them is a definition like +// any other. +func (s *SpecValidator) walkInlineSchemas(at pathSegments, v *spec.Schema, res *Result) bool { + for _, name := range sortedKeys(v.Properties) { + held := v.Properties[name] + if !s.walkRequired(at.structuralChild(jsonProperties).child(name), &held, res) { + return false + } + } + + for _, pattern := range sortedKeys(v.PatternProperties) { + held := v.PatternProperties[pattern] + if !s.walkRequired(at.structuralChild(jsonPatternProperties).child(pattern), &held, res) { + return false + } + } + + if v.Items != nil { + if v.Items.Schema != nil && !s.walkRequired(at.child(jsonItems), v.Items.Schema, res) { + return false + } + for i := range v.Items.Schemas { + if !s.walkRequired(at.child(jsonItems).item(i), &v.Items.Schemas[i], res) { + return false + } + } + } + + if v.AdditionalProperties != nil && v.AdditionalProperties.Schema != nil && + !s.walkRequired(at.child(jsonAdditionalProperties), v.AdditionalProperties.Schema, res) { + return false + } + + // a composition member is walked for the schemas it holds, never for its + // own required entries + for _, composition := range []struct { + keyword string + members []spec.Schema + }{ + {jsonAllOf, v.AllOf}, + {jsonAnyOf, v.AnyOf}, + {jsonOneOf, v.OneOf}, + } { + for i := range composition.members { + if !s.walkInlineSchemas(at.child(composition.keyword).item(i), &composition.members[i], res) { + return false + } + } + } + + if v.Not != nil { + return s.walkInlineSchemas(at.child(jsonNot), v.Not, res) + } + + return true +} + +// declaresProperty reports whether a schema, or any schema composed into it by +// allOf, declares the named property, and whether that declaration is readOnly. +// +// An allOf member may be written as a $ref, which is followed here: a property +// contributed by a base definition is declared just as plainly as one written +// in place. +func (s *SpecValidator) declaresProperty(v *spec.Schema, name string, hops int) (readOnly, declared bool) { + if v == nil || hops <= 0 { + return false, false + } + + if held, ok := v.Properties[name]; ok { + return held.ReadOnly, true + } + + for i := range v.AllOf { + member := &v.AllOf[i] + if member.Ref.String() != "" { + resolved, err := s.resolveRef(&member.Ref) + if err != nil { + continue + } + member = resolved + } + + if readOnly, ok := s.declaresProperty(member, name, hops-1); ok { + return readOnly, true + } + } + + return false, false +} diff --git a/vendor/github.com/go-openapi/validate/resolvable.go b/vendor/github.com/go-openapi/validate/resolvable.go new file mode 100644 index 000000000..bbd35d360 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/resolvable.go @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "strconv" + "strings" + + "github.com/go-openapi/jsonpointer" +) + +// resolvable trims a pointer down to the deepest node the document holds. +// +// Checks walk an expanded, model-level view of a specification, which holds +// members the document itself never wrote: a parameter merged in from a path +// item, a member of a schema reached through a $ref. A pointer built along the +// way may therefore end on something a reader cannot go to. +// +// Trimming is the last word on a location, applied once every check has had its +// say: it only ever shortens, so a pointer that already addressed a node comes +// back untouched, and one that did not still says as much as it truthfully can. +// This is what makes [Located.Pointer] always resolve. +func (s *SpecValidator) resolvable(pointer string) string { + if pointer == "" || s.document == nil { + return pointer + } + + node := s.document + for at := 0; at < len(pointer); { + end := strings.IndexByte(pointer[at+1:], '/') + token := pointer[at+1:] + if end >= 0 { + token = pointer[at+1 : at+1+end] + } + + member, isHeld := memberOf(node, jsonpointer.Unescape(token)) + if !isHeld { + return pointer[:at] + } + node = member + + if end < 0 { + break + } + at += end + 1 + } + + return pointer +} + +// memberOf returns the member a reference token addresses in a decoded JSON +// node, and whether the node holds one at all. +func memberOf(node any, token string) (any, bool) { + switch held := node.(type) { + case map[string]any: + member, isHeld := held[token] + + return member, isHeld + case []any: + index, err := strconv.Atoi(token) + if err != nil || index < 0 || index >= len(held) { + return nil, false + } + + return held[index], true + default: + return nil, false + } +} diff --git a/vendor/github.com/go-openapi/validate/result.go b/vendor/github.com/go-openapi/validate/result.go index ede945503..5684774a5 100644 --- a/vendor/github.com/go-openapi/validate/result.go +++ b/vendor/github.com/go-openapi/validate/result.go @@ -14,6 +14,25 @@ import ( var emptyResult = &Result{MatchCount: 1} +// Located pairs a validation error with the location of the value that caused it. +type Located struct { + // Err is the reported error or warning. + Err error + + // Pointer locates the offending value as an RFC 6901 JSON pointer, + // relative to the validated document. + // + // It is empty when the document as a whole is the answer: either because + // the finding is about the document rather than a value in it, such as a + // duplicate operation id, or because the value in question is the root. + // An empty pointer is a valid one, addressing the whole document. + // + // A finding about something a document does not contain, a missing + // required property say, is located on the value that should contain it: + // what is absent has no node to point at. + Pointer string +} + // Result represents a validation result set, composed of // errors and warnings. // @@ -25,12 +44,17 @@ var emptyResult = &Result{MatchCount: 1} // schema validation. Results from the validation branch // with most matches get eventually selected. // -// Proposal for enhancement: keep path of key originating the error. +// Use [Result.LocatedErrors] to know where each error happened. type Result struct { Errors []error Warnings []error MatchCount int + // errorLocations[i] locates Errors[i], and likewise for warnings. Kept + // aligned by the add methods; see [Result.LocatedErrors]. + errorLocations []string + warningLocations []string + // the object data data any @@ -110,7 +134,7 @@ func (r *Result) Merge(others ...*Result) *Result { r.mergeWithoutRootSchemata(other) r.rootObjectSchemata.Append(other.rootObjectSchemata) if other.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(other) + redeemResult(other) } } return r @@ -173,11 +197,11 @@ func (r *Result) MergeAsErrors(others ...*Result) *Result { for _, other := range others { if other != nil { r.resetCaches() - r.AddErrors(other.Errors...) - r.AddErrors(other.Warnings...) + r.carryErrors(other.Errors, other.errorLocations) + r.carryErrors(other.Warnings, other.warningLocations) r.MatchCount += other.MatchCount if other.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(other) + redeemResult(other) } } } @@ -191,11 +215,11 @@ func (r *Result) MergeAsWarnings(others ...*Result) *Result { for _, other := range others { if other != nil { r.resetCaches() - r.AddWarnings(other.Errors...) - r.AddWarnings(other.Warnings...) + r.carryWarnings(other.Errors, other.errorLocations) + r.carryWarnings(other.Warnings, other.warningLocations) r.MatchCount += other.MatchCount if other.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(other) + redeemResult(other) } } } @@ -207,39 +231,79 @@ func (r *Result) MergeAsWarnings(others ...*Result) *Result { // Since the same check may be passed several times while exploring the // spec structure (via $ref, ...) reported messages are kept // unique. +// +// Errors added this way carry no location. Validators use [Result.addErrorsAt] +// so that [Result.LocatedErrors] can tell where the failure happened. func (r *Result) AddErrors(errors ...error) { - for _, e := range errors { - found := false - if e != nil { - for _, isReported := range r.Errors { - if e.Error() == isReported.Error() { - found = true - break - } - } - if !found { - r.Errors = append(r.Errors, e) - } - } - } + r.addLocatedErrors("", errors...) } // AddWarnings adds warnings to this validation result (if not already reported). func (r *Result) AddWarnings(warnings ...error) { - for _, e := range warnings { - found := false - if e != nil { - for _, isReported := range r.Warnings { - if e.Error() == isReported.Error() { - found = true - break - } - } - if !found { - r.Warnings = append(r.Warnings, e) - } + r.addLocatedWarnings("", warnings...) +} + +// isReportedError tells if the same message is already part of a collection. +func isReportedError(reported []error, e error) bool { + msg := e.Error() + for _, isReported := range reported { + if msg == isReported.Error() { + return true } } + + return false +} + +// locationAt reads a location out of a slice that may be shorter than the +// errors it describes. +func locationAt(locations []string, i int) string { + if i < len(locations) { + return locations[i] + } + + return "" +} + +// appendLocation records the location of the error that has just been appended, +// keeping the location slice aligned with the error slice it describes. +// +// Errors may reach a Result without going through the methods here (a caller +// assigning Errors directly, say), so the slice is padded rather than assumed +// to be in step. +func appendLocation(locations []string, upTo int, pointer string) []string { + for len(locations) < upTo-1 { + locations = append(locations, "") + } + + return append(locations, pointer) +} + +// LocatedErrors returns the reported errors, each paired with the JSON pointer +// of the value that caused it. +// +// The pointer is empty whenever the location is unknown, so callers should +// treat it as a hint and keep using the error message as the primary report. +func (r *Result) LocatedErrors() []Located { + return locate(r.Errors, r.errorLocations) +} + +// LocatedWarnings returns the reported warnings, each paired with the JSON +// pointer of the value that caused it. +func (r *Result) LocatedWarnings() []Located { + return locate(r.Warnings, r.warningLocations) +} + +func locate(errs []error, locations []string) []Located { + located := make([]Located, len(errs)) + for i, err := range errs { + located[i] = Located{Err: err} + if i < len(locations) { + located[i].Pointer = locations[i] + } + } + + return located } // IsValid returns true when this result is valid. @@ -298,6 +362,106 @@ func (r *Result) AsError() error { return errors.CompositeValidationError(r.Errors...) } +// Reset clears this result so it may be reused, keeping allocated capacity. +// +// It implements the hook the pool calls when a result is borrowed and when it +// is redeemed. Calling it on a result still in use loses its findings. +func (r *Result) Reset() { + _ = r.cleared() +} + +// addErrorsAt adds errors located at the given path. +func (r *Result) addErrorsAt(at pathSegments, errors ...error) { + r.addLocatedErrors(at.pointer(), errors...) +} + +// addWarningsAt adds warnings located at the given path. +func (r *Result) addWarningsAt(at pathSegments, warnings ...error) { + r.addLocatedWarnings(at.pointer(), warnings...) +} + +func (r *Result) addLocatedErrors(pointer string, errors ...error) { + for _, e := range errors { + if e == nil { + continue + } + + if isReportedError(r.Errors, e) { + continue + } + + r.Errors = append(r.Errors, e) + r.errorLocations = appendLocation(r.errorLocations, len(r.Errors), pointer) + } +} + +func (r *Result) addLocatedWarnings(pointer string, warnings ...error) { + for _, e := range warnings { + if e == nil { + continue + } + + if isReportedError(r.Warnings, e) { + continue + } + + r.Warnings = append(r.Warnings, e) + r.warningLocations = appendLocation(r.warningLocations, len(r.Warnings), pointer) + } +} + +// relocate rewrites every location this result recorded. +// +// The parameter and header validators are the ones a generated client uses at +// runtime, so they locate a finding by the name of the parameter or header it +// concerns: a name is all the caller has. When spec validation borrows them to +// check a default or an example, that name addresses nothing in the document, +// and the value's own node is the best location available for everything the +// borrowed validator found. +func (r *Result) relocate(at pathSegments) { + if r == nil { + return + } + + pointer := at.pointer() + r.errorLocations = fillLocations(r.errorLocations[:0], len(r.Errors), pointer) + r.warningLocations = fillLocations(r.warningLocations[:0], len(r.Warnings), pointer) +} + +// fillLocations records the same location for a whole run of findings. +func fillLocations(locations []string, count int, pointer string) []string { + for range count { + locations = append(locations, pointer) + } + + return locations +} + +// redirect rewrites every location this result recorded with the given mapping. +func (r *Result) redirect(through func(string) string) { + for i, pointer := range r.errorLocations { + r.errorLocations[i] = through(pointer) + } + for i, pointer := range r.warningLocations { + r.warningLocations[i] = through(pointer) + } +} + +// carryErrors adds errors from another result as errors, one by one, so that +// each keeps the location that result recorded for it. +func (r *Result) carryErrors(errs []error, locations []string) { + for i, e := range errs { + r.addLocatedErrors(locationAt(locations, i), e) + } +} + +// carryWarnings adds errors from another result as warnings, keeping locations. +func (r *Result) carryWarnings(errs []error, locations []string) { + for i, e := range errs { + r.addLocatedWarnings(locationAt(locations, i), e) + } +} + func (r *Result) resetCaches() { r.cachedFieldSchemata = nil r.cachedItemSchemata = nil @@ -324,7 +488,7 @@ func (r *Result) mergeForField(obj map[string]any, field string, other *Result) }) } if other.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(other) + redeemResult(other) } return r @@ -352,7 +516,7 @@ func (r *Result) mergeForSlice(slice reflect.Value, i int, other *Result) *Resul } if other.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(other) + redeemResult(other) } return r @@ -391,8 +555,8 @@ func (r *Result) addSliceSchemata(slice reflect.Value, i int, schema *spec.Schem // mergeWithoutRootSchemata merges other into r, ignoring the rootObject schemata. func (r *Result) mergeWithoutRootSchemata(other *Result) { r.resetCaches() - r.AddErrors(other.Errors...) - r.AddWarnings(other.Warnings...) + r.carryErrors(other.Errors, other.errorLocations) + r.carryWarnings(other.Warnings, other.warningLocations) r.MatchCount += other.MatchCount if other.fieldSchemata != nil { @@ -438,32 +602,40 @@ func (r *Result) keepRelevantErrors() *Result { // codes would require to change a lot here. So, for the moment, let's go with // placeholders. strippedErrors := []error{} - for _, e := range r.Errors { + strippedErrorLocations := []string{} + for i, e := range r.Errors { if isImportant(e) { strippedErrors = append(strippedErrors, stripImportantTag(e)) + strippedErrorLocations = append(strippedErrorLocations, locationAt(r.errorLocations, i)) } } strippedWarnings := []error{} - for _, e := range r.Warnings { + strippedWarningLocations := []string{} + for i, e := range r.Warnings { if isImportant(e) { strippedWarnings = append(strippedWarnings, stripImportantTag(e)) + strippedWarningLocations = append(strippedWarningLocations, locationAt(r.warningLocations, i)) } } var strippedResult *Result if r.wantsRedeemOnMerge { - strippedResult = pools.poolOfResults.BorrowResult() + strippedResult = validatorPools.results.Borrow() } else { strippedResult = new(Result) } strippedResult.Errors = strippedErrors + strippedResult.errorLocations = strippedErrorLocations strippedResult.Warnings = strippedWarnings + strippedResult.warningLocations = strippedWarningLocations return strippedResult } func (r *Result) cleared() *Result { // clear the Result to be reusable. Keep allocated capacity. r.Errors = r.Errors[:0] + r.errorLocations = r.errorLocations[:0] r.Warnings = r.Warnings[:0] + r.warningLocations = r.warningLocations[:0] r.MatchCount = 0 r.data = nil r.rootObjectSchemata.one = nil diff --git a/vendor/github.com/go-openapi/validate/schema.go b/vendor/github.com/go-openapi/validate/schema.go index 706b7f5ef..9b49007b5 100644 --- a/vendor/github.com/go-openapi/validate/schema.go +++ b/vendor/github.com/go-openapi/validate/schema.go @@ -15,7 +15,17 @@ import ( // SchemaValidator validates data against a JSON schema. type SchemaValidator struct { - Path string + // Path is the location of the validated value, in the legacy dot-separated + // notation. It is what surfaces as the name of a validation error. + // + // Deprecated: a dotted path is ambiguous whenever a property name contains + // a dot. Prefer the JSON pointer rendering of the same location. + Path string + + // path is the same location, kept as JSON pointer reference tokens so that + // children may be derived from it unambiguously. + path pathSegments + in string Schema *spec.Schema validators [8]valueValidator @@ -32,7 +42,7 @@ func AgainstSchema(schema *spec.Schema, data any, formats strfmt.Registry, optio append(options, WithRecycleValidators(true), withRecycleResults(true))..., ).Validate(data) defer func() { - pools.poolOfResults.RedeemResult(res) + redeemResult(res) }() if res.HasErrors() { @@ -51,10 +61,39 @@ func NewSchemaValidator(schema *spec.Schema, rootSchema any, root string, format o(opts) } - return newSchemaValidator(schema, rootSchema, root, formats, opts) + // the caller still owns this schema, and validation expands what it walks: work on a copy, + // once, here - every validator below this one is then free to expand in place + if !opts.ownSchemata && schema != nil { + cloned, err := deepCloneSchema(*schema) + if err != nil { + panic(invalidSchemaProvidedMsg(err).Error()) + } + + if rootSchema == schema { + rootSchema = &cloned + } + + schema = &cloned + opts.ownSchemata = true + } + + return newSchemaValidator(schema, rootSchema, rootPathFromString(root), formats, opts) } -func newSchemaValidator(schema *spec.Schema, rootSchema any, root string, formats strfmt.Registry, opts *SchemaValidatorOptions) *SchemaValidator { +// rootPathFromString interprets the root path of the exported constructors. +// +// The caller hands over an opaque string, so there is no telling which of its +// dots are separators and which belong to a name: it is taken as a single +// reference token. +func rootPathFromString(root string) pathSegments { + if root == "" { + return rootPath() + } + + return newPathSegments(root) +} + +func newSchemaValidator(schema *spec.Schema, rootSchema any, root pathSegments, formats strfmt.Registry, opts *SchemaValidatorOptions) *SchemaValidator { if schema == nil { return nil } @@ -77,12 +116,13 @@ func newSchemaValidator(schema *spec.Schema, rootSchema any, root string, format var s *SchemaValidator if opts.recycleValidators { - s = pools.poolOfSchemaValidators.BorrowValidator() + s = validatorPools.schemaValidators.Borrow() } else { s = new(SchemaValidator) } - s.Path = root + s.path = root + s.Path = root.dotted() s.in = "body" s.Schema = schema s.Root = rootSchema @@ -104,8 +144,11 @@ func newSchemaValidator(schema *spec.Schema, rootSchema any, root string, format } // SetPath sets the path for this schema validator. +// +// Note that the sub-validators are built when the validator is created, so +// this only affects errors reported by this validator, not by its children. func (s *SchemaValidator) SetPath(path string) { - s.Path = path + s.setPath(rootPathFromString(path)) } // Applies returns true when this schema validator applies. @@ -131,7 +174,7 @@ func (s *SchemaValidator) Validate(data any) *Result { var result *Result if s.Options.recycleResult { - result = pools.poolOfResults.BorrowResult() + result = validatorPools.results.Borrow() result.data = data } else { result = &Result{data: data} @@ -169,7 +212,7 @@ func (s *SchemaValidator) Validate(data any) *Result { // to map[string]interface{}. var dd any if err := jsonutils.FromDynamicJSON(data, &dd); err != nil { - result.AddErrors(err) + result.addErrorsAt(s.path, err) result.Inc() return result @@ -185,7 +228,7 @@ func (s *SchemaValidator) Validate(data any) *Result { if s.Schema.Type.Contains(integerType) { // avoid lossy conversion in, erri := num.Int64() if erri != nil { - result.AddErrors(invalidTypeConversionMsg(s.Path, erri)) + result.addErrorsAt(s.path, invalidTypeConversionMsg(s.Path, erri)) result.Inc() return result @@ -194,7 +237,7 @@ func (s *SchemaValidator) Validate(data any) *Result { } else { nf, errf := num.Float64() if errf != nil { - result.AddErrors(invalidTypeConversionMsg(s.Path, errf)) + result.addErrorsAt(s.path, invalidTypeConversionMsg(s.Path, errf)) result.Inc() return result @@ -235,7 +278,7 @@ func (s *SchemaValidator) Validate(data any) *Result { func (s *SchemaValidator) typeValidator() valueValidator { return newTypeValidator( - s.Path, + s.path, s.in, s.Schema.Type, s.Schema.Nullable, @@ -246,7 +289,7 @@ func (s *SchemaValidator) typeValidator() valueValidator { func (s *SchemaValidator) commonValidator() valueValidator { return newBasicCommonValidator( - s.Path, + s.path, s.in, s.Schema.Default, s.Schema.Enum, @@ -256,7 +299,7 @@ func (s *SchemaValidator) commonValidator() valueValidator { func (s *SchemaValidator) sliceValidator() valueValidator { return newSliceValidator( - s.Path, + s.path, s.in, s.Schema.MaxItems, s.Schema.MinItems, @@ -271,7 +314,7 @@ func (s *SchemaValidator) sliceValidator() valueValidator { func (s *SchemaValidator) numberValidator() valueValidator { return newNumberValidator( - s.Path, + s.path, s.in, s.Schema.Default, s.Schema.MultipleOf, @@ -287,7 +330,7 @@ func (s *SchemaValidator) numberValidator() valueValidator { func (s *SchemaValidator) stringValidator() valueValidator { return newStringValidator( - s.Path, + s.path, s.in, nil, false, @@ -301,7 +344,7 @@ func (s *SchemaValidator) stringValidator() valueValidator { func (s *SchemaValidator) formatValidator() valueValidator { return newFormatValidator( - s.Path, + s.path, s.in, s.Schema.Format, s.KnownFormats, @@ -312,14 +355,14 @@ func (s *SchemaValidator) formatValidator() valueValidator { func (s *SchemaValidator) schemaPropsValidator() valueValidator { sch := s.Schema return newSchemaPropsValidator( - s.Path, s.in, sch.AllOf, sch.OneOf, sch.AnyOf, sch.Not, sch.Dependencies, s.Root, s.KnownFormats, + s.path, s.in, sch.AllOf, sch.OneOf, sch.AnyOf, sch.Not, sch.Dependencies, s.Root, s.KnownFormats, s.Options, ) } func (s *SchemaValidator) objectValidator() valueValidator { return newObjectValidator( - s.Path, + s.path, s.in, s.Schema.MaxProperties, s.Schema.MinProperties, @@ -333,8 +376,13 @@ func (s *SchemaValidator) objectValidator() valueValidator { ) } +func (s *SchemaValidator) setPath(path pathSegments) { + s.path = path + s.Path = path.dotted() +} + func (s *SchemaValidator) redeem() { - pools.poolOfSchemaValidators.RedeemValidator(s) + validatorPools.schemaValidators.Redeem(s) } func (s *SchemaValidator) redeemChildren() { diff --git a/vendor/github.com/go-openapi/validate/schema_option.go b/vendor/github.com/go-openapi/validate/schema_option.go index 3ca489c0f..09a03eba1 100644 --- a/vendor/github.com/go-openapi/validate/schema_option.go +++ b/vendor/github.com/go-openapi/validate/schema_option.go @@ -18,6 +18,15 @@ type SchemaValidatorOptions struct { recycleResult bool skipSchemataResult bool pathLoaderWithOptions func(string, ...loading.Option) (json.RawMessage, error) + + // ownSchemata tells the validators that the schemata they walk are theirs to rewrite. + // + // Validation expands every schema carrying a $ref or an id, and expansion rewrites what it is + // given. The copy that makes this safe is taken once, at the entry point - the whole document + // in [SpecValidator.Validate], the single schema in [NewSchemaValidator] - because a copy per + // schema multiplies with the recursion, and because parameters, path items and responses + // expand too, not only schemata. + ownSchemata bool } // Option sets optional rules for schema validation. diff --git a/vendor/github.com/go-openapi/validate/schema_props.go b/vendor/github.com/go-openapi/validate/schema_props.go index 2c4354d08..d7ecb14ce 100644 --- a/vendor/github.com/go-openapi/validate/schema_props.go +++ b/vendor/github.com/go-openapi/validate/schema_props.go @@ -12,7 +12,7 @@ import ( ) type schemaPropsValidator struct { - Path string + Path pathSegments In string AllOf []spec.Schema OneOf []spec.Schema @@ -28,12 +28,8 @@ type schemaPropsValidator struct { Options *SchemaValidatorOptions } -func (s *schemaPropsValidator) SetPath(path string) { - s.Path = path -} - func newSchemaPropsValidator( - path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root any, formats strfmt.Registry, + path pathSegments, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root any, formats strfmt.Registry, opts *SchemaValidatorOptions, ) *schemaPropsValidator { if opts == nil { @@ -60,7 +56,7 @@ func newSchemaPropsValidator( var s *schemaPropsValidator if opts.recycleValidators { - s = pools.poolOfSchemaPropsValidators.BorrowValidator() + s = validatorPools.schemaPropsValidators.Borrow() } else { s = new(schemaPropsValidator) } @@ -91,7 +87,7 @@ func (s *schemaPropsValidator) Applies(source any, _ reflect.Kind) bool { func (s *schemaPropsValidator) Validate(data any) *Result { var mainResult *Result if s.Options.recycleResult { - mainResult = pools.poolOfResults.BorrowResult() + mainResult = validatorPools.results.Borrow() } else { mainResult = new(Result) } @@ -111,17 +107,17 @@ func (s *schemaPropsValidator) Validate(data any) *Result { } if len(s.anyOfValidators) > 0 { - keepResultAnyOf = pools.poolOfResults.BorrowResult() + keepResultAnyOf = validatorPools.results.Borrow() s.validateAnyOf(data, mainResult, keepResultAnyOf) } if len(s.oneOfValidators) > 0 { - keepResultOneOf = pools.poolOfResults.BorrowResult() + keepResultOneOf = validatorPools.results.Borrow() s.validateOneOf(data, mainResult, keepResultOneOf) } if len(s.allOfValidators) > 0 { - keepResultAllOf = pools.poolOfResults.BorrowResult() + keepResultAllOf = validatorPools.results.Borrow() s.validateAllOf(data, mainResult, keepResultAllOf) } @@ -154,7 +150,7 @@ func (s *schemaPropsValidator) validateAnyOf(data any, mainResult, keepResultAny if result.IsValid() { if bestFailures != nil && bestFailures.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(bestFailures) + redeemResult(bestFailures) } _ = keepResultAnyOf.cleared() @@ -166,7 +162,7 @@ func (s *schemaPropsValidator) validateAnyOf(data any, mainResult, keepResultAny // MatchCount is used to select errors from the schema with most positive checks if bestFailures == nil || result.MatchCount > bestFailures.MatchCount { if bestFailures != nil && bestFailures.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(bestFailures) + redeemResult(bestFailures) } bestFailures = result @@ -174,11 +170,11 @@ func (s *schemaPropsValidator) validateAnyOf(data any, mainResult, keepResultAny } if result.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(result) // this result is ditched + redeemResult(result) // this result is ditched } } - mainResult.AddErrors(mustValidateAtLeastOneSchemaMsg(s.Path)) + mainResult.addErrorsAt(s.Path, mustValidateAtLeastOneSchemaMsg(s.Path.dotted())) mainResult.Merge(bestFailures) } @@ -205,7 +201,7 @@ func (s *schemaPropsValidator) validateOneOf(data any, mainResult, keepResultOne if firstSuccess == nil { firstSuccess = result } else if result.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(result) // this result is ditched + redeemResult(result) // this result is ditched } continue @@ -214,29 +210,29 @@ func (s *schemaPropsValidator) validateOneOf(data any, mainResult, keepResultOne // MatchCount is used to select errors from the schema with most positive checks if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) { if bestFailures != nil && bestFailures.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(bestFailures) + redeemResult(bestFailures) } bestFailures = result } else if result.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(result) // this result is ditched + redeemResult(result) // this result is ditched } } switch validated { case 0: - mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, "Found none valid")) + mainResult.addErrorsAt(s.Path, mustValidateOnlyOneSchemaMsg(s.Path.dotted(), "Found none valid")) mainResult.Merge(bestFailures) // firstSucess necessarily nil case 1: mainResult.Merge(firstSuccess) if bestFailures != nil && bestFailures.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(bestFailures) + redeemResult(bestFailures) } default: - mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, fmt.Sprintf("Found %d valid alternatives", validated))) + mainResult.addErrorsAt(s.Path, mustValidateOnlyOneSchemaMsg(s.Path.dotted(), fmt.Sprintf("Found %d valid alternatives", validated))) mainResult.Merge(bestFailures) if firstSuccess != nil && firstSuccess.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(firstSuccess) + redeemResult(firstSuccess) } } } @@ -260,10 +256,10 @@ func (s *schemaPropsValidator) validateAllOf(data any, mainResult, keepResultAll switch validated { case 0: - mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, ". None validated")) + mainResult.addErrorsAt(s.Path, mustValidateAllSchemasMsg(s.Path.dotted(), ". None validated")) case len(s.allOfValidators): default: - mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, "")) + mainResult.addErrorsAt(s.Path, mustValidateAllSchemasMsg(s.Path.dotted(), "")) } } @@ -274,16 +270,16 @@ func (s *schemaPropsValidator) validateNot(data any, mainResult *Result) { } // We keep inner IMPORTANT! errors no matter what MatchCount tells us if result.IsValid() { - mainResult.AddErrors(mustNotValidatechemaMsg(s.Path)) + mainResult.addErrorsAt(s.Path, mustNotValidatechemaMsg(s.Path.dotted())) } if result.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(result) // this result is ditched + redeemResult(result) // this result is ditched } } func (s *schemaPropsValidator) validateDependencies(data any, mainResult *Result) { val := data.(map[string]any) //nolint:forcetypeassert // caller guarantees map[string]any - for key := range val { + for _, key := range sortedKeys(val) { dep, ok := s.Dependencies[key] if !ok { continue @@ -291,7 +287,7 @@ func (s *schemaPropsValidator) validateDependencies(data any, mainResult *Result if dep.Schema != nil { mainResult.Merge( - newSchemaValidator(dep.Schema, s.Root, s.Path+"."+key, s.KnownFormats, s.Options).Validate(data), + newSchemaValidator(dep.Schema, s.Root, s.Path.child(key), s.KnownFormats, s.Options).Validate(data), ) continue } @@ -299,15 +295,19 @@ func (s *schemaPropsValidator) validateDependencies(data any, mainResult *Result if len(dep.Property) > 0 { for _, depKey := range dep.Property { if _, ok := val[depKey]; !ok { - mainResult.AddErrors(hasADependencyMsg(s.Path, depKey)) + mainResult.addErrorsAt(s.Path, hasADependencyMsg(s.Path.dotted(), depKey)) } } } } } +func (s *schemaPropsValidator) setPath(path pathSegments) { + s.Path = path +} + func (s *schemaPropsValidator) redeem() { - pools.poolOfSchemaPropsValidators.RedeemValidator(s) + validatorPools.schemaPropsValidators.Redeem(s) } func (s *schemaPropsValidator) redeemChildren() { diff --git a/vendor/github.com/go-openapi/validate/security_requirements.go b/vendor/github.com/go-openapi/validate/security_requirements.go new file mode 100644 index 000000000..b6c10f3b2 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/security_requirements.go @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "strings" + + "github.com/go-openapi/spec" +) + +// validateSecurityRequirements checks the security requirements declared by the document and by +// each of its operations against the security definitions. +// +// A requirement names a security scheme and lists the scopes an operation needs from it: +// +// security: +// - petstore_auth: [ "write:pets" ] +// - api_key: [] +// +// Three rules apply: +// +// - the name must be declared in securityDefinitions (error) +// - only an oauth2 requirement carries scopes; every other scheme type must list none (error) +// - an oauth2 requirement should only name scopes its scheme declares (warning) +// +// The JSON meta-schema types a requirement as an object of string arrays and never reads +// securityDefinitions, so it can express none of the three. +// +// An empty requirement object ({}) names no scheme and passes. So does an empty security array, +// which an operation uses to drop the requirements the document sets for every operation. +func (s *SpecValidator) validateSecurityRequirements() *Result { + res := validatorPools.results.Borrow() + definitions := s.spec.Spec().SecurityDefinitions + + res.Merge(checkSecurityRequirements( + newPathSegments(swaggerSecurity), + s.spec.Spec().Security, + definitions, + )) + + operations := s.expandedAnalyzer().Operations() + for _, method := range sortedKeys(operations) { + byPath := operations[method] + for _, path := range sortedKeys(byPath) { + op := byPath[path] + if op == nil { + continue + } + + res.Merge(checkSecurityRequirements( + operationPath(path, method).child(swaggerSecurity), + op.Security, + definitions, + )) + } + } + + return res +} + +// checkSecurityRequirements checks the list of security requirements held at the given location. +// +// Requirements are checked in the order the document lists them, and the schemes one requirement +// names in sorted order: a requirement is a map, so the document's own order is lost (see +// [sortedKeys]). +func checkSecurityRequirements(at pathSegments, requirements []map[string][]string, definitions spec.SecurityDefinitions) *Result { + res := validatorPools.results.Borrow() + + for i, requirement := range requirements { + for _, name := range sortedKeys(requirement) { + scopes := requirement[name] + schemeAt := at.item(i).child(name) + + scheme, isDeclared := definitions[name] + if !isDeclared || scheme == nil { + res.addErrorsAt(schemeAt, securitySchemeNotDeclaredMsg(name)) + + continue + } + + if scheme.Type != securitySchemeOAuth2 { + if len(scopes) > 0 { + res.addErrorsAt(schemeAt, securityScopesNotEmptyMsg(name, strings.Join(scopes, ", "), scheme.Type)) + } + + continue + } + + for _, scope := range scopes { + if _, isKnown := scheme.Scopes[scope]; !isKnown { + res.addWarningsAt(schemeAt, securityScopeNotDeclaredMsg(name, scope)) + } + } + } + } + + return res +} diff --git a/vendor/github.com/go-openapi/validate/slice_validator.go b/vendor/github.com/go-openapi/validate/slice_validator.go index 8f49d1370..0a0ee7402 100644 --- a/vendor/github.com/go-openapi/validate/slice_validator.go +++ b/vendor/github.com/go-openapi/validate/slice_validator.go @@ -4,7 +4,6 @@ package validate import ( - "fmt" "reflect" "github.com/go-openapi/spec" @@ -12,7 +11,7 @@ import ( ) type schemaSliceValidator struct { - Path string + Path pathSegments In string MaxItems *int64 MinItems *int64 @@ -24,7 +23,7 @@ type schemaSliceValidator struct { Options *SchemaValidatorOptions } -func newSliceValidator(path, in string, +func newSliceValidator(path pathSegments, in string, maxItems, minItems *int64, uniqueItems bool, additionalItems *spec.SchemaOrBool, items *spec.SchemaOrArray, root any, formats strfmt.Registry, opts *SchemaValidatorOptions, @@ -35,7 +34,7 @@ func newSliceValidator(path, in string, var v *schemaSliceValidator if opts.recycleValidators { - v = pools.poolOfSliceValidators.BorrowValidator() + v = validatorPools.sliceValidators.Borrow() } else { v = new(schemaSliceValidator) } @@ -54,10 +53,6 @@ func newSliceValidator(path, in string, return v } -func (s *schemaSliceValidator) SetPath(path string) { - s.Path = path -} - func (s *schemaSliceValidator) Applies(source any, kind reflect.Kind) bool { _, ok := source.(*spec.Schema) r := ok && kind == reflect.Slice @@ -73,7 +68,7 @@ func (s *schemaSliceValidator) Validate(data any) *Result { var result *Result if s.Options.recycleResult { - result = pools.poolOfResults.BorrowResult() + result = validatorPools.results.Borrow() } else { result = new(Result) } @@ -85,8 +80,10 @@ func (s *schemaSliceValidator) Validate(data any) *Result { if s.Items != nil && s.Items.Schema != nil { for i := range size { - validator := newSchemaValidator(s.Items.Schema, s.Root, s.Path, s.KnownFormats, s.Options) - validator.SetPath(fmt.Sprintf("%s.%d", s.Path, i)) + // the index has to reach the constructor: the sub-validators that + // report the error are built there, and setting the path afterwards + // would leave them located on the array rather than on the item. + validator := newSchemaValidator(s.Items.Schema, s.Root, s.Path.item(i), s.KnownFormats, s.Options) value := val.Index(i) result.mergeForSlice(val, i, validator.Validate(value.Interface())) } @@ -100,41 +97,45 @@ func (s *schemaSliceValidator) Validate(data any) *Result { break } - validator := newSchemaValidator(&s.Items.Schemas[i], s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats, s.Options) + validator := newSchemaValidator(&s.Items.Schemas[i], s.Root, s.Path.item(i), s.KnownFormats, s.Options) result.mergeForSlice(val, i, validator.Validate(val.Index(i).Interface())) } } if s.AdditionalItems != nil && itemsSize < size { if s.Items != nil && len(s.Items.Schemas) > 0 && !s.AdditionalItems.Allows { - result.AddErrors(arrayDoesNotAllowAdditionalItemsMsg()) + result.addErrorsAt(s.Path, arrayDoesNotAllowAdditionalItemsMsg()) } if s.AdditionalItems.Schema != nil { for i := itemsSize; i < size-itemsSize+1; i++ { - validator := newSchemaValidator(s.AdditionalItems.Schema, s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats, s.Options) + validator := newSchemaValidator(s.AdditionalItems.Schema, s.Root, s.Path.item(i), s.KnownFormats, s.Options) result.mergeForSlice(val, i, validator.Validate(val.Index(i).Interface())) } } } if s.MinItems != nil { - if err := MinItems(s.Path, s.In, int64(size), *s.MinItems); err != nil { - result.AddErrors(err) + if err := MinItems(s.Path.dotted(), s.In, int64(size), *s.MinItems); err != nil { + result.addErrorsAt(s.Path, err) } } if s.MaxItems != nil { - if err := MaxItems(s.Path, s.In, int64(size), *s.MaxItems); err != nil { - result.AddErrors(err) + if err := MaxItems(s.Path.dotted(), s.In, int64(size), *s.MaxItems); err != nil { + result.addErrorsAt(s.Path, err) } } if s.UniqueItems { - if err := UniqueItems(s.Path, s.In, val.Interface()); err != nil { - result.AddErrors(err) + if err := UniqueItems(s.Path.dotted(), s.In, val.Interface()); err != nil { + result.addErrorsAt(s.Path, err) } } result.Inc() return result } +func (s *schemaSliceValidator) setPath(path pathSegments) { + s.Path = path +} + func (s *schemaSliceValidator) redeem() { - pools.poolOfSliceValidators.RedeemValidator(s) + validatorPools.sliceValidators.Redeem(s) } diff --git a/vendor/github.com/go-openapi/validate/sorted.go b/vendor/github.com/go-openapi/validate/sorted.go new file mode 100644 index 000000000..829a042c6 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/sorted.go @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package validate + +import ( + "cmp" + "maps" + "slices" + "strings" + + "github.com/go-openapi/spec" +) + +// sortedKeys returns the keys of a map in ascending order. +// +// Findings are reported in the order the checks walk the document, and several +// of them walk a map: definitions, paths, response codes, headers, properties. +// Go randomises map iteration, so the same bytes validated twice would list +// their findings in a different order — and where a check stops on the first +// fault it meets, would name a different offender altogether. +// +// Walking keys in sorted order makes both defined: findings come out in +// definition-name (or path, or status-code) order, on every run. +func sortedKeys[K cmp.Ordered, V any](m map[K]V) []K { + return slices.Sorted(maps.Keys(m)) +} + +// sortedRefs orders references by the location they point at. +// +// The analyzer gathers references in a map, so the slice it hands back comes +// out in a different order on every run. See [sortedKeys]. +func sortedRefs(refs []spec.Ref) []spec.Ref { + slices.SortFunc(refs, func(a, b spec.Ref) int { + return strings.Compare(a.String(), b.String()) + }) + + return refs +} diff --git a/vendor/github.com/go-openapi/validate/spec.go b/vendor/github.com/go-openapi/validate/spec.go index d6a61eae2..133752345 100644 --- a/vendor/github.com/go-openapi/validate/spec.go +++ b/vendor/github.com/go-openapi/validate/spec.go @@ -4,8 +4,6 @@ package validate import ( - "bytes" - "encoding/gob" "encoding/json" "fmt" "slices" @@ -30,7 +28,6 @@ import ( // // - Proposal for enhancement: $ref should not have siblings // - Proposal for enhancement: make sure documentation reflects all checks and warnings -// - Proposal for enhancement: check on discriminators // - Proposal for enhancement: explicit message on unsupported keywords (better than "forbidden property"...) // - Proposal for enhancement: full list of unresolved refs // - Proposal for enhancement: validate numeric constraints (issue#581): this should be handled like defaults and examples @@ -48,13 +45,17 @@ func Spec(doc *loads.Document, formats strfmt.Registry, options ...Option) error // SpecValidator validates a swagger 2.0 spec. type SpecValidator struct { - schema *spec.Schema // swagger 2.0 schema - spec *loads.Document - analyzer *analysis.Spec - expanded *loads.Document - KnownFormats strfmt.Registry - Options Opts // validation options - schemaOptions *SchemaValidatorOptions + schema *spec.Schema // swagger 2.0 schema + spec *loads.Document + analyzer *analysis.Spec + expanded *loads.Document + refLocations refLocations + refRedirects refRedirects + paramLocations paramLocations + document any // the document as decoded, to tell what it holds + KnownFormats strfmt.Registry + Options Opts // validation options + schemaOptions *SchemaValidatorOptions } // NewSpecValidator creates a new swagger spec validator instance. @@ -96,26 +97,53 @@ func (s *SpecValidator) Validate(data any) (*Result, *Result) { errs.AddErrors(invalidDocumentMsg()) return errs, warnings // no point in continuing } + + // Validation expands what it walks - schemata, but also parameters, path items and responses - + // and expansion rewrites what it is given. Take one copy of the whole document here and work + // on that, so the caller gets back the document it handed over. Raw() still reads the bytes as + // they were authored, so the checks below that go through them are unaffected. + // + // Cloning here rather than per schema is what keeps the cost flat: a copy taken inside + // newSchemaValidator is paid again at every level of a recursive document. + raw := sd.Raw() + sd = sd.Pristine() + s.schemaOptions.ownSchemata = true s.spec = sd s.analyzer = analysis.New(sd.Spec()) + // where each $ref sits, as authored: refs are reported against the + // unexpanded document, before expansion flattens them away + s.refLocations = newRefLocations(s.analyzer) + // where each operation declares its parameters: the document addresses + // them by index, and expansion loses that + s.paramLocations = newParamLocations(sd.Spec()) + // where each $ref leads: checks walk the expanded document, and a finding + // below a $ref has to be brought back to a node the document contains + s.refRedirects = newRefRedirects(s.analyzer) // Raw spec unmarshalling errors var obj any - if err := json.Unmarshal(sd.Raw(), &obj); err != nil { + if err := json.Unmarshal(raw, &obj); err != nil { // NOTE: under normal conditions, the *load.Document has been already unmarshalled // So this one is just a paranoid check on the behavior of the spec package panic(InvalidDocumentError) } + s.document = obj defer func() { + // bring findings reached through a $ref back onto the document, then + // hold every location to what the document actually addresses + errs.redirect(s.refRedirects.through) + errs.redirect(s.resolvable) // errs holds all errors and warnings, // warnings only warnings errs.MergeAsWarnings(warnings) - warnings.AddErrors(errs.Warnings...) + // reported as errors of the warnings-only result, but keeping the + // location each was recorded with + warnings.carryErrors(errs.Warnings, errs.warningLocations) }() // Swagger schema validator - schv := newSchemaValidator(s.schema, nil, "", s.KnownFormats, s.schemaOptions) + schv := newSchemaValidator(s.schema, nil, rootPath(), s.KnownFormats, s.schemaOptions) errs.Merge(schv.Validate(obj)) // error - // There may be a point in continuing to try and determine more accurate errors if !s.Options.ContinueOnErrors && errs.HasErrors() { @@ -132,6 +160,9 @@ func (s *SpecValidator) Validate(data any) (*Result, *Result) { errs.Merge(s.validateDuplicatePropertyNames()) // error - errs.Merge(s.validateParameters()) // error - errs.Merge(s.validateItems()) // error - + errs.Merge(s.validateSecurityRequirements()) // error and warning + errs.Merge(s.validateDiscriminators()) // error - + errs.Merge(s.validateCollectionFormats()) // warning only // Properties in required definition MUST validate their schema // Properties SHOULD NOT be declared as both required and readOnly (warning) @@ -167,24 +198,25 @@ func (s *SpecValidator) SetContinueOnErrors(c bool) { } func (s *SpecValidator) validateNonEmptyPathParamNames() *Result { - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() if s.spec.Spec().Paths == nil { - // There is no Paths object: error - res.AddErrors(noValidPathMsg()) + // There is no Paths object: the document itself lacks it, so + // there is no node below it to point at + res.addErrorsAt(rootPath(), noValidPathMsg()) return res } if s.spec.Spec().Paths.Paths == nil { // Paths may be empty: warning - res.AddWarnings(noValidPathMsg()) + res.addWarningsAt(newPathSegments(swaggerPaths), noValidPathMsg()) return res } - for k := range s.spec.Spec().Paths.Paths { + for _, k := range sortedKeys(s.spec.Spec().Paths.Paths) { if strings.Contains(k, "{}") { - res.AddErrors(emptyPathParameterMsg(k)) + res.addErrorsAt(newPathSegments(swaggerPaths, k), emptyPathParameterMsg(k)) } } @@ -201,21 +233,55 @@ func (s *SpecValidator) validateDuplicateOperationIDs() *Result { // fallback on possible incomplete picture because of previous errors analyzer = s.analyzer } - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() + + // the message says how many times an identifier is used, so the count is + // what it needs; a reader needs somewhere to go, so the first operation to + // declare the identifier is remembered along with it known := make(map[string]int) - for _, v := range analyzer.OperationIDs() { - if v != "" { - known[v]++ + declaredAt := make(map[string]pathSegments) + operations := analyzer.Operations() + for _, method := range sortedKeys(operations) { + byPath := operations[method] + for _, path := range sortedKeys(byPath) { + op := byPath[path] + id := operationIdentity(method, path, op) + known[id]++ + if _, isKnown := declaredAt[id]; !isKnown { + declaredAt[id] = operationIDPath(path, method, op) + } } } - for k, v := range known { - if v > 1 { - res.AddErrors(nonUniqueOperationIDMsg(k, v)) + + for _, k := range sortedKeys(known) { + if v := known[k]; v > 1 { + res.addErrorsAt(declaredAt[k], nonUniqueOperationIDMsg(k, v)) } } return res } +// operationIdentity names an operation the way the analyzer does: by its +// operationId, or by method and path when it declares none. +func operationIdentity(method, path string, op *spec.Operation) string { + if op == nil || op.ID == "" { + return strings.ToUpper(method) + " " + path + } + + return op.ID +} + +// operationIDPath locates the operationId of an operation, or the operation +// itself when it declares none. +func operationIDPath(path, method string, op *spec.Operation) pathSegments { + at := operationPath(path, method) + if op == nil || op.ID == "" { + return at + } + + return at.child(swaggerOperationID) +} + type dupProp struct { Name string Definition string @@ -223,8 +289,10 @@ type dupProp struct { func (s *SpecValidator) validateDuplicatePropertyNames() *Result { // definition can't declare a property that's already defined by one of its ancestors - res := pools.poolOfResults.BorrowResult() - for k, sch := range s.spec.Spec().Definitions { + res := validatorPools.results.Borrow() + definitions := s.spec.Spec().Definitions + for _, k := range sortedKeys(definitions) { + sch := definitions[k] if len(sch.AllOf) == 0 { continue } @@ -238,8 +306,15 @@ func (s *SpecValidator) validateDuplicatePropertyNames() *Result { res.Merge(rec) } if len(ancs) > 0 { - res.AddErrors(circularAncestryDefinitionMsg(k, ancs)) - return res + res.addErrorsAt(newPathSegments(swaggerDefinitions, k), circularAncestryDefinitionMsg(k, ancs)) + if !s.Options.ContinueOnErrors { + return res + } + + // the ancestry loops back on itself: searching it for duplicate + // property names would not terminate, so this definition stops here + // and the next one is examined. + continue } knowns := make(map[string]struct{}) @@ -252,7 +327,7 @@ func (s *SpecValidator) validateDuplicatePropertyNames() *Result { for _, v := range dups { pns = append(pns, v.Definition+"."+v.Name) } - res.AddErrors(duplicatePropertiesMsg(k, pns)) + res.addErrorsAt(newPathSegments(swaggerDefinitions, k), duplicatePropertiesMsg(k, pns)) } } @@ -272,7 +347,7 @@ func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, schn := nm schc := &sch - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() for schc.Ref.String() != "" { // gather property names @@ -296,7 +371,7 @@ func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, return dups, res } - for k := range schc.Properties { + for _, k := range sortedKeys(schc.Properties) { _, ok := knowns[k] if ok { dups = append(dups, dupProp{Name: k, Definition: schn}) @@ -309,7 +384,7 @@ func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, } func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, knowns map[string]struct{}) ([]string, *Result) { - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() if sch.Ref.String() == "" && len(sch.AllOf) == 0 { // Safeguard. We should not be able to actually get there return nil, res @@ -360,14 +435,17 @@ func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, kno //nolint:gocognit // refactor in a forthcoming PR func (s *SpecValidator) validateItems() *Result { // validate parameter, items, schema and response objects for presence of item if type is array - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() - for method, pi := range s.analyzer.Operations() { - for path, op := range pi { + operations := s.analyzer.Operations() + for _, method := range sortedKeys(operations) { + pi := operations[method] + for _, path := range sortedKeys(pi) { + op := pi[path] for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { if param.TypeName() == arrayType && param.ItemsTypeName() == "" { - res.AddErrors(arrayInParamRequiresItemsMsg(param.Name, op.ID)) + res.addErrorsAt(s.parameterPath(path, method, param.In, param.Name), arrayInParamRequiresItemsMsg(param.Name, op.ID)) continue } if param.In != swaggerBody { @@ -375,7 +453,7 @@ func (s *SpecValidator) validateItems() *Result { items := param.Items for items.TypeName() == arrayType { if items.ItemsTypeName() == "" { - res.AddErrors(arrayInParamRequiresItemsMsg(param.Name, op.ID)) + res.addErrorsAt(s.parameterPath(path, method, param.In, param.Name), arrayInParamRequiresItemsMsg(param.Name, op.ID)) break } items = items.Items @@ -384,32 +462,22 @@ func (s *SpecValidator) validateItems() *Result { } else { // In: body if param.Schema != nil { - res.Merge(s.validateSchemaItems(*param.Schema, fmt.Sprintf("body param %q", param.Name), op.ID)) + res.Merge(s.validateSchemaItems(*param.Schema, s.parameterPath(path, method, param.In, param.Name).child(jsonSchema), + fmt.Sprintf("body param %q", param.Name), op.ID)) } } } - var responses []spec.Response - if op.Responses != nil { - if op.Responses.Default != nil { - responses = append(responses, *op.Responses.Default) - } - if op.Responses.StatusCodeResponses != nil { - for _, v := range op.Responses.StatusCodeResponses { - responses = append(responses, v) - } - } - } - - for _, resp := range responses { + for _, resp := range responsesOf(op) { + at := responsePath(path, method, resp.code) // Response headers with array - for hn, hv := range resp.Headers { - if hv.TypeName() == arrayType && hv.ItemsTypeName() == "" { - res.AddErrors(arrayInHeaderRequiresItemsMsg(hn, op.ID)) + for _, hn := range sortedKeys(resp.resp.Headers) { + if hv := resp.resp.Headers[hn]; hv.TypeName() == arrayType && hv.ItemsTypeName() == "" { + res.addErrorsAt(at.children(swaggerHeaders, hn), arrayInHeaderRequiresItemsMsg(hn, op.ID)) } } - if resp.Schema != nil { - res.Merge(s.validateSchemaItems(*resp.Schema, "response body", op.ID)) + if resp.resp.Schema != nil { + res.Merge(s.validateSchemaItems(*resp.resp.Schema, at.child(jsonSchema), "response body", op.ID)) } } } @@ -418,24 +486,24 @@ func (s *SpecValidator) validateItems() *Result { } // Verifies constraints on array type. -func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID string) *Result { - res := pools.poolOfResults.BorrowResult() +func (s *SpecValidator) validateSchemaItems(schema spec.Schema, at pathSegments, prefix, opID string) *Result { + res := validatorPools.results.Borrow() if !schema.Type.Contains(arrayType) { return res } if schema.Items == nil || schema.Items.Len() == 0 { - res.AddErrors(arrayRequiresItemsMsg(prefix, opID)) + res.addErrorsAt(at, arrayRequiresItemsMsg(prefix, opID)) return res } if schema.Items.Schema != nil { schema = *schema.Items.Schema if _, err := compileRegexp(schema.Pattern); err != nil { - res.AddErrors(invalidItemsPatternMsg(prefix, opID, schema.Pattern)) + res.addErrorsAt(at, invalidItemsPatternMsg(prefix, opID, schema.Pattern)) } - res.Merge(s.validateSchemaItems(schema, prefix, opID)) + res.Merge(s.validateSchemaItems(schema, at.child(jsonItems), prefix, opID)) } return res } @@ -443,7 +511,7 @@ func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID str func (s *SpecValidator) validatePathParamPresence(path string, fromPath, fromOperation []string) *Result { // Each defined operation path parameters must correspond to a named element in the API's path pattern. // (For example, you cannot have a path parameter named id for the following path /pets/{petId} but you must have a path parameter named petId.) - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() for _, l := range fromPath { var matched bool for _, r := range fromOperation { @@ -453,7 +521,7 @@ func (s *SpecValidator) validatePathParamPresence(path string, fromPath, fromOpe } } if !matched { - res.AddErrors(noParameterInPathMsg(l)) + res.addErrorsAt(newPathSegments(swaggerPaths, path), noParameterInPathMsg(l)) } } @@ -463,7 +531,7 @@ func (s *SpecValidator) validatePathParamPresence(path string, fromPath, fromOpe matched = true } if !matched { - res.AddErrors(pathParamNotInPathMsg(path, p)) + res.addErrorsAt(newPathSegments(swaggerPaths, path), pathParamNotInPathMsg(path, p)) } } @@ -496,9 +564,9 @@ func (s *SpecValidator) validateReferencedParameters() *Result { if len(expected) == 0 { return nil } - result := pools.poolOfResults.BorrowResult() - for k := range expected { - result.AddWarnings(unusedParamMsg(k)) + result := validatorPools.results.Borrow() + for _, k := range sortedKeys(expected) { + result.addWarningsAt(localRefPath(k), unusedParamMsg(k)) } return result } @@ -521,10 +589,12 @@ func (s *SpecValidator) validateReferencedResponses() *Result { if len(expected) == 0 { return nil } - result := pools.poolOfResults.BorrowResult() - for k := range expected { - result.AddWarnings(unusedResponseMsg(k)) + + result := validatorPools.results.Borrow() + for _, k := range sortedKeys(expected) { + result.addWarningsAt(localRefPath(k), unusedResponseMsg(k)) } + return result } @@ -548,59 +618,63 @@ func (s *SpecValidator) validateReferencedDefinitions() *Result { } result := new(Result) - for k := range expected { - result.AddWarnings(unusedDefinitionMsg(k)) + for _, k := range sortedKeys(expected) { + result.addWarningsAt(localRefPath(k), unusedDefinitionMsg(k)) } return result } func (s *SpecValidator) validateRequiredDefinitions() *Result { // Each property listed in the required array must be defined in the properties of the model - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() + + definitions := s.spec.Spec().Definitions DEFINITIONS: - for d, schema := range s.spec.Spec().Definitions { - if schema.Required != nil { // Safeguard - for _, pn := range schema.Required { - red := s.validateRequiredProperties(pn, d, &schema) //#nosec - // NOTE: capture validity before merging: Merge may redeem `red` to the - // pool (wantsRedeemOnMerge), after which reading it races with a concurrent - // BorrowResult().cleared() in another goroutine sharing the global pool. - isValid := red.IsValid() - res.Merge(red) - if !isValid && !s.Options.ContinueOnErrors { - break DEFINITIONS // there is an error, let's stop that bleeding - } - } + for _, d := range sortedKeys(definitions) { + schema := definitions[d] + red := validatorPools.results.Borrow() + keepGoing := s.walkRequired(newPathSegments(swaggerDefinitions, d), &schema, red) //#nosec + res.Merge(red) + if !keepGoing { + break DEFINITIONS // there is an error, let's stop that bleeding } } return res } -func (s *SpecValidator) validateRequiredProperties(path, in string, v *spec.Schema) *Result { +// validateRequiredProperties checks one entry of a required array. +// +// schemaAt locates the schema being searched for the property, which moves as +// the search descends into additionalProperties. requiredAt locates the entry +// of the required array that started it, and stays put. +func (s *SpecValidator) validateRequiredProperties( + path string, of schemaIdentity, schemaAt, requiredAt pathSegments, v *spec.Schema, +) *Result { + in := of.name // Takes care of recursive property definitions, which may be nested in additionalProperties schemas - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() propertyMatch := false patternMatch := false additionalPropertiesMatch := false isReadOnly := false - // Regular properties - if _, ok := v.Properties[path]; ok { + // Regular properties, including those a base definition contributes + if readOnly, declared := s.declaresProperty(v, path, maxCompositionHops); declared { propertyMatch = true - isReadOnly = v.Properties[path].ReadOnly + isReadOnly = readOnly } // NOTE: patternProperties are not supported in swagger. Even though, we continue validation here // We check all defined patterns: if one regexp is invalid, croaks an error - for pp, pv := range v.PatternProperties { + for _, pp := range sortedKeys(v.PatternProperties) { re, err := compileRegexp(pp) if err != nil { - res.AddErrors(invalidPatternMsg(pp, in)) + res.addErrorsAt(schemaAt, invalidPatternMsg(pp, in)) } else if re.MatchString(path) { patternMatch = true if !propertyMatch { - isReadOnly = pv.ReadOnly + isReadOnly = v.PatternProperties[pp].ReadOnly } } } @@ -613,7 +687,7 @@ func (s *SpecValidator) validateRequiredProperties(path, in string, v *spec.Sche // additionalProperties as schema are upported in swagger // recursively validates additionalProperties schema // Proposal for enhancement: anyOf, allOf, oneOf like in schemaPropsValidator - red := s.validateRequiredProperties(path, in, v.AdditionalProperties.Schema) + red := s.validateRequiredProperties(path, of, schemaAt.child(jsonAdditionalProperties), requiredAt, v.AdditionalProperties.Schema) if red.IsValid() { additionalPropertiesMatch = true if !propertyMatch && !patternMatch { @@ -626,11 +700,11 @@ func (s *SpecValidator) validateRequiredProperties(path, in string, v *spec.Sche } if !propertyMatch && !patternMatch && !additionalPropertiesMatch { - res.AddErrors(requiredButNotDefinedMsg(path, in)) + res.addErrorsAt(requiredAt, of.requiredButNotDefined(path)) } if isReadOnly { - res.AddWarnings(readOnlyAndRequiredMsg(in, path)) + res.addWarningsAt(requiredAt, readOnlyAndRequiredMsg(in, path)) } return res } @@ -646,26 +720,29 @@ func (s *SpecValidator) validateParameters() *Result { // - parameters with pattern property must specify valid patterns // - $ref in parameters must resolve // - path param must be required - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() rexGarbledPathSegment := mustCompileRegexp(`.*[{}\s]+.*`) - for method, pi := range s.expandedAnalyzer().Operations() { + operations := s.expandedAnalyzer().Operations() + for _, method := range sortedKeys(operations) { + pi := operations[method] methodPaths := make(map[string]map[string]string) - for path, op := range pi { + for _, path := range sortedKeys(pi) { + op := pi[path] if s.Options.StrictPathParamUniqueness { pathToAdd := pathHelp.stripParametersInPath(path) // Warn on garbled path afer param stripping if rexGarbledPathSegment.MatchString(pathToAdd) { - res.AddWarnings(pathStrippedParamGarbledMsg(pathToAdd)) + res.addWarningsAt(newPathSegments(swaggerPaths, path), pathStrippedParamGarbledMsg(pathToAdd)) } // Check uniqueness of stripped paths if _, found := methodPaths[method][pathToAdd]; found { // Sort names for stable, testable output if strings.Compare(path, methodPaths[method][pathToAdd]) < 0 { - res.AddErrors(pathOverlapMsg(path, methodPaths[method][pathToAdd])) + res.addErrorsAt(newPathSegments(swaggerPaths, path), pathOverlapMsg(path, methodPaths[method][pathToAdd])) } else { - res.AddErrors(pathOverlapMsg(methodPaths[method][pathToAdd], path)) + res.addErrorsAt(newPathSegments(swaggerPaths, path), pathOverlapMsg(methodPaths[method][pathToAdd], path)) } } else { if _, found := methodPaths[method]; !found { @@ -697,10 +774,10 @@ func (s *SpecValidator) validateParameters() *Result { for _, pr := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { // An expanded parameter must validate the Parameter schema (an unexpanded $ref always passes high-level schema validation) - schv := newSchemaValidator(¶mSchema, s.schema, fmt.Sprintf("%s.%s.parameters.%s", path, method, pr.Name), s.KnownFormats, s.schemaOptions) + schv := newSchemaValidator(¶mSchema, s.schema, s.parameterPath(path, method, pr.In, pr.Name), s.KnownFormats, s.schemaOptions) var obj any if err := jsonutils.FromDynamicJSON(pr, &obj); err != nil { - res.AddErrors(err) + res.addErrorsAt(s.parameterPath(path, method, pr.In, pr.Name), err) return res } @@ -709,7 +786,7 @@ func (s *SpecValidator) validateParameters() *Result { // Validate pattern regexp for parameters with a Pattern property if _, err := compileRegexp(pr.Pattern); err != nil { - res.AddErrors(invalidPatternInParamMsg(op.ID, pr.Name, pr.Pattern)) + res.addErrorsAt(s.parameterPath(path, method, pr.In, pr.Name), invalidPatternInParamMsg(op.ID, pr.Name, pr.Pattern)) } // There must be at most one parameter in body: list them all @@ -722,7 +799,7 @@ func (s *SpecValidator) validateParameters() *Result { paramNames = append(paramNames, pr.Name) // Path declared in path must have the required: true property if !pr.Required { - res.AddErrors(pathParamRequiredMsg(op.ID, pr.Name)) + res.addErrorsAt(s.parameterPath(path, method, pr.In, pr.Name), pathParamRequiredMsg(op.ID, pr.Name)) } } @@ -733,31 +810,31 @@ func (s *SpecValidator) validateParameters() *Result { if pr.Type != numberType && pr.Type != integerType && (pr.Maximum != nil || pr.Minimum != nil || pr.MultipleOf != nil) { // A non-numeric parameter has validation keywords for numeric instances (number and integer) - res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type)) + res.addWarningsAt(s.parameterPath(path, method, pr.In, pr.Name), parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type)) } if pr.Type != stringType && // A non-string parameter has validation keywords for strings (pr.MaxLength != nil || pr.MinLength != nil || pr.Pattern != "") { - res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type)) + res.addWarningsAt(s.parameterPath(path, method, pr.In, pr.Name), parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type)) } if pr.Type != arrayType && // A non-array parameter has validation keywords for arrays (pr.MaxItems != nil || pr.MinItems != nil || pr.UniqueItems) { - res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type)) + res.addWarningsAt(s.parameterPath(path, method, pr.In, pr.Name), parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type)) } } // In:formData and In:body are mutually exclusive if hasBody && hasForm { - res.AddErrors(bothFormDataAndBodyMsg(op.ID)) + res.addErrorsAt(operationPath(path, method), bothFormDataAndBodyMsg(op.ID)) } // There must be at most one body param // Accurately report situations when more than 1 body param is declared (possibly unnamed) if len(bodyParams) > 1 { sort.Strings(bodyParams) - res.AddErrors(multipleBodyParamMsg(op.ID, bodyParams)) + res.addErrorsAt(operationPath(path, method), multipleBodyParamMsg(op.ID, bodyParams)) } // Check uniqueness of parameters in path @@ -765,7 +842,7 @@ func (s *SpecValidator) validateParameters() *Result { for i, p := range paramsInPath { for j, q := range paramsInPath { if p == q && i > j { - res.AddErrors(pathParamNotUniqueMsg(path, p, q)) + res.addErrorsAt(newPathSegments(swaggerPaths, path), pathParamNotUniqueMsg(path, p, q)) break } } @@ -775,7 +852,7 @@ func (s *SpecValidator) validateParameters() *Result { rexGarbledParam := mustCompileRegexp(`{.*[{}\s]+.*}`) for _, p := range paramsInPath { if rexGarbledParam.MatchString(p) { - res.AddWarnings(pathParamGarbledMsg(path, p)) + res.addWarningsAt(newPathSegments(swaggerPaths, path), pathParamGarbledMsg(path, p)) } } @@ -788,10 +865,10 @@ func (s *SpecValidator) validateParameters() *Result { func (s *SpecValidator) validateReferencesValid() *Result { // each reference must point to a valid object - res := pools.poolOfResults.BorrowResult() - for _, r := range s.analyzer.AllRefs() { + res := validatorPools.results.Borrow() + for _, r := range sortedRefs(s.analyzer.AllRefs()) { if !r.IsValidURI(s.spec.SpecFilePath()) { // Safeguard - spec should always yield a valid URI - res.AddErrors(invalidRefMsg(r.String())) + res.addErrorsAt(s.refLocations.at(r.String()), invalidRefMsg(r.String())) } } if !res.HasErrors() { @@ -803,13 +880,48 @@ func (s *SpecValidator) validateReferencesValid() *Result { // is set, this is a no-op: loads falls back to the document's own loader. exp, err := s.spec.Expanded(s.schemaOptions.expandOptions("")) if err != nil { - res.AddErrors(unresolvedReferencesMsg(err)) + res.addErrorsAt(s.firstUnresolvableRef(), unresolvedReferencesMsg(err)) } s.expanded = exp } return res } +// firstUnresolvableRef locates the declaration of the first local $ref, in +// document order, that points at a node the document does not hold. +// +// Expansion reports the whole document in a single message, naming only the +// reference it happened to trip on, so the finding has no location of its own. +// A document usually has one broken reference; when it has several, this is the +// first one a reader would meet. +func (s *SpecValidator) firstUnresolvableRef() pathSegments { + first := rootPath() + found := false + + for _, r := range s.analyzer.AllRefs() { + value := r.String() + if !strings.HasPrefix(value, "#/") { + // a remote reference cannot be checked against the document alone + continue + } + + pointer, err := jsonpointer.New(strings.TrimPrefix(value, "#")) + if err != nil { + continue + } + if _, _, err := pointer.Get(s.document); err == nil { + continue + } + + at := s.refLocations.at(value) + if !found || at.pointer() < first.pointer() { + first, found = at, true + } + } + + return first +} + func (s *SpecValidator) checkUniqueParams(path, method string, op *spec.Operation) *Result { // Check for duplicate parameters declaration in param section. // Each parameter should have a unique `name` and `type` combination @@ -817,7 +929,7 @@ func (s *SpecValidator) checkUniqueParams(path, method string, op *spec.Operatio // However, there are some issues with such a factorization: // - analysis does not seem to fully expand params // - param keys may be altered by x-go-name - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() pnames := make(map[string]struct{}) if op.Parameters != nil { // Safeguard @@ -830,7 +942,7 @@ func (s *SpecValidator) checkUniqueParams(path, method string, op *spec.Operatio key := fmt.Sprintf("%s#%s", pr.In, pr.Name) if _, ok = pnames[key]; ok { - res.AddErrors(duplicateParamNameMsg(pr.In, pr.Name, op.ID)) + res.addErrorsAt(s.parameterPath(path, method, pr.In, pr.Name), duplicateParamNameMsg(pr.In, pr.Name, op.ID)) } pnames[key] = struct{}{} } @@ -848,14 +960,15 @@ func (s *SpecValidator) expandedAnalyzer() *analysis.Spec { return s.analyzer } +// deepCloneSchema returns a copy of src that shares nothing with it. +// +// The copy goes through JSON, which is the form [spec.Schema] is defined by. gob drops any field +// holding its zero value and flattens a pointer to what it points at, so a *float64 pointing at +// 0 - "minimum": 0, which the JSON Schema meta-schema spells for every positiveInteger - came +// back nil and the bound was lost. JSON is also the faster of the two on this model. func deepCloneSchema(src spec.Schema) (spec.Schema, error) { - var b bytes.Buffer - if err := gob.NewEncoder(&b).Encode(src); err != nil { - return spec.Schema{}, err - } - var dst spec.Schema - if err := gob.NewDecoder(&b).Decode(&dst); err != nil { + if err := jsonutils.FromDynamicJSON(src, &dst); err != nil { return spec.Schema{}, err } diff --git a/vendor/github.com/go-openapi/validate/spec_messages.go b/vendor/github.com/go-openapi/validate/spec_messages.go index eeb8a8695..541af4d91 100644 --- a/vendor/github.com/go-openapi/validate/spec_messages.go +++ b/vendor/github.com/go-openapi/validate/spec_messages.go @@ -44,6 +44,15 @@ const ( // DefaultValueInDoesNotValidateError ... DefaultValueInDoesNotValidateError = "in operation %q, default value in %s does not validate its schema" + // DiscriminatorNotDefinedError indicates a schema whose discriminator names a property the + // schema does not declare. A discriminator tells subtypes apart by the value of that property, + // so an instance has nowhere to carry the value when the property is not declared. + DiscriminatorNotDefinedError = "discriminator %q of %q is not defined as a property of that schema" + + // DiscriminatorNotRequiredError indicates a schema whose discriminator property is declared but + // left optional. An instance that omits it cannot be resolved to a subtype. + DiscriminatorNotRequiredError = "discriminator %q of %q is not in the required property list" + // DuplicateParamNameError ... DuplicateParamNameError = "duplicate parameter name %q for %q in operation %q" @@ -132,6 +141,17 @@ const ( // RequiredButNotDefinedError ... RequiredButNotDefinedError = "%q is present in required but not defined as property in definition %q" + // RequiredButNotDefinedInSchemaError is the same slip, in a schema a definition holds rather than + // in the definition itself. + RequiredButNotDefinedInSchemaError = "%q is present in required but not defined as property in schema %q" + + // SecuritySchemeNotDeclaredError indicates a security requirement naming a scheme that + // securityDefinitions does not declare. + SecuritySchemeNotDeclaredError = "security requirement %q is not declared in securityDefinitions" + + // SecurityScopesNotEmptyError indicates a security requirement listing scopes on a scheme that is + // not oauth2. Only an oauth2 requirement carries scopes; every other type must list none. + SecurityScopesNotEmptyError = "security requirement %q lists scopes (%s), but the security scheme it names is of type %q: only oauth2 requirements carry scopes" // SomeParametersBrokenError indicates that some parameters could not be resolved, which might result in partial checks to be carried on. SomeParametersBrokenError = "some parameters definitions are broken in %q.%s. Cannot carry on full checks on parameters for operation %s" @@ -168,6 +188,11 @@ const ( // RequiredHasDefaultWarning indicates that a required parameter property should not have a default. RequiredHasDefaultWarning = "%s in %s has a default value and is required as parameter" + // SecurityScopeNotDeclaredWarning flags an oauth2 security requirement asking for a scope that the + // scheme does not list in its scopes. Swagger 2.0 does not spell out that the two must agree, so + // this is reported as a warning: a specification that names an undeclared scope stays valid. + SecurityScopeNotDeclaredWarning = "security requirement %q requires scope %q, which the security scheme does not declare" + // UnusedDefinitionWarning ... UnusedDefinitionWarning = "definition %q is not used anywhere" @@ -177,6 +202,12 @@ const ( // UnusedResponseWarning ... UnusedResponseWarning = "response %q is not used anywhere" + // CollectionFormatIgnoredWarning flags a collectionFormat on a parameter, header or items whose + // type is not array. collectionFormat says how to join the members of an array into one value, so + // it does nothing anywhere else. It is a warning, not an error: Swagger 2.0 defines the member as + // applying when the type is array, and does not forbid writing it elsewhere. + CollectionFormatIgnoredWarning = "collectionFormat %q is ignored in %s: it joins the members of an array, and the type is %q" + // DubiousAbsoluteRefWarning flags a $ref pointing to an absolute local file location that escapes the // spec's base path. Absolute local references are legitimate when they stay beneath the base path // (flattening/expansion introduces such anchors for cyclical $refs), but an absolute reference that @@ -260,6 +291,10 @@ func requiredButNotDefinedMsg(path, definition string) errors.Error { return errors.New(errors.CompositeErrorCode, RequiredButNotDefinedError, path, definition) } +func requiredButNotDefinedInSchemaMsg(path, schema string) errors.Error { + return errors.New(errors.CompositeErrorCode, RequiredButNotDefinedInSchemaError, path, schema) +} + func pathParamGarbledMsg(path, param string) errors.Error { return errors.New(errors.CompositeErrorCode, PathParamGarbledWarning, path, param) } @@ -409,6 +444,31 @@ func invalidObjectMsg(path, in string) errors.Error { // func invalidResponseDefinitionAsSchemaMsg(path, method string) errors.Error { // return errors.New(errors.CompositeErrorCode, InvalidResponseDefinitionAsSchemaError, path, method) // } + +func collectionFormatIgnoredMsg(collectionFormat, in, typ string) errors.Error { + return errors.New(errors.CompositeErrorCode, CollectionFormatIgnoredWarning, collectionFormat, in, typ) +} + +func discriminatorNotDefinedMsg(discriminator, in string) errors.Error { + return errors.New(errors.CompositeErrorCode, DiscriminatorNotDefinedError, discriminator, in) +} + +func discriminatorNotRequiredMsg(discriminator, in string) errors.Error { + return errors.New(errors.CompositeErrorCode, DiscriminatorNotRequiredError, discriminator, in) +} + +func securitySchemeNotDeclaredMsg(name string) errors.Error { + return errors.New(errors.CompositeErrorCode, SecuritySchemeNotDeclaredError, name) +} + +func securityScopesNotEmptyMsg(name, scopes, schemeType string) errors.Error { + return errors.New(errors.CompositeErrorCode, SecurityScopesNotEmptyError, name, scopes, schemeType) +} + +func securityScopeNotDeclaredMsg(name, scope string) errors.Error { + return errors.New(errors.CompositeErrorCode, SecurityScopeNotDeclaredWarning, name, scope) +} + func someParametersBrokenMsg(path, method, operationID string) errors.Error { return errors.New(errors.CompositeErrorCode, SomeParametersBrokenError, path, method, operationID) } diff --git a/vendor/github.com/go-openapi/validate/spec_ref_warnings.go b/vendor/github.com/go-openapi/validate/spec_ref_warnings.go index 49c72314c..d56cb177c 100644 --- a/vendor/github.com/go-openapi/validate/spec_ref_warnings.go +++ b/vendor/github.com/go-openapi/validate/spec_ref_warnings.go @@ -34,12 +34,12 @@ const minDistinctHostsToWarn = 2 // // All findings are warnings: they do not affect validity (see Result.IsValid). func (s *SpecValidator) validateDubiousRefs() *Result { - res := pools.poolOfResults.BorrowResult() + res := validatorPools.results.Borrow() baseDir, hasBase := s.localBaseDir() remoteHosts := make(map[string]struct{}) - for _, r := range s.analyzer.AllRefs() { + for _, r := range sortedRefs(s.analyzer.AllRefs()) { u := r.GetURL() if u == nil { // Safeguard: a valid spec always yields parseable refs continue @@ -48,7 +48,7 @@ func (s *SpecValidator) validateDubiousRefs() *Result { // Rule 1: absolute local reference escaping the base path. if refPath, isLocalAbs := absoluteLocalRefPath(r, u); isLocalAbs { if !hasBase || !isBeneathBase(refPath, baseDir) { - res.AddWarnings(dubiousAbsoluteRefMsg(r.String())) + res.addWarningsAt(s.refLocations.at(r.String()), dubiousAbsoluteRefMsg(r.String())) } continue } diff --git a/vendor/github.com/go-openapi/validate/type.go b/vendor/github.com/go-openapi/validate/type.go index d29574c34..3016783f0 100644 --- a/vendor/github.com/go-openapi/validate/type.go +++ b/vendor/github.com/go-openapi/validate/type.go @@ -15,7 +15,7 @@ import ( ) type typeValidator struct { - Path string + Path pathSegments In string Type spec.StringOrArray Nullable bool @@ -23,14 +23,14 @@ type typeValidator struct { Options *SchemaValidatorOptions } -func newTypeValidator(path, in string, typ spec.StringOrArray, nullable bool, format string, opts *SchemaValidatorOptions) *typeValidator { +func newTypeValidator(path pathSegments, in string, typ spec.StringOrArray, nullable bool, format string, opts *SchemaValidatorOptions) *typeValidator { if opts == nil { opts = new(SchemaValidatorOptions) } var t *typeValidator if opts.recycleValidators { - t = pools.poolOfTypeValidators.BorrowValidator() + t = validatorPools.typeValidators.Borrow() } else { t = new(typeValidator) } @@ -45,10 +45,6 @@ func newTypeValidator(path, in string, typ spec.StringOrArray, nullable bool, fo return t } -func (t *typeValidator) SetPath(path string) { - t.Path = path -} - func (t *typeValidator) Applies(source any, _ reflect.Kind) bool { // typeValidator applies to Schema, Parameter and Header objects switch source.(type) { @@ -72,7 +68,7 @@ func (t *typeValidator) Validate(data any) *Result { if data == nil { // nil or zero value for the passed structure require Type: null if len(t.Type) > 0 && !t.Type.Contains(nullType) && !t.Nullable { // NOTE: if a property is not required it also passes this - return errorHelp.sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), nullType), t.Options.recycleResult) + return errorHelp.sErrAt(t.Path, errors.InvalidType(t.Path.dotted(), t.In, strings.Join(t.Type, ","), nullType), t.Options.recycleResult) } return emptyResult @@ -98,7 +94,7 @@ func (t *typeValidator) Validate(data any) *Result { !isFloatInt && !isIntFloat && !isLowerInt && !isLowerFloat if formatMismatch { // NOTE: test case - return errorHelp.sErr(errors.InvalidType(t.Path, t.In, t.Format, format), t.Options.recycleResult) + return errorHelp.sErrAt(t.Path, errors.InvalidType(t.Path.dotted(), t.In, t.Format, format), t.Options.recycleResult) } if !t.Type.Contains(numberType) && !t.Type.Contains(integerType) && t.Format != "" && (kind == reflect.String || kind == reflect.Slice) { @@ -106,7 +102,7 @@ func (t *typeValidator) Validate(data any) *Result { } if !t.Type.Contains(schType) && !isFloatInt && !isIntFloat { - return errorHelp.sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), schType), t.Options.recycleResult) + return errorHelp.sErrAt(t.Path, errors.InvalidType(t.Path.dotted(), t.In, strings.Join(t.Type, ","), schType), t.Options.recycleResult) } return emptyResult @@ -201,6 +197,10 @@ func (t *typeValidator) schemaInfoForType(data any) (string, string) { return "", "" } +func (t *typeValidator) setPath(path pathSegments) { + t.Path = path +} + func (t *typeValidator) redeem() { - pools.poolOfTypeValidators.RedeemValidator(t) + validatorPools.typeValidators.Redeem(t) } diff --git a/vendor/github.com/go-openapi/validate/update-fixtures.sh b/vendor/github.com/go-openapi/validate/update-fixtures.sh deleted file mode 100644 index 8ee55ca3b..000000000 --- a/vendor/github.com/go-openapi/validate/update-fixtures.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers -# SPDX-License-Identifier: Apache-2.0 - -set -eu -o pipefail -dir=$(git rev-parse --show-toplevel) -scratch=$(mktemp -d -t tmp.XXXXXXXXXX) - -function finish { - rm -rf "$scratch" -} -trap finish EXIT SIGHUP SIGINT SIGTERM - -cd "$scratch" -git clone https://github.com/json-schema-org/JSON-Schema-Test-Suite Suite -cp -r Suite/tests/draft4/* "$dir/fixtures/jsonschema_suite" -cp -a Suite/remotes "$dir/fixtures/jsonschema_suite" diff --git a/vendor/github.com/go-openapi/validate/validator.go b/vendor/github.com/go-openapi/validate/validator.go index e7aebc525..3989b21e7 100644 --- a/vendor/github.com/go-openapi/validate/validator.go +++ b/vendor/github.com/go-openapi/validate/validator.go @@ -4,7 +4,6 @@ package validate import ( - "fmt" "reflect" "github.com/go-openapi/errors" @@ -18,7 +17,7 @@ type EntityValidator interface { } type valueValidator interface { - SetPath(path string) + setPath(path pathSegments) Applies(source any, kind reflect.Kind) bool Validate(data any) *Result } @@ -26,21 +25,21 @@ type valueValidator interface { type itemsValidator struct { items *spec.Items root any - path string + path pathSegments in string validators [6]valueValidator KnownFormats strfmt.Registry Options *SchemaValidatorOptions } -func newItemsValidator(path, in string, items *spec.Items, root any, formats strfmt.Registry, opts *SchemaValidatorOptions) *itemsValidator { +func newItemsValidator(path pathSegments, in string, items *spec.Items, root any, formats strfmt.Registry, opts *SchemaValidatorOptions) *itemsValidator { if opts == nil { opts = new(SchemaValidatorOptions) } var iv *itemsValidator if opts.recycleValidators { - iv = pools.poolOfItemsValidators.BorrowValidator() + iv = validatorPools.itemsValidators.Borrow() } else { iv = new(itemsValidator) } @@ -74,12 +73,12 @@ func (i *itemsValidator) Validate(index int, data any) *Result { kind := tpe.Kind() var result *Result if i.Options.recycleResult { - result = pools.poolOfResults.BorrowResult() + result = validatorPools.results.Borrow() } else { result = new(Result) } - path := fmt.Sprintf("%s.%d", i.path, index) + path := i.path.item(index) for idx, validator := range i.validators { if !validator.Applies(i.root, kind) { @@ -97,7 +96,7 @@ func (i *itemsValidator) Validate(index int, data any) *Result { continue } - validator.SetPath(path) + validator.setPath(path) err := validator.Validate(data) if i.Options.recycleValidators { i.validators[idx] = nil // prevents further (unsafe) usage @@ -130,7 +129,7 @@ func (i *itemsValidator) typeValidator() valueValidator { func (i *itemsValidator) commonValidator() valueValidator { return newBasicCommonValidator( - "", + nil, // located by the item index, set on each Validate call i.in, i.items.Default, i.items.Enum, @@ -140,7 +139,7 @@ func (i *itemsValidator) commonValidator() valueValidator { func (i *itemsValidator) sliceValidator() valueValidator { return newBasicSliceValidator( - "", + nil, // located by the item index, set on each Validate call i.in, i.items.Default, i.items.MaxItems, @@ -155,7 +154,7 @@ func (i *itemsValidator) sliceValidator() valueValidator { func (i *itemsValidator) numberValidator() valueValidator { return newNumberValidator( - "", + nil, // located by the item index, set on each Validate call i.in, i.items.Default, i.items.MultipleOf, @@ -171,7 +170,7 @@ func (i *itemsValidator) numberValidator() valueValidator { func (i *itemsValidator) stringValidator() valueValidator { return newStringValidator( - "", + nil, // located by the item index, set on each Validate call i.in, i.items.Default, false, // Required @@ -185,7 +184,7 @@ func (i *itemsValidator) stringValidator() valueValidator { func (i *itemsValidator) formatValidator() valueValidator { return newFormatValidator( - "", + nil, // located by the item index, set on each Validate call i.in, i.items.Format, i.KnownFormats, @@ -194,7 +193,7 @@ func (i *itemsValidator) formatValidator() valueValidator { } func (i *itemsValidator) redeem() { - pools.poolOfItemsValidators.RedeemValidator(i) + validatorPools.itemsValidators.Redeem(i) } func (i *itemsValidator) redeemChildren() { @@ -213,21 +212,21 @@ func (i *itemsValidator) redeemChildren() { } type basicCommonValidator struct { - Path string + Path pathSegments In string Default any Enum []any Options *SchemaValidatorOptions } -func newBasicCommonValidator(path, in string, def any, enum []any, opts *SchemaValidatorOptions) *basicCommonValidator { +func newBasicCommonValidator(path pathSegments, in string, def any, enum []any, opts *SchemaValidatorOptions) *basicCommonValidator { if opts == nil { opts = new(SchemaValidatorOptions) } var b *basicCommonValidator if opts.recycleValidators { - b = pools.poolOfBasicCommonValidators.BorrowValidator() + b = validatorPools.basicCommonValidators.Borrow() } else { b = new(basicCommonValidator) } @@ -241,10 +240,6 @@ func newBasicCommonValidator(path, in string, def any, enum []any, opts *SchemaV return b } -func (b *basicCommonValidator) SetPath(path string) { - b.Path = path -} - func (b *basicCommonValidator) Applies(source any, _ reflect.Kind) bool { switch source.(type) { case *spec.Parameter, *spec.Schema, *spec.Header: @@ -279,11 +274,15 @@ func (b *basicCommonValidator) Validate(data any) (res *Result) { } } - return errorHelp.sErr(errors.EnumFail(b.Path, b.In, data, b.Enum), b.Options.recycleResult) + return errorHelp.sErrAt(b.Path, errors.EnumFail(b.Path.dotted(), b.In, data, b.Enum), b.Options.recycleResult) +} + +func (b *basicCommonValidator) setPath(path pathSegments) { + b.Path = path } func (b *basicCommonValidator) redeem() { - pools.poolOfBasicCommonValidators.RedeemValidator(b) + validatorPools.basicCommonValidators.Redeem(b) } // A HeaderValidator has very limited subset of validations to apply. @@ -312,7 +311,7 @@ func newHeaderValidator(name string, header *spec.Header, formats strfmt.Registr var p *HeaderValidator if opts.recycleValidators { - p = pools.poolOfHeaderValidators.BorrowValidator() + p = validatorPools.headerValidators.Borrow() } else { p = new(HeaderValidator) } @@ -323,7 +322,7 @@ func newHeaderValidator(name string, header *spec.Header, formats strfmt.Registr p.Options = opts p.validators = [6]valueValidator{ newTypeValidator( - name, + newPathSegments(name), "header", spec.StringOrArray([]string{header.Type}), header.Nullable, @@ -355,7 +354,7 @@ func (p *HeaderValidator) Validate(data any) *Result { var result *Result if p.Options.recycleResult { - result = pools.poolOfResults.BorrowResult() + result = validatorPools.results.Borrow() } else { result = new(Result) } @@ -397,7 +396,7 @@ func (p *HeaderValidator) Validate(data any) *Result { func (p *HeaderValidator) commonValidator() valueValidator { return newBasicCommonValidator( - p.name, + newPathSegments(p.name), "response", p.header.Default, p.header.Enum, @@ -407,7 +406,7 @@ func (p *HeaderValidator) commonValidator() valueValidator { func (p *HeaderValidator) sliceValidator() valueValidator { return newBasicSliceValidator( - p.name, + newPathSegments(p.name), "response", p.header.Default, p.header.MaxItems, @@ -422,7 +421,7 @@ func (p *HeaderValidator) sliceValidator() valueValidator { func (p *HeaderValidator) numberValidator() valueValidator { return newNumberValidator( - p.name, + newPathSegments(p.name), "response", p.header.Default, p.header.MultipleOf, @@ -438,7 +437,7 @@ func (p *HeaderValidator) numberValidator() valueValidator { func (p *HeaderValidator) stringValidator() valueValidator { return newStringValidator( - p.name, + newPathSegments(p.name), "response", p.header.Default, true, @@ -452,7 +451,7 @@ func (p *HeaderValidator) stringValidator() valueValidator { func (p *HeaderValidator) formatValidator() valueValidator { return newFormatValidator( - p.name, + newPathSegments(p.name), "response", p.header.Format, p.KnownFormats, @@ -461,7 +460,7 @@ func (p *HeaderValidator) formatValidator() valueValidator { } func (p *HeaderValidator) redeem() { - pools.poolOfHeaderValidators.RedeemValidator(p) + validatorPools.headerValidators.Redeem(p) } func (p *HeaderValidator) redeemChildren() { @@ -504,7 +503,7 @@ func newParamValidator(param *spec.Parameter, formats strfmt.Registry, opts *Sch var p *ParamValidator if opts.recycleValidators { - p = pools.poolOfParamValidators.BorrowValidator() + p = validatorPools.paramValidators.Borrow() } else { p = new(ParamValidator) } @@ -514,7 +513,7 @@ func newParamValidator(param *spec.Parameter, formats strfmt.Registry, opts *Sch p.Options = opts p.validators = [6]valueValidator{ newTypeValidator( - param.Name, + newPathSegments(param.Name), param.In, spec.StringOrArray([]string{param.Type}), param.Nullable, @@ -539,7 +538,7 @@ func (p *ParamValidator) Validate(data any) *Result { var result *Result if p.Options.recycleResult { - result = pools.poolOfResults.BorrowResult() + result = validatorPools.results.Borrow() } else { result = new(Result) } @@ -589,7 +588,7 @@ func (p *ParamValidator) Validate(data any) *Result { func (p *ParamValidator) commonValidator() valueValidator { return newBasicCommonValidator( - p.param.Name, + newPathSegments(p.param.Name), p.param.In, p.param.Default, p.param.Enum, @@ -599,7 +598,7 @@ func (p *ParamValidator) commonValidator() valueValidator { func (p *ParamValidator) sliceValidator() valueValidator { return newBasicSliceValidator( - p.param.Name, + newPathSegments(p.param.Name), p.param.In, p.param.Default, p.param.MaxItems, @@ -614,7 +613,7 @@ func (p *ParamValidator) sliceValidator() valueValidator { func (p *ParamValidator) numberValidator() valueValidator { return newNumberValidator( - p.param.Name, + newPathSegments(p.param.Name), p.param.In, p.param.Default, p.param.MultipleOf, @@ -630,7 +629,7 @@ func (p *ParamValidator) numberValidator() valueValidator { func (p *ParamValidator) stringValidator() valueValidator { return newStringValidator( - p.param.Name, + newPathSegments(p.param.Name), p.param.In, p.param.Default, p.param.Required, @@ -644,7 +643,7 @@ func (p *ParamValidator) stringValidator() valueValidator { func (p *ParamValidator) formatValidator() valueValidator { return newFormatValidator( - p.param.Name, + newPathSegments(p.param.Name), p.param.In, p.param.Format, p.KnownFormats, @@ -653,7 +652,7 @@ func (p *ParamValidator) formatValidator() valueValidator { } func (p *ParamValidator) redeem() { - pools.poolOfParamValidators.RedeemValidator(p) + validatorPools.paramValidators.Redeem(p) } func (p *ParamValidator) redeemChildren() { @@ -672,7 +671,7 @@ func (p *ParamValidator) redeemChildren() { } type basicSliceValidator struct { - Path string + Path pathSegments In string Default any MaxItems *int64 @@ -685,7 +684,7 @@ type basicSliceValidator struct { } func newBasicSliceValidator( - path, in string, + path pathSegments, in string, def any, maxItems, minItems *int64, uniqueItems bool, items *spec.Items, source any, formats strfmt.Registry, opts *SchemaValidatorOptions, @@ -696,7 +695,7 @@ func newBasicSliceValidator( var s *basicSliceValidator if opts.recycleValidators { - s = pools.poolOfBasicSliceValidators.BorrowValidator() + s = validatorPools.basicSliceValidators.Borrow() } else { s = new(basicSliceValidator) } @@ -715,10 +714,6 @@ func newBasicSliceValidator( return s } -func (s *basicSliceValidator) SetPath(path string) { - s.Path = path -} - func (s *basicSliceValidator) Applies(source any, kind reflect.Kind) bool { switch source.(type) { case *spec.Parameter, *spec.Items, *spec.Header: @@ -738,20 +733,20 @@ func (s *basicSliceValidator) Validate(data any) *Result { size := int64(val.Len()) if s.MinItems != nil { - if err := MinItems(s.Path, s.In, size, *s.MinItems); err != nil { - return errorHelp.sErr(err, s.Options.recycleResult) + if err := MinItems(s.Path.dotted(), s.In, size, *s.MinItems); err != nil { + return errorHelp.sErrAt(s.Path, err, s.Options.recycleResult) } } if s.MaxItems != nil { - if err := MaxItems(s.Path, s.In, size, *s.MaxItems); err != nil { - return errorHelp.sErr(err, s.Options.recycleResult) + if err := MaxItems(s.Path.dotted(), s.In, size, *s.MaxItems); err != nil { + return errorHelp.sErrAt(s.Path, err, s.Options.recycleResult) } } if s.UniqueItems { - if err := UniqueItems(s.Path, s.In, data); err != nil { - return errorHelp.sErr(err, s.Options.recycleResult) + if err := UniqueItems(s.Path.dotted(), s.In, data); err != nil { + return errorHelp.sErrAt(s.Path, err, s.Options.recycleResult) } } @@ -767,7 +762,7 @@ func (s *basicSliceValidator) Validate(data any) *Result { return err } if err.wantsRedeemOnMerge { - pools.poolOfResults.RedeemResult(err) + redeemResult(err) } } } @@ -775,12 +770,16 @@ func (s *basicSliceValidator) Validate(data any) *Result { return nil } +func (s *basicSliceValidator) setPath(path pathSegments) { + s.Path = path +} + func (s *basicSliceValidator) redeem() { - pools.poolOfBasicSliceValidators.RedeemValidator(s) + validatorPools.basicSliceValidators.Redeem(s) } type numberValidator struct { - Path string + Path pathSegments In string Default any MultipleOf *float64 @@ -795,7 +794,7 @@ type numberValidator struct { } func newNumberValidator( - path, in string, def any, + path pathSegments, in string, def any, multipleOf, maximum *float64, exclusiveMaximum bool, minimum *float64, exclusiveMinimum bool, typ, format string, opts *SchemaValidatorOptions, @@ -806,7 +805,7 @@ func newNumberValidator( var n *numberValidator if opts.recycleValidators { - n = pools.poolOfNumberValidators.BorrowValidator() + n = validatorPools.numberValidators.Borrow() } else { n = new(numberValidator) } @@ -826,10 +825,6 @@ func newNumberValidator( return n } -func (n *numberValidator) SetPath(path string) { - n.Path = path -} - func (n *numberValidator) Applies(source any, kind reflect.Kind) bool { switch source.(type) { case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header: @@ -871,7 +866,7 @@ func (n *numberValidator) Validate(val any) *Result { var res, resMultiple, resMinimum, resMaximum *Result if n.Options.recycleResult { - res = pools.poolOfResults.BorrowResult() + res = validatorPools.results.Borrow() } else { res = new(Result) } @@ -881,58 +876,58 @@ func (n *numberValidator) Validate(val any) *Result { data := valueHelp.asFloat64(val) // Is the provided value within the range of the specified numeric type and format? - res.AddErrors(IsValueValidAgainstRange(val, n.Type, n.Format, "Checked", n.Path)) + res.addErrorsAt(n.Path, IsValueValidAgainstRange(val, n.Type, n.Format, "Checked", n.Path.dotted())) if n.MultipleOf != nil { - resMultiple = pools.poolOfResults.BorrowResult() + resMultiple = validatorPools.results.Borrow() // Is the constraint specifier within the range of the specific numeric type and format? - resMultiple.AddErrors(IsValueValidAgainstRange(*n.MultipleOf, n.Type, n.Format, "MultipleOf", n.Path)) + resMultiple.addErrorsAt(n.Path, IsValueValidAgainstRange(*n.MultipleOf, n.Type, n.Format, "MultipleOf", n.Path.dotted())) if resMultiple.IsValid() { // Constraint validated with compatible types - if err := MultipleOfNativeType(n.Path, n.In, val, *n.MultipleOf); err != nil { - resMultiple.Merge(errorHelp.sErr(err, n.Options.recycleResult)) + if err := MultipleOfNativeType(n.Path.dotted(), n.In, val, *n.MultipleOf); err != nil { + resMultiple.Merge(errorHelp.sErrAt(n.Path, err, n.Options.recycleResult)) } } else { // Constraint nevertheless validated, converted as general number - if err := MultipleOf(n.Path, n.In, data, *n.MultipleOf); err != nil { - resMultiple.Merge(errorHelp.sErr(err, n.Options.recycleResult)) + if err := MultipleOf(n.Path.dotted(), n.In, data, *n.MultipleOf); err != nil { + resMultiple.Merge(errorHelp.sErrAt(n.Path, err, n.Options.recycleResult)) } } } if n.Maximum != nil { - resMaximum = pools.poolOfResults.BorrowResult() + resMaximum = validatorPools.results.Borrow() // Is the constraint specifier within the range of the specific numeric type and format? - resMaximum.AddErrors(IsValueValidAgainstRange(*n.Maximum, n.Type, n.Format, "Maximum boundary", n.Path)) + resMaximum.addErrorsAt(n.Path, IsValueValidAgainstRange(*n.Maximum, n.Type, n.Format, "Maximum boundary", n.Path.dotted())) if resMaximum.IsValid() { // Constraint validated with compatible types - if err := MaximumNativeType(n.Path, n.In, val, *n.Maximum, n.ExclusiveMaximum); err != nil { - resMaximum.Merge(errorHelp.sErr(err, n.Options.recycleResult)) + if err := MaximumNativeType(n.Path.dotted(), n.In, val, *n.Maximum, n.ExclusiveMaximum); err != nil { + resMaximum.Merge(errorHelp.sErrAt(n.Path, err, n.Options.recycleResult)) } } else { // Constraint nevertheless validated, converted as general number - if err := Maximum(n.Path, n.In, data, *n.Maximum, n.ExclusiveMaximum); err != nil { - resMaximum.Merge(errorHelp.sErr(err, n.Options.recycleResult)) + if err := Maximum(n.Path.dotted(), n.In, data, *n.Maximum, n.ExclusiveMaximum); err != nil { + resMaximum.Merge(errorHelp.sErrAt(n.Path, err, n.Options.recycleResult)) } } } if n.Minimum != nil { - resMinimum = pools.poolOfResults.BorrowResult() + resMinimum = validatorPools.results.Borrow() // Is the constraint specifier within the range of the specific numeric type and format? - resMinimum.AddErrors(IsValueValidAgainstRange(*n.Minimum, n.Type, n.Format, "Minimum boundary", n.Path)) + resMinimum.addErrorsAt(n.Path, IsValueValidAgainstRange(*n.Minimum, n.Type, n.Format, "Minimum boundary", n.Path.dotted())) if resMinimum.IsValid() { // Constraint validated with compatible types - if err := MinimumNativeType(n.Path, n.In, val, *n.Minimum, n.ExclusiveMinimum); err != nil { - resMinimum.Merge(errorHelp.sErr(err, n.Options.recycleResult)) + if err := MinimumNativeType(n.Path.dotted(), n.In, val, *n.Minimum, n.ExclusiveMinimum); err != nil { + resMinimum.Merge(errorHelp.sErrAt(n.Path, err, n.Options.recycleResult)) } } else { // Constraint nevertheless validated, converted as general number - if err := Minimum(n.Path, n.In, data, *n.Minimum, n.ExclusiveMinimum); err != nil { - resMinimum.Merge(errorHelp.sErr(err, n.Options.recycleResult)) + if err := Minimum(n.Path.dotted(), n.In, data, *n.Minimum, n.ExclusiveMinimum); err != nil { + resMinimum.Merge(errorHelp.sErrAt(n.Path, err, n.Options.recycleResult)) } } } @@ -942,12 +937,16 @@ func (n *numberValidator) Validate(val any) *Result { return res } +func (n *numberValidator) setPath(path pathSegments) { + n.Path = path +} + func (n *numberValidator) redeem() { - pools.poolOfNumberValidators.RedeemValidator(n) + validatorPools.numberValidators.Redeem(n) } type stringValidator struct { - Path string + Path pathSegments In string Default any Required bool @@ -959,7 +958,7 @@ type stringValidator struct { } func newStringValidator( - path, in string, + path pathSegments, in string, def any, required, allowEmpty bool, maxLength, minLength *int64, pattern string, opts *SchemaValidatorOptions, ) *stringValidator { @@ -969,7 +968,7 @@ func newStringValidator( var s *stringValidator if opts.recycleValidators { - s = pools.poolOfStringValidators.BorrowValidator() + s = validatorPools.stringValidators.Borrow() } else { s = new(stringValidator) } @@ -987,10 +986,6 @@ func newStringValidator( return s } -func (s *stringValidator) SetPath(path string) { - s.Path = path -} - func (s *stringValidator) Applies(source any, kind reflect.Kind) bool { switch source.(type) { case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header: @@ -1009,35 +1004,39 @@ func (s *stringValidator) Validate(val any) *Result { data, ok := val.(string) if !ok { - return errorHelp.sErr(errors.InvalidType(s.Path, s.In, stringType, val), s.Options.recycleResult) + return errorHelp.sErrAt(s.Path, errors.InvalidType(s.Path.dotted(), s.In, stringType, val), s.Options.recycleResult) } if s.Required && !s.AllowEmptyValue && (s.Default == nil || s.Default == "") { - if err := RequiredString(s.Path, s.In, data); err != nil { - return errorHelp.sErr(err, s.Options.recycleResult) + if err := RequiredString(s.Path.dotted(), s.In, data); err != nil { + return errorHelp.sErrAt(s.Path, err, s.Options.recycleResult) } } if s.MaxLength != nil { - if err := MaxLength(s.Path, s.In, data, *s.MaxLength); err != nil { - return errorHelp.sErr(err, s.Options.recycleResult) + if err := MaxLength(s.Path.dotted(), s.In, data, *s.MaxLength); err != nil { + return errorHelp.sErrAt(s.Path, err, s.Options.recycleResult) } } if s.MinLength != nil { - if err := MinLength(s.Path, s.In, data, *s.MinLength); err != nil { - return errorHelp.sErr(err, s.Options.recycleResult) + if err := MinLength(s.Path.dotted(), s.In, data, *s.MinLength); err != nil { + return errorHelp.sErrAt(s.Path, err, s.Options.recycleResult) } } if s.Pattern != "" { - if err := Pattern(s.Path, s.In, data, s.Pattern); err != nil { - return errorHelp.sErr(err, s.Options.recycleResult) + if err := Pattern(s.Path.dotted(), s.In, data, s.Pattern); err != nil { + return errorHelp.sErrAt(s.Path, err, s.Options.recycleResult) } } return nil } +func (s *stringValidator) setPath(path pathSegments) { + s.Path = path +} + func (s *stringValidator) redeem() { - pools.poolOfStringValidators.RedeemValidator(s) + validatorPools.stringValidators.Redeem(s) } diff --git a/vendor/github.com/google/go-containerregistry/pkg/name/doc.go b/vendor/github.com/google/go-containerregistry/pkg/name/doc.go index b294794dc..b67ad0ffc 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/name/doc.go +++ b/vendor/github.com/google/go-containerregistry/pkg/name/doc.go @@ -17,9 +17,11 @@ // What's in a name? For image references, not nearly enough! // // Image references look a lot like URLs, but they differ in that they don't -// contain the scheme (http or https), they can end with a :tag or a @digest -// (the latter being validated), and they perform defaulting for missing -// components. +// contain the scheme (http or https), they can end with a :tag, an @digest +// (the latter being validated), or both. When a reference includes both a tag +// and a digest, it is treated as a digest reference: the digest is the +// identifier used for verification, while the tag is retained only in the +// original string form. // // Since image references don't contain the scheme, we do our best to infer // if we use http or https from the given hostname. We allow http fallback for diff --git a/vendor/github.com/google/go-containerregistry/pkg/name/ref.go b/vendor/github.com/google/go-containerregistry/pkg/name/ref.go index 0a0486772..539d0ff31 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/name/ref.go +++ b/vendor/github.com/google/go-containerregistry/pkg/name/ref.go @@ -37,6 +37,7 @@ type Reference interface { } // ParseReference parses the string as a reference, either by tag or digest. +// References that include both a tag and digest parse as Digest references. func ParseReference(s string, opts ...Option) (Reference, error) { if t, err := NewTag(s, opts...); err == nil { return t, nil diff --git a/vendor/github.com/google/go-containerregistry/pkg/name/repository.go b/vendor/github.com/google/go-containerregistry/pkg/name/repository.go index efde6e869..ad7b32911 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/name/repository.go +++ b/vendor/github.com/google/go-containerregistry/pkg/name/repository.go @@ -72,7 +72,7 @@ func (r Repository) Scope(action string) string { } func checkRepository(repository string) error { - return checkElement("repository", repository, repositoryChars, 2, 255) + return checkElement("repository", repository, repositoryChars, 1, 255) } // NewRepository returns a new Repository representing the given name, according to the given strictness. diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel index 04b4bebf3..3964ec00a 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel @@ -38,6 +38,7 @@ go_library( "@org_golang_google_protobuf//reflect/protoreflect", "@org_golang_google_protobuf//reflect/protoregistry", "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/emptypb", "@org_golang_google_protobuf//types/known/fieldmaskpb", "@org_golang_google_protobuf//types/known/structpb", "@org_golang_google_protobuf//types/known/timestamppb", @@ -49,6 +50,7 @@ go_test( name = "runtime_test", size = "small", srcs = [ + "context_internal_test.go", "context_test.go", "convert_test.go", "errors_test.go", diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go index 00b2228a1..5d0c91d33 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "fmt" + "math" "net" "net/http" "net/textproto" @@ -157,7 +158,7 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM for _, val := range vals { // For backwards-compatibility, pass through 'authorization' header with no prefix. - if key == "Authorization" { + if key == "Authorization" && isValidGRPCMetadataTextValue(val) { pairs = append(pairs, "authorization", val) } if h, ok := mux.incomingHeaderMatcher(key); ok { @@ -182,9 +183,9 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM } } } - if host := req.Header.Get(xForwardedHost); host != "" { + if host := req.Header.Get(xForwardedHost); host != "" && isValidGRPCMetadataTextValue(host) { pairs = append(pairs, strings.ToLower(xForwardedHost), host) - } else if req.Host != "" { + } else if req.Host != "" && isValidGRPCMetadataTextValue(req.Host) { pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host) } @@ -195,7 +196,9 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM } } if len(xff) > 0 { - pairs = append(pairs, strings.ToLower(xForwardedFor), strings.Join(xff, ", ")) + if value := strings.Join(xff, ", "); isValidGRPCMetadataTextValue(value) { + pairs = append(pairs, strings.ToLower(xForwardedFor), value) + } } if timeout != 0 { @@ -302,10 +305,16 @@ func timeoutDecode(s string) (time.Duration, error) { if !ok { return 0, fmt.Errorf("timeout unit is not recognized: %q", s) } - t, err := strconv.ParseInt(s[:size-1], 10, 64) + t, err := strconv.ParseUint(s[:size-1], 10, 64) if err != nil { return 0, err } + // Guard against overflowing time.Duration, which is an int64 nanosecond + // count: without this a large value wraps to a bogus (often negative) + // deadline instead of the long timeout the client asked for. + if t > uint64(math.MaxInt64)/uint64(d) { + return time.Duration(math.MaxInt64), nil + } return d * time.Duration(t), nil } diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go index 2e50082ad..2bb7c8fa6 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go @@ -90,7 +90,7 @@ func Float32Slice(val, sep string) ([]float32, error) { // Int64 converts the given string representation of an integer into int64. func Int64(val string) (int64, error) { - return strconv.ParseInt(val, 0, 64) + return strconv.ParseInt(val, 10, 64) } // Int64Slice converts 'val' where individual integers are separated by @@ -110,7 +110,7 @@ func Int64Slice(val, sep string) ([]int64, error) { // Int32 converts the given string representation of an integer into int32. func Int32(val string) (int32, error) { - i, err := strconv.ParseInt(val, 0, 32) + i, err := strconv.ParseInt(val, 10, 32) if err != nil { return 0, err } @@ -134,7 +134,7 @@ func Int32Slice(val, sep string) ([]int32, error) { // Uint64 converts the given string representation of an integer into uint64. func Uint64(val string) (uint64, error) { - return strconv.ParseUint(val, 0, 64) + return strconv.ParseUint(val, 10, 64) } // Uint64Slice converts 'val' where individual integers are separated by @@ -154,7 +154,7 @@ func Uint64Slice(val, sep string) ([]uint64, error) { // Uint32 converts the given string representation of an integer into uint32. func Uint32(val string) (uint32, error) { - i, err := strconv.ParseUint(val, 0, 32) + i, err := strconv.ParseUint(val, 10, 32) if err != nil { return 0, err } diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go index 3d0706300..43b30f587 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "math" "reflect" "strconv" @@ -311,6 +312,12 @@ func decodeNonProtoField(d *json.Decoder, unmarshaler protojson.UnmarshalOptions // TODO(yugui) Should use proto.StructProperties? return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface()) case float64: + // Enum values are int32 on the wire. A fractional or out-of-range + // number would otherwise be silently truncated/wrapped into a bogus + // enum here, unlike protojson which rejects it, so reject it too. + if v != math.Trunc(v) || v < math.MinInt32 || v > math.MaxInt32 { + return fmt.Errorf("%v is not a valid value for enum %T", repr, rv.Interface()) + } rv.Set(reflect.ValueOf(int32(v)).Convert(rv.Type())) return nil default: diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go index 69edf5eff..3b4586be1 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go @@ -158,7 +158,15 @@ func DefaultHeaderMatcher(key string) (string, bool) { case isPermanentHTTPHeader(key): return MetadataPrefix + key, true case strings.HasPrefix(key, MetadataHeaderPrefix): - return key[len(MetadataHeaderPrefix):], true + mdKey := key[len(MetadataHeaderPrefix):] + // The grpcgateway- namespace is reserved for permanent HTTP headers the + // gateway maps itself, so refuse to forward a Grpc-Metadata- header that + // strips into it. Otherwise Grpc-Metadata-grpcgateway-host lets a client + // inject a value indistinguishable from the gateway-set grpcgateway-host. + if strings.HasPrefix(strings.ToLower(mdKey), MetadataPrefix) { + return "", false + } + return mdKey, true } return "", false } diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go index e54507145..48cab90f8 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go @@ -196,6 +196,16 @@ func (p Pattern) MatchAndEscape(components []string, verb string, unescapingMode return nil, ErrNotMatch } end -= p.tailLen + if pos > 0 && pos == end { + // A deep wildcard ("**") is allowed to match zero path segments when it is + // the first thing being matched in the pattern (pos == 0). But once a literal + // or variable segment has already consumed a component, "**" needs the request + // path to continue past that segment — it cannot succeed with nothing left to + // consume at all (though an empty trailing segment, e.g. from a trailing slash, + // still counts as a real component and is fine). + // See https://github.com/grpc-ecosystem/grpc-gateway/issues/5771. + return nil, ErrNotMatch + } c := strings.Join(components[pos:end], "/") if c, err = unescape(c, unescapingMode, true); err != nil { return nil, err diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go index 8549dfb97..4f9221a09 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go @@ -16,6 +16,7 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/emptypb" field_mask "google.golang.org/protobuf/types/known/fieldmaskpb" "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" @@ -224,7 +225,7 @@ func parseField(fieldDescriptor protoreflect.FieldDescriptor, value string) (pro // Look for enum by name v := enum.Descriptor().Values().ByName(protoreflect.Name(value)) if v == nil { - i, err := strconv.Atoi(value) + i, err := strconv.ParseInt(value, 10, 32) if err != nil { return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value) } @@ -370,6 +371,14 @@ func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (p return protoreflect.Value{}, err } msg = &v + case "google.protobuf.Empty": + // An Empty carries nothing, so the only thing the value can say is that the + // field is present. Accept the two spellings of "no content" and reject + // anything else, rather than silently ignoring it. + if value != "" && value != "{}" { + return protoreflect.Value{}, fmt.Errorf("expected an empty value or %q, got %q", "{}", value) + } + msg = &emptypb.Empty{} default: return protoreflect.Value{}, fmt.Errorf("unsupported message type: %q", string(msgDescriptor.FullName())) } diff --git a/vendor/github.com/oklog/ulid/v2/ulid.go b/vendor/github.com/oklog/ulid/v2/ulid.go index 77e9ddd63..e07e1a681 100644 --- a/vendor/github.com/oklog/ulid/v2/ulid.go +++ b/vendor/github.com/oklog/ulid/v2/ulid.go @@ -505,7 +505,16 @@ func (id *ULID) Scan(src interface{}) error { case string: return id.UnmarshalText([]byte(x)) case []byte: - return id.UnmarshalBinary(x) + // Drivers often return text/varchar columns as []byte. Accept both + // the 16-byte binary form and the 26-character text encoding. + switch len(x) { + case len(*id): + return id.UnmarshalBinary(x) + case EncodedSize: + return id.UnmarshalText(x) + default: + return ErrDataSize + } } return ErrScanValue diff --git a/vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go b/vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go index 820bf436a..2cd16f13a 100644 --- a/vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go +++ b/vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go @@ -39,7 +39,7 @@ func init() { // token = 1* // qdtext = > - for c := 0; c < 256; c++ { + for c := range 256 { var t octetType isCtl := c <= 31 || c == 127 isChar := 0 <= c && c <= 127 diff --git a/vendor/github.com/prometheus/client_golang/prometheus/build_info_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/build_info_collector.go index 450189f35..b80b964c9 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/build_info_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/build_info_collector.go @@ -32,7 +32,8 @@ func NewBuildInfoCollector() Collector { "Build information about the main Go module.", nil, Labels{"path": path, "version": version, "checksum": sum}, ), - GaugeValue, 1)} + GaugeValue, 1, + )} c.init(c.self) return c } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go index a3c92e7a4..881d91dee 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go @@ -21,7 +21,6 @@ import ( "github.com/cespare/xxhash/v2" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/model" - "google.golang.org/protobuf/proto" "github.com/prometheus/client_golang/prometheus/internal" ) @@ -181,8 +180,8 @@ func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, const d.constLabelPairs = make([]*dto.LabelPair, 0, len(constLabels)) for n, v := range constLabels { d.constLabelPairs = append(d.constLabelPairs, &dto.LabelPair{ - Name: proto.String(n), - Value: proto.String(v), + Name: new(n), + Value: new(v), }) } sort.Sort(internal.LabelPairSorter(d.constLabelPairs)) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/get_pid.go b/vendor/github.com/prometheus/client_golang/prometheus/get_pid.go index 614fd61be..c7be2a0ca 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/get_pid.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/get_pid.go @@ -12,7 +12,6 @@ // limitations under the License. //go:build !js || wasm -// +build !js wasm package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go b/vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go index eaf8059ee..0ddc8c6ee 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go @@ -12,7 +12,6 @@ // limitations under the License. //go:build js && !wasm -// +build js,!wasm package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go index 520cbd7d4..a4725849f 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go @@ -211,23 +211,28 @@ func newBaseGoCollector() baseGoCollector { goroutinesDesc: NewDesc( "go_goroutines", "Number of goroutines that currently exist.", - nil, nil), + nil, nil, + ), threadsDesc: NewDesc( "go_threads", "Number of OS threads created.", - nil, nil), + nil, nil, + ), gcDesc: NewDesc( "go_gc_duration_seconds", "A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.", - nil, nil), + nil, nil, + ), gcLastTimeDesc: NewDesc( "go_memstats_last_gc_time_seconds", "Number of seconds since 1970 of last garbage collection.", - nil, nil), + nil, nil, + ), goInfoDesc: NewDesc( "go_info", "Information about the Go environment.", - nil, Labels{"version": runtime.Version()}), + nil, Labels{"version": runtime.Version()}, + ), } } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go index 1db1c4be0..23091e177 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go @@ -11,9 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build go1.17 -// +build go1.17 - package prometheus import ( @@ -27,7 +24,6 @@ import ( "github.com/prometheus/client_golang/prometheus/internal" dto "github.com/prometheus/client_model/go" - "google.golang.org/protobuf/proto" ) const ( @@ -573,14 +569,14 @@ func (h *batchHistogram) Write(out *dto.Metric) error { // by obtaining the next float64 value down, in order. upperBound := math.Nextafter(h.buckets[i+1], h.buckets[i]) dtoBuckets = append(dtoBuckets, &dto.Bucket{ - CumulativeCount: proto.Uint64(totalCount), - UpperBound: proto.Float64(upperBound), + CumulativeCount: new(totalCount), + UpperBound: new(upperBound), }) } out.Histogram = &dto.Histogram{ Bucket: dtoBuckets, - SampleCount: proto.Uint64(totalCount), - SampleSum: proto.Float64(sum), + SampleCount: new(totalCount), + SampleSum: new(sum), } return nil } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go index 88bae3b32..1d6ca1614 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go @@ -803,8 +803,8 @@ func (h *histogram) Write(out *dto.Metric) error { his := &dto.Histogram{ Bucket: make([]*dto.Bucket, len(h.upperBounds)), - SampleCount: proto.Uint64(count), - SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), + SampleCount: new(count), + SampleSum: new(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), CreatedTimestamp: timestamppb.New(h.lastResetTime), } out.Histogram = his @@ -814,8 +814,8 @@ func (h *histogram) Write(out *dto.Metric) error { for i, upperBound := range h.upperBounds { cumCount += atomic.LoadUint64(&coldCounts.buckets[i]) his.Bucket[i] = &dto.Bucket{ - CumulativeCount: proto.Uint64(cumCount), - UpperBound: proto.Float64(upperBound), + CumulativeCount: new(cumCount), + UpperBound: new(upperBound), } if e := h.exemplars[i].Load(); e != nil { his.Bucket[i].Exemplar = e.(*dto.Exemplar) @@ -824,15 +824,15 @@ func (h *histogram) Write(out *dto.Metric) error { // If there is an exemplar for the +Inf bucket, we have to add that bucket explicitly. if e := h.exemplars[len(h.upperBounds)].Load(); e != nil { b := &dto.Bucket{ - CumulativeCount: proto.Uint64(count), - UpperBound: proto.Float64(math.Inf(1)), + CumulativeCount: new(count), + UpperBound: new(math.Inf(1)), Exemplar: e.(*dto.Exemplar), } his.Bucket = append(his.Bucket, b) } if h.nativeHistogramSchema > math.MinInt32 { - his.ZeroThreshold = proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.nativeHistogramZeroThresholdBits))) - his.Schema = proto.Int32(atomic.LoadInt32(&coldCounts.nativeHistogramSchema)) + his.ZeroThreshold = new(math.Float64frombits(atomic.LoadUint64(&coldCounts.nativeHistogramZeroThresholdBits))) + his.Schema = new(atomic.LoadInt32(&coldCounts.nativeHistogramSchema)) zeroBucket := atomic.LoadUint64(&coldCounts.nativeHistogramZeroBucket) defer func() { @@ -840,7 +840,7 @@ func (h *histogram) Write(out *dto.Metric) error { coldCounts.nativeHistogramBucketsNegative.Range(addAndReset(&hotCounts.nativeHistogramBucketsNegative, &hotCounts.nativeHistogramBucketsNumber)) }() - his.ZeroCount = proto.Uint64(zeroBucket) + his.ZeroCount = new(zeroBucket) his.NegativeSpan, his.NegativeDelta = makeBuckets(&coldCounts.nativeHistogramBucketsNegative) his.PositiveSpan, his.PositiveDelta = makeBuckets(&coldCounts.nativeHistogramBucketsPositive) @@ -1331,12 +1331,12 @@ func (h *constHistogram) Write(out *dto.Metric) error { buckets := make([]*dto.Bucket, 0, len(h.buckets)) - his.SampleCount = proto.Uint64(h.count) - his.SampleSum = proto.Float64(h.sum) + his.SampleCount = new(h.count) + his.SampleSum = new(h.sum) for upperBound, count := range h.buckets { buckets = append(buckets, &dto.Bucket{ - CumulativeCount: proto.Uint64(count), - UpperBound: proto.Float64(upperBound), + CumulativeCount: new(count), + UpperBound: new(upperBound), }) } @@ -1481,7 +1481,7 @@ func pickSchema(bucketFactor float64) int32 { func makeBuckets(buckets *sync.Map) ([]*dto.BucketSpan, []int64) { var ii []int - buckets.Range(func(k, v any) bool { + buckets.Range(func(k, _ any) bool { ii = append(ii, k.(int)) return true }) @@ -1518,13 +1518,13 @@ func makeBuckets(buckets *sync.Map) ([]*dto.BucketSpan, []int64) { // at the very beginning, or because we have found a gap // of more than two buckets. spans = append(spans, &dto.BucketSpan{ - Offset: proto.Int32(iDelta), + Offset: new(iDelta), Length: proto.Uint32(0), }) } else { // We have found a small gap (or no gap at all). // Insert empty buckets as needed. - for j := int32(0); j < iDelta; j++ { + for range iDelta { appendDelta(0) } } @@ -1570,7 +1570,7 @@ func addAndReset(hotBuckets *sync.Map, bucketNumber *uint32) func(k, v any) bool } func deleteSyncMap(m *sync.Map) { - m.Range(func(k, v any) bool { + m.Range(func(k, _ any) bool { m.Delete(k) return true }) @@ -1578,7 +1578,7 @@ func deleteSyncMap(m *sync.Map) { func findSmallestKey(m *sync.Map) int { result := math.MaxInt32 - m.Range(func(k, v any) bool { + m.Range(func(k, _ any) bool { key := k.(int) if key < result { result = key @@ -1956,7 +1956,7 @@ func NewConstNativeHistogram( PositiveSpan: PositiveSpan, PositiveDelta: PositiveDelta, - ZeroCount: proto.Uint64(zeroBucket), + ZeroCount: new(zeroBucket), }, labelPairs: MakeLabelPairs(desc, labelValues), } @@ -2044,13 +2044,13 @@ func makeBucketsFromMap(buckets map[int]int64) ([]*dto.BucketSpan, []int64) { // at the very beginning, or because we have found a gap // of more than two buckets. spans = append(spans, &dto.BucketSpan{ - Offset: proto.Int32(iDelta), + Offset: new(iDelta), Length: proto.Uint32(0), }) } else { // We have found a small gap (or no gap at all). // Insert empty buckets as needed. - for j := int32(0); j < iDelta; j++ { + for range iDelta { appendDelta(0) } } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go index d273b6640..e38dfe0ad 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go @@ -11,9 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build go1.17 -// +build go1.17 - package internal import ( diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/metric.go index c5cb90adf..e4bbf3b8e 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/metric.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/metric.go @@ -22,7 +22,6 @@ import ( dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/model" - "google.golang.org/protobuf/proto" ) var separatorByteSlice = []byte{model.SeparatorByte} // For convenient use with xxhash. @@ -153,7 +152,7 @@ type timestampedMetric struct { func (m timestampedMetric) Write(pb *dto.Metric) error { e := m.Metric.Write(pb) - pb.TimestampMs = proto.Int64(m.t.Unix()*1000 + int64(m.t.Nanosecond()/1000000)) + pb.TimestampMs = new(m.t.Unix()*1000 + int64(m.t.Nanosecond()/1000000)) return e } @@ -209,8 +208,8 @@ func (m *withExemplarsMetric) Write(pb *dto.Metric) error { } else { // The +Inf bucket should be explicitly added if there is an exemplar for it, similar to non-const histogram logic in https://github.com/prometheus/client_golang/blob/main/prometheus/histogram.go#L357-L365. b := &dto.Bucket{ - CumulativeCount: proto.Uint64(h.GetSampleCount()), - UpperBound: proto.Float64(math.Inf(1)), + CumulativeCount: new(h.GetSampleCount()), + UpperBound: new(math.Inf(1)), Exemplar: e, } h.Bucket = append(h.Bucket, b) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/num_threads.go b/vendor/github.com/prometheus/client_golang/prometheus/num_threads.go index 7c12b2108..7ffac2134 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/num_threads.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/num_threads.go @@ -12,7 +12,6 @@ // limitations under the License. //go:build !js || wasm -// +build !js wasm package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go b/vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go index 7348df01d..65f4263f9 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go @@ -12,7 +12,6 @@ // limitations under the License. //go:build js && !wasm -// +build js,!wasm package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_darwin.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_darwin.go index 2b16298f4..46e7e45aa 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_darwin.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_darwin.go @@ -54,21 +54,22 @@ func getOpenFileCount() (float64, error) { // benefits, however, include fewer system calls and not failing when at the // open file soft limit. - if dir, err := os.Open("/dev/fd"); err != nil { + dir, err := os.Open("/dev/fd") + if err != nil { return 0.0, err - } else { - defer dir.Close() - - // Avoid ReadDir(), as it calls stat(2) on each descriptor. Not only is - // that info not used, but KQUEUE descriptors fail stat(2), which causes - // the whole method to fail. - if names, err := dir.Readdirnames(0); err != nil { - return 0.0, err - } else { - // Subtract 1 to ignore the open /dev/fd descriptor above. - return float64(len(names) - 1), nil - } } + defer dir.Close() + + // Avoid ReadDir(), as it calls stat(2) on each descriptor. Not only is + // that info not used, but KQUEUE descriptors fail stat(2), which causes + // the whole method to fail. + names, err := dir.Readdirnames(0) + if err != nil { + return 0.0, err + } + + // Subtract 1 to ignore the open /dev/fd descriptor above. + return float64(len(names) - 1), nil } func (c *processCollector) processCollect(ch chan<- Metric) { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_not_supported.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_not_supported.go index 7732b7f37..8650b6f4a 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_not_supported.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_not_supported.go @@ -12,7 +12,6 @@ // limitations under the License. //go:build wasip1 || js || ios -// +build wasip1 js ios package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_procfsenabled.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_procfsenabled.go index 8074f70f5..56c97d62e 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_procfsenabled.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_procfsenabled.go @@ -12,7 +12,6 @@ // limitations under the License. //go:build !windows && !js && !wasip1 && !darwin -// +build !windows,!js,!wasip1,!darwin package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go index c28af5ce2..0af3deebf 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go @@ -51,10 +51,12 @@ import ( ) const ( + acceptHeader = "Accept" contentTypeHeader = "Content-Type" contentEncodingHeader = "Content-Encoding" acceptEncodingHeader = "Accept-Encoding" processStartTimeHeader = "Process-Start-Time-Unix" + varyHeader = "Vary" ) // Compression represents the content encodings handlers support for the HTTP @@ -70,9 +72,8 @@ const ( func defaultCompressionFormats() []Compression { if internal.NewZstdWriter != nil { return []Compression{Identity, Gzip, Zstd} - } else { - return []Compression{Identity, Gzip} } + return []Compression{Identity, Gzip} } var gzipPool = sync.Pool{ @@ -315,11 +316,20 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO } } - var contentType expfmt.Format - if opts.EnableOpenMetrics { - contentType = expfmt.NegotiateIncludingOpenMetrics(req.Header) - } else { - contentType = expfmt.Negotiate(req.Header) + var ( + contentType expfmt.Format + acceptedFormats = opts.AcceptedFormats + ) + if len(acceptedFormats) == 0 { + acceptedFormats = expfmt.DefaultAcceptedFormats() + if opts.EnableOpenMetrics { + acceptedFormats = expfmt.DefaultOpenMetricsAcceptedFormats() + } + } + contentType = expfmt.NegotiateAccept(req.Header, acceptedFormats...) + rsp.Header().Add(varyHeader, acceptHeader) + if len(compressions) > 0 { + rsp.Header().Add(varyHeader, acceptEncodingHeader) } rsp.Header().Set(contentTypeHeader, string(contentType)) @@ -598,6 +608,8 @@ type HandlerOpts struct { // a trailing ".0" if they would otherwise look like integer numbers // (which changes the identity of the resulting series on the Prometheus // server). + // + // Note that setting AcceptedFormats overrides this option. EnableOpenMetrics bool // EnableOpenMetricsTextCreatedSamples specifies if this handler should add, extra, synthetic // Created Timestamps for counters, histograms and summaries, which for the current @@ -622,6 +634,18 @@ type HandlerOpts struct { // NOTE: This feature is experimental and not covered by OpenMetrics or Prometheus // exposition format. ProcessStartTime time.Time + // AcceptedFormats allows customizing the formats the handler will negotiate + // with the client based on the request's Accept header. + // The client's Accept header and q-values take precedence, but the order of + // formats in AcceptedFormats specifies the server's preference order used as a + // tie-breaker (e.g. for wildcard "*/*" requests or equal q-values) and fallback. + // If empty, the default set is used (expfmt.DefaultAcceptedFormats()). + // If empty and EnableOpenMetrics is true, stable OpenMetrics formats are negotiated + // (expfmt.DefaultOpenMetricsAcceptedFormats()). + // This is useful for testing experimental formats (e.g. OpenMetrics 2.0) + // or restricting the formats you want to allow. + // Using EnableOpenMetrics with an empty AcceptedFormats is still the recommended option for the majority of cases. + AcceptedFormats []expfmt.Format } // httpError removes any content-encoding header and then calls http.Error with diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go index d4c0954f3..258a2a5b5 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go @@ -41,7 +41,7 @@ type options struct { func defaultOptions() *options { return &options{ - getExemplarFn: func(req *http.Request) prometheus.Labels { return nil }, + getExemplarFn: func(_ *http.Request) prometheus.Labels { return nil }, extraLabelsFromRequest: map[string]LabelValueFromRequest{}, } } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go index ed0681c8b..4151b59c4 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go @@ -17,6 +17,7 @@ import ( "bytes" "errors" "fmt" + "maps" "os" "path/filepath" "runtime" @@ -31,7 +32,6 @@ import ( "github.com/cespare/xxhash/v2" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" - "google.golang.org/protobuf/proto" ) const ( @@ -296,6 +296,7 @@ func (r *Registry) Register(c Collector) error { defer func() { // Drain channel in case of premature return to not leak a goroutine. for range descChan { + continue } r.mtx.Unlock() }() @@ -369,9 +370,7 @@ func (r *Registry) Register(c Collector) error { for hash := range newDescIDs { r.descIDs[hash] = struct{}{} } - for name, dimHash := range newDimHashesByName { - r.dimHashesByName[name] = dimHash - } + maps.Copy(r.dimHashesByName, newDimHashesByName) return nil } @@ -476,7 +475,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { for { select { case collector := <-checkedCollectors: - safeErrs.Append((safeCollect(collector, checkedMetricChan))) + safeErrs.Append(safeCollect(collector, checkedMetricChan)) case collector := <-uncheckedCollectors: safeErrs.Append(safeCollect(collector, uncheckedMetricChan)) default: @@ -502,10 +501,12 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { defer func() { if checkedMetricChan != nil { for range checkedMetricChan { + continue } } if uncheckedMetricChan != nil { for range uncheckedMetricChan { + continue } } }() @@ -727,10 +728,10 @@ func processMetric( } } else { // New name. metricFamily = &dto.MetricFamily{} - metricFamily.Name = proto.String(desc.fqName) - metricFamily.Help = proto.String(desc.help) + metricFamily.Name = new(desc.fqName) + metricFamily.Help = new(desc.help) if desc.unit != "" { - metricFamily.Unit = proto.String(desc.unit) + metricFamily.Unit = new(desc.unit) } // TODO(beorn7): Simplify switch once Desc has type. switch { @@ -956,7 +957,8 @@ func checkMetricConsistency( if !utf8.ValidString(labelPair.GetValue()) { return fmt.Errorf( "collected metric %q { %s} has a label named %q whose value is not utf8: %#v", - name, dtoMetric, labelName, labelPair.GetValue()) + name, dtoMetric, labelName, labelPair.GetValue(), + ) } previousLabelName = labelName } @@ -981,7 +983,7 @@ func checkMetricConsistency( h.Write(separatorByteSlice) } if dtoMetric.TimestampMs != nil { - h.WriteString(strconv.FormatInt(*(dtoMetric.TimestampMs), 10)) + h.WriteString(strconv.FormatInt(*dtoMetric.TimestampMs, 10)) h.Write(separatorByteSlice) } hSum := h.Sum64() @@ -1013,7 +1015,7 @@ func checkDescConsistency( copy(lpsFromDesc, desc.constLabelPairs) for _, l := range desc.variableLabels.names { lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ - Name: proto.String(l), + Name: new(l), }) } if len(lpsFromDesc) != len(dtoMetric.Label) { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go index c12b8d13d..d92850ca0 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go @@ -25,7 +25,6 @@ import ( dto "github.com/prometheus/client_model/go" "github.com/beorn7/perks/quantile" - "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -337,8 +336,8 @@ func (s *summary) Write(out *dto.Metric) error { s.bufMtx.Unlock() s.flushColdBuf() - sum.SampleCount = proto.Uint64(s.cnt) - sum.SampleSum = proto.Float64(s.sum) + sum.SampleCount = new(s.cnt) + sum.SampleSum = new(s.sum) for _, rank := range s.sortedObjectives { var q float64 @@ -348,8 +347,8 @@ func (s *summary) Write(out *dto.Metric) error { q = s.headStream.Query(rank) } qs = append(qs, &dto.Quantile{ - Quantile: proto.Float64(rank), - Value: proto.Float64(q), + Quantile: new(rank), + Value: new(q), }) } @@ -512,8 +511,8 @@ func (s *noObjectivesSummary) Write(out *dto.Metric) error { } sum := &dto.Summary{ - SampleCount: proto.Uint64(count), - SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), + SampleCount: new(count), + SampleSum: new(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), CreatedTimestamp: s.createdTs, } @@ -718,13 +717,13 @@ func (s *constSummary) Write(out *dto.Metric) error { } qs := make([]*dto.Quantile, 0, len(s.quantiles)) - sum.SampleCount = proto.Uint64(s.count) - sum.SampleSum = proto.Float64(s.sum) + sum.SampleCount = new(s.count) + sum.SampleSum = new(s.sum) for rank, q := range s.quantiles { qs = append(qs, &dto.Quantile{ - Quantile: proto.Float64(rank), - Value: proto.Float64(q), + Quantile: new(rank), + Value: new(q), }) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/value.go b/vendor/github.com/prometheus/client_golang/prometheus/value.go index cc23011fa..c856e4f33 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/value.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/value.go @@ -23,7 +23,6 @@ import ( "github.com/prometheus/client_golang/prometheus/internal" dto "github.com/prometheus/client_model/go" - "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -196,11 +195,11 @@ func populateMetric( m.Label = labelPairs switch t { case CounterValue: - m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e, CreatedTimestamp: ct} + m.Counter = &dto.Counter{Value: new(v), Exemplar: e, CreatedTimestamp: ct} case GaugeValue: - m.Gauge = &dto.Gauge{Value: proto.Float64(v)} + m.Gauge = &dto.Gauge{Value: new(v)} case UntypedValue: - m.Untyped = &dto.Untyped{Value: proto.Float64(v)} + m.Untyped = &dto.Untyped{Value: new(v)} default: return fmt.Errorf("encountered unknown type %v", t) } @@ -227,8 +226,8 @@ func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair { labelPairs := make([]*dto.LabelPair, 0, totalLen) for i, l := range desc.variableLabels.names { labelPairs = append(labelPairs, &dto.LabelPair{ - Name: proto.String(l), - Value: proto.String(labelValues[i]), + Name: new(l), + Value: new(labelValues[i]), }) } labelPairs = append(labelPairs, desc.constLabelPairs...) @@ -244,7 +243,7 @@ const ExemplarMaxRunes = 128 // number of runes in the label names and values exceeds ExemplarMaxRunes. func newExemplar(value float64, ts time.Time, l Labels) (*dto.Exemplar, error) { e := &dto.Exemplar{} - e.Value = proto.Float64(value) + e.Value = new(value) tsProto := timestamppb.New(ts) if err := tsProto.CheckValid(); err != nil { return nil, err @@ -262,8 +261,8 @@ func newExemplar(value float64, ts time.Time, l Labels) (*dto.Exemplar, error) { } runes += utf8.RuneCountInString(value) labelPairs = append(labelPairs, &dto.LabelPair{ - Name: proto.String(name), - Value: proto.String(value), + Name: new(name), + Value: new(value), }) } if runes > ExemplarMaxRunes { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go index 697f55558..cc9ae8f20 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go @@ -20,7 +20,6 @@ import ( "github.com/prometheus/client_golang/prometheus/internal" dto "github.com/prometheus/client_model/go" - "google.golang.org/protobuf/proto" ) // WrapRegistererWith returns a Registerer wrapping the provided @@ -212,8 +211,8 @@ func (m *wrappingMetric) Write(out *dto.Metric) error { } for ln, lv := range m.labels { out.Label = append(out.Label, &dto.LabelPair{ - Name: proto.String(ln), - Value: proto.String(lv), + Name: new(ln), + Value: new(lv), }) } sort.Sort(internal.LabelPairSorter(out.Label)) diff --git a/vendor/github.com/prometheus/common/expfmt/encode.go b/vendor/github.com/prometheus/common/expfmt/encode.go index 6945356ca..651e69a2c 100644 --- a/vendor/github.com/prometheus/common/expfmt/encode.go +++ b/vendor/github.com/prometheus/common/expfmt/encode.go @@ -18,6 +18,7 @@ import ( "io" "mime" "net/http" + "slices" "github.com/munnerz/goautoneg" dto "github.com/prometheus/client_model/go" @@ -36,7 +37,7 @@ func init() { FmtProtoText, FmtProtoCompact, FmtOpenMetrics_1_0_0, - fmtOpenMetrics_2_0_0, + FmtOpenMetrics_2_0_0, FmtOpenMetrics_0_0_1, } { if parsed := goautoneg.ParseAccept(string(f)); len(parsed) > 0 { @@ -45,6 +46,37 @@ func init() { } } +var ( + defaultAcceptedFormats = []Format{ + FmtProtoDelim, + FmtProtoText, + FmtProtoCompact, + FmtText, + } + + defaultOpenMetricsAcceptedFormats = []Format{ + FmtOpenMetrics_1_0_0, + FmtOpenMetrics_0_0_1, + FmtProtoDelim, + FmtProtoText, + FmtProtoCompact, + FmtText, + } +) + +// DefaultAcceptedFormats returns a copy of standard accepted formats for Negotiate, +// ordered by preference (delimited protobuf, protobuf text, compact protobuf text, +// and Prometheus text format). +func DefaultAcceptedFormats() []Format { + return slices.Clone(defaultAcceptedFormats) +} + +// DefaultOpenMetricsAcceptedFormats returns a copy of standard accepted formats including +// stable OpenMetrics formats, ordered by preference. +func DefaultOpenMetricsAcceptedFormats() []Format { + return slices.Clone(defaultOpenMetricsAcceptedFormats) +} + // Encoder types encode metric families into an underlying wire protocol. type Encoder interface { Encode(*dto.MetricFamily) error @@ -78,19 +110,19 @@ func (ec encoderCloser) Close() error { // appropriate accepted type is found, FmtText is returned (which is the // Prometheus text format). // -// Deprecated: Use NegotiateAccept(h, FmtProtoDelim, FmtProtoText, FmtProtoCompact, FmtText) +// Deprecated: Use NegotiateAccept(h, DefaultAcceptedFormats()...) // or specify only the formats supported by your server. func Negotiate(h http.Header) Format { - return NegotiateAccept(h, FmtProtoDelim, FmtProtoText, FmtProtoCompact, FmtText) + return NegotiateAccept(h, defaultAcceptedFormats...) } -// NegotiateIncludingOpenMetrics works like Negotiate but includes -// FmtOpenMetrics as an option for the result. +// NegotiateIncludingOpenMetrics works like Negotiate but includes all stable +// FmtOpenMetrics formats as an option for the result. // -// Deprecated: Use NegotiateAccept(h, FmtOpenMetrics_1_0_0, FmtOpenMetrics_0_0_1, FmtProtoDelim, FmtProtoText, FmtProtoCompact, FmtText) +// Deprecated: Use NegotiateAccept(h, DefaultOpenMetricsAcceptedFormats()...) // or specify only the formats supported by your server. func NegotiateIncludingOpenMetrics(h http.Header) Format { - return NegotiateAccept(h, FmtOpenMetrics_1_0_0, FmtOpenMetrics_0_0_1, FmtProtoDelim, FmtProtoText, FmtProtoCompact, FmtText) + return NegotiateAccept(h, defaultOpenMetricsAcceptedFormats...) } // NegotiateAccept returns the Content-Type based on the given Accept header diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go index 40035f201..ea9a0a2a0 100644 --- a/vendor/github.com/prometheus/common/expfmt/expfmt.go +++ b/vendor/github.com/prometheus/common/expfmt/expfmt.go @@ -16,27 +16,20 @@ package expfmt import ( "errors" + "mime" "strings" "github.com/prometheus/common/model" ) -// Format specifies the HTTP content type of the different wire protocols. -type Format string - // 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. +// protocols. const ( TextVersion = "0.0.4" ProtoType = `application/vnd.google.protobuf` ProtoProtocol = `io.prometheus.client.MetricFamily` - // Deprecated: Use expfmt.NewFormat(expfmt.TypeProtoCompact) instead. - ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";" + ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";" + OpenMetricsType = `application/openmetrics-text` //nolint:revive // Allow for underscores. OpenMetricsVersion_0_0_1 = "0.0.1" @@ -44,27 +37,28 @@ const ( OpenMetricsVersion_1_0_0 = "1.0.0" //nolint:revive // Allow for underscores. OpenMetricsVersion_2_0_0 = "2.0.0" +) - // The Content-Type values for the different wire protocols. Do not do direct - // comparisons to these constants, instead use the comparison functions. - // - // Deprecated: Use expfmt.NewFormat(expfmt.TypeUnknown) instead. - FmtUnknown Format = `` - // Deprecated: Use expfmt.NewFormat(expfmt.TypeTextPlain) instead. - FmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8` - // Deprecated: Use expfmt.NewFormat(expfmt.TypeProtoDelim) instead. - FmtProtoDelim Format = ProtoFmt + ` encoding=delimited` - // Deprecated: Use expfmt.NewFormat(expfmt.TypeProtoText) instead. - FmtProtoText Format = ProtoFmt + ` encoding=text` - // Deprecated: Use expfmt.NewFormat(expfmt.TypeProtoCompact) instead. +// Format specifies the HTTP content type of the different wire protocols. +// The Content-Type values for the different wire protocols represent +// baseline Content-Types used for HTTP headers and content negotiation. +// +// Because Content-Types on the wire may include dynamic parameters +// (such as "; escaping=...") or whitespace variations, avoid comparing Format +// values using direct equality (==). +type Format string + +const ( + FmtUnknown Format = `` + FmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8` + FmtProtoDelim Format = ProtoFmt + ` encoding=delimited` + FmtProtoText Format = ProtoFmt + ` encoding=text` FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text` - // Deprecated: Use expfmt.NewFormat(expfmt.TypeOpenMetrics) instead. + //nolint:revive // Allow for underscores. + FmtOpenMetrics_2_0_0 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_2_0_0 + `; charset=utf-8` //nolint:revive // Allow for underscores. FmtOpenMetrics_1_0_0 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_1_0_0 + `; charset=utf-8` //nolint:revive // Allow for underscores. - fmtOpenMetrics_2_0_0 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_2_0_0 + `; charset=utf-8` - // Deprecated: Use expfmt.NewFormat(expfmt.TypeOpenMetrics) instead. - //nolint:revive // Allow for underscores. FmtOpenMetrics_0_0_1 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_0_0_1 + `; charset=utf-8` ) @@ -90,7 +84,7 @@ const ( // 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 +// encode.go. If a type has more than one version, the latest stable version will be // returned. func NewFormat(t FormatType) Format { switch t { @@ -112,8 +106,8 @@ func NewFormat(t FormatType) Format { // NewOpenMetricsFormat generates a new OpenMetrics format matching the // specified version number. // -// Note: OpenMetrics version 2.0.0 is experimental and encode-only (currently -// supporting counter, gauge, and untyped metric types). +// Note: OpenMetrics version 2.0.0 is experimental and encode-only (supporting +// counter, gauge, summary, untyped, histogram, and gaugehistogram metric types). func NewOpenMetricsFormat(version string) (Format, error) { if version == OpenMetricsVersion_0_0_1 { return FmtOpenMetrics_0_0_1, nil @@ -122,33 +116,21 @@ func NewOpenMetricsFormat(version string) (Format, error) { return FmtOpenMetrics_1_0_0, nil } if version == OpenMetricsVersion_2_0_0 { - // OpenMetrics 2.0.0 is experimental and encode-only (counter/gauge/untyped). - return fmtOpenMetrics_2_0_0, nil + // OpenMetrics 2.0.0 is experimental and encode-only. + return FmtOpenMetrics_2_0_0, nil } return FmtUnknown, errors.New("unknown open metrics version string") } -// WithEscapingScheme returns a copy of Format with the specified escaping -// scheme appended to the end. If an escaping scheme already exists it is -// removed. -func (f Format) WithEscapingScheme(s model.EscapingScheme) Format { - var terms []string - for p := range strings.SplitSeq(string(f), ";") { - toks := strings.Split(p, "=") - if len(toks) != 2 { - trimmed := strings.TrimSpace(p) - if len(trimmed) > 0 { - terms = append(terms, trimmed) - } - continue - } - key := strings.TrimSpace(toks[0]) - if key != model.EscapingKey { - terms = append(terms, strings.TrimSpace(p)) - } +// Version returns the version parameter without validating whether it is supported. +// It returns an empty string if the parameter is absent or the Content-Type +// cannot be parsed. +func (f Format) Version() string { + _, params, err := mime.ParseMediaType(string(f)) + if err != nil { + return "" } - terms = append(terms, model.EscapingKey+"="+s.String()) - return Format(strings.Join(terms, "; ")) + return params["version"] } // FormatType deduces an overall FormatType for the given format. @@ -200,8 +182,31 @@ func (f Format) FormatType() FormatType { } } -// 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 +// WithEscapingScheme returns a copy of Format with the specified escaping +// scheme appended to the end. If an escaping scheme already exists it is +// removed. +func (f Format) WithEscapingScheme(s model.EscapingScheme) Format { + var terms []string + for p := range strings.SplitSeq(string(f), ";") { + toks := strings.Split(p, "=") + if len(toks) != 2 { + trimmed := strings.TrimSpace(p) + if len(trimmed) > 0 { + terms = append(terms, trimmed) + } + continue + } + key := strings.TrimSpace(toks[0]) + if key != model.EscapingKey { + terms = append(terms, strings.TrimSpace(p)) + } + } + terms = append(terms, model.EscapingKey+"="+s.String()) + return Format(strings.Join(terms, "; ")) +} + +// ToEscapingScheme returns an EscapingScheme depending on the Format. IFF the +// Format contains an 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 (f Format) ToEscapingScheme() model.EscapingScheme { diff --git a/vendor/github.com/prometheus/common/expfmt/openmetrics_2_0_create.go b/vendor/github.com/prometheus/common/expfmt/openmetrics_2_0_create.go index 8ca9b6be7..600ac32f5 100644 --- a/vendor/github.com/prometheus/common/expfmt/openmetrics_2_0_create.go +++ b/vendor/github.com/prometheus/common/expfmt/openmetrics_2_0_create.go @@ -21,6 +21,7 @@ import ( "math" "strconv" "strings" + "unicode/utf8" dto "github.com/prometheus/client_model/go" "google.golang.org/protobuf/types/known/timestamppb" @@ -31,11 +32,16 @@ import ( // It returns the number of bytes written and any error encountered. // // NOTE: This method targets OpenMetrics 2.0.0 (currently aligned with 2.0-rc.0) which is experimental and -// encode-only (currently supporting counter, gauge, and untyped metric types). -// Breaking changes might happen in the future. This implementation is still a -// work-in-progress, and does not yet support all features of the format. +// encode-only. All metric types defined in client_model (counter, gauge, summary, untyped, histogram, +// and gaugehistogram) are supported; info and stateset are not supported as they are not present in +// client_model. Breaking changes might happen in the future. // EncoderOptions are accepted for signature compatibility with // MetricFamilyToOpenMetrics and are currently ignored. +// +// OpenMetrics 2.0 enforces stricter validation rules defined in the specification +// than Prometheus text or OpenMetrics 1.0 formats (such as requiring non-negative +// count and sum, and non-negative quantile values for summaries). Consequently, +// MetricFamilyToOpenMetrics20 may reject metric families that the other encoders accept. func MetricFamilyToOpenMetrics20(out io.Writer, in *dto.MetricFamily, options ...EncoderOption) (written int, err error) { // Options are accepted for signature compatibility and ignored. _ = options @@ -46,8 +52,26 @@ func MetricFamilyToOpenMetrics20(out io.Writer, in *dto.MetricFamily, options .. if containsRawNewline(name) { return 0, fmt.Errorf("MetricFamily name %q contains raw newlines", name) } - if in.Unit != nil && containsRawNewline(*in.Unit) { - return 0, fmt.Errorf("MetricFamily unit %q contains raw newlines", *in.Unit) + if !utf8.ValidString(name) { + return 0, fmt.Errorf("MetricFamily name %q is not valid UTF-8", name) + } + if in.Help != nil { + if !utf8.ValidString(*in.Help) { + return 0, fmt.Errorf("MetricFamily help %q is not valid UTF-8", *in.Help) + } + // A carriage return may appear in HELP, but not at the end, where it + // would make the line end in "\r\n". + if strings.HasSuffix(*in.Help, "\r") { + return 0, fmt.Errorf("MetricFamily help %q ends with a carriage return", *in.Help) + } + } + if in.Unit != nil { + if containsRawNewline(*in.Unit) { + return 0, fmt.Errorf("MetricFamily unit %q contains raw newlines", *in.Unit) + } + if !utf8.ValidString(*in.Unit) { + return 0, fmt.Errorf("MetricFamily unit %q is not valid UTF-8", *in.Unit) + } } // Try the interface upgrade. If it doesn't work, we'll use a @@ -340,21 +364,773 @@ func writeOpenMetrics20Timestamp(w enhancedWriter, f float64) (int, error) { return written, err } -// Stubs for Summary and Histogram - func writeCompositeSummary(w enhancedWriter, name string, metric *dto.Metric) (int, error) { - _ = w - _ = name - _ = metric - return 0, errors.New("summary not implemented yet") + s := metric.Summary + if s == nil { + return 0, fmt.Errorf("expected summary in metric %s", name) + } + + if err := validateLabels20(metric.Label); err != nil { + return 0, err + } + for _, lp := range metric.Label { + if lp.GetName() == "quantile" { + return 0, fmt.Errorf("metric %s is a summary but label set contains %q label", name, "quantile") + } + } + + sum := s.GetSampleSum() + if math.IsNaN(sum) { + return 0, fmt.Errorf("summary sum cannot be NaN in metric %s", name) + } + if sum < 0 { + return 0, fmt.Errorf("summary sum cannot be negative (%g) in metric %s", sum, name) + } + + var prevQuantile float64 + for i, q := range s.Quantile { + if q == nil { + return 0, fmt.Errorf("expected non-nil quantile in metric %s", name) + } + qv := q.GetQuantile() + if math.IsNaN(qv) { + return 0, fmt.Errorf("summary quantile cannot be NaN in metric %s", name) + } + if qv < 0 || qv > 1 { + return 0, fmt.Errorf("summary quantile %g must be between 0 and 1 in metric %s", qv, name) + } + if i > 0 && qv <= prevQuantile { + return 0, fmt.Errorf("summary quantiles must be strictly increasing: %g <= %g in metric %s", qv, prevQuantile, name) + } + prevQuantile = qv + + v := q.GetValue() + if !math.IsNaN(v) && v < 0 { + return 0, fmt.Errorf("summary quantile value cannot be negative (%g) in metric %s", v, name) + } + } + + if s.CreatedTimestamp != nil { + if err := s.CreatedTimestamp.CheckValid(); err != nil { + return 0, fmt.Errorf("invalid created timestamp in metric %s: %w", name, err) + } + } + + written := 0 + n, err := writeOpenMetricsNameAndLabelPairs(w, name, metric.Label, "", 0) + written += n + if err != nil { + return written, err + } + + n, err = w.WriteString(" {count:") + written += n + if err != nil { + return written, err + } + + n, err = writeUint(w, s.GetSampleCount()) + written += n + if err != nil { + return written, err + } + + n, err = w.WriteString(",sum:") + written += n + if err != nil { + return written, err + } + + n, err = writeFloat(w, sum) + written += n + if err != nil { + return written, err + } + + n, err = w.WriteString(",quantile:[") + written += n + if err != nil { + return written, err + } + + for i, q := range s.Quantile { + if i > 0 { + err = w.WriteByte(',') + written++ + if err != nil { + return written, err + } + } + n, err = writeFloat(w, q.GetQuantile()) + written += n + if err != nil { + return written, err + } + err = w.WriteByte(':') + written++ + if err != nil { + return written, err + } + n, err = writeFloat(w, q.GetValue()) + written += n + if err != nil { + return written, err + } + } + + n, err = w.WriteString("]}") + written += n + if err != nil { + return written, err + } + + if metric.TimestampMs != nil { + err = w.WriteByte(' ') + written++ + if err != nil { + return written, err + } + n, err = writeOpenMetrics20Timestamp(w, float64(*metric.TimestampMs)/1000) + written += n + if err != nil { + return written, err + } + } + + if s.CreatedTimestamp != nil { + n, err = w.WriteString(" st@") + written += n + if err != nil { + return written, err + } + n, err = writeProtoTimestamp(w, s.CreatedTimestamp) + written += n + if err != nil { + return written, err + } + } + + err = w.WriteByte('\n') + written++ + if err != nil { + return written, err + } + + return written, nil } func writeCompositeHistogram(w enhancedWriter, name string, metric *dto.Metric, isGauge bool) (int, error) { - _ = w - _ = name - _ = metric - _ = isGauge - return 0, errors.New("histogram not implemented yet") + h := metric.Histogram + if h == nil { + return 0, fmt.Errorf("expected histogram in metric %s", name) + } + + isNative := h.Schema != nil + hasClassicBuckets := len(h.Bucket) > 0 || !isNative + + if err := validateLabels20(metric.Label); err != nil { + return 0, err + } + if hasClassicBuckets { + for _, lp := range metric.Label { + if lp.GetName() == "le" { + return 0, fmt.Errorf("metric %s has classic buckets but label set contains %q label", name, "le") + } + } + } + + if h.SampleCountFloat != nil { + c := *h.SampleCountFloat + if math.IsNaN(c) { + if isGauge { + return 0, fmt.Errorf("gaugehistogram count cannot be NaN in metric %s", name) + } + return 0, fmt.Errorf("histogram count cannot be NaN in metric %s", name) + } + if !isGauge && c < 0 { + return 0, fmt.Errorf("histogram count cannot be negative (%g) in metric %s", c, name) + } + } + + var isFloatCount bool + var sampleCountFloat float64 + var sampleCountUint uint64 + switch { + case h.SampleCountFloat != nil && (*h.SampleCountFloat > 0 || h.SampleCount == nil || isGauge): + isFloatCount = true + sampleCountFloat = *h.SampleCountFloat + case h.SampleCount != nil: + sampleCountUint = *h.SampleCount + sampleCountFloat = float64(sampleCountUint) + } + + if isNative { + if err := validateNativeHistogram(name, h, isGauge); err != nil { + return 0, err + } + } + + if hasClassicBuckets { + if err := validateClassicBuckets(name, h, sampleCountFloat, sampleCountUint, isFloatCount, isGauge); err != nil { + return 0, err + } + } + + if !isGauge && h.CreatedTimestamp != nil { + if err := h.CreatedTimestamp.CheckValid(); err != nil { + return 0, fmt.Errorf("invalid created timestamp in metric %s: %w", name, err) + } + } + + written := 0 + n, err := writeOpenMetricsNameAndLabelPairs(w, name, metric.Label, "", 0) + written += n + if err != nil { + return written, err + } + + n, err = w.WriteString(" {") + written += n + if err != nil { + return written, err + } + + if isGauge { + n, err = w.WriteString("gcount:") + } else { + n, err = w.WriteString("count:") + } + written += n + if err != nil { + return written, err + } + + if isFloatCount { + n, err = writeFloat(w, sampleCountFloat) + } else { + n, err = writeUint(w, sampleCountUint) + } + written += n + if err != nil { + return written, err + } + + if isGauge { + n, err = w.WriteString(",gsum:") + } else { + n, err = w.WriteString(",sum:") + } + written += n + if err != nil { + return written, err + } + n, err = writeFloat(w, h.GetSampleSum()) + written += n + if err != nil { + return written, err + } + + if isNative { + n, err = writeNativeBuckets(w, h, isGauge) + written += n + if err != nil { + return written, err + } + } + + var classicExemplars []*dto.Exemplar + if hasClassicBuckets { + n, err = writeClassicBuckets(w, h, sampleCountFloat, sampleCountUint, isFloatCount, isGauge, &classicExemplars) + written += n + if err != nil { + return written, err + } + } + + err = w.WriteByte('}') + written++ + if err != nil { + return written, err + } + + if metric.TimestampMs != nil { + err = w.WriteByte(' ') + written++ + if err != nil { + return written, err + } + n, err = writeOpenMetrics20Timestamp(w, float64(*metric.TimestampMs)/1000) + written += n + if err != nil { + return written, err + } + } + + if !isGauge && h.CreatedTimestamp != nil { + ts := h.CreatedTimestamp + n, err = w.WriteString(" st@") + written += n + if err != nil { + return written, err + } + n, err = writeProtoTimestamp(w, ts) + written += n + if err != nil { + return written, err + } + } + + var exemplarsToEmit []*dto.Exemplar + if len(classicExemplars) > 0 { + // We follow the spec suggestion and prefer classic histogram + // exemplars in dual mode. + exemplarsToEmit = classicExemplars + } else if len(h.Exemplars) > 0 { + exemplarsToEmit = h.Exemplars + } + + for _, e := range exemplarsToEmit { + if e == nil || e.Timestamp == nil { + continue + } + n, err = writeExemplar20(w, e) + written += n + if err != nil { + return written, err + } + } + + err = w.WriteByte('\n') + written++ + if err != nil { + return written, err + } + + return written, nil +} + +func validateNativeHistogram(name string, h *dto.Histogram, isGauge bool) error { + schema := *h.Schema + if schema < -4 || schema > 8 { + return fmt.Errorf("native histogram schema %d is out of range [-4, 8] in metric %s", schema, name) + } + + zeroThreshold := h.GetZeroThreshold() + if math.IsNaN(zeroThreshold) || math.IsInf(zeroThreshold, 0) || zeroThreshold < 0 { + return fmt.Errorf("native histogram zero_threshold %g must be a non-negative, finite number in metric %s", zeroThreshold, name) + } + + if h.ZeroCountFloat != nil { + c := *h.ZeroCountFloat + if math.IsNaN(c) { + return fmt.Errorf("native histogram zero_count cannot be NaN in metric %s", name) + } + if !isGauge && c < 0 { + return fmt.Errorf("native histogram zero_count cannot be negative (%g) in metric %s", c, name) + } + } + + if err := validateSpansAndBuckets(name, "negative", h.NegativeSpan, h.NegativeDelta, h.NegativeCount, isGauge); err != nil { + return err + } + return validateSpansAndBuckets(name, "positive", h.PositiveSpan, h.PositiveDelta, h.PositiveCount, isGauge) +} + +func validateSpansAndBuckets( + name string, + spanName string, + spans []*dto.BucketSpan, + deltas []int64, + floatCounts []float64, + isGauge bool, +) error { + isFloatBuckets := len(floatCounts) > 0 + var numBuckets int + if isFloatBuckets { + numBuckets = len(floatCounts) + } else { + numBuckets = len(deltas) + } + + var totalLength uint64 + for i, span := range spans { + if span == nil { + return errors.New("expected non-nil bucket span") + } + if i > 0 && span.GetOffset() < 0 { + return fmt.Errorf("subsequent %s span offset cannot be negative: %d in metric %s", spanName, span.GetOffset(), name) + } + totalLength += uint64(span.GetLength()) + } + + if numBuckets == 0 { + if totalLength == 0 { + return nil + } + return fmt.Errorf("sum of %s span lengths (%d) does not match bucket count (0) in metric %s", spanName, totalLength, name) + } + + if totalLength != uint64(numBuckets) { + return fmt.Errorf("sum of %s span lengths (%d) does not match bucket count (%d) in metric %s", spanName, totalLength, numBuckets, name) + } + + if isFloatBuckets { + for _, v := range floatCounts { + if math.IsNaN(v) { + return fmt.Errorf("%s bucket count cannot be NaN in metric %s", spanName, name) + } + if !isGauge && v < 0 { + return fmt.Errorf("%s bucket count cannot be negative (%g) in metric %s", spanName, v, name) + } + } + } else { + var current int64 + for _, d := range deltas { + current += d + if !isGauge && current < 0 { + return fmt.Errorf("%s bucket count cannot be negative (%d) in metric %s", spanName, current, name) + } + } + } + return nil +} + +func writeNativeBuckets(w enhancedWriter, h *dto.Histogram, isGauge bool) (int, error) { + schema := *h.Schema + zeroThreshold := h.GetZeroThreshold() + + var isFloatZeroCount bool + var zeroCountFloat float64 + var zeroCountUint uint64 + switch { + case h.ZeroCountFloat != nil && (*h.ZeroCountFloat > 0 || h.ZeroCount == nil || isGauge): + isFloatZeroCount = true + zeroCountFloat = *h.ZeroCountFloat + case h.ZeroCount != nil: + zeroCountUint = *h.ZeroCount + zeroCountFloat = float64(zeroCountUint) + } + + written := 0 + n, err := w.WriteString(",schema:") + written += n + if err != nil { + return written, err + } + n, err = writeInt(w, int64(schema)) + written += n + if err != nil { + return written, err + } + + n, err = w.WriteString(",zero_threshold:") + written += n + if err != nil { + return written, err + } + n, err = writeFloat(w, zeroThreshold) + written += n + if err != nil { + return written, err + } + + n, err = w.WriteString(",zero_count:") + written += n + if err != nil { + return written, err + } + if isFloatZeroCount { + n, err = writeFloat(w, zeroCountFloat) + } else { + n, err = writeUint(w, zeroCountUint) + } + written += n + if err != nil { + return written, err + } + + n, err = writeSpansAndBuckets(w, ",negative_spans:[", ",negative_buckets:[", h.NegativeSpan, h.NegativeDelta, h.NegativeCount) + written += n + if err != nil { + return written, err + } + + n, err = writeSpansAndBuckets(w, ",positive_spans:[", ",positive_buckets:[", h.PositiveSpan, h.PositiveDelta, h.PositiveCount) + written += n + if err != nil { + return written, err + } + + return written, nil +} + +func writeSpansAndBuckets( + w enhancedWriter, + spansPrefix string, + bucketsPrefix string, + spans []*dto.BucketSpan, + deltas []int64, + floatCounts []float64, +) (int, error) { + isFloatBuckets := len(floatCounts) > 0 + var numBuckets int + if isFloatBuckets { + numBuckets = len(floatCounts) + } else { + numBuckets = len(deltas) + } + + if numBuckets == 0 { + return 0, nil + } + + written := 0 + n, err := w.WriteString(spansPrefix) + written += n + if err != nil { + return written, err + } + for i, span := range spans { + if i > 0 { + err = w.WriteByte(',') + written++ + if err != nil { + return written, err + } + } + n, err = writeInt(w, int64(span.GetOffset())) + written += n + if err != nil { + return written, err + } + err = w.WriteByte(':') + written++ + if err != nil { + return written, err + } + n, err = writeUint(w, uint64(span.GetLength())) + written += n + if err != nil { + return written, err + } + } + err = w.WriteByte(']') + written++ + if err != nil { + return written, err + } + + n, err = w.WriteString(bucketsPrefix) + written += n + if err != nil { + return written, err + } + if isFloatBuckets { + for i, v := range floatCounts { + if i > 0 { + err = w.WriteByte(',') + written++ + if err != nil { + return written, err + } + } + n, err = writeFloat(w, v) + written += n + if err != nil { + return written, err + } + } + } else { + var current int64 + for i, d := range deltas { + if i > 0 { + err = w.WriteByte(',') + written++ + if err != nil { + return written, err + } + } + current += d + n, err = writeInt(w, current) + written += n + if err != nil { + return written, err + } + } + } + err = w.WriteByte(']') + written++ + if err != nil { + return written, err + } + + return written, nil +} + +func validateClassicBuckets( + name string, + h *dto.Histogram, + sampleCount float64, + sampleCountUint uint64, + isFloatCount bool, + isGauge bool, +) error { + var infSeen bool + var prevBound float64 + var prevCount float64 + for i, b := range h.Bucket { + if b == nil { + return errors.New("expected non-nil bucket") + } + ub := b.GetUpperBound() + if math.IsNaN(ub) { + return fmt.Errorf("classic bucket upper bound cannot be NaN in metric %s", name) + } + if i > 0 && ub <= prevBound { + return fmt.Errorf("classic bucket upper bounds must be strictly increasing: %g <= %g in metric %s", ub, prevBound, name) + } + prevBound = ub + + if b.CumulativeCountFloat != nil { + c := *b.CumulativeCountFloat + if math.IsNaN(c) { + return fmt.Errorf("classic bucket count cannot be NaN in metric %s", name) + } + if !isGauge && c < 0 { + return fmt.Errorf("classic bucket count cannot be negative (%g) in metric %s", c, name) + } + } + + var bCount float64 + switch { + case b.CumulativeCountFloat != nil && (*b.CumulativeCountFloat > 0 || b.CumulativeCount == nil || isGauge): + bCount = *b.CumulativeCountFloat + case b.CumulativeCount != nil: + bCount = float64(*b.CumulativeCount) + } + + if !isGauge && i > 0 && bCount < prevCount { + return fmt.Errorf("classic bucket counts must be monotonically increasing: %g < %g in metric %s", bCount, prevCount, name) + } + prevCount = bCount + + if math.IsInf(ub, +1) { + if i != len(h.Bucket)-1 { + return fmt.Errorf("+Inf bucket must be the last bucket in metric %s", name) + } + infSeen = true + if isFloatCount { + if bCount != sampleCount { + return fmt.Errorf("classic bucket +Inf count (%g) does not match sample count (%g) in metric %s", bCount, sampleCount, name) + } + } else { + if b.CumulativeCount != nil { + if *b.CumulativeCount != sampleCountUint { + return fmt.Errorf("classic bucket +Inf count (%d) does not match sample count (%d) in metric %s", *b.CumulativeCount, sampleCountUint, name) + } + } else { + if bCount < 0 || bCount > math.MaxUint64 || uint64(bCount) != sampleCountUint || float64(uint64(bCount)) != bCount { + return fmt.Errorf("classic bucket +Inf count (%g) does not match sample count (%d) in metric %s", bCount, sampleCountUint, name) + } + } + } + } + } + + if !infSeen && len(h.Bucket) > 0 && !isGauge { + if sampleCount < prevCount { + return fmt.Errorf("sample count (%g) is less than highest bucket count (%g) in metric %s", sampleCount, prevCount, name) + } + } + return nil +} + +func writeClassicBuckets( + w enhancedWriter, + h *dto.Histogram, + sampleCount float64, + sampleCountUint uint64, + isFloatCount bool, + isGauge bool, + collectedExemplars *[]*dto.Exemplar, +) (int, error) { + var infSeen bool + written := 0 + n, err := w.WriteString(",bucket:[") + written += n + if err != nil { + return written, err + } + + for i, b := range h.Bucket { + if i > 0 { + err = w.WriteByte(',') + written++ + if err != nil { + return written, err + } + } + n, err = writeFloat(w, b.GetUpperBound()) + written += n + if err != nil { + return written, err + } + err = w.WriteByte(':') + written++ + if err != nil { + return written, err + } + switch { + case b.CumulativeCountFloat != nil && (*b.CumulativeCountFloat > 0 || b.CumulativeCount == nil || isGauge): + n, err = writeFloat(w, *b.CumulativeCountFloat) + case b.CumulativeCount != nil: + n, err = writeUint(w, *b.CumulativeCount) + default: + n, err = writeUint(w, 0) + } + written += n + if err != nil { + return written, err + } + if math.IsInf(b.GetUpperBound(), +1) { + infSeen = true + } + if b.Exemplar != nil && b.Exemplar.Timestamp != nil { + *collectedExemplars = append(*collectedExemplars, b.Exemplar) + } + } + + if !infSeen { + if len(h.Bucket) > 0 { + err = w.WriteByte(',') + written++ + if err != nil { + return written, err + } + } + n, err = w.WriteString("+Inf:") + written += n + if err != nil { + return written, err + } + if isFloatCount { + n, err = writeFloat(w, sampleCount) + } else { + n, err = writeUint(w, sampleCountUint) + } + written += n + if err != nil { + return written, err + } + } + + err = w.WriteByte(']') + written++ + if err != nil { + return written, err + } + + return written, nil } func validateLabels20(labels []*dto.LabelPair) error { @@ -391,20 +1167,40 @@ func writeProtoTimestamp(w enhancedWriter, ts *timestamppb.Timestamp) (int, erro if err := ts.CheckValid(); err != nil { return 0, err } - n, err := writeInt(w, ts.Seconds) + if ts.Nanos == 0 { + return writeInt(w, ts.Seconds) + } + sec := ts.Seconds + nanos := int64(ts.Nanos) + if sec < 0 { + sec++ + nanos = 1_000_000_000 - nanos + if sec == 0 { + n, err := w.WriteString("-0") + if err != nil { + return n, err + } + n2, err := writeNanos(w, nanos) + return n + n2, err + } + } + + n, err := writeInt(w, sec) if err != nil { return n, err } - if ts.Nanos == 0 { - return n, nil - } - err = w.WriteByte('.') - written := n + 1 + n2, err := writeNanos(w, nanos) + return n + n2, err +} + +func writeNanos(w enhancedWriter, nanos int64) (int, error) { + err := w.WriteByte('.') if err != nil { - return written, err + return 0, err } + written := 1 bp := numBufPool.Get().(*[]byte) - *bp = strconv.AppendInt((*bp)[:0], int64(ts.Nanos), 10) + *bp = strconv.AppendInt((*bp)[:0], nanos, 10) pad := 9 - len(*bp) for range pad { err = w.WriteByte('0') diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go index 4ce1f40b8..10529300f 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_parse.go +++ b/vendor/github.com/prometheus/common/expfmt/text_parse.go @@ -194,6 +194,7 @@ func (p *TextParser) reset(in io.Reader) { // start of a line (or whitespace leading up to it). func (p *TextParser) startOfLine() stateFn { p.lineCount++ + p.currentMetric = nil p.currentMetricIsInsideBraces = false p.currentMetricInsideBracesIsPresent = false if p.skipBlankTab(); p.err != nil { @@ -339,12 +340,11 @@ func (p *TextParser) startLabelName() stateFn { return nil // Unexpected end of input. } if p.currentByte == '}' { - if p.currentMF == nil { + if p.currentMetric == nil { // The closing brace was reached before any metric name was read, // e.g. for the input "{}". There is no metric to attach labels to, // so this is a malformed exposition. This mirrors the guard in - // startLabelValue. currentMF (not currentMetric) is checked because - // reset only clears currentMF between parses. + // startLabelValue. currentMetric is cleared at the start of each line. p.parseError("invalid metric name") p.currentLabelPairs = nil return nil @@ -495,7 +495,7 @@ func (p *TextParser) startLabelValue() stateFn { return p.startLabelName case '}': - if p.currentMF == nil { + if p.currentMetric == nil { p.parseError("invalid metric name") return nil } diff --git a/vendor/github.com/prometheus/common/model/value.go b/vendor/github.com/prometheus/common/model/value.go index 8dffd9c4a..eed5c9ef3 100644 --- a/vendor/github.com/prometheus/common/model/value.go +++ b/vendor/github.com/prometheus/common/model/value.go @@ -224,28 +224,6 @@ func (ss SampleStream) MarshalJSON() ([]byte, error) { } } -func (ss *SampleStream) UnmarshalJSON(b []byte) error { - v := struct { - Metric Metric `json:"metric"` - Values []SamplePair `json:"values"` - Histograms []SampleHistogramPair `json:"histograms"` - }{ - Metric: ss.Metric, - Values: ss.Values, - Histograms: ss.Histograms, - } - - if err := json.Unmarshal(b, &v); err != nil { - return err - } - - ss.Metric = v.Metric - ss.Values = v.Values - ss.Histograms = v.Histograms - - return nil -} - // Scalar is a scalar value evaluated at the set timestamp. type Scalar struct { Value SampleValue `json:"value"` diff --git a/vendor/github.com/prometheus/common/model/value_float127.go b/vendor/github.com/prometheus/common/model/value_float127.go new file mode 100644 index 000000000..821cc1e72 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/value_float127.go @@ -0,0 +1,70 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build go1.27 + +package model + +import ( + "bytes" + "encoding/json/jsontext" + "errors" +) + +var nullBytes = []byte("null") + +func (s *SamplePair) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if t, err := dec.ReadToken(); err != nil { + return err + } else if t.Kind() == jsontext.KindNull { + return nil + } else if t.Kind() != jsontext.KindBeginArray { + return errors.New("expected [") + } + + // Loop until we see the end of the array (tolerate arrays of any length). + for i := 0; dec.PeekKind() != jsontext.KindEndArray; i++ { + switch i { + case 0: + if v, err := dec.ReadValue(); err != nil { + return err + } else if bytes.Equal(v, nullBytes) { + // Skip null values to match SamplePair#UnmarshalJSON behavior. + } else if err := s.Timestamp.UnmarshalJSON(v); err != nil { + return err + } + case 1: + if v, err := dec.ReadValue(); err != nil { + return err + } else if bytes.Equal(v, nullBytes) { + // Skip null values to match SamplePair#UnmarshalJSON behavior. + } else if err := s.Value.UnmarshalJSON(v); err != nil { + return err + } + default: + // Skip any remaining array items to match UnmarshalJSON behavior. + if err := dec.SkipValue(); err != nil { + return err + } + } + } + + // Read the final end array token. + if t, err := dec.ReadToken(); err != nil { + return err + } else if t.Kind() != jsontext.KindEndArray { + return errors.New("expected ]") + } + + return nil +} diff --git a/vendor/github.com/prometheus/common/model/value_histogram127.go b/vendor/github.com/prometheus/common/model/value_histogram127.go new file mode 100644 index 000000000..fbcfb3f94 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/value_histogram127.go @@ -0,0 +1,95 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build go1.27 + +package model + +import ( + "bytes" + "encoding/json/jsontext" + "encoding/json/v2" + "errors" +) + +func (s *SampleHistogramPair) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if t, err := dec.ReadToken(); err != nil { + return err + } else if t.Kind() != jsontext.KindBeginArray { + return errors.New("expected [") + } + + if v, err := dec.ReadValue(); err != nil { + return err + } else if bytes.Equal(v, nullBytes) { + // Skip null values to match SamplePair#UnmarshalJSON behavior. + } else if err := s.Timestamp.UnmarshalJSON(v); err != nil { + return err + } + + if err := json.UnmarshalDecode(dec, &s.Histogram); err != nil { + return err + } else if s.Histogram == nil { + return errors.New("histogram is nil") + } + + if t, err := dec.ReadToken(); err != nil { + return err + } else if t.Kind() != jsontext.KindEndArray { + return errors.New("expected ]") + } + return nil +} + +func (s *HistogramBucket) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if t, err := dec.ReadToken(); err != nil { + return err + } else if t.Kind() != jsontext.KindBeginArray { + return errors.New("expected [") + } + + if err := json.UnmarshalDecode(dec, &s.Boundaries); err != nil { + return err + } + + if v, err := dec.ReadValue(); err != nil { + return err + } else if bytes.Equal(v, nullBytes) { + // Skip null values to match SamplePair#UnmarshalJSON behavior. + } else if err := s.Lower.UnmarshalJSON(v); err != nil { + return err + } + + if v, err := dec.ReadValue(); err != nil { + return err + } else if bytes.Equal(v, nullBytes) { + // Skip null values to match SamplePair#UnmarshalJSON behavior. + } else if err := s.Upper.UnmarshalJSON(v); err != nil { + return err + } + + if v, err := dec.ReadValue(); err != nil { + return err + } else if bytes.Equal(v, nullBytes) { + // Skip null values to match SamplePair#UnmarshalJSON behavior. + } else if err := s.Count.UnmarshalJSON(v); err != nil { + return err + } + + if t, err := dec.ReadToken(); err != nil { + return err + } else if t.Kind() != jsontext.KindEndArray { + return errors.New("expected ]") + } + return nil +} diff --git a/vendor/github.com/prometheus/procfs/.golangci.yml b/vendor/github.com/prometheus/procfs/.golangci.yml index eac920ba8..23ecd4505 100644 --- a/vendor/github.com/prometheus/procfs/.golangci.yml +++ b/vendor/github.com/prometheus/procfs/.golangci.yml @@ -34,14 +34,6 @@ linters: capital: true misspell: locale: US - revive: - rules: - - name: var-naming - # TODO(SuperQ): See: https://github.com/prometheus/prometheus/issues/17766 - arguments: - - [] - - [] - - - skip-package-name-checks: true exclusions: presets: - comments diff --git a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md index 853eb9d49..812a71bb9 100644 --- a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md +++ b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md @@ -96,7 +96,7 @@ The `proc` and `sys` filesystems are pseudo file systems and work a bit differen Many of the files are changing continuously and the data being read can in some cases change between subsequent reads in the same file. Also, most of the files are relatively small (less than a few KBs), and system calls to the `stat` function will often return the wrong size. Therefore, for most files it's recommended to read the -full file in a single operation using an internal utility function called `util.ReadFileNoStat`. +full file in a single operation using an internal utility function called `parsers.ReadFileNoStat`. This function is similar to `os.ReadFile`, but it avoids the system call to `stat` to get the current size of the file. @@ -104,7 +104,7 @@ Note that parsing the file's contents can still be performed one line at a time. the full file, and then using a scanner on the `[]byte` or `string` containing the data. ``` - data, err := util.ReadFileNoStat("/proc/cpuinfo") + data, err := parsers.ReadFileNoStat("/proc/cpuinfo") if err != nil { return err } @@ -113,9 +113,9 @@ the full file, and then using a scanner on the `[]byte` or `string` containing t ``` The `/sys` filesystem contains many very small files which contain only a single numeric or text value. These files -can be read using an internal function called `util.SysReadFile` which is similar to `os.ReadFile` but does +can be read using an internal function called `parsers.SysReadFile` which is similar to `os.ReadFile` but does not bother to check the size of the file before reading. ``` - data, err := util.SysReadFile("/sys/class/power_supply/BAT0/capacity") + data, err := parsers.SysReadFile("/sys/class/power_supply/BAT0/capacity") ``` diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common index a7c5f553e..cd54cb419 100644 --- a/vendor/github.com/prometheus/procfs/Makefile.common +++ b/vendor/github.com/prometheus/procfs/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v2.11.4 +GOLANGCI_LINT_VERSION ?= v2.12.2 GOLANGCI_FMT_OPTS ?= # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. @@ -165,8 +165,9 @@ common-deps: .PHONY: update-go-deps update-go-deps: @echo ">> updating Go dependencies" + # GOTOOLCHAIN prevents go get from pulling deps that require a newer Go version. @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ - $(GO) get $$m; \ + GOTOOLCHAIN=go$$($(GO) mod edit -json | jq -r .Go) $(GO) get $$m; \ done $(GO) mod tidy @@ -246,6 +247,7 @@ common-docker-repo-name: .PHONY: common-docker $(BUILD_DOCKER_ARCHS) common-docker: $(BUILD_DOCKER_ARCHS) +# DOCKER_ARCHS holds promu architecture names, which are not OCI platform strings. $(BUILD_DOCKER_ARCHS): common-docker-%: @for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \ dockerfile=$${variant#*:}; \ @@ -254,10 +256,16 @@ $(BUILD_DOCKER_ARCHS): common-docker-%: if [ "$*" = "armv7" ]; then \ distroless_arch="arm"; \ fi; \ + arch="$*"; \ + case "$$arch" in \ + armv*) docker_platform="linux/arm/v$${arch#armv}";; \ + *) docker_platform="linux/$$arch";; \ + esac; \ if [ "$$dockerfile" = "Dockerfile" ]; then \ echo "Building default variant ($$variant_name) for linux-$* using $$dockerfile"; \ docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \ -f $$dockerfile \ + --platform "$$docker_platform" \ --build-arg ARCH="$*" \ --build-arg OS="linux" \ --build-arg DISTROLESS_ARCH="$$distroless_arch" \ @@ -271,6 +279,7 @@ $(BUILD_DOCKER_ARCHS): common-docker-%: echo "Building $$variant_name variant for linux-$* using $$dockerfile"; \ docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" \ -f $$dockerfile \ + --platform "$$docker_platform" \ --build-arg ARCH="$*" \ --build-arg OS="linux" \ --build-arg DISTROLESS_ARCH="$$distroless_arch" \ diff --git a/vendor/github.com/prometheus/procfs/cmdline.go b/vendor/github.com/prometheus/procfs/cmdline.go index 4f1cac1f0..6a2e7bb0e 100644 --- a/vendor/github.com/prometheus/procfs/cmdline.go +++ b/vendor/github.com/prometheus/procfs/cmdline.go @@ -16,12 +16,12 @@ package procfs import ( "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // CmdLine returns the command line of the kernel. func (fs FS) CmdLine() ([]string, error) { - data, err := util.ReadFileNoStat(fs.proc.Path("cmdline")) + data, err := parsers.ReadFileNoStat(fs.proc.Path("cmdline")) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/cpuinfo.go b/vendor/github.com/prometheus/procfs/cpuinfo.go index 4b23d8d6b..7a31a4555 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo.go @@ -24,7 +24,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // CPUInfo contains general information about a system CPU found in /proc/cpuinfo. @@ -65,7 +65,7 @@ var ( // CPUInfo returns information about current system CPUs. // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt func (fs FS) CPUInfo() ([]CPUInfo, error) { - data, err := util.ReadFileNoStat(fs.proc.Path("cpuinfo")) + data, err := parsers.ReadFileNoStat(fs.proc.Path("cpuinfo")) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/crypto.go b/vendor/github.com/prometheus/procfs/crypto.go index d93b712e0..c4ba05b15 100644 --- a/vendor/github.com/prometheus/procfs/crypto.go +++ b/vendor/github.com/prometheus/procfs/crypto.go @@ -20,7 +20,7 @@ import ( "io" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // Crypto holds info parsed from /proc/crypto. @@ -55,7 +55,7 @@ var cryptoFile = "crypto" // https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html func (fs FS) Crypto() ([]Crypto, error) { path := fs.proc.Path(cryptoFile) - b, err := util.ReadFileNoStat(path) + b, err := parsers.ReadFileNoStat(path) if err != nil { return nil, fmt.Errorf("%w: Cannot read file %v: %w", ErrFileRead, b, err) @@ -112,7 +112,7 @@ func parseCrypto(r io.Reader) ([]Crypto, error) { // parseKV parses a key/value pair into the appropriate field of c. func (c *Crypto) parseKV(k, v string) error { - vp := util.NewValueParser(v) + vp := parsers.NewValueParser(v) switch k { case "async": diff --git a/vendor/github.com/prometheus/procfs/fs_statfs_notype.go b/vendor/github.com/prometheus/procfs/fs_statfs_notype.go index 0bef25bdd..fc16802dc 100644 --- a/vendor/github.com/prometheus/procfs/fs_statfs_notype.go +++ b/vendor/github.com/prometheus/procfs/fs_statfs_notype.go @@ -15,8 +15,8 @@ package procfs -// isRealProc returns true on architectures that don't have a Type argument +// isRealProc returns false on architectures that don't have a Type argument // in their Statfs_t struct. func isRealProc(_ string) (bool, error) { - return true, nil + return false, nil } diff --git a/vendor/github.com/prometheus/procfs/fscache.go b/vendor/github.com/prometheus/procfs/fscache.go index 9dde85707..388295cb4 100644 --- a/vendor/github.com/prometheus/procfs/fscache.go +++ b/vendor/github.com/prometheus/procfs/fscache.go @@ -21,7 +21,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // Fscacheinfo represents fscache statistics. @@ -229,7 +229,7 @@ type Fscacheinfo struct { // Fscacheinfo returns information about current fscache statistics. // See https://www.kernel.org/doc/Documentation/filesystems/caching/fscache.txt func (fs FS) Fscacheinfo() (Fscacheinfo, error) { - b, err := util.ReadFileNoStat(fs.proc.Path("fs/fscache/stats")) + b, err := parsers.ReadFileNoStat(fs.proc.Path("fs/fscache/stats")) if err != nil { return Fscacheinfo{}, err } diff --git a/vendor/github.com/prometheus/procfs/internal/fs/fs.go b/vendor/github.com/prometheus/procfs/internal/fs/fs.go index e7ccad66b..bdd8010a4 100644 --- a/vendor/github.com/prometheus/procfs/internal/fs/fs.go +++ b/vendor/github.com/prometheus/procfs/internal/fs/fs.go @@ -31,6 +31,9 @@ const ( // DefaultSelinuxMountPoint is the common mount point of the selinuxfs. DefaultSelinuxMountPoint = "/sys/fs/selinux" + + // DefaultResctrlMountPoint is the common mount point of the resctrl filesystem. + DefaultResctrlMountPoint = "/sys/fs/resctrl" ) // FS represents a pseudo-filesystem, normally /proc or /sys, which provides an diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/parsers/parse.go similarity index 99% rename from vendor/github.com/prometheus/procfs/internal/util/parse.go rename to vendor/github.com/prometheus/procfs/internal/parsers/parse.go index 30c587201..5789ae5db 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/parse.go +++ b/vendor/github.com/prometheus/procfs/internal/parsers/parse.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package util +package parsers import ( "errors" diff --git a/vendor/github.com/prometheus/procfs/internal/util/readfile.go b/vendor/github.com/prometheus/procfs/internal/parsers/readfile.go similarity index 98% rename from vendor/github.com/prometheus/procfs/internal/util/readfile.go rename to vendor/github.com/prometheus/procfs/internal/parsers/readfile.go index 0e41f71af..c68d29215 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/readfile.go +++ b/vendor/github.com/prometheus/procfs/internal/parsers/readfile.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package util +package parsers import ( "io" diff --git a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go b/vendor/github.com/prometheus/procfs/internal/parsers/sysreadfile.go similarity index 99% rename from vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go rename to vendor/github.com/prometheus/procfs/internal/parsers/sysreadfile.go index f6a4a4de6..0f72f6021 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go +++ b/vendor/github.com/prometheus/procfs/internal/parsers/sysreadfile.go @@ -13,7 +13,7 @@ //go:build (linux || darwin) && !appengine -package util +package parsers import ( "bytes" diff --git a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go b/vendor/github.com/prometheus/procfs/internal/parsers/sysreadfile_compat.go similarity index 98% rename from vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go rename to vendor/github.com/prometheus/procfs/internal/parsers/sysreadfile_compat.go index c80e082cb..6e19c4555 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go +++ b/vendor/github.com/prometheus/procfs/internal/parsers/sysreadfile_compat.go @@ -13,7 +13,7 @@ //go:build (linux && appengine) || (!linux && !darwin) -package util +package parsers import ( "fmt" diff --git a/vendor/github.com/prometheus/procfs/internal/util/valueparser.go b/vendor/github.com/prometheus/procfs/internal/parsers/valueparser.go similarity index 99% rename from vendor/github.com/prometheus/procfs/internal/util/valueparser.go rename to vendor/github.com/prometheus/procfs/internal/parsers/valueparser.go index e0ed671ea..6289fd670 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/valueparser.go +++ b/vendor/github.com/prometheus/procfs/internal/parsers/valueparser.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package util +package parsers import ( "strconv" diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go index 5374da9fa..8a6f73747 100644 --- a/vendor/github.com/prometheus/procfs/ipvs.go +++ b/vendor/github.com/prometheus/procfs/ipvs.go @@ -25,7 +25,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // IPVSStats holds IPVS statistics, as exposed by the kernel in `/proc/net/ip_vs_stats`. @@ -66,7 +66,7 @@ type IPVSBackendStatus struct { // IPVSStats reads the IPVS statistics from the specified `proc` filesystem. func (fs FS) IPVSStats() (IPVSStats, error) { - data, err := util.ReadFileNoStat(fs.proc.Path("net/ip_vs_stats")) + data, err := parsers.ReadFileNoStat(fs.proc.Path("net/ip_vs_stats")) if err != nil { return IPVSStats{}, err } diff --git a/vendor/github.com/prometheus/procfs/kernel_random.go b/vendor/github.com/prometheus/procfs/kernel_random.go index e7c5b8cf2..cbcd12b43 100644 --- a/vendor/github.com/prometheus/procfs/kernel_random.go +++ b/vendor/github.com/prometheus/procfs/kernel_random.go @@ -18,7 +18,7 @@ package procfs import ( "os" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // KernelRandom contains information about to the kernel's random number generator. @@ -48,7 +48,7 @@ func (fs FS) KernelRandom() (KernelRandom, error) { "write_wakeup_threshold": &random.WriteWakeupThreshold, "read_wakeup_threshold": &random.ReadWakeupThreshold, } { - val, err := util.ReadUintFromFile(fs.proc.Path("sys", "kernel", "random", file)) + val, err := parsers.ReadUintFromFile(fs.proc.Path("sys", "kernel", "random", file)) if os.IsNotExist(err) { continue } diff --git a/vendor/github.com/prometheus/procfs/kernel_tainted.go b/vendor/github.com/prometheus/procfs/kernel_tainted.go new file mode 100644 index 000000000..9707f0280 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/kernel_tainted.go @@ -0,0 +1,95 @@ +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build linux + +package procfs + +import ( + "github.com/prometheus/procfs/internal/parsers" +) + +// KernelTaintBit represents a single kernel taint flag. +type KernelTaintBit struct { + // Index is the zero-based bit position in the tainted bitmask. + Index int + // Flag is the letter code identifying this taint (e.g. "L" for soft lockup). + // See https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html + Flag string + // Description is a human-readable explanation of what this taint means. + Description string + // Set indicates whether this taint flag is currently active. + Set bool +} + +// KernelTainted holds the kernel taint state read from /proc/sys/kernel/tainted. +type KernelTainted struct { + // Value is the raw integer from /proc/sys/kernel/tainted. + Value uint64 + // Bits contains each known taint flag and whether it is currently set. + // Flags are listed in bit-position order (bit 0 first). + Bits []KernelTaintBit +} + +// kernelTaintBitDefs lists all known kernel taint flags in bit-position order. +// Reference: https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html +var kernelTaintBitDefs = []struct { + flag string + description string +}{ + {"P", "Proprietary module was loaded."}, + {"F", "Module was force loaded."}, + {"S", "SMP kernel oops on an officially SMP incapable processor."}, + {"R", "Module was force unloaded."}, + {"M", "Processor reported a Machine Check Exception (MCE)."}, + {"B", "Bad page referenced or some unexpected page flags."}, + {"U", "Taint requested by userspace application."}, + {"D", "Kernel died recently, i.e. there was an OOPS or BUG."}, + {"A", "An ACPI table was overridden by user."}, + {"W", "Kernel issued warning."}, + {"C", "Staging driver was loaded."}, + {"I", "Workaround for bug in platform firmware applied."}, + {"O", "Externally-built (out-of-tree) module was loaded."}, + {"E", "Unsigned module was loaded."}, + {"L", "Soft lockup occurred."}, + {"K", "Kernel has been live patched."}, + {"X", "Auxiliary taint, defined and used by distros."}, + {"T", "The kernel was built with the struct randomization plugin."}, + {"N", "An in-kernel test such as a KUnit test has been run."}, + {"J", "Userspace used a mutating debug operation in fwctl."}, +} + +// KernelTainted reads /proc/sys/kernel/tainted and returns the raw taint value +// along with each known flag parsed into a KernelTainted struct. +// See https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html +func (fs FS) KernelTainted() (KernelTainted, error) { + value, err := parsers.SysReadUintFromFile(fs.proc.Path("sys", "kernel", "tainted")) + if err != nil { + return KernelTainted{}, err + } + return parseTainted(value), nil +} + +// parseTainted builds a KernelTainted from the raw taint bitmask value. +func parseTainted(value uint64) KernelTainted { + bits := make([]KernelTaintBit, len(kernelTaintBitDefs)) + for i, def := range kernelTaintBitDefs { + bits[i] = KernelTaintBit{ + Index: i, + Flag: def.flag, + Description: def.description, + Set: value&(1</environ`. func (p Proc) Environ() ([]string, error) { environments := make([]string, 0) - data, err := util.ReadFileNoStat(p.path("environ")) + data, err := parsers.ReadFileNoStat(p.path("environ")) if err != nil { return environments, err } diff --git a/vendor/github.com/prometheus/procfs/proc_fdinfo.go b/vendor/github.com/prometheus/procfs/proc_fdinfo.go index fa57761db..9e3e313e1 100644 --- a/vendor/github.com/prometheus/procfs/proc_fdinfo.go +++ b/vendor/github.com/prometheus/procfs/proc_fdinfo.go @@ -19,7 +19,7 @@ import ( "fmt" "regexp" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) var ( @@ -49,7 +49,7 @@ type ProcFDInfo struct { // FDInfo constructor. On kernels older than 3.8, InotifyInfos will always be empty. func (p Proc) FDInfo(fd string) (*ProcFDInfo, error) { - data, err := util.ReadFileNoStat(p.path("fdinfo", fd)) + data, err := parsers.ReadFileNoStat(p.path("fdinfo", fd)) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/proc_interrupts.go b/vendor/github.com/prometheus/procfs/proc_interrupts.go index 643b500d5..2a2412c4f 100644 --- a/vendor/github.com/prometheus/procfs/proc_interrupts.go +++ b/vendor/github.com/prometheus/procfs/proc_interrupts.go @@ -22,7 +22,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // Interrupt represents a single interrupt line. @@ -42,7 +42,7 @@ type Interrupts map[string]Interrupt // Interrupts creates a new instance from a given Proc instance. func (p Proc) Interrupts() (Interrupts, error) { - data, err := util.ReadFileNoStat(p.fs.proc.Path("interrupts")) + data, err := parsers.ReadFileNoStat(p.fs.proc.Path("interrupts")) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/proc_io.go b/vendor/github.com/prometheus/procfs/proc_io.go index dd8086ba2..ca221bb65 100644 --- a/vendor/github.com/prometheus/procfs/proc_io.go +++ b/vendor/github.com/prometheus/procfs/proc_io.go @@ -16,7 +16,7 @@ package procfs import ( "fmt" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // ProcIO models the content of /proc//io. @@ -43,7 +43,7 @@ type ProcIO struct { func (p Proc) IO() (ProcIO, error) { pio := ProcIO{} - data, err := util.ReadFileNoStat(p.path("io")) + data, err := parsers.ReadFileNoStat(p.path("io")) if err != nil { return pio, err } diff --git a/vendor/github.com/prometheus/procfs/proc_netstat.go b/vendor/github.com/prometheus/procfs/proc_netstat.go index 7f94cc891..6a118f58a 100644 --- a/vendor/github.com/prometheus/procfs/proc_netstat.go +++ b/vendor/github.com/prometheus/procfs/proc_netstat.go @@ -21,7 +21,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // ProcNetstat models the content of /proc//net/netstat. @@ -146,6 +146,20 @@ type TcpExt struct { // nolint:revive TCPMTUPFail *float64 TCPMTUPSuccess *float64 TCPWqueueTooBig *float64 + + // Legacy TcpExt counters dropped from recent kernels' TcpExt table; + // modeled so consumers retain metric parity with older kernels that + // still print them in /proc/net/netstat. + TCPLoss *float64 + PAWSPassive *float64 + TCPForwardRetrans *float64 + TCPSchedulerFailed *float64 + TCPPrequeued *float64 + TCPDirectCopyFromBacklog *float64 + TCPDirectCopyFromPrequeue *float64 + TCPPrequeueDropped *float64 + TCPFACKReorder *float64 + TCPHPHitsToUser *float64 } type IpExt struct { // nolint:revive @@ -171,7 +185,7 @@ type IpExt struct { // nolint:revive func (p Proc) Netstat() (ProcNetstat, error) { filename := p.path("net/netstat") - data, err := util.ReadFileNoStat(filename) + data, err := parsers.ReadFileNoStat(filename) if err != nil { return ProcNetstat{PID: p.PID}, err } @@ -396,6 +410,26 @@ func parseProcNetstat(r io.Reader, fileName string) (ProcNetstat, error) { procNetstat.TCPMTUPSuccess = &value case "TCPWqueueTooBig": procNetstat.TCPWqueueTooBig = &value + case "TCPLoss": + procNetstat.TCPLoss = &value + case "PAWSPassive": + procNetstat.PAWSPassive = &value + case "TCPForwardRetrans": + procNetstat.TCPForwardRetrans = &value + case "TCPSchedulerFailed": + procNetstat.TCPSchedulerFailed = &value + case "TCPPrequeued": + procNetstat.TCPPrequeued = &value + case "TCPDirectCopyFromBacklog": + procNetstat.TCPDirectCopyFromBacklog = &value + case "TCPDirectCopyFromPrequeue": + procNetstat.TCPDirectCopyFromPrequeue = &value + case "TCPPrequeueDropped": + procNetstat.TCPPrequeueDropped = &value + case "TCPFACKReorder": + procNetstat.TCPFACKReorder = &value + case "TCPHPHitsToUser": + procNetstat.TCPHPHitsToUser = &value } case "IpExt": switch key { diff --git a/vendor/github.com/prometheus/procfs/proc_psi.go b/vendor/github.com/prometheus/procfs/proc_psi.go index cc2c5de87..5f0fbdffb 100644 --- a/vendor/github.com/prometheus/procfs/proc_psi.go +++ b/vendor/github.com/prometheus/procfs/proc_psi.go @@ -30,7 +30,7 @@ import ( "io" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) const lineFormat = "avg10=%f avg60=%f avg300=%f total=%d" @@ -59,7 +59,7 @@ type PSIStats struct { // resource from /proc/pressure/. At time of writing this can be // either "cpu", "memory" or "io". func (fs FS) PSIStatsForResource(resource string) (PSIStats, error) { - data, err := util.ReadFileNoStat(fs.proc.Path(fmt.Sprintf("%s/%s", "pressure", resource))) + data, err := parsers.ReadFileNoStat(fs.proc.Path(fmt.Sprintf("%s/%s", "pressure", resource))) if err != nil { return PSIStats{}, fmt.Errorf("%w: psi_stats: unavailable for %q: %w", ErrFileRead, resource, err) } diff --git a/vendor/github.com/prometheus/procfs/proc_smaps.go b/vendor/github.com/prometheus/procfs/proc_smaps.go index f637309b3..dff5cfb88 100644 --- a/vendor/github.com/prometheus/procfs/proc_smaps.go +++ b/vendor/github.com/prometheus/procfs/proc_smaps.go @@ -23,7 +23,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) var ( @@ -60,7 +60,7 @@ type ProcSMapsRollup struct { // If smaps_rollup does not exists (require kernel >= 4.15), the content of /proc/pid/smaps will // we read and summed. func (p Proc) ProcSMapsRollup() (ProcSMapsRollup, error) { - data, err := util.ReadFileNoStat(p.path("smaps_rollup")) + data, err := parsers.ReadFileNoStat(p.path("smaps_rollup")) if err != nil && os.IsNotExist(err) { return p.procSMapsRollupManual() } diff --git a/vendor/github.com/prometheus/procfs/proc_snmp.go b/vendor/github.com/prometheus/procfs/proc_snmp.go index 8d9a9bcd6..531bc8371 100644 --- a/vendor/github.com/prometheus/procfs/proc_snmp.go +++ b/vendor/github.com/prometheus/procfs/proc_snmp.go @@ -21,7 +21,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // ProcSnmp models the content of /proc//net/snmp. @@ -135,7 +135,7 @@ type UdpLite struct { // nolint:revive func (p Proc) Snmp() (ProcSnmp, error) { filename := p.path("net/snmp") - data, err := util.ReadFileNoStat(filename) + data, err := parsers.ReadFileNoStat(filename) if err != nil { return ProcSnmp{PID: p.PID}, err } diff --git a/vendor/github.com/prometheus/procfs/proc_snmp6.go b/vendor/github.com/prometheus/procfs/proc_snmp6.go index 841fef464..8296a4aed 100644 --- a/vendor/github.com/prometheus/procfs/proc_snmp6.go +++ b/vendor/github.com/prometheus/procfs/proc_snmp6.go @@ -22,7 +22,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // ProcSnmp6 models the content of /proc//net/snmp6. @@ -140,7 +140,7 @@ type UdpLite6 struct { // nolint:revive func (p Proc) Snmp6() (ProcSnmp6, error) { filename := p.path("net/snmp6") - data, err := util.ReadFileNoStat(filename) + data, err := parsers.ReadFileNoStat(filename) if err != nil { // On systems with IPv6 disabled, this file won't exist. // Do nothing. diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go index 02e3f9e31..d9e544bcc 100644 --- a/vendor/github.com/prometheus/procfs/proc_stat.go +++ b/vendor/github.com/prometheus/procfs/proc_stat.go @@ -18,7 +18,7 @@ import ( "fmt" "os" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // Originally, this USER_HZ value was dynamically retrieved via a sysconf call @@ -134,7 +134,7 @@ func (p Proc) NewStat() (ProcStat, error) { // Stat returns the current status information of the process. func (p Proc) Stat() (ProcStat, error) { - data, err := util.ReadFileNoStat(p.path("stat")) + data, err := parsers.ReadFileNoStat(p.path("stat")) if err != nil { return ProcStat{}, err } diff --git a/vendor/github.com/prometheus/procfs/proc_statm.go b/vendor/github.com/prometheus/procfs/proc_statm.go index 6bcc97ec9..5fbe27965 100644 --- a/vendor/github.com/prometheus/procfs/proc_statm.go +++ b/vendor/github.com/prometheus/procfs/proc_statm.go @@ -18,7 +18,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // - https://man7.org/linux/man-pages/man5/proc_pid_statm.5.html @@ -53,7 +53,7 @@ func (p Proc) NewStatm() (ProcStatm, error) { // Statm returns the current memory usage information of the process. func (p Proc) Statm() (ProcStatm, error) { - data, err := util.ReadFileNoStat(p.path("statm")) + data, err := parsers.ReadFileNoStat(p.path("statm")) if err != nil { return ProcStatm{}, err } diff --git a/vendor/github.com/prometheus/procfs/proc_status.go b/vendor/github.com/prometheus/procfs/proc_status.go index 12d65581c..8c1652e17 100644 --- a/vendor/github.com/prometheus/procfs/proc_status.go +++ b/vendor/github.com/prometheus/procfs/proc_status.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // ProcStatus provides status information about the process, @@ -100,7 +100,7 @@ type ProcStatus struct { // NewStatus returns the current status information of the process. func (p Proc) NewStatus() (ProcStatus, error) { - data, err := util.ReadFileNoStat(p.path("status")) + data, err := parsers.ReadFileNoStat(p.path("status")) if err != nil { return ProcStatus{}, err } diff --git a/vendor/github.com/prometheus/procfs/proc_sys.go b/vendor/github.com/prometheus/procfs/proc_sys.go index 52658a4d5..c465b6be0 100644 --- a/vendor/github.com/prometheus/procfs/proc_sys.go +++ b/vendor/github.com/prometheus/procfs/proc_sys.go @@ -17,7 +17,7 @@ import ( "fmt" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) func sysctlToPath(sysctl string) string { @@ -25,7 +25,7 @@ func sysctlToPath(sysctl string) string { } func (fs FS) SysctlStrings(sysctl string) ([]string, error) { - value, err := util.SysReadFile(fs.proc.Path("sys", sysctlToPath(sysctl))) + value, err := parsers.SysReadFile(fs.proc.Path("sys", sysctlToPath(sysctl))) if err != nil { return nil, err } @@ -41,7 +41,7 @@ func (fs FS) SysctlInts(sysctl string) ([]int, error) { values := make([]int, len(fields)) for i, f := range fields { - vp := util.NewValueParser(f) + vp := parsers.NewValueParser(f) values[i] = vp.Int() if err := vp.Err(); err != nil { return nil, fmt.Errorf("%w: field %d in sysctl %s is not a valid int: %w", ErrFileParse, i, sysctl, err) diff --git a/vendor/github.com/prometheus/procfs/slab.go b/vendor/github.com/prometheus/procfs/slab.go index 32a04678a..b78bac634 100644 --- a/vendor/github.com/prometheus/procfs/slab.go +++ b/vendor/github.com/prometheus/procfs/slab.go @@ -21,7 +21,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) var ( @@ -142,7 +142,7 @@ func (fs FS) SlabInfo() (SlabInfo, error) { // TODO: Consider passing options to allow for parsing different // slabinfo versions. However, slabinfo 2.1 has been stable since // kernel 2.6.10 and later. - data, err := util.ReadFileNoStat(fs.proc.Path("slabinfo")) + data, err := parsers.ReadFileNoStat(fs.proc.Path("slabinfo")) if err != nil { return SlabInfo{}, err } diff --git a/vendor/github.com/prometheus/procfs/softirqs.go b/vendor/github.com/prometheus/procfs/softirqs.go index 47b73a729..dcd585933 100644 --- a/vendor/github.com/prometheus/procfs/softirqs.go +++ b/vendor/github.com/prometheus/procfs/softirqs.go @@ -21,7 +21,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // Softirqs represents the softirq statistics. @@ -40,7 +40,7 @@ type Softirqs struct { func (fs FS) Softirqs() (Softirqs, error) { fileName := fs.proc.Path("softirqs") - data, err := util.ReadFileNoStat(fileName) + data, err := parsers.ReadFileNoStat(fileName) if err != nil { return Softirqs{}, err } diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go index 593ad0f62..781bd28ad 100644 --- a/vendor/github.com/prometheus/procfs/stat.go +++ b/vendor/github.com/prometheus/procfs/stat.go @@ -23,7 +23,7 @@ import ( "strings" "github.com/prometheus/procfs/internal/fs" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // CPUStat shows how much time the cpu spend in various stages. @@ -167,7 +167,7 @@ func (fs FS) NewStat() (Stat, error) { // See: https://www.kernel.org/doc/Documentation/filesystems/proc.txt func (fs FS) Stat() (Stat, error) { fileName := fs.proc.Path("stat") - data, err := util.ReadFileNoStat(fileName) + data, err := parsers.ReadFileNoStat(fileName) if err != nil { return Stat{}, err } diff --git a/vendor/github.com/prometheus/procfs/swaps.go b/vendor/github.com/prometheus/procfs/swaps.go index ee17bf488..8f9bbfb5c 100644 --- a/vendor/github.com/prometheus/procfs/swaps.go +++ b/vendor/github.com/prometheus/procfs/swaps.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // Swap represents an entry in /proc/swaps. @@ -34,7 +34,7 @@ type Swap struct { // Swaps returns a slice of all configured swap devices on the system. func (fs FS) Swaps() ([]*Swap, error) { - data, err := util.ReadFileNoStat(fs.proc.Path("swaps")) + data, err := parsers.ReadFileNoStat(fs.proc.Path("swaps")) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/vm.go b/vendor/github.com/prometheus/procfs/vm.go index 52180c03e..62725b420 100644 --- a/vendor/github.com/prometheus/procfs/vm.go +++ b/vendor/github.com/prometheus/procfs/vm.go @@ -21,7 +21,7 @@ import ( "path/filepath" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // The VM interface is described at @@ -102,11 +102,11 @@ func (fs FS) VM() (*VM, error) { name := filepath.Join(path, f.Name()) // ignore errors on read, as there are some write only // in /proc/sys/vm - value, err := util.SysReadFile(name) + value, err := parsers.SysReadFile(name) if err != nil { continue } - vp := util.NewValueParser(value) + vp := parsers.NewValueParser(value) switch f.Name() { case "admin_reserve_kbytes": @@ -143,7 +143,7 @@ func (fs FS) VM() (*VM, error) { stringSlice := strings.Fields(value) pint64Slice := make([]*int64, 0, len(stringSlice)) for _, value := range stringSlice { - vp := util.NewValueParser(value) + vp := parsers.NewValueParser(value) pint64Slice = append(pint64Slice, vp.PInt64()) } vm.LowmemReserveRatio = pint64Slice diff --git a/vendor/github.com/prometheus/procfs/zoneinfo.go b/vendor/github.com/prometheus/procfs/zoneinfo.go index 63d1898bc..71b3c2b65 100644 --- a/vendor/github.com/prometheus/procfs/zoneinfo.go +++ b/vendor/github.com/prometheus/procfs/zoneinfo.go @@ -22,7 +22,7 @@ import ( "regexp" "strings" - "github.com/prometheus/procfs/internal/util" + "github.com/prometheus/procfs/internal/parsers" ) // Zoneinfo holds info parsed from /proc/zoneinfo. @@ -103,7 +103,7 @@ func parseZoneinfo(zoneinfoData []byte) ([]Zoneinfo, error) { if len(parts) < 2 { continue } - vp := util.NewValueParser(parts[1]) + vp := parsers.NewValueParser(parts[1]) switch parts[0] { case "nr_free_pages": zoneinfoElement.NrFreePages = vp.PInt64() @@ -179,7 +179,7 @@ func parseZoneinfo(zoneinfoData []byte) ([]Zoneinfo, error) { protectionValues = strings.Replace(protectionValues, ")", "", 1) protectionValues = strings.TrimSpace(protectionValues) protectionStringMap := strings.Split(protectionValues, ", ") - val, err := util.ParsePInt64s(protectionStringMap) + val, err := parsers.ParsePInt64s(protectionStringMap) if err == nil { zoneinfoElement.Protection = val } diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/version.go b/vendor/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/version.go index 33a07b0b2..bef4014dc 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/version.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/version.go @@ -4,4 +4,4 @@ package otelgrpc // Version is the current release version of the gRPC instrumentation. -const Version = "0.71.0" +const Version = "0.72.0" diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/util.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/util.go index 0de0bd83c..1ec064b1d 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/util.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv/util.go @@ -38,11 +38,9 @@ func SplitHostPort(hostport string) (host string, port int) { host = hostport[1:addrEnd] return host, port } - } else { - if i := strings.LastIndexByte(hostport, ':'); i < 0 { - host = hostport - return host, port - } + } else if !strings.Contains(hostport, ":") { + host = hostport + return host, port } host, pStr, err := net.SplitHostPort(hostport) diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/version.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/version.go index 3a144d2f2..dc6907f65 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/version.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/version.go @@ -4,4 +4,4 @@ package otelhttptrace // Version is the current release version of the httptrace instrumentation. -const Version = "0.71.0" +const Version = "0.72.0" diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/common.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/common.go index 733b75dca..b32f99a93 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/common.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/common.go @@ -10,12 +10,31 @@ import ( "go.opentelemetry.io/otel/trace" ) -// Attribute keys that can be added to a span. +// Legacy HTTP attribute keys retained for compatibility. const ( - ReadBytesKey = attribute.Key("http.read_bytes") // if anything was read from the request body, the total number of bytes read - ReadErrorKey = attribute.Key("http.read_error") // If an error occurred while reading a request, the string of the error (io.EOF is not recorded) - WroteBytesKey = attribute.Key("http.wrote_bytes") // if anything was written to the response writer, the total number of bytes written - WriteErrorKey = attribute.Key("http.write_error") // if an error occurred while writing a reply, the string of the error (io.EOF is not recorded) + // ReadBytesKey is the attribute key for the number of bytes returned by an + // individual read from an HTTP request body. + // + // Deprecated: there is no direct semantic-convention replacement. + ReadBytesKey = attribute.Key("http.read_bytes") + + // ReadErrorKey is the attribute key for the string form of a non-EOF error + // returned while reading an HTTP request body. + // + // Deprecated: there is no direct semantic-convention replacement. + ReadErrorKey = attribute.Key("http.read_error") + + // WroteBytesKey is the attribute key for the number of bytes returned by an + // individual write to an HTTP response body. + // + // Deprecated: there is no direct semantic-convention replacement. + WroteBytesKey = attribute.Key("http.wrote_bytes") + + // WriteErrorKey is the attribute key for the string form of a non-EOF error + // returned while writing an HTTP response body. + // + // Deprecated: there is no direct semantic-convention replacement. + WriteErrorKey = attribute.Key("http.write_error") ) // Filter is a predicate used to determine whether a given http.request should diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/config.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/config.go index 08ba0778f..45d4ee161 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/config.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/config.go @@ -143,14 +143,15 @@ const ( ) // WithMessageEvents configures the Handler to record the specified events -// (span.AddEvent) on spans. By default only summary attributes are added at the -// end of the request. +// (span.AddEvent) on spans. By default, no read or write events are recorded. // // Valid events are: -// - ReadEvents: Record the number of bytes read after every http.Request.Body.Read -// using the ReadBytesKey -// - WriteEvents: Record the number of bytes written after every http.ResponeWriter.Write -// using the WriteBytesKey +// - ReadEvents: Record a "read" span event after every http.Request.Body.Read. +// - WriteEvents: Record a "write" span event after every http.ResponseWriter.Write. +// +// The events do not include per-call byte-count attributes. Total request and +// response body sizes are recorded on the span according to HTTP semantic +// conventions. func WithMessageEvents(events ...Event) Option { return optionFunc(func(c *config) { for _, e := range events { diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/handler.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/handler.go index 844363a09..d42f4f870 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/handler.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/handler.go @@ -129,8 +129,8 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http readRecordFunc := func(int64) {} if h.readEvent { - readRecordFunc = func(n int64) { - span.AddEvent("read", trace.WithAttributes(ReadBytesKey.Int64(n))) + readRecordFunc = func(int64) { + span.AddEvent("read") } } @@ -150,8 +150,8 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http writeRecordFunc := func(int64) {} if h.writeEvent { - writeRecordFunc = func(n int64) { - span.AddEvent("write", trace.WithAttributes(WroteBytesKey.Int64(n))) + writeRecordFunc = func(int64) { + span.AddEvent("write") } } @@ -180,12 +180,21 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http if !found { ctx = ContextWithLabeler(ctx, labeler) } + rCtx := r.WithContext(ctx) + defer func() { + // Copy MultipartForm back to the original request so net/http can + // find and remove any temp files ParseMultipartForm created on the + // copy. Deferred so the copy-back also runs during panic unwinding, + // letting net/http cleanup paths that still run (HTTP/2 handler + // recovery, outer recovery middleware) find the form. + if rCtx.MultipartForm != nil { + r.MultipartForm = rCtx.MultipartForm + } + }() + next.ServeHTTP(w, rCtx) - r = r.WithContext(ctx) - next.ServeHTTP(w, r) - - if r.Pattern != "" { - span.SetName(h.spanNameFormatter(h.operation, r)) + if rCtx.Pattern != "" { + span.SetName(h.spanNameFormatter(h.operation, rCtx)) } statusCode := rww.StatusCode() @@ -204,9 +213,9 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http ServerName: h.server, ResponseSize: bytesWritten, MetricAttributes: semconv.MetricAttributes{ - Req: r, + Req: rCtx, StatusCode: statusCode, - AdditionalAttributes: append(labeler.Get(), h.metricAttributesFromRequest(r)...), + AdditionalAttributes: append(labeler.Get(), h.metricAttributesFromRequest(rCtx)...), }, MetricData: semconv.MetricData{ RequestSize: bytesRead, diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv/util.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv/util.go index 0de0bd83c..1ec064b1d 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv/util.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv/util.go @@ -38,11 +38,9 @@ func SplitHostPort(hostport string) (host string, port int) { host = hostport[1:addrEnd] return host, port } - } else { - if i := strings.LastIndexByte(hostport, ':'); i < 0 { - host = hostport - return host, port - } + } else if !strings.Contains(hostport, ":") { + host = hostport + return host, port } host, pStr, err := net.SplitHostPort(hostport) diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/labeler.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/labeler.go index 8362b8246..3c0fa99a2 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/labeler.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/labeler.go @@ -56,3 +56,27 @@ func LabelerFromContext(ctx context.Context) (*Labeler, bool) { } return l, ok } + +// clientLabelerContextKey is a separate context key for the client-side Labeler. +// This prevents server-side Labeler attributes (e.g., http.route) from leaking +// into client-side metrics when a server handler propagates its request context +// into an outbound HTTP client request. +const clientLabelerContextKey labelerContextKeyType = 1 + +// ContextWithClientLabeler returns a new context with the provided Labeler instance +// for use with client-side HTTP instrumentation (otelhttp.Transport). +// Attributes added to this labeler will be attached to client-side metrics. +func ContextWithClientLabeler(parent context.Context, l *Labeler) context.Context { + return context.WithValue(parent, clientLabelerContextKey, l) +} + +// ClientLabelerFromContext retrieves a Labeler instance from the provided context +// for use with client-side HTTP instrumentation. If no Labeler was found, a new, +// empty Labeler is returned and the second return value is false. +func ClientLabelerFromContext(ctx context.Context) (*Labeler, bool) { + l, ok := ctx.Value(clientLabelerContextKey).(*Labeler) + if !ok { + l = &Labeler{} + } + return l, ok +} diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/transport.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/transport.go index 82501eab3..22bbcc737 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/transport.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/transport.go @@ -9,6 +9,7 @@ import ( "io" "net/http" "net/http/httptrace" + "sync" "sync/atomic" "time" @@ -19,7 +20,6 @@ import ( otelsemconv "go.opentelemetry.io/otel/semconv/v1.43.0" "go.opentelemetry.io/otel/trace" - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv" ) @@ -82,6 +82,142 @@ func defaultTransportFormatter(_ string, r *http.Request) string { return "HTTP " + r.Method } +// requestTracker tracks the request body lifecycle of a single RoundTrip and +// records the client metrics exactly once, after the request body reaches a +// final state. +// +// A single tracker is allocated per request with a body, replacing the +// body-wrapper allocation of the untracked implementation: the first request +// body is wrapped by the embedded first field, and the lifecycle state is +// held in explicit fields with methods instead of escaping closures. Only +// GetBody retries allocate an additional trackedRequestBody. +type requestTracker struct { + transport *Transport + first trackedRequestBody + + originalGetBody func() (io.ReadCloser, error) + + // mu protects body, published, and recorded. Body close callbacks may + // fire on a different goroutine (e.g. during transport retries or + // asynchronous closes) while the main goroutine publishes the metric + // data after RoundTrip returns. + mu sync.Mutex + body *trackedRequestBody // Last wrapped request body; nil records no data. + published bool + recorded bool + + // Metric data published when RoundTrip returns; immutable afterwards. + ctx context.Context + duration time.Duration + opts semconv.MetricOpts +} + +func newRequestTracker(t *Transport, r *http.Request) *requestTracker { + rt := &requestTracker{transport: t} + rt.first = trackedRequestBody{body: r.Body, tracker: rt} + rt.body = &rt.first + r.Body = &rt.first + if r.GetBody != nil { + rt.originalGetBody = r.GetBody + r.GetBody = rt.getBody + } + return rt +} + +func (rt *requestTracker) getBody() (io.ReadCloser, error) { + b, err := rt.originalGetBody() + if err != nil { + // The underlying transport will fail to make a retry request, + // hence, record no data. + rt.setBody(nil) + return nil, err + } + if b == nil || b == http.NoBody { + return b, nil + } + tb := &trackedRequestBody{body: b, tracker: rt} + rt.setBody(tb) + return tb, nil +} + +func (rt *requestTracker) setBody(b *trackedRequestBody) { + rt.mu.Lock() + rt.body = b + rt.mu.Unlock() +} + +// publish stores the metric data gathered when RoundTrip returns and records +// the metrics if the request body already reached a final state. +func (rt *requestTracker) publish(ctx context.Context, d time.Duration, opts semconv.MetricOpts) { + rt.mu.Lock() + rt.ctx = ctx + rt.duration = d + rt.opts = opts + rt.published = true + rt.mu.Unlock() + rt.maybeRecord() +} + +// maybeRecord records the client metrics once the metric data has been +// published and the request body has reached a final state. Close is the +// only authoritative completion signal for a non-nil body: a body may yield +// more bytes than its declared ContentLength, so a read count is never proof +// of completion. +func (rt *requestTracker) maybeRecord() { + rt.mu.Lock() + body := rt.body + record := rt.published && !rt.recorded && (body == nil || body.closed.Load()) + if record { + rt.recorded = true + } + rt.mu.Unlock() + if !record { + return + } + + // The winning caller evaluates the request size here so the recorded + // value reflects the latest byte count. + var requestSize int64 + if body != nil { + requestSize = body.read.Load() + } + rt.transport.semconv.RecordMetrics( + rt.ctx, + semconv.MetricData{ + RequestSize: requestSize, + RequestDuration: rt.duration, + }, + rt.opts, + ) +} + +// trackedRequestBody wraps a request body to count read bytes and signal the +// tracker when the body is closed. +type trackedRequestBody struct { + body io.ReadCloser + tracker *requestTracker + + read atomic.Int64 + closed atomic.Bool +} + +var _ io.ReadCloser = (*trackedRequestBody)(nil) + +func (b *trackedRequestBody) Read(p []byte) (int, error) { + n, err := b.body.Read(p) + b.read.Add(int64(n)) + return n, err +} + +func (b *trackedRequestBody) Close() error { + // Finalize telemetry before delegating to the underlying Close, which + // may block (mirroring wrappedBody.Close). Otherwise a blocking close + // could suppress client metrics indefinitely. + b.closed.Store(true) + b.tracker.maybeRecord() + return b.body.Close() +} + // RoundTrip creates a Span and propagates its context via the provided request's headers // before handing the request to the configured base RoundTripper. The created span will // end when the response body is closed or when a read from the body returns io.EOF. @@ -110,33 +246,20 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) { ctx = httptrace.WithClientTrace(ctx, t.clientTrace(ctx)) } - labeler, found := LabelerFromContext(ctx) + labeler, found := ClientLabelerFromContext(ctx) if !found { - ctx = ContextWithLabeler(ctx, labeler) + ctx = ContextWithClientLabeler(ctx, labeler) } r = r.Clone(ctx) // According to RoundTripper spec, we shouldn't modify the origin request. - var lastBW *request.BodyWrapper // Records the last body wrapper. Can be nil. - maybeWrapBody := func(body io.ReadCloser) io.ReadCloser { - if body == nil || body == http.NoBody { - return body - } - bw := request.NewBodyWrapper(body, func(int64) {}) - lastBW = bw - return bw - } - r.Body = maybeWrapBody(r.Body) - if r.GetBody != nil { - originalGetBody := r.GetBody - r.GetBody = func() (io.ReadCloser, error) { - b, err := originalGetBody() - if err != nil { - lastBW = nil // The underlying transport will fail to make a retry request, hence, record no data. - return nil, err - } - return maybeWrapBody(b), nil - } + // Track the request body lifecycle so metrics report the final read + // size even when the transport keeps reading the body after RoundTrip + // returns. Bodyless requests allocate no tracker and record + // synchronously below. + var tracker *requestTracker + if r.Body != nil && r.Body != http.NoBody { + tracker = newRequestTracker(t, r) } span.SetAttributes(t.semconv.RequestTraceAttrs(r)...) @@ -147,29 +270,32 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) { res, err = ensureResponseBody(t.rt, r, res) } - // Record the metrics on error or no error. + requestDuration := time.Since(requestStartTime) statusCode := 0 if err == nil { statusCode = res.StatusCode } - var requestSize int64 - if lastBW != nil { - requestSize = lastBW.BytesRead() + metricOpts := t.semconv.MetricOptions(semconv.MetricAttributes{ + Req: r, + Resp: res, + StatusCode: statusCode, + Err: err, + AdditionalAttributes: append(labeler.Get(), t.metricAttributesFromRequest(r)...), + }) + + if tracker != nil { + // Delay metric recording until the request body reaches a final + // state. The transport can continue reading the body after + // RoundTrip returns, including on errors, since RoundTrippers may + // close the request body asynchronously. + tracker.publish(ctx, requestDuration, metricOpts) + } else { + t.semconv.RecordMetrics( + ctx, + semconv.MetricData{RequestDuration: requestDuration}, + metricOpts, + ) } - t.semconv.RecordMetrics( - ctx, - semconv.MetricData{ - RequestSize: requestSize, - RequestDuration: time.Since(requestStartTime), - }, - t.semconv.MetricOptions(semconv.MetricAttributes{ - Req: r, - Resp: res, - StatusCode: statusCode, - Err: err, - AdditionalAttributes: append(labeler.Get(), t.metricAttributesFromRequest(r)...), - }), - ) if err != nil { span.SetAttributes(otelsemconv.ErrorType(err)) @@ -263,8 +389,7 @@ func (wb *wrappedBody) Read(b []byte) (int, error) { case nil: // nothing to do here but fall through to the return case io.EOF: - wb.recordBytesRead() - wb.span.End() + wb.recordMetricsOnce() default: wb.span.SetAttributes(otelsemconv.ErrorType(err)) wb.span.SetStatus(codes.Error, err.Error()) @@ -272,21 +397,24 @@ func (wb *wrappedBody) Read(b []byte) (int, error) { return n, err } -// recordBytesRead is a function that ensures the number of bytes read is recorded once and only once. -func (wb *wrappedBody) recordBytesRead() { - // note: it is more performant (and equally correct) to use atomic.Bool over sync.Once here. In the event that - // two goroutines are racing to call this method, the number of bytes read will no longer increase. Using - // CompareAndSwap allows later goroutines to return quickly and not block waiting for the race winner to finish - // calling wb.record(wb.read.Load()). +// recordMetricsOnce ensures the final number of bytes read is recorded once. +func (wb *wrappedBody) recordMetricsOnce() { + // note: it is more performant (and equally correct) to use atomic.Bool + // over sync.Once here. In the event that two goroutines are racing to + // call this method, the number of bytes read will no longer increase. + // Using CompareAndSwap allows later goroutines to return quickly and not + // block waiting for the race winner to finish calling + // wb.record(wb.read.Load()). if wb.recorded.CompareAndSwap(false, true) { - // Record the total number of bytes read wb.record(wb.read.Load()) + wb.span.End() } } func (wb *wrappedBody) Close() error { - wb.recordBytesRead() - wb.span.End() + // Finalize telemetry before delegating to the underlying Close, which + // may block (e.g. upgraded streams or custom RoundTripper bodies). + wb.recordMetricsOnce() if wb.body != nil { return wb.body.Close() } diff --git a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/version.go b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/version.go index 9017f2f43..05267f2fd 100644 --- a/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/version.go +++ b/vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/version.go @@ -4,4 +4,4 @@ package otelhttp // Version is the current release version of the otelhttp instrumentation. -const Version = "0.71.0" +const Version = "0.72.0" diff --git a/vendor/go.opentelemetry.io/otel/.golangci.yml b/vendor/go.opentelemetry.io/otel/.golangci.yml index a0ba70805..1fef8520b 100644 --- a/vendor/go.opentelemetry.io/otel/.golangci.yml +++ b/vendor/go.opentelemetry.io/otel/.golangci.yml @@ -230,13 +230,6 @@ linters: - revive path: schema/v.*/types/.* text: avoid meaningless package names - # TODO: Having appropriate comments for exported objects helps development, - # even for objects in internal packages. Appropriate comments for all - # exported objects should be added and this exclusion removed. - - linters: - - revive - path: .*internal/.* - text: exported (method|function|type|const) (.+) should have comment or be unexported # Yes, they are, but it's okay in a test. - linters: - revive @@ -272,7 +265,10 @@ formatters: - golines settings: gofumpt: - extra-rules: true + extra: + group-params: true + clothe-returns: true + balance-calls: true goimports: local-prefixes: - go.opentelemetry.io/otel diff --git a/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/vendor/go.opentelemetry.io/otel/CHANGELOG.md index 4d473a1e8..18903c889 100644 --- a/vendor/go.opentelemetry.io/otel/CHANGELOG.md +++ b/vendor/go.opentelemetry.io/otel/CHANGELOG.md @@ -11,6 +11,93 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm +## [1.47.0/0.69.0/0.23.0/0.1.0] - 2026-10-02 + +This release contains the first stable release of the OpenTelemetry Go Logs API and SDK. +Our project stability guarantees now apply to the following modules: + +- `go.opentelemetry.io/otel/log` +- `go.opentelemetry.io/otel/sdk/log` + +See our [versioning policy](VERSIONING.md) for more information about these stability guarantees. + +### Added + +- Add `String` method for `KeyValue` type in `go.opentelemetry.io/otel/attribute`. (#8205) +- Add `String` method for `Set` type in `go.opentelemetry.io/otel/attribute`. (#8347) +- Add `WithMaxExportBatchSize` to `go.opentelemetry.io/otel/sdk/metric` to configure the maximum export batch size for `PeriodicReader`. (#8960) +- Add `WithAttributeValueDepthLimit`, `DefaultAttributeValueDepthLimit`, and `SpanLimits.AttributeValueDepthLimit` in `go.opentelemetry.io/otel/sdk/trace` to configure the maximum depth of span, event, link, and instrumentation scope attribute values. (#8938) +- Add `WithAttributeValueDepthLimit` in `go.opentelemetry.io/otel/sdk/log` to configure the maximum depth of log record and instrumentation scope attribute values. (#8938) +- Add `WithMaxResponseSize` to `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`, + `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`, and + `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#8941) +- Add experimental `ProbabilitySampler` in `go.opentelemetry.io/otel/sdk/trace/x` that conforms to the [OpenTelemetry specification's threshold-based sampling algorithm](https://opentelemetry.io/docs/specs/otel/trace/sdk/#probabilitysampler). (#8123) +- Add experimental `*Binder` extension interfaces in `go.opentelemetry.io/otel/metric/x` for instruments that support binding attributes ahead of time. (#8760) +- Add the experimental `Finisher` synchronous metric instrument extension interface to `go.opentelemetry.io/otel/metric/x`. (#8906) + +### Changed + +- Use the [OpenTelemetry Attribute Collection representation for non-OTLP protocols](https://opentelemetry.io/docs/specs/otel/common/#attribute-collection-representation-for-non-otlp) for metric data diffs in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#8993) +- Apply a maximum depth of 64 by default to span, event, link, log record, and instrumentation scope attribute values in `go.opentelemetry.io/otel/sdk/trace` and `go.opentelemetry.io/otel/sdk/log`. (#8938) +- Reduce allocations when applying attribute value length limits in `go.opentelemetry.io/otel/sdk/trace` and `go.opentelemetry.io/otel/sdk/log` by rebuilding composite values only when truncation is needed. (#8912) +- Decode `traceparent` using a hex lookup table in `go.opentelemetry.io/otel/propagation`, which rejects the specification-disallowed upper-case characters without a separate scan of the header. (#8739) +- Decode all characters at constant indices in `TraceIDFromHex` and `SpanIDFromHex` in `go.opentelemetry.io/otel/trace` to eliminate bounds checks. (#8740) + +### Fixed + +- Count valid U+FFFD replacement characters toward attribute value length limits in `go.opentelemetry.io/otel/trace`, `go.opentelemetry.io/otel/sdk/trace`, and `go.opentelemetry.io/otel/sdk/log`. +- Truncate string attribute values to empty strings when the configured length limit is zero, including malformed UTF-8, in `go.opentelemetry.io/otel/trace`, `go.opentelemetry.io/otel/sdk/trace`, and `go.opentelemetry.io/otel/sdk/log`. (#9054) +- Fix a data race in `NewPeriodicReader` where `r.inst` was assigned after the background goroutine was launched in `go.opentelemetry.io/otel/sdk/metric`. (#9028) +- Prevent precision loss for large `int64` values in `Sum`, `Histogram`, and `ExponentialHistogram` aggregations in `go.opentelemetry.io/otel/sdk/metric`. (#8981) +- Ensure `grpc.DialOption` values passed via `WithDialOption` take precedence over conflicting internally-computed defaults in + `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`, + `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`, and + `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#8805, #8834, #8836) +- Treat overflowing `OTEL_METRIC_EXPORT_INTERVAL` and `OTEL_METRIC_EXPORT_TIMEOUT` values as invalid in `go.opentelemetry.io/otel/sdk/metric`. (#8800) +- Prevent a panic in `NewFixedSizeReservoir` and `FixedSizeReservoirProvider` when given a negative size in `go.opentelemetry.io/otel/sdk/metric/exemplar`; negative sizes are now clamped to zero, consistent with a size of zero. (#8832) +- Preserve exponential histogram `ZeroThreshold` during OTLP metric export in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#8801) +- Ensure metric helpers in `go.opentelemetry.io/otel/semconv/v1.32.0`, `go.opentelemetry.io/otel/semconv/v1.33.0`, and `go.opentelemetry.io/otel/semconv/v1.34.0` record measurements only once when no attributes are provided. (#8849) +- Treat empty `OTEL_TRACES_SAMPLER` and `OTEL_TRACES_SAMPLER_ARG` values as unset in `go.opentelemetry.io/otel/sdk/trace`. (#8873) +- Normalize global `OTEL_EXPORTER_OTLP_ENDPOINT` path joining in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` so trailing-slash base URLs do not produce double-slash log export paths. (#8864) +- Prevent a deadlock when formatting an error passed to `RecordError` calls back into the span in `go.opentelemetry.io/otel/sdk/trace`. (#8815) +- Prevent `SimpleSpanProcessor.Shutdown` from panicking when constructed with a nil exporter in `go.opentelemetry.io/otel/sdk/trace`. (#8844) +- Propagate invalid exponential histogram scale errors to Prometheus exporter self-observability metrics in `go.opentelemetry.io/otel/exporters/prometheus`. (#8839) +- Retain instrument advisory attributes configured with `go.opentelemetry.io/otel/metric/x.WithDefaultAttributes` when a matching View in `go.opentelemetry.io/otel/sdk/metric` does not specify an attribute filter. (#8859) +- Ignore HTTP URL paths when building OTLP/gRPC metric exporter targets from `OTEL_EXPORTER_OTLP_ENDPOINT` and `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`, while preserving `unix://` and `unix-abstract://` targets; treat `unix-abstract://` endpoints as insecure in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#8862) +- Ignore HTTP(S) paths when deriving gRPC trace exporter endpoints from `OTEL_EXPORTER_OTLP_ENDPOINT` and `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#8852) +- Bound memory used while parsing dense W3C property metadata by storing it compactly and materializing `Property` values on demand in `go.opentelemetry.io/otel/baggage` and `go.opentelemetry.io/otel/propagation`. + +### Removed + +- Remove the experimental `OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE` environment variable in `go.opentelemetry.io/otel/sdk/metric`. + Use the `WithMaxExportBatchSize` option instead. (#8960) + +## [1.47.0-rc.1] - 2026-08-28 + +This is a release candidate for the v1.47.0 release. +That release is expected to include the `v1` release of the OpenTelemetry Go Logs API and SDK and will provide stability guarantees for the following modules: + +- `go.opentelemetry.io/otel/log` +- `go.opentelemetry.io/otel/sdk/log` + +See our [versioning policy](VERSIONING.md) for more information about these stability guarantees. + +### Added + +- Add `Logger`, `GetLoggerProvider`, and `SetLoggerProvider` to `go.opentelemetry.io/otel`. (#8874) + +### Deprecated + +- Deprecate `go.opentelemetry.io/otel/log/global`; use the equivalent APIs in `go.opentelemetry.io/otel`. (#8874) + +### Fixed + +- Ignore attempts to unregister unknown span processors in `go.opentelemetry.io/otel/sdk/trace`. (#8840) + +### Removed + +- Drop support for [Go 1.25]. (#8876) + ## [1.46.0/0.68.0/0.22.0/0.0.19] - 2026-08-25 This release is the last to support [Go 1.25]. @@ -3810,7 +3897,9 @@ It contains api and sdk for trace and meter. - CircleCI build CI manifest files. - CODEOWNERS file to track owners of this project. -[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.46.0...HEAD +[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.47.0...HEAD +[1.47.0/0.69.0/0.23.0/0.1.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.47.0 +[1.47.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.47.0-rc.1 [1.46.0/0.68.0/0.22.0/0.0.19]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.46.0 [1.45.0/0.67.0/0.21.0/0.0.18]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.45.0 [1.44.0/0.66.0/0.20.0/0.0.17]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.44.0 diff --git a/vendor/go.opentelemetry.io/otel/CLAUDE.md b/vendor/go.opentelemetry.io/otel/CLAUDE.md deleted file mode 100644 index dd3c4594f..000000000 --- a/vendor/go.opentelemetry.io/otel/CLAUDE.md +++ /dev/null @@ -1,3 +0,0 @@ -# Instructions for Claude Code - -@AGENTS.md diff --git a/vendor/go.opentelemetry.io/otel/CODEOWNERS b/vendor/go.opentelemetry.io/otel/CODEOWNERS index 26a03aed1..41937a389 100644 --- a/vendor/go.opentelemetry.io/otel/CODEOWNERS +++ b/vendor/go.opentelemetry.io/otel/CODEOWNERS @@ -12,6 +12,6 @@ # https://help.github.com/en/articles/about-code-owners # -* @MrAlias @XSAM @dashpole @pellared @dmathieu @flc1125 +* @MrAlias @XSAM @dashpole @pellared @dmathieu @flc1125 @ps-mir CODEOWNERS @MrAlias @pellared @dashpole @XSAM @dmathieu diff --git a/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md b/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md index 2aba71e19..958a698db 100644 --- a/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md +++ b/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md @@ -779,7 +779,7 @@ func newInstrumentation() (*instrumentation, error) { if !x.Observability.Enabled() { return nil, nil } - + meter := otel.GetMeterProvider().Meter( "", metric.WithInstrumentationVersion(sdk.Version()), @@ -949,7 +949,7 @@ func BenchmarkExportSpans(b *testing.B) { {"ObsDisabled", false}, {"ObsEnabled", true}, } - + for _, scenario := range scenarios { b.Run(scenario.name, func(b *testing.B) { b.Setenv( @@ -980,7 +980,7 @@ func newInstrumentation() (*instrumentation, error) { if !x.Observability.Enabled() { return nil, nil } - + m := otel.GetMeterProvider().Meter(/* initialize meter */) counter, err := otelconv.NewSDKComponentCounter(m) // Use the partially initialized counter if available. @@ -996,7 +996,7 @@ func newInstrumentation() *instrumentation { if !x.Observability.Enabled() { return nil, nil } - + m := otel.GetMeterProvider().Meter(/* initialize meter */) counter, err := otelconv.NewSDKComponentCounter(m) if err != nil { @@ -1023,7 +1023,7 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) if e.inst.Enabled(ctx) { e.inst.recordSpanExportStarted(ctx, len(spans)) } - + err := e.doExport(ctx, spans) if e.inst.Enabled(ctx) { @@ -1043,11 +1043,11 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error { // ❌ Do not break the context propagation. e.inst.recordSpanExportStarted(context.Background(), len(spans)) - + err := e.doExport(ctx, spans) /* ... */ - + return err } ``` @@ -1118,7 +1118,7 @@ func TestObservability(t *testing.T) { // Reset component ID counter to ensure deterministic component names. componentIDCounter.Store(0) - + /* ... test code ... */ } ``` @@ -1203,18 +1203,20 @@ For more information about the maintainer role, see the [community repository](h ### Approvers - [Flc](https://github.com/flc1125), Independent +- [Puneet Singh](https://github.com/ps-mir), Independent For more information about the approver role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver). ### Triagers -- [Alex Kats](https://github.com/akats7), Capital One +- [Marc Schäfer](https://github.com/marcschaeferger), T&A SYSTEME GmbH For more information about the triager role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager). ### Emeritus - [Aaron Clawson](https://github.com/MadVikingGod) +- [Alex Kats](https://github.com/akats7) - [Anthony Mirabella](https://github.com/Aneurysm9) - [Cheng-Zhen Yang](https://github.com/scorpionknifes) - [Chester Cheung](https://github.com/hanyuancheung) diff --git a/vendor/go.opentelemetry.io/otel/README.md b/vendor/go.opentelemetry.io/otel/README.md index 9291d1470..bcdb73e01 100644 --- a/vendor/go.opentelemetry.io/otel/README.md +++ b/vendor/go.opentelemetry.io/otel/README.md @@ -3,12 +3,11 @@ [![ci](https://github.com/open-telemetry/opentelemetry-go/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/open-telemetry/opentelemetry-go/actions/workflows/ci.yml) [![codecov.io](https://codecov.io/gh/open-telemetry/opentelemetry-go/coverage.svg?branch=main)](https://app.codecov.io/gh/open-telemetry/opentelemetry-go?branch=main) [![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel)](https://pkg.go.dev/go.opentelemetry.io/otel) -[![Go Report Card](https://goreportcard.com/badge/go.opentelemetry.io/otel)](https://goreportcard.com/report/go.opentelemetry.io/otel) [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/open-telemetry/opentelemetry-go/badge)](https://scorecard.dev/viewer/?uri=github.com/open-telemetry/opentelemetry-go) [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9996/badge)](https://www.bestpractices.dev/projects/9996) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/opentelemetry-go.svg)](https://issues.oss-fuzz.com/issues?q=project:opentelemetry-go) [![FOSSA Status](https://app.fossa.com/api/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-go.svg?type=shield&issueType=license)](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-go?ref=badge_shield&issueType=license) -[![Slack](https://img.shields.io/badge/slack-@cncf/otel--go-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C01NPAXACKT) +[![Slack](https://img.shields.io/badge/slack-@cncf/otel--go-brightgreen.svg?logo=slack)](https://slack.cncf.io/) OpenTelemetry-Go is the [Go](https://golang.org/) implementation of [OpenTelemetry](https://opentelemetry.io/). It provides a set of APIs to directly measure performance and behavior of your software and send this data to observability platforms. @@ -19,7 +18,7 @@ It provides a set of APIs to directly measure performance and behavior of your s |---------|--------------------| | Traces | Stable | | Metrics | Stable | -| Logs | Beta[^1] | +| Logs | Stable | Progress and status specific to this repository is tracked in our [project boards](https://github.com/open-telemetry/opentelemetry-go/projects) @@ -29,8 +28,6 @@ and Project versioning information and stability guarantees can be found in the [versioning documentation](VERSIONING.md). -[^1]: https://github.com/orgs/open-telemetry/projects/43 - ### Compatibility OpenTelemetry-Go ensures compatibility with the current supported versions of @@ -55,25 +52,18 @@ Currently, this project supports the following environments. |----------|------------|--------------| | Ubuntu | 1.27 | amd64 | | Ubuntu | 1.26 | amd64 | -| Ubuntu | 1.25 | amd64 | | Ubuntu | 1.27 | 386 | | Ubuntu | 1.26 | 386 | -| Ubuntu | 1.25 | 386 | | Ubuntu | 1.27 | arm64 | | Ubuntu | 1.26 | arm64 | -| Ubuntu | 1.25 | arm64 | | macOS | 1.27 | amd64 | | macOS | 1.26 | amd64 | -| macOS | 1.25 | amd64 | | macOS | 1.27 | arm64 | | macOS | 1.26 | arm64 | -| macOS | 1.25 | arm64 | | Windows | 1.27 | amd64 | | Windows | 1.26 | amd64 | -| Windows | 1.25 | amd64 | | Windows | 1.27 | 386 | | Windows | 1.26 | 386 | -| Windows | 1.25 | 386 | While this project should work for other systems, no compatibility guarantees are made for those systems currently. @@ -120,10 +110,3 @@ All officially supported exporters for the OpenTelemetry project are contained i ## Contributing See the [contributing documentation](CONTRIBUTING.md). - -### Emeritus - -- [Alex Kats](https://github.com/akats7), Triager - -For more information about the emeritus role, see the -[community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager). diff --git a/vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go b/vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go index 4fcdd2dbe..499aa3318 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go +++ b/vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go @@ -21,6 +21,7 @@ func New() Hash { return Hash{d: xxhash.New()} } +// Uint64 hashes val into h, returning the updated Hash. func (h Hash) Uint64(val uint64) Hash { var buf [8]byte binary.LittleEndian.PutUint64(buf[:], val) @@ -40,10 +41,12 @@ func (h Hash) Bool(val bool) Hash { // nolint:revive // This is a hashing functi return h.Uint64(0) } +// Float64 hashes val into h, returning the updated Hash. func (h Hash) Float64(val float64) Hash { return h.Uint64(math.Float64bits(val)) } +// Int64 hashes val into h, returning the updated Hash. func (h Hash) Int64(val int64) Hash { return h.Uint64(uint64(val)) // nolint:gosec // Overflow doesn't matter since we are hashing. } diff --git a/vendor/go.opentelemetry.io/otel/attribute/kv.go b/vendor/go.opentelemetry.io/otel/attribute/kv.go index c4f0dd928..60d49739a 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/kv.go +++ b/vendor/go.opentelemetry.io/otel/attribute/kv.go @@ -13,6 +13,16 @@ type KeyValue struct { Value Value } +// String returns a string representation of KeyValue using the +// [OpenTelemetry Attribute representation for non-OTLP protocols] rules. +// +// The KeyValue is encoded as a JSON object containing a single key-value pair. +// +// [OpenTelemetry Attribute representation for non-OTLP protocols]: https://opentelemetry.io/docs/specs/otel/common/#attribute-representation-for-non-otlp +func (kv KeyValue) String() string { + return formatMap([]KeyValue{kv}) +} + // Valid reports whether kv is a valid OpenTelemetry attribute. func (kv KeyValue) Valid() bool { return kv.Key.Defined() diff --git a/vendor/go.opentelemetry.io/otel/attribute/set.go b/vendor/go.opentelemetry.io/otel/attribute/set.go index 56a70a9f6..d3b2e240b 100644 --- a/vendor/go.opentelemetry.io/otel/attribute/set.go +++ b/vendor/go.opentelemetry.io/otel/attribute/set.go @@ -409,6 +409,21 @@ func computeDataReflect(kvs []KeyValue) any { return at.Interface() } +// String returns a string representation of the Set using the +// [OpenTelemetry Attribute Collection representation for non-OTLP protocols] +// rules. +// +// The Set is encoded as a JSON object. A nil or empty Set is encoded as an +// empty JSON object. +// +// [OpenTelemetry Attribute Collection representation for non-OTLP protocols]: https://opentelemetry.io/docs/specs/otel/common/#attribute-collection-representation-for-non-otlp +func (l *Set) String() string { + if l == nil || l.hash == 0 { + return "{}" + } + return formatMapValue(l.data) +} + // MarshalJSON returns the JSON encoding of the Set. func (l *Set) MarshalJSON() ([]byte, error) { return json.Marshal(l.data) diff --git a/vendor/go.opentelemetry.io/otel/baggage/baggage.go b/vendor/go.opentelemetry.io/otel/baggage/baggage.go index 25c739d08..72a58c1b6 100644 --- a/vendor/go.opentelemetry.io/otel/baggage/baggage.go +++ b/vendor/go.opentelemetry.io/otel/baggage/baggage.go @@ -247,10 +247,78 @@ func (p properties) String() string { return strings.Join(props, propertyDelimiter) } +// validateMetadata validates non-empty W3C property elements without decoding +// or materializing Property values. Empty elements are accepted to preserve +// existing parsing behavior. +func validateMetadata(raw string) (string, bool) { + start := 0 + for end := 0; end <= len(raw); end++ { + if end != len(raw) && raw[end] != propertyDelimiter[0] { + continue + } + + if start != end { + if _, ok := parsePropertyFields(raw[start:end]); !ok { + return raw[start:end], false + } + } + start = end + 1 + } + return "", true +} + +// normalizeMetadata removes empty property elements while preserving the raw +// representation of all non-empty elements. +func normalizeMetadata(metadata string) string { + if metadata == "" || + (metadata[0] != propertyDelimiter[0] && + metadata[len(metadata)-1] != propertyDelimiter[0] && + !strings.Contains(metadata, propertyDelimiter+propertyDelimiter)) { + return metadata + } + + var normalized strings.Builder + normalized.Grow(len(metadata)) + for property := range strings.SplitSeq(metadata, propertyDelimiter) { + if property == "" { + continue + } + if normalized.Len() > 0 { + _, _ = normalized.WriteString(propertyDelimiter) + } + _, _ = normalized.WriteString(property) + } + return normalized.String() +} + +func propertiesFromMetadata(metadata string) properties { + if metadata == "" { + return nil + } + + props := make(properties, 0, strings.Count(metadata, propertyDelimiter)+1) + for pStr := range strings.SplitSeq(metadata, propertyDelimiter) { + if pStr == "" { + continue + } + p, err := parseProperty(pStr) + if err != nil { + return nil + } + props = append(props, p) + } + return props +} + // Member is a list-member of a baggage-string as defined by the W3C Baggage // specification. type Member struct { key, value string + + // metadata contains the opaque W3C property suffix extracted from the wire + // without the leading semicolon. properties contains API-created + // properties. The fields are mutually exclusive. + metadata string properties properties // hasData indicates whether the created property contains data or not. @@ -307,21 +375,16 @@ func newInvalidMember() Member { return Member{} } -// parseMember attempts to decode a Member from the passed string. It returns -// an error if the input is invalid according to the W3C Baggage -// specification. +// parseMember attempts to decode a Member from the passed string. Property +// metadata grammar is validated without decoding or materializing properties. func parseMember(member string) (Member, error) { - var props properties - keyValue, properties, found := strings.Cut(member, propertyDelimiter) + var metadata string + keyValue, rawMetadata, found := strings.Cut(member, propertyDelimiter) if found { - // Parse the member properties. - for pStr := range strings.SplitSeq(properties, propertyDelimiter) { - p, err := parseProperty(pStr) - if err != nil { - return newInvalidMember(), err - } - props = append(props, p) + if invalid, ok := validateMetadata(rawMetadata); !ok { + return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidProperty, invalid) } + metadata = normalizeMetadata(rawMetadata) } // Parse the member key/value pair. @@ -349,7 +412,7 @@ func parseMember(member string) (Member, error) { } value := replaceInvalidUTF8Sequences(len(rawVal), unescapeVal) - return Member{key: key, value: value, properties: props, hasData: true}, nil + return Member{key: key, value: value, metadata: metadata, hasData: true}, nil } // replaceInvalidUTF8Sequences replaces invalid UTF-8 sequences with '�'. @@ -399,10 +462,14 @@ func (m Member) Key() string { return m.key } func (m Member) Value() string { return m.value } // Properties returns a copy of the Member properties. -func (m Member) Properties() []Property { return m.properties.Copy() } +func (m Member) Properties() []Property { + if m.metadata != "" { + return propertiesFromMetadata(m.metadata) + } + return m.properties.Copy() +} -// String encodes Member into a header string compliant with the W3C Baggage -// specification. +// String encodes Member into a baggage header string. // It would return empty string if the key is invalid with the W3C Baggage // specification. This could happen for a UTF-8 key, as it may contain // invalid characters. @@ -413,12 +480,31 @@ func (m Member) String() string { } s := m.key + keyValueDelimiter + valueEscape(m.value) - if len(m.properties) > 0 { + if m.metadata != "" { + s += propertyDelimiter + m.metadata + } else if len(m.properties) > 0 { s += propertyDelimiter + m.properties.String() } return s } +func memberFromItem(key string, item baggage.Item) Member { + return Member{ + key: key, + value: item.Value(), + metadata: item.Metadata(), + properties: fromInternalProperties(item.Properties()), + hasData: true, + } +} + +func itemFromMember(member Member) baggage.Item { + if member.metadata != "" { + return baggage.NewItemWithMetadata(member.value, member.metadata) + } + return baggage.NewItemWithProperties(member.value, member.properties.asInternal()) +} + // Baggage is a list of baggage members representing the baggage-string as // defined by the W3C Baggage specification. type Baggage struct { //nolint:golint @@ -444,10 +530,7 @@ func New(members ...Member) (Baggage, error) { return Baggage{}, errInvalidMember } // OpenTelemetry resolves duplicates by last-one-wins. - b[m.key] = baggage.Item{ - Value: m.value, - Properties: m.properties.asInternal(), - } + b[m.key] = itemFromMember(m) } var truncateErr error @@ -467,11 +550,7 @@ func New(members ...Member) (Baggage, error) { totalBytes := 0 first := true for k := range b { - m := Member{ - key: k, - value: b[k].Value, - properties: fromInternalProperties(b[k].Properties), - } + m := memberFromItem(k, b[k]) memberSize := len(m.String()) if !first { memberSize++ // comma separator @@ -563,10 +642,7 @@ func Parse(bStr string) (Baggage, error) { } // OpenTelemetry resolves duplicates by last-one-wins. - b[m.key] = baggage.Item{ - Value: m.value, - Properties: m.properties.asInternal(), - } + b[m.key] = itemFromMember(m) sizes[m.key] = memberBytes totalBytes = newTotalBytes } @@ -597,12 +673,7 @@ func (b Baggage) Member(key string) Member { return newInvalidMember() } - return Member{ - key: key, - value: v.Value, - properties: fromInternalProperties(v.Properties), - hasData: true, - } + return memberFromItem(key, v) } // Members returns all the baggage list-members. @@ -617,12 +688,7 @@ func (b Baggage) Members() []Member { members := make([]Member, 0, len(b.list)) for k, v := range b.list { - members = append(members, Member{ - key: k, - value: v.Value, - properties: fromInternalProperties(v.Properties), - hasData: true, - }) + members = append(members, memberFromItem(k, v)) } return members } @@ -652,10 +718,7 @@ func (b Baggage) SetMember(member Member) (Baggage, error) { list[k] = v } - list[member.key] = baggage.Item{ - Value: member.value, - Properties: member.properties.asInternal(), - } + list[member.key] = itemFromMember(member) return Baggage{list: list}, nil } @@ -692,11 +755,7 @@ func (b Baggage) Len() int { func (b Baggage) String() string { members := make([]string, 0, len(b.list)) for k, v := range b.list { - s := Member{ - key: k, - value: v.Value, - properties: fromInternalProperties(v.Properties), - }.String() + s := memberFromItem(k, v).String() // Ignored empty members. if s != "" { @@ -706,9 +765,14 @@ func (b Baggage) String() string { return strings.Join(members, listDelimiter) } -// parsePropertyInternal attempts to decode a Property from the passed string. -// It follows the spec at https://www.w3.org/TR/baggage/#definition. -func parsePropertyInternal(s string) (p Property, ok bool) { +type propertyFields struct { + key, rawValue string + hasValue bool +} + +// parsePropertyFields validates and locates a property's fields without +// decoding or allocating them. +func parsePropertyFields(s string) (fields propertyFields, ok bool) { // For the entire function we will use " key = value " as an example. // Attempting to parse the key. // First skip spaces at the beginning "< >key = value " (they could be empty). @@ -727,7 +791,7 @@ func parsePropertyInternal(s string) (p Property, ok bool) { // If we couldn't find any valid key character, // it means the key is either empty or invalid. if keyStart == keyEnd { - return p, ok + return fields, ok } // Skip spaces after the key: " key< >= value ". @@ -735,15 +799,14 @@ func parsePropertyInternal(s string) (p Property, ok bool) { if index == len(s) { // A key can have no value, like: " key ". - ok = true - p.key = s[keyStart:keyEnd] - return p, ok + fields.key = s[keyStart:keyEnd] + return fields, true } // If we have not reached the end and we can't find the '=' delimiter, // it means the property is invalid. if s[index] != keyValueDelimiter[0] { - return p, ok + return fields, ok } // Attempting to parse the value. @@ -769,23 +832,59 @@ func parsePropertyInternal(s string) (p Property, ok bool) { // we have not reached the end, it means the property is // invalid, something like: " key = value value1". if index != len(s) { - return p, ok + return fields, ok + } + rawVal := s[valueStart:valueEnd] + if !validPercentEncoding(rawVal) { + return fields, ok + } + + fields.key = s[keyStart:keyEnd] + fields.rawValue = rawVal + fields.hasValue = true + return fields, true +} + +func validPercentEncoding(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] != '%' { + continue + } + if i+2 >= len(s) || !isHex(s[i+1]) || !isHex(s[i+2]) { + return false + } + i += 2 + } + return true +} + +func isHex(c byte) bool { + return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' +} + +// parsePropertyInternal attempts to decode a Property from the passed string. +// It follows the spec at https://www.w3.org/TR/baggage/#definition. +func parsePropertyInternal(s string) (p Property, ok bool) { + fields, ok := parsePropertyFields(s) + if !ok { + return p, false + } + if !fields.hasValue { + p.key = fields.key + return p, true } // Decode a percent-encoded value. - rawVal := s[valueStart:valueEnd] - unescapeVal, err := url.PathUnescape(rawVal) + unescapeVal, err := url.PathUnescape(fields.rawValue) if err != nil { - return p, ok + return p, false } - value := replaceInvalidUTF8Sequences(len(rawVal), unescapeVal) + value := replaceInvalidUTF8Sequences(len(fields.rawValue), unescapeVal) - ok = true - p.key = s[keyStart:keyEnd] + p.key = fields.key p.hasValue = true - p.value = value - return p, ok + return p, true } func skipSpace(s string, offset int) int { diff --git a/vendor/go.opentelemetry.io/otel/codes/codes.go b/vendor/go.opentelemetry.io/otel/codes/codes.go index 9355545a8..1502de350 100644 --- a/vendor/go.opentelemetry.io/otel/codes/codes.go +++ b/vendor/go.opentelemetry.io/otel/codes/codes.go @@ -32,7 +32,7 @@ const ( maxCode = 3 ) -// Code is an 32-bit representation of a status state. +// Code is a 32-bit representation of a status state. type Code uint32 var codeToStr = map[Code]string{ diff --git a/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile b/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile index 20eecba40..82653bca9 100644 --- a/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile +++ b/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile @@ -1,4 +1,4 @@ # This is a renovate-friendly source of Docker images. FROM python:3.13.6-slim-bullseye@sha256:e98b521460ee75bca92175c16247bdf7275637a8faaeb2bcfa19d879ae5c4b9a AS python -FROM otel/weaver:v0.25.1@sha256:9ad46ca9cd4fa5974b121f886aa3e9946a8ef8ea905001a96c018d21f9db87ca AS weaver +FROM otel/weaver:v0.26.1@sha256:9094862c0ab261bdbcb079bb981f9a573b3659b130a6d2ab8616eca6ba37aaec AS weaver FROM avtodev/markdown-lint:v1@sha256:6aeedc2f49138ce7a1cd0adffc1b1c0321b841dc2102408967d9301c031949ee AS markdown diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/gen.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/gen.go index df08789be..34ecb287f 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/gen.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/gen.go @@ -18,8 +18,8 @@ package internal //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig\"}" --out=oconf/envconfig.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/envconfig_test.go.tmpl "--data={}" --out=oconf/envconfig_test.go -//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options.go.tmpl "--data={\"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry\"}" --out=oconf/options.go -//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options_test.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig\"}" --out=oconf/options_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options.go.tmpl "--data={\"isHTTP\": false, \"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry\"}" --out=oconf/options.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options_test.go.tmpl "--data={\"isHTTP\": false, \"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig\"}" --out=oconf/options_test.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/optiontypes.go.tmpl "--data={}" --out=oconf/optiontypes.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/tls.go.tmpl "--data={}" --out=oconf/tls.go diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go index 700dc0d1c..d79217e02 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go @@ -121,11 +121,22 @@ func withEndpointForGRPC(u *url.URL) func(cfg Config) Config { return func(cfg Config) Config { // For OTLP/gRPC endpoints, this is the target to which the // exporter is going to send telemetry. - cfg.Metrics.Endpoint = path.Join(u.Host, u.Path) + cfg.Metrics.Endpoint = grpcEndpoint(u) return cfg } } +func grpcEndpoint(u *url.URL) string { + switch strings.ToLower(u.Scheme) { + case "http", "https": + return u.Host + case "": + return path.Join(u.Host, u.Path) + default: + return u.String() + } +} + // WithEnvCompression retrieves the specified config and passes it to ConfigFn as a Compression. func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOptionsReader) { return func(e *envconfig.EnvOptionsReader) { @@ -142,7 +153,7 @@ func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOpt func withEndpointScheme(u *url.URL) GenericOption { switch strings.ToLower(u.Scheme) { - case "http", "unix": + case "http", "unix", "unix-abstract": return WithInsecure() default: return WithSecure() diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go index 4b4f164e1..95c232ba7 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go @@ -51,6 +51,7 @@ type ( // This type is compatible with `http.Transport.Proxy` and can be used to set a custom proxy function to the OTLP HTTP client. HTTPTransportProxyFunc func(*http.Request) (*url.URL, error) + // SignalConfig holds the configuration for exporting a single signal. SignalConfig struct { Endpoint string Insecure bool @@ -72,6 +73,7 @@ type ( HTTPClient *http.Client } + // Config holds the configuration for an otlpmetric exporter. Config struct { // Signal specific configurations Metrics SignalConfig @@ -144,30 +146,36 @@ func NewGRPCConfig(opts ...GRPCOption) Config { cfg = opt.ApplyGRPCOption(cfg) } + // dialOptsPrefix holds the internally computed defaults. It is prepended + // to cfg.DialOptions so that a raw grpc.DialOption supplied via WithDialOption + // always takes precedence: grpc.DialOption values are opaque closures, so this code has no way to + // detect a conflicting user-supplied option and defer to it instead. + var dialOptsPrefix []grpc.DialOption if cfg.ServiceConfig != "" { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) } // Prioritize GRPCCredentials over Insecure (passing both is an error). if cfg.Metrics.GRPCCredentials != nil { //nolint:gocritic // if-else is clearer than switch - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Metrics.GRPCCredentials)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(cfg.Metrics.GRPCCredentials)) } else if cfg.Metrics.Insecure { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(insecure.NewCredentials())) } else { // Default to using the host's root CA. creds := credentials.NewTLS(nil) cfg.Metrics.GRPCCredentials = creds - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(creds)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(creds)) } if cfg.Metrics.Compression == GzipCompression { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) } if cfg.ReconnectionPeriod != 0 { p := grpc.ConnectParams{ Backoff: backoff.DefaultConfig, MinConnectTimeout: cfg.ReconnectionPeriod, } - cfg.DialOptions = append(cfg.DialOptions, grpc.WithConnectParams(p)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithConnectParams(p)) } + cfg.DialOptions = append(dialOptsPrefix, cfg.DialOptions...) return cfg } @@ -257,6 +265,7 @@ func (h *httpOption) ApplyHTTPOption(cfg Config) Config { func (httpOption) private() {} +// NewHTTPOption creates an option that is only applied to the HTTP driver. func NewHTTPOption(fn func(cfg Config) Config) HTTPOption { return &httpOption{fn: fn} } @@ -272,12 +281,16 @@ func (h *grpcOption) ApplyGRPCOption(cfg Config) Config { func (grpcOption) private() {} +// NewGRPCOption creates an option that is only applied to the gRPC driver. func NewGRPCOption(fn func(cfg Config) Config) GRPCOption { return &grpcOption{fn: fn} } // Generic Options +// WithEndpoint configures the metrics host and port only; endpoint should +// resemble "example.com" or "localhost:4317". To configure the scheme and +// path, use WithEndpointURL. func WithEndpoint(endpoint string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Endpoint = endpoint @@ -285,6 +298,8 @@ func WithEndpoint(endpoint string) GenericOption { }) } +// WithEndpointURL configures the metrics scheme, host, port, and path; the +// provided value should resemble "https://example.com:4318/v1/metrics". func WithEndpointURL(v string) GenericOption { return newGenericOption(func(cfg Config) Config { u, err := url.Parse(v) @@ -306,6 +321,7 @@ func WithEndpointURL(v string) GenericOption { }) } +// WithCompression configures the compression used for exports. func WithCompression(compression Compression) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Compression = compression @@ -313,6 +329,7 @@ func WithCompression(compression Compression) GenericOption { }) } +// WithURLPath configures the URL path the exporter sends requests to. func WithURLPath(urlPath string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.URLPath = urlPath @@ -320,6 +337,7 @@ func WithURLPath(urlPath string) GenericOption { }) } +// WithRetry configures the retry policy used on failed exports. func WithRetry(rc retry.Config) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.RetryConfig = rc @@ -327,6 +345,8 @@ func WithRetry(rc retry.Config) GenericOption { }) } +// WithTLSClientConfig configures the TLS configuration used by the +// exporter's client. func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { return newSplitOption(func(cfg Config) Config { cfg.Metrics.TLSCfg = tlsCfg.Clone() @@ -337,6 +357,8 @@ func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { }) } +// WithInsecure disables client transport security for the exporter's +// connection. func WithInsecure() GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Insecure = true @@ -344,6 +366,8 @@ func WithInsecure() GenericOption { }) } +// WithSecure enables client transport security for the exporter's +// connection. func WithSecure() GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Insecure = false @@ -351,6 +375,7 @@ func WithSecure() GenericOption { }) } +// WithHeaders configures headers sent with every export request. func WithHeaders(headers map[string]string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Headers = headers @@ -358,6 +383,8 @@ func WithHeaders(headers map[string]string) GenericOption { }) } +// WithTimeout configures the max waiting time for the backend to process +// each export batch. func WithTimeout(duration time.Duration) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Timeout = duration @@ -365,6 +392,8 @@ func WithTimeout(duration time.Duration) GenericOption { }) } +// WithMaxRequestSize configures the maximum size, in bytes, of a serialized +// export request, before compression. func WithMaxRequestSize(size int) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.MaxRequestSize = size @@ -372,6 +401,8 @@ func WithMaxRequestSize(size int) GenericOption { }) } +// WithTemporalitySelector configures the TemporalitySelector used to +// determine the temporality of exported metrics. func WithTemporalitySelector(selector metric.TemporalitySelector) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.TemporalitySelector = selector @@ -379,6 +410,8 @@ func WithTemporalitySelector(selector metric.TemporalitySelector) GenericOption }) } +// WithAggregationSelector configures the AggregationSelector used to +// determine the aggregation of exported metrics. func WithAggregationSelector(selector metric.AggregationSelector) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.AggregationSelector = selector @@ -386,6 +419,8 @@ func WithAggregationSelector(selector metric.AggregationSelector) GenericOption }) } +// WithProxy configures the proxy function used by the exporter's HTTP +// client. func WithProxy(pf HTTPTransportProxyFunc) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Proxy = pf @@ -393,6 +428,7 @@ func WithProxy(pf HTTPTransportProxyFunc) GenericOption { }) } +// WithHTTPClient configures the HTTP client used to make requests. func WithHTTPClient(c *http.Client) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.HTTPClient = c diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/metricdata.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/metricdata.go index 6c07896a8..a72d89900 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/metricdata.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/metricdata.go @@ -235,6 +235,7 @@ func ExponentialHistogramDataPoints[N int64 | float64]( Sum: &sum, Scale: dPt.Scale, ZeroCount: dPt.ZeroCount, + ZeroThreshold: dPt.ZeroThreshold, Exemplars: Exemplars(dPt.Exemplars), Positive: ExponentialHistogramDataPointBuckets(dPt.PositiveBucket), diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/version.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/version.go index 143faa636..c8c954a00 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/version.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/version.go @@ -5,5 +5,5 @@ package otlpmetricgrpc // Version is the current release version of the OpenTelemetry OTLP over gRPC metrics exporter in use. func Version() string { - return "1.46.0" + return "1.47.0" } diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go index 41aa7ff34..ab56cae55 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go @@ -31,11 +31,12 @@ import ( type client struct { // req is cloned for every upload the client makes. - req *http.Request - compression Compression - maxRequestSize int - requestFunc retry.RequestFunc - httpClient *http.Client + req *http.Request + compression Compression + maxRequestSize int + maxResponseSize int64 + requestFunc retry.RequestFunc + httpClient *http.Client inst *observ.Instrumentation } @@ -59,13 +60,6 @@ var ourTransport = &http.Transport{ var errInsecureEndpointWithTLS = errors.New("insecure HTTP endpoint cannot use TLS client configuration") -// maxResponseBodySize is the maximum number of bytes to read from a response -// body. It is set to 4 MiB per the OTLP specification recommendation to -// mitigate excessive memory usage caused by a misconfigured or malicious -// server. If exceeded, the response is treated as a not-retryable error. -// This is a variable to allow tests to override it. -var maxResponseBodySize int64 = 4 * 1024 * 1024 - // newClient creates a new HTTP metric client. func newClient(cfg oconf.Config) (*client, error) { if cfg.Metrics.Insecure && cfg.Metrics.TLSCfg != nil { @@ -120,12 +114,13 @@ func newClient(cfg oconf.Config) (*client, error) { inst, err := observ.NewInstrumentation(counter.NextExporterID(), cfg.Metrics.Endpoint) return &client{ - compression: Compression(cfg.Metrics.Compression), - maxRequestSize: cfg.Metrics.MaxRequestSize, - req: req, - requestFunc: cfg.RetryConfig.RequestFunc(evaluate), - httpClient: httpClient, - inst: inst, + compression: Compression(cfg.Metrics.Compression), + maxRequestSize: cfg.Metrics.MaxRequestSize, + maxResponseSize: cfg.Metrics.MaxResponseSize, + req: req, + requestFunc: cfg.RetryConfig.RequestFunc(evaluate), + httpClient: httpClient, + inst: inst, }, err } @@ -204,11 +199,7 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou // Read the partial success message, if any. var respData bytes.Buffer - if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { - var maxBytesErr *http.MaxBytesError - if errors.As(err, &maxBytesErr) { - return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) - } + if err := internal.CopyResponseBody(&respData, resp.Body, c.maxResponseSize); err != nil { return err } if respData.Len() == 0 { @@ -239,11 +230,7 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou // message to be returned. It will help in // debugging the actual issue. var respData bytes.Buffer - if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { - var maxBytesErr *http.MaxBytesError - if errors.As(err, &maxBytesErr) { - return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) - } + if err := internal.CopyResponseBody(&respData, resp.Body, c.maxResponseSize); err != nil { return err } respStr := strings.TrimSpace(respData.String()) diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/config.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/config.go index 35e6bb12d..b57eccdaa 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/config.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/config.go @@ -200,6 +200,15 @@ func WithMaxRequestSize(size int) Option { return wrappedOption{oconf.WithMaxRequestSize(size)} } +// WithMaxResponseSize sets the maximum size, in bytes, of an OTLP/HTTP +// response body, after decompression, that the exporter will read. +// +// By default, a limit of 4 MiB is used. Values less than or equal to zero are +// ignored. The response-size limit cannot be disabled. +func WithMaxResponseSize(size int64) Option { + return wrappedOption{oconf.WithMaxResponseSize(size)} +} + // WithRetry sets the retry policy for transient retryable errors that are // returned by the target endpoint. // diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/gen.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/gen.go index 9b1727caa..50185118a 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/gen.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/gen.go @@ -6,6 +6,8 @@ package internal //go:generate gotmpl --body=../../../../../internal/shared/otlp/partialsuccess.go.tmpl "--data={}" --out=partialsuccess.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/partialsuccess_test.go.tmpl "--data={}" --out=partialsuccess_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/response.go.tmpl "--data={}" --out=response.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/response_test.go.tmpl "--data={}" --out=response_test.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/retry/retry.go.tmpl "--data={}" --out=retry/retry.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/retry/retry_test.go.tmpl "--data={}" --out=retry/retry_test.go @@ -15,8 +17,8 @@ package internal //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig\"}" --out=oconf/envconfig.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/envconfig_test.go.tmpl "--data={}" --out=oconf/envconfig_test.go -//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options.go.tmpl "--data={\"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry\"}" --out=oconf/options.go -//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options_test.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig\"}" --out=oconf/options_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options.go.tmpl "--data={\"isHTTP\": true, \"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry\"}" --out=oconf/options.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options_test.go.tmpl "--data={\"isHTTP\": true, \"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig\"}" --out=oconf/options_test.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/optiontypes.go.tmpl "--data={}" --out=oconf/optiontypes.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/tls.go.tmpl "--data={}" --out=oconf/tls.go diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go index c0a6392dd..d782805a8 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go @@ -121,11 +121,22 @@ func withEndpointForGRPC(u *url.URL) func(cfg Config) Config { return func(cfg Config) Config { // For OTLP/gRPC endpoints, this is the target to which the // exporter is going to send telemetry. - cfg.Metrics.Endpoint = path.Join(u.Host, u.Path) + cfg.Metrics.Endpoint = grpcEndpoint(u) return cfg } } +func grpcEndpoint(u *url.URL) string { + switch strings.ToLower(u.Scheme) { + case "http", "https": + return u.Host + case "": + return path.Join(u.Host, u.Path) + default: + return u.String() + } +} + // WithEnvCompression retrieves the specified config and passes it to ConfigFn as a Compression. func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOptionsReader) { return func(e *envconfig.EnvOptionsReader) { @@ -142,7 +153,7 @@ func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOpt func withEndpointScheme(u *url.URL) GenericOption { switch strings.ToLower(u.Scheme) { - case "http", "unix": + case "http", "unix", "unix-abstract": return WithInsecure() default: return WithSecure() diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/options.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/options.go index a3e4641c2..be2005b0d 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/options.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/options.go @@ -38,6 +38,9 @@ const ( // DefaultMaxRequestSize is the default maximum size of a serialized export // request, before compression. DefaultMaxRequestSize int = 64 * 1024 * 1024 + // DefaultMaxResponseSize is the default maximum size of an OTLP/HTTP + // response body, after decompression. + DefaultMaxResponseSize int64 = 4 * 1024 * 1024 // DefaultBackoff is a default base backoff time used in the // exponential backoff strategy. DefaultBackoff time.Duration = 300 * time.Millisecond @@ -51,15 +54,17 @@ type ( // This type is compatible with `http.Transport.Proxy` and can be used to set a custom proxy function to the OTLP HTTP client. HTTPTransportProxyFunc func(*http.Request) (*url.URL, error) + // SignalConfig holds the configuration for exporting a single signal. SignalConfig struct { - Endpoint string - Insecure bool - TLSCfg *tls.Config - Headers map[string]string - Compression Compression - MaxRequestSize int - Timeout time.Duration - URLPath string + Endpoint string + Insecure bool + TLSCfg *tls.Config + Headers map[string]string + Compression Compression + MaxRequestSize int + MaxResponseSize int64 + Timeout time.Duration + URLPath string TemporalitySelector metric.TemporalitySelector AggregationSelector metric.AggregationSelector @@ -72,6 +77,7 @@ type ( HTTPClient *http.Client } + // Config holds the configuration for an otlpmetric exporter. Config struct { // Signal specific configurations Metrics SignalConfig @@ -91,11 +97,12 @@ type ( func NewHTTPConfig(opts ...HTTPOption) Config { cfg := Config{ Metrics: SignalConfig{ - Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort), - URLPath: DefaultMetricsPath, - Compression: NoCompression, - MaxRequestSize: DefaultMaxRequestSize, - Timeout: DefaultTimeout, + Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort), + URLPath: DefaultMetricsPath, + Compression: NoCompression, + MaxRequestSize: DefaultMaxRequestSize, + MaxResponseSize: DefaultMaxResponseSize, + Timeout: DefaultTimeout, TemporalitySelector: metric.DefaultTemporalitySelector, AggregationSelector: metric.DefaultAggregationSelector, @@ -144,30 +151,36 @@ func NewGRPCConfig(opts ...GRPCOption) Config { cfg = opt.ApplyGRPCOption(cfg) } + // dialOptsPrefix holds the internally computed defaults. It is prepended + // to cfg.DialOptions so that a raw grpc.DialOption supplied via WithDialOption + // always takes precedence: grpc.DialOption values are opaque closures, so this code has no way to + // detect a conflicting user-supplied option and defer to it instead. + var dialOptsPrefix []grpc.DialOption if cfg.ServiceConfig != "" { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) } // Prioritize GRPCCredentials over Insecure (passing both is an error). if cfg.Metrics.GRPCCredentials != nil { //nolint:gocritic // if-else is clearer than switch - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Metrics.GRPCCredentials)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(cfg.Metrics.GRPCCredentials)) } else if cfg.Metrics.Insecure { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(insecure.NewCredentials())) } else { // Default to using the host's root CA. creds := credentials.NewTLS(nil) cfg.Metrics.GRPCCredentials = creds - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(creds)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(creds)) } if cfg.Metrics.Compression == GzipCompression { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) } if cfg.ReconnectionPeriod != 0 { p := grpc.ConnectParams{ Backoff: backoff.DefaultConfig, MinConnectTimeout: cfg.ReconnectionPeriod, } - cfg.DialOptions = append(cfg.DialOptions, grpc.WithConnectParams(p)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithConnectParams(p)) } + cfg.DialOptions = append(dialOptsPrefix, cfg.DialOptions...) return cfg } @@ -257,6 +270,7 @@ func (h *httpOption) ApplyHTTPOption(cfg Config) Config { func (httpOption) private() {} +// NewHTTPOption creates an option that is only applied to the HTTP driver. func NewHTTPOption(fn func(cfg Config) Config) HTTPOption { return &httpOption{fn: fn} } @@ -272,12 +286,16 @@ func (h *grpcOption) ApplyGRPCOption(cfg Config) Config { func (grpcOption) private() {} +// NewGRPCOption creates an option that is only applied to the gRPC driver. func NewGRPCOption(fn func(cfg Config) Config) GRPCOption { return &grpcOption{fn: fn} } // Generic Options +// WithEndpoint configures the metrics host and port only; endpoint should +// resemble "example.com" or "localhost:4317". To configure the scheme and +// path, use WithEndpointURL. func WithEndpoint(endpoint string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Endpoint = endpoint @@ -285,6 +303,8 @@ func WithEndpoint(endpoint string) GenericOption { }) } +// WithEndpointURL configures the metrics scheme, host, port, and path; the +// provided value should resemble "https://example.com:4318/v1/metrics". func WithEndpointURL(v string) GenericOption { return newGenericOption(func(cfg Config) Config { u, err := url.Parse(v) @@ -306,6 +326,7 @@ func WithEndpointURL(v string) GenericOption { }) } +// WithCompression configures the compression used for exports. func WithCompression(compression Compression) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Compression = compression @@ -313,6 +334,7 @@ func WithCompression(compression Compression) GenericOption { }) } +// WithURLPath configures the URL path the exporter sends requests to. func WithURLPath(urlPath string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.URLPath = urlPath @@ -320,6 +342,7 @@ func WithURLPath(urlPath string) GenericOption { }) } +// WithRetry configures the retry policy used on failed exports. func WithRetry(rc retry.Config) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.RetryConfig = rc @@ -327,6 +350,8 @@ func WithRetry(rc retry.Config) GenericOption { }) } +// WithTLSClientConfig configures the TLS configuration used by the +// exporter's client. func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { return newSplitOption(func(cfg Config) Config { cfg.Metrics.TLSCfg = tlsCfg.Clone() @@ -337,6 +362,8 @@ func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { }) } +// WithInsecure disables client transport security for the exporter's +// connection. func WithInsecure() GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Insecure = true @@ -344,6 +371,8 @@ func WithInsecure() GenericOption { }) } +// WithSecure enables client transport security for the exporter's +// connection. func WithSecure() GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Insecure = false @@ -351,6 +380,7 @@ func WithSecure() GenericOption { }) } +// WithHeaders configures headers sent with every export request. func WithHeaders(headers map[string]string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Headers = headers @@ -358,6 +388,8 @@ func WithHeaders(headers map[string]string) GenericOption { }) } +// WithTimeout configures the max waiting time for the backend to process +// each export batch. func WithTimeout(duration time.Duration) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Timeout = duration @@ -365,6 +397,8 @@ func WithTimeout(duration time.Duration) GenericOption { }) } +// WithMaxRequestSize configures the maximum size, in bytes, of a serialized +// export request, before compression. func WithMaxRequestSize(size int) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.MaxRequestSize = size @@ -372,6 +406,19 @@ func WithMaxRequestSize(size int) GenericOption { }) } +// WithMaxResponseSize configures the maximum size, in bytes, of an OTLP/HTTP +// response body, after decompression. +func WithMaxResponseSize(size int64) HTTPOption { + return NewHTTPOption(func(cfg Config) Config { + if size > 0 { + cfg.Metrics.MaxResponseSize = size + } + return cfg + }) +} + +// WithTemporalitySelector configures the TemporalitySelector used to +// determine the temporality of exported metrics. func WithTemporalitySelector(selector metric.TemporalitySelector) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.TemporalitySelector = selector @@ -379,6 +426,8 @@ func WithTemporalitySelector(selector metric.TemporalitySelector) GenericOption }) } +// WithAggregationSelector configures the AggregationSelector used to +// determine the aggregation of exported metrics. func WithAggregationSelector(selector metric.AggregationSelector) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.AggregationSelector = selector @@ -386,6 +435,8 @@ func WithAggregationSelector(selector metric.AggregationSelector) GenericOption }) } +// WithProxy configures the proxy function used by the exporter's HTTP +// client. func WithProxy(pf HTTPTransportProxyFunc) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.Proxy = pf @@ -393,6 +444,7 @@ func WithProxy(pf HTTPTransportProxyFunc) GenericOption { }) } +// WithHTTPClient configures the HTTP client used to make requests. func WithHTTPClient(c *http.Client) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Metrics.HTTPClient = c diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/response.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/response.go new file mode 100644 index 000000000..0b48bf14b --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/response.go @@ -0,0 +1,31 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// DO NOT MODIFY. Generated by gotmpl. +// source: internal/shared/otlp/response.go.tmpl + +package internal + +import ( + "errors" + "fmt" + "io" +) + +// CopyResponseBody copies at most maxSize bytes from src to dst. It returns +// an error if src contains more than maxSize bytes. +func CopyResponseBody(dst io.Writer, src io.Reader, maxSize int64) error { + if _, err := io.Copy(dst, io.LimitReader(src, maxSize)); err != nil { + return err + } + + var extra [1]byte + _, err := io.ReadFull(src, extra[:]) + if err == nil { + return fmt.Errorf("response body too large: exceeded %d bytes", maxSize) + } + if errors.Is(err, io.EOF) { + return nil + } + return err +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/metricdata.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/metricdata.go index 6c07896a8..a72d89900 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/metricdata.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/metricdata.go @@ -235,6 +235,7 @@ func ExponentialHistogramDataPoints[N int64 | float64]( Sum: &sum, Scale: dPt.Scale, ZeroCount: dPt.ZeroCount, + ZeroThreshold: dPt.ZeroThreshold, Exemplars: Exemplars(dPt.Exemplars), Positive: ExponentialHistogramDataPointBuckets(dPt.PositiveBucket), diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/version.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/version.go index aeb497f09..53f7bc797 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/version.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/version.go @@ -5,4 +5,4 @@ package internal // Version is the current release version of the OpenTelemetry OTLP HTTP metric // exporter in use. -const Version = "1.46.0" +const Version = "1.47.0" diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go index 078a9db0a..1754a7fcb 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go @@ -9,6 +9,8 @@ import ( "go.opentelemetry.io/otel/sdk/instrumentation" ) +// InstrumentationScope transforms il into an OTLP InstrumentationScope, +// returning nil if il is the zero value. func InstrumentationScope(il instrumentation.Scope) *commonpb.InstrumentationScope { if il == (instrumentation.Scope{}) { return nil diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/doc.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/doc.go index b01358fc8..3dbc84275 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/doc.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/doc.go @@ -12,8 +12,9 @@ The environment variables described below can be used for configuration. OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT (default: "https://localhost:4317") - target to which the exporter sends telemetry. The target syntax is defined in https://github.com/grpc/grpc/blob/master/doc/naming.md. -The value must contain a scheme ("http" or "https") and host. -The value may additionally contain a port, and a path. +If the value uses the "http" or "https" scheme, the host and optional port are +used as the gRPC target and any path is ignored. +Values with other schemes are passed to gRPC as-is. The value should not contain a query string or fragment. OTEL_EXPORTER_OTLP_TRACES_ENDPOINT takes precedence over OTEL_EXPORTER_OTLP_ENDPOINT. The configuration can be overridden by [WithEndpoint], [WithEndpointURL], [WithInsecure], and [WithGRPCConn] options. diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/gen.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/gen.go index ec16d0145..26066e336 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/gen.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/gen.go @@ -14,8 +14,8 @@ package internal //go:generate gotmpl --body=../../../../../internal/shared/otlp/envconfig/envconfig_test.go.tmpl "--data={}" --out=envconfig/envconfig_test.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/envconfig.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/envconfig\"}" --out=otlpconfig/envconfig.go -//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/options.go.tmpl "--data={\"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry\"}" --out=otlpconfig/options.go -//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/options_test.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/envconfig\"}" --out=otlpconfig/options_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/options.go.tmpl "--data={\"isHTTP\": false, \"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry\"}" --out=otlpconfig/options.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/options_test.go.tmpl "--data={\"isHTTP\": false, \"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/envconfig\"}" --out=otlpconfig/options_test.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/optiontypes.go.tmpl "--data={}" --out=otlpconfig/optiontypes.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/tls.go.tmpl "--data={}" --out=otlpconfig/tls.go diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/envconfig.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/envconfig.go index 3bfc2a6f3..ce41a22eb 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/envconfig.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/envconfig.go @@ -119,10 +119,20 @@ func withEndpointScheme(u *url.URL) GenericOption { } func withEndpointForGRPC(u *url.URL) func(cfg Config) Config { + target := u.String() + switch strings.ToLower(u.Scheme) { + case "http", "https": + target = u.Host + case "": + if u.Host != "" { + target = path.Join(u.Host, u.Path) + } + } + return func(cfg Config) Config { // For OTLP/gRPC endpoints, this is the target to which the // exporter is going to send telemetry. - cfg.Traces.Endpoint = path.Join(u.Host, u.Path) + cfg.Traces.Endpoint = target return cfg } } diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/options.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/options.go index a56847a3b..b990dd3f7 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/options.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/options.go @@ -44,6 +44,7 @@ type ( // This type is compatible with `http.Transport.Proxy` and can be used to set a custom proxy function to the OTLP HTTP client. HTTPTransportProxyFunc func(*http.Request) (*url.URL, error) + // SignalConfig holds the configuration for exporting a single signal. SignalConfig struct { Endpoint string Insecure bool @@ -63,6 +64,7 @@ type ( HTTPClient *http.Client } + // Config holds the configuration for an otlptrace exporter. Config struct { // Signal specific configurations Traces SignalConfig @@ -126,37 +128,42 @@ func NewGRPCConfig(opts ...GRPCOption) Config { Timeout: DefaultTimeout, }, RetryConfig: retry.DefaultConfig, - DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)}, } cfg = ApplyGRPCEnvConfigs(cfg) for _, opt := range opts { cfg = opt.ApplyGRPCOption(cfg) } + // dialOptsPrefix holds the internally computed defaults. It is prepended + // to cfg.DialOptions so that a raw grpc.DialOption supplied via WithDialOption + // always takes precedence: grpc.DialOption values are opaque closures, so this code has no way to + // detect a conflicting user-supplied option and defer to it instead. + dialOptsPrefix := []grpc.DialOption{grpc.WithUserAgent(userAgent)} if cfg.ServiceConfig != "" { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) } // Prioritize GRPCCredentials over Insecure (passing both is an error). if cfg.Traces.GRPCCredentials != nil { //nolint:gocritic // if-else is clearer than switch - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Traces.GRPCCredentials)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(cfg.Traces.GRPCCredentials)) } else if cfg.Traces.Insecure { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(insecure.NewCredentials())) } else { // Default to using the host's root CA. creds := credentials.NewTLS(nil) cfg.Traces.GRPCCredentials = creds - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(creds)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(creds)) } if cfg.Traces.Compression == GzipCompression { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) } if cfg.ReconnectionPeriod != 0 { p := grpc.ConnectParams{ Backoff: backoff.DefaultConfig, MinConnectTimeout: cfg.ReconnectionPeriod, } - cfg.DialOptions = append(cfg.DialOptions, grpc.WithConnectParams(p)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithConnectParams(p)) } + cfg.DialOptions = append(dialOptsPrefix, cfg.DialOptions...) return cfg } @@ -246,6 +253,7 @@ func (h *httpOption) ApplyHTTPOption(cfg Config) Config { func (httpOption) private() {} +// NewHTTPOption creates an option that is only applied to the HTTP driver. func NewHTTPOption(fn func(cfg Config) Config) HTTPOption { return &httpOption{fn: fn} } @@ -261,6 +269,7 @@ func (h *grpcOption) ApplyGRPCOption(cfg Config) Config { func (grpcOption) private() {} +// NewGRPCOption creates an option that is only applied to the gRPC driver. func NewGRPCOption(fn func(cfg Config) Config) GRPCOption { return &grpcOption{fn: fn} } @@ -300,6 +309,7 @@ func WithEndpointURL(v string) GenericOption { }) } +// WithCompression configures the compression used for exports. func WithCompression(compression Compression) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Compression = compression @@ -307,6 +317,7 @@ func WithCompression(compression Compression) GenericOption { }) } +// WithURLPath configures the URL path the exporter sends requests to. func WithURLPath(urlPath string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.URLPath = urlPath @@ -314,6 +325,7 @@ func WithURLPath(urlPath string) GenericOption { }) } +// WithRetry configures the retry policy used on failed exports. func WithRetry(rc retry.Config) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.RetryConfig = rc @@ -321,6 +333,8 @@ func WithRetry(rc retry.Config) GenericOption { }) } +// WithTLSClientConfig configures the TLS configuration used by the +// exporter's client. func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { return newSplitOption(func(cfg Config) Config { cfg.Traces.TLSCfg = tlsCfg.Clone() @@ -331,6 +345,8 @@ func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { }) } +// WithInsecure disables client transport security for the exporter's +// connection. func WithInsecure() GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Insecure = true @@ -338,6 +354,8 @@ func WithInsecure() GenericOption { }) } +// WithSecure enables client transport security for the exporter's +// connection. func WithSecure() GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Insecure = false @@ -345,6 +363,7 @@ func WithSecure() GenericOption { }) } +// WithHeaders configures headers sent with every export request. func WithHeaders(headers map[string]string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Headers = headers @@ -352,6 +371,8 @@ func WithHeaders(headers map[string]string) GenericOption { }) } +// WithTimeout configures the max waiting time for the backend to process +// each export batch. func WithTimeout(duration time.Duration) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Timeout = duration @@ -359,6 +380,8 @@ func WithTimeout(duration time.Duration) GenericOption { }) } +// WithMaxRequestSize configures the maximum size, in bytes, of a serialized +// export request, before compression. func WithMaxRequestSize(size int) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.MaxRequestSize = size @@ -366,6 +389,8 @@ func WithMaxRequestSize(size int) GenericOption { }) } +// WithProxy configures the proxy function used by the exporter's HTTP +// client. func WithProxy(pf HTTPTransportProxyFunc) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Proxy = pf @@ -373,6 +398,7 @@ func WithProxy(pf HTTPTransportProxyFunc) GenericOption { }) } +// WithHTTPClient configures the HTTP client used to make requests. func WithHTTPClient(c *http.Client) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.HTTPClient = c @@ -380,6 +406,7 @@ func WithHTTPClient(c *http.Client) GenericOption { }) } +// WithProtocol configures the protocol used to encode and send telemetry. func WithProtocol(protocol Protocol) GenericOption { return newSplitOption( // For OTLP/HTTP endpoints, this is the encoding format of the payloads sent to the collector. diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/version.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/version.go index d26674e57..badf29557 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/version.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/version.go @@ -5,4 +5,4 @@ package internal // Version is the current release version of the OpenTelemetry OTLP gRPC trace // exporter in use. -const Version = "1.46.0" +const Version = "1.47.0" diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/options.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/options.go index ea20363c0..516113b78 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/options.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/options.go @@ -74,9 +74,10 @@ func WithEndpoint(endpoint string) Option { return wrappedOption{otlpconfig.WithEndpoint(endpoint)} } -// WithEndpointURL sets the target endpoint URL (scheme, host, port, path) -// the Exporter will connect to. The provided endpoint URL should resemble -// "https://example.com:4318/v1/traces". +// WithEndpointURL sets the target endpoint URL (scheme, host, port) the +// Exporter will connect to. The provided endpoint URL should resemble +// "https://example.com:4317". If the URL contains a path, it is ignored by +// the gRPC client. // // If the OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_TRACES_ENDPOINT // environment variable is set, and this option is not passed, that variable @@ -90,7 +91,7 @@ func WithEndpoint(endpoint string) Option { // If an invalid URL is provided, the default value will be kept. // // By default, if an environment variable is not set, and this option is not -// passed, "https://localhost:4317/v1/traces" will be used. +// passed, "https://localhost:4317" will be used. // // This option has no effect if WithGRPCConn is used. func WithEndpointURL(u string) Option { diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go index 00b4572ef..698a7571b 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go @@ -36,13 +36,6 @@ const ( contentTypeJSON = "application/json" ) -// maxResponseBodySize is the maximum number of bytes to read from a response -// body. It is set to 4 MiB per the OTLP specification recommendation to -// mitigate excessive memory usage caused by a misconfigured or malicious -// server. If exceeded, the response is treated as a not-retryable error. -// This is a variable to allow tests to override it. -var maxResponseBodySize int64 = 4 * 1024 * 1024 - var gzPool = sync.Pool{ New: func() any { w := gzip.NewWriter(io.Discard) @@ -217,11 +210,7 @@ func (c *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc // Success, do not retry. // Read the partial success message, if any. var respData bytes.Buffer - if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { - var maxBytesErr *http.MaxBytesError - if errors.As(err, &maxBytesErr) { - return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) - } + if err := internal.CopyResponseBody(&respData, resp.Body, c.cfg.MaxResponseSize); err != nil { return err } if respData.Len() == 0 { @@ -259,11 +248,7 @@ func (c *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc // message to be returned. It will help in // debugging the actual issue. var respData bytes.Buffer - if _, err := io.Copy(&respData, http.MaxBytesReader(nil, resp.Body, maxResponseBodySize)); err != nil { - var maxBytesErr *http.MaxBytesError - if errors.As(err, &maxBytesErr) { - return fmt.Errorf("response body too large: exceeded %d bytes", maxBytesErr.Limit) - } + if err := internal.CopyResponseBody(&respData, resp.Body, c.cfg.MaxResponseSize); err != nil { return err } respStr := strings.TrimSpace(respData.String()) diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/gen.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/gen.go index 9064f6564..c4d2df34f 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/gen.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/gen.go @@ -6,6 +6,8 @@ package internal //go:generate gotmpl --body=../../../../../internal/shared/otlp/partialsuccess.go.tmpl "--data={}" --out=partialsuccess.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/partialsuccess_test.go.tmpl "--data={}" --out=partialsuccess_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/response.go.tmpl "--data={}" --out=response.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/response_test.go.tmpl "--data={}" --out=response_test.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/retry/retry.go.tmpl "--data={}" --out=retry/retry.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/retry/retry_test.go.tmpl "--data={}" --out=retry/retry_test.go @@ -14,8 +16,8 @@ package internal //go:generate gotmpl --body=../../../../../internal/shared/otlp/envconfig/envconfig_test.go.tmpl "--data={}" --out=envconfig/envconfig_test.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/envconfig.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/envconfig\"}" --out=otlpconfig/envconfig.go -//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/options.go.tmpl "--data={\"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry\"}" --out=otlpconfig/options.go -//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/options_test.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/envconfig\"}" --out=otlpconfig/options_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/options.go.tmpl "--data={\"isHTTP\": true, \"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry\"}" --out=otlpconfig/options.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/options_test.go.tmpl "--data={\"isHTTP\": true, \"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/envconfig\"}" --out=otlpconfig/options_test.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/optiontypes.go.tmpl "--data={}" --out=otlpconfig/optiontypes.go //go:generate gotmpl --body=../../../../../internal/shared/otlp/otlptrace/otlpconfig/tls.go.tmpl "--data={}" --out=otlpconfig/tls.go diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig/envconfig.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig/envconfig.go index 96f857f97..e129bd7d7 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig/envconfig.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig/envconfig.go @@ -119,10 +119,20 @@ func withEndpointScheme(u *url.URL) GenericOption { } func withEndpointForGRPC(u *url.URL) func(cfg Config) Config { + target := u.String() + switch strings.ToLower(u.Scheme) { + case "http", "https": + target = u.Host + case "": + if u.Host != "" { + target = path.Join(u.Host, u.Path) + } + } + return func(cfg Config) Config { // For OTLP/gRPC endpoints, this is the target to which the // exporter is going to send telemetry. - cfg.Traces.Endpoint = path.Join(u.Host, u.Path) + cfg.Traces.Endpoint = target return cfg } } diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig/options.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig/options.go index f1c1d2712..090bc660e 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig/options.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig/options.go @@ -34,6 +34,9 @@ const ( // DefaultMaxRequestSize is the default maximum size of a serialized export // request, before compression. DefaultMaxRequestSize int = 64 * 1024 * 1024 + // DefaultMaxResponseSize is the default maximum size of an OTLP/HTTP + // response body, after decompression. + DefaultMaxResponseSize int64 = 4 * 1024 * 1024 // DefaultTimeout is a default max waiting time for the backend to process // each span batch. DefaultTimeout time.Duration = 10 * time.Second @@ -44,16 +47,18 @@ type ( // This type is compatible with `http.Transport.Proxy` and can be used to set a custom proxy function to the OTLP HTTP client. HTTPTransportProxyFunc func(*http.Request) (*url.URL, error) + // SignalConfig holds the configuration for exporting a single signal. SignalConfig struct { - Endpoint string - Insecure bool - TLSCfg *tls.Config - Headers map[string]string - Compression Compression - Protocol Protocol - MaxRequestSize int - Timeout time.Duration - URLPath string + Endpoint string + Insecure bool + TLSCfg *tls.Config + Headers map[string]string + Compression Compression + Protocol Protocol + MaxRequestSize int + MaxResponseSize int64 + Timeout time.Duration + URLPath string // gRPC configurations GRPCCredentials credentials.TransportCredentials @@ -63,6 +68,7 @@ type ( HTTPClient *http.Client } + // Config holds the configuration for an otlptrace exporter. Config struct { // Signal specific configurations Traces SignalConfig @@ -82,12 +88,13 @@ type ( func NewHTTPConfig(opts ...HTTPOption) Config { cfg := Config{ Traces: SignalConfig{ - Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort), - URLPath: DefaultTracesPath, - Compression: NoCompression, - Protocol: ProtocolHTTPProtobuf, - MaxRequestSize: DefaultMaxRequestSize, - Timeout: DefaultTimeout, + Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort), + URLPath: DefaultTracesPath, + Compression: NoCompression, + Protocol: ProtocolHTTPProtobuf, + MaxRequestSize: DefaultMaxRequestSize, + MaxResponseSize: DefaultMaxResponseSize, + Timeout: DefaultTimeout, }, RetryConfig: retry.DefaultConfig, } @@ -126,37 +133,42 @@ func NewGRPCConfig(opts ...GRPCOption) Config { Timeout: DefaultTimeout, }, RetryConfig: retry.DefaultConfig, - DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)}, } cfg = ApplyGRPCEnvConfigs(cfg) for _, opt := range opts { cfg = opt.ApplyGRPCOption(cfg) } + // dialOptsPrefix holds the internally computed defaults. It is prepended + // to cfg.DialOptions so that a raw grpc.DialOption supplied via WithDialOption + // always takes precedence: grpc.DialOption values are opaque closures, so this code has no way to + // detect a conflicting user-supplied option and defer to it instead. + dialOptsPrefix := []grpc.DialOption{grpc.WithUserAgent(userAgent)} if cfg.ServiceConfig != "" { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) } // Prioritize GRPCCredentials over Insecure (passing both is an error). if cfg.Traces.GRPCCredentials != nil { //nolint:gocritic // if-else is clearer than switch - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Traces.GRPCCredentials)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(cfg.Traces.GRPCCredentials)) } else if cfg.Traces.Insecure { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(insecure.NewCredentials())) } else { // Default to using the host's root CA. creds := credentials.NewTLS(nil) cfg.Traces.GRPCCredentials = creds - cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(creds)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithTransportCredentials(creds)) } if cfg.Traces.Compression == GzipCompression { - cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) } if cfg.ReconnectionPeriod != 0 { p := grpc.ConnectParams{ Backoff: backoff.DefaultConfig, MinConnectTimeout: cfg.ReconnectionPeriod, } - cfg.DialOptions = append(cfg.DialOptions, grpc.WithConnectParams(p)) + dialOptsPrefix = append(dialOptsPrefix, grpc.WithConnectParams(p)) } + cfg.DialOptions = append(dialOptsPrefix, cfg.DialOptions...) return cfg } @@ -246,6 +258,7 @@ func (h *httpOption) ApplyHTTPOption(cfg Config) Config { func (httpOption) private() {} +// NewHTTPOption creates an option that is only applied to the HTTP driver. func NewHTTPOption(fn func(cfg Config) Config) HTTPOption { return &httpOption{fn: fn} } @@ -261,6 +274,7 @@ func (h *grpcOption) ApplyGRPCOption(cfg Config) Config { func (grpcOption) private() {} +// NewGRPCOption creates an option that is only applied to the gRPC driver. func NewGRPCOption(fn func(cfg Config) Config) GRPCOption { return &grpcOption{fn: fn} } @@ -300,6 +314,7 @@ func WithEndpointURL(v string) GenericOption { }) } +// WithCompression configures the compression used for exports. func WithCompression(compression Compression) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Compression = compression @@ -307,6 +322,7 @@ func WithCompression(compression Compression) GenericOption { }) } +// WithURLPath configures the URL path the exporter sends requests to. func WithURLPath(urlPath string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.URLPath = urlPath @@ -314,6 +330,7 @@ func WithURLPath(urlPath string) GenericOption { }) } +// WithRetry configures the retry policy used on failed exports. func WithRetry(rc retry.Config) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.RetryConfig = rc @@ -321,6 +338,8 @@ func WithRetry(rc retry.Config) GenericOption { }) } +// WithTLSClientConfig configures the TLS configuration used by the +// exporter's client. func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { return newSplitOption(func(cfg Config) Config { cfg.Traces.TLSCfg = tlsCfg.Clone() @@ -331,6 +350,8 @@ func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { }) } +// WithInsecure disables client transport security for the exporter's +// connection. func WithInsecure() GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Insecure = true @@ -338,6 +359,8 @@ func WithInsecure() GenericOption { }) } +// WithSecure enables client transport security for the exporter's +// connection. func WithSecure() GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Insecure = false @@ -345,6 +368,7 @@ func WithSecure() GenericOption { }) } +// WithHeaders configures headers sent with every export request. func WithHeaders(headers map[string]string) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Headers = headers @@ -352,6 +376,8 @@ func WithHeaders(headers map[string]string) GenericOption { }) } +// WithTimeout configures the max waiting time for the backend to process +// each export batch. func WithTimeout(duration time.Duration) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Timeout = duration @@ -359,6 +385,8 @@ func WithTimeout(duration time.Duration) GenericOption { }) } +// WithMaxRequestSize configures the maximum size, in bytes, of a serialized +// export request, before compression. func WithMaxRequestSize(size int) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.MaxRequestSize = size @@ -366,6 +394,19 @@ func WithMaxRequestSize(size int) GenericOption { }) } +// WithMaxResponseSize configures the maximum size, in bytes, of an OTLP/HTTP +// response body, after decompression. +func WithMaxResponseSize(size int64) HTTPOption { + return NewHTTPOption(func(cfg Config) Config { + if size > 0 { + cfg.Traces.MaxResponseSize = size + } + return cfg + }) +} + +// WithProxy configures the proxy function used by the exporter's HTTP +// client. func WithProxy(pf HTTPTransportProxyFunc) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.Proxy = pf @@ -373,6 +414,7 @@ func WithProxy(pf HTTPTransportProxyFunc) GenericOption { }) } +// WithHTTPClient configures the HTTP client used to make requests. func WithHTTPClient(c *http.Client) GenericOption { return newGenericOption(func(cfg Config) Config { cfg.Traces.HTTPClient = c @@ -380,6 +422,7 @@ func WithHTTPClient(c *http.Client) GenericOption { }) } +// WithProtocol configures the protocol used to encode and send telemetry. func WithProtocol(protocol Protocol) GenericOption { return newSplitOption( // For OTLP/HTTP endpoints, this is the encoding format of the payloads sent to the collector. diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpjson/export_trace_service_request.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpjson/export_trace_service_request.go index 9e7756f61..02dddf821 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpjson/export_trace_service_request.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpjson/export_trace_service_request.go @@ -486,6 +486,7 @@ func decodeAnyValue(jav *AnyValue) *commonpb.AnyValue { // Float64 encodes non-finite values as strings per ProtoJSON specs. type Float64 float64 +// MarshalJSON implements the [json.Marshaler] interface. func (f Float64) MarshalJSON() ([]byte, error) { switch value := float64(f); { case math.IsNaN(value): @@ -499,6 +500,7 @@ func (f Float64) MarshalJSON() ([]byte, error) { } } +// UnmarshalJSON implements the [json.Unmarshaler] interface. func (f *Float64) UnmarshalJSON(data []byte) error { var str string if err := json.Unmarshal(data, &str); err == nil { @@ -530,10 +532,12 @@ func (f *Float64) UnmarshalJSON(data []byte) error { // Int64 encodes int64 as a quoted decimal string per ProtoJSON specs. type Int64 int64 +// MarshalJSON implements the [json.Marshaler] interface. func (i Int64) MarshalJSON() ([]byte, error) { return []byte(`"` + strconv.FormatInt(int64(i), 10) + `"`), nil } +// UnmarshalJSON implements the [json.Unmarshaler] interface. func (i *Int64) UnmarshalJSON(data []byte) error { // expects either a string representation or a number var s string @@ -556,10 +560,12 @@ func (i *Int64) UnmarshalJSON(data []byte) error { // Uint64 encodes uint64 as a quoted decimal string per ProtoJSON specs. type Uint64 uint64 +// MarshalJSON implements the [json.Marshaler] interface. func (i Uint64) MarshalJSON() ([]byte, error) { return []byte(`"` + strconv.FormatUint(uint64(i), 10) + `"`), nil } +// UnmarshalJSON implements the [json.Unmarshaler] interface. func (i *Uint64) UnmarshalJSON(data []byte) error { // expects either a string representation or a number var s string @@ -584,6 +590,7 @@ const base16Alphabets = "0123456789ABCDEF" // TraceID encodes a 16-byte trace ID as a case-insensitive hex-encoded string. type TraceID [16]byte +// MarshalJSON implements the [json.Marshaler] interface. func (t TraceID) MarshalJSON() ([]byte, error) { var b [34]byte b[0] = '"' @@ -595,6 +602,7 @@ func (t TraceID) MarshalJSON() ([]byte, error) { return b[:], nil } +// UnmarshalJSON implements the [json.Unmarshaler] interface. func (t *TraceID) UnmarshalJSON(data []byte) error { var str string if err := json.Unmarshal(data, &str); err != nil { @@ -614,6 +622,7 @@ func (t *TraceID) UnmarshalJSON(data []byte) error { // SpanID encodes an 8-byte span ID as a case-insensitive hex-encoded string. type SpanID [8]byte +// MarshalJSON implements the [json.Marshaler] interface. func (s SpanID) MarshalJSON() ([]byte, error) { var b [18]byte b[0] = '"' @@ -625,6 +634,7 @@ func (s SpanID) MarshalJSON() ([]byte, error) { return b[:], nil } +// UnmarshalJSON implements the [json.Unmarshaler] interface. func (s *SpanID) UnmarshalJSON(data []byte) error { var str string if err := json.Unmarshal(data, &str); err != nil { diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/response.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/response.go new file mode 100644 index 000000000..0b48bf14b --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/response.go @@ -0,0 +1,31 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// DO NOT MODIFY. Generated by gotmpl. +// source: internal/shared/otlp/response.go.tmpl + +package internal + +import ( + "errors" + "fmt" + "io" +) + +// CopyResponseBody copies at most maxSize bytes from src to dst. It returns +// an error if src contains more than maxSize bytes. +func CopyResponseBody(dst io.Writer, src io.Reader, maxSize int64) error { + if _, err := io.Copy(dst, io.LimitReader(src, maxSize)); err != nil { + return err + } + + var extra [1]byte + _, err := io.ReadFull(src, extra[:]) + if err == nil { + return fmt.Errorf("response body too large: exceeded %d bytes", maxSize) + } + if errors.Is(err, io.EOF) { + return nil + } + return err +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/version.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/version.go index 87fcc4c6e..0149ae744 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/version.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/version.go @@ -5,4 +5,4 @@ package internal // Version is the current release version of the OpenTelemetry OTLP HTTP trace // exporter in use. -const Version = "1.46.0" +const Version = "1.47.0" diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/options.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/options.go index b17ac12e1..5b0d7a28b 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/options.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/options.go @@ -172,6 +172,15 @@ func WithMaxRequestSize(size int) Option { return wrappedOption{otlpconfig.WithMaxRequestSize(size)} } +// WithMaxResponseSize sets the maximum size, in bytes, of an OTLP/HTTP +// response body, after decompression, that the exporter will read. +// +// By default, a limit of 4 MiB is used. Values less than or equal to zero are +// ignored. The response-size limit cannot be disabled. +func WithMaxResponseSize(size int64) Option { + return wrappedOption{otlpconfig.WithMaxResponseSize(size)} +} + // WithRetry configures the retry policy for transient errors that may occurs // when exporting traces. An exponential back-off algorithm is used to ensure // endpoints are not overwhelmed with retries. If unset, the default retry diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/version.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/version.go index fd8ee8102..78e4f8e61 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/version.go +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/version.go @@ -5,5 +5,5 @@ package otlptrace // Version is the current release version of the OpenTelemetry OTLP trace exporter in use. func Version() string { - return "1.46.0" + return "1.47.0" } diff --git a/vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go b/vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go index 40ea38066..0cac2fdce 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go +++ b/vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go @@ -16,7 +16,6 @@ import ( "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/prometheus/otlptranslator" - "google.golang.org/protobuf/proto" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -409,12 +408,13 @@ func addExponentialHistogramMetric[N int64 | float64]( scale := dp.Scale if scale < -4 { // Reject scales below -4 as they cannot be represented in Prometheus + scaleErr := fmt.Errorf("%w: %d (min -4)", errEHScaleBelowMin, scale) reportError( ch, desc, - fmt.Errorf("%w: %d (min -4)", errEHScaleBelowMin, scale), + scaleErr, ) - err = errors.Join(err, e) + err = errors.Join(err, scaleErr) continue } @@ -796,8 +796,8 @@ func (c *collector) validateMetrics(name, description string, metricType *dto.Me if !exist { c.metricFamilies[name] = &dto.MetricFamily{ - Name: proto.String(name), - Help: proto.String(description), + Name: new(name), + Help: new(description), Type: metricType, } return false, "" diff --git a/vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/observ/instrumentation.go b/vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/observ/instrumentation.go index 101c8db26..f85228d1b 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/observ/instrumentation.go +++ b/vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/observ/instrumentation.go @@ -76,10 +76,13 @@ func put[T any](p *sync.Pool, s *[]T) { p.Put(s) } +// ComponentName returns the component name for the exporter with the +// provided ID. func ComponentName(id int64) string { return fmt.Sprintf("%s/%d", ComponentType, id) } +// Instrumentation is experimental instrumentation for the exporter. type Instrumentation struct { inflightMetric metric.Int64UpDownCounter exportedMetric metric.Int64Counter @@ -90,6 +93,10 @@ type Instrumentation struct { setOpt metric.MeasurementOption } +// NewInstrumentation returns instrumentation for the exporter identified by +// id. +// +// If the experimental observability is disabled, nil is returned. func NewInstrumentation(id int64) (*Instrumentation, error) { if !x.Observability.Enabled() { return nil, nil diff --git a/vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/version.go b/vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/version.go index 049cdfece..c0c2da52e 100644 --- a/vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/version.go +++ b/vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/version.go @@ -6,4 +6,4 @@ package internal // Version is the current release version of the OpenTelemetry prometheus // exporter in use. -const Version = "0.68.0" +const Version = "0.69.0" diff --git a/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go b/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go index cbeb14fcd..d682f8c81 100644 --- a/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go +++ b/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go @@ -16,12 +16,35 @@ package baggage // but OpenTelemetry does not, therefore, this is represented as a map. type List map[string]Item -// Item is the value and metadata properties part of a list-member. +// Item is the value and metadata or properties part of a list-member. +// Metadata and properties are mutually exclusive representations. type Item struct { - Value string - Properties []Property + value string + metadata string + properties []Property } +// NewItemWithMetadata returns an Item with opaque W3C metadata. +func NewItemWithMetadata(value, metadata string) Item { + return Item{value: value, metadata: metadata} +} + +// NewItemWithProperties returns an Item with materialized properties. +func NewItemWithProperties(value string, properties []Property) Item { + return Item{value: value, properties: properties} +} + +// Value returns the value of i. +func (i Item) Value() string { return i.value } + +// Metadata returns the opaque W3C metadata of i. It is empty for an Item +// created with properties. +func (i Item) Metadata() string { return i.metadata } + +// Properties returns the materialized properties of i. It is nil for an Item +// created with metadata. +func (i Item) Properties() []Property { return i.properties } + // Property is a metadata entry for a list-member. type Property struct { Key, Value string diff --git a/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go b/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go index de294461c..1234ead63 100644 --- a/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go +++ b/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go @@ -21,6 +21,9 @@ type ErrorHandler interface { Handle(error) } +// ErrDelegator is an ErrorHandler that forwards errors to a delegate +// ErrorHandler set with setDelegate. Before a delegate is set, it logs +// errors to STDERR. type ErrDelegator struct { delegate atomic.Pointer[ErrorHandler] } @@ -28,6 +31,8 @@ type ErrDelegator struct { // Compile-time check that delegator implements ErrorHandler. var _ ErrorHandler = (*ErrDelegator)(nil) +// Handle handles err by forwarding it to the configured delegate, or +// logging it to STDERR if no delegate is set. func (d *ErrDelegator) Handle(err error) { if eh := d.delegate.Load(); eh != nil { (*eh).Handle(err) diff --git a/vendor/go.opentelemetry.io/otel/internal/global/logger.go b/vendor/go.opentelemetry.io/otel/internal/global/logger.go new file mode 100644 index 000000000..e4328daa9 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/internal/global/logger.go @@ -0,0 +1,96 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package global + +import ( + "context" + "sync" + "sync/atomic" + + "go.opentelemetry.io/otel/log" + "go.opentelemetry.io/otel/log/embedded" +) + +type loggerProvider struct { + embedded.LoggerProvider + + mu sync.Mutex + loggers map[il]*logger + delegate log.LoggerProvider +} + +// This is a compile-time guarantee that loggerProvider implements LoggerProvider. +var _ log.LoggerProvider = (*loggerProvider)(nil) + +func (p *loggerProvider) Logger(name string, options ...log.LoggerOption) log.Logger { + p.mu.Lock() + defer p.mu.Unlock() + + if p.delegate != nil { + return p.delegate.Logger(name, options...) + } + + cfg := log.NewLoggerConfig(options...) + key := il{ + name: name, + version: cfg.InstrumentationVersion(), + schema: cfg.SchemaURL(), + attrs: cfg.InstrumentationAttributes(), + } + + if p.loggers == nil { + l := &logger{name: name, options: options} + p.loggers = map[il]*logger{key: l} + return l + } + + if l, ok := p.loggers[key]; ok { + return l + } + + l := &logger{name: name, options: options} + p.loggers[key] = l + return l +} + +func (p *loggerProvider) setDelegate(provider log.LoggerProvider) { + p.mu.Lock() + defer p.mu.Unlock() + + p.delegate = provider + for _, l := range p.loggers { + l.setDelegate(provider) + } + p.loggers = nil // Only set logger delegates once. +} + +type logger struct { + embedded.Logger + + name string + options []log.LoggerOption + + delegate atomic.Value // log.Logger +} + +// This is a compile-time guarantee that logger implements Logger. +var _ log.Logger = (*logger)(nil) + +func (l *logger) Emit(ctx context.Context, r log.Record) { + if del, ok := l.delegate.Load().(log.Logger); ok { + del.Emit(ctx, r) + } +} + +func (l *logger) Enabled(ctx context.Context, param log.EnabledParameters) bool { + var enabled bool + if del, ok := l.delegate.Load().(log.Logger); ok { + enabled = del.Enabled(ctx, param) + } + return enabled +} + +func (l *logger) setDelegate(provider log.LoggerProvider) { + l.delegate.Store(provider.Logger(l.name, l.options...)) +} diff --git a/vendor/go.opentelemetry.io/otel/internal/global/state.go b/vendor/go.opentelemetry.io/otel/internal/global/state.go index f8fcb82bc..bd388d834 100644 --- a/vendor/go.opentelemetry.io/otel/internal/global/state.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/state.go @@ -9,6 +9,7 @@ import ( "sync/atomic" "go.opentelemetry.io/otel/internal/errorhandler" + "go.opentelemetry.io/otel/log" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" @@ -26,16 +27,22 @@ type ( meterProviderHolder struct { mp metric.MeterProvider } + + loggerProviderHolder struct { + provider log.LoggerProvider + } ) var ( - globalTracer = defaultTracerValue() - globalPropagators = defaultPropagatorsValue() - globalMeterProvider = defaultMeterProvider() + globalTracer = defaultTracerValue() + globalPropagators = defaultPropagatorsValue() + globalMeterProvider = defaultMeterProvider() + globalLoggerProvider = defaultLoggerProvider() delegateTraceOnce sync.Once delegateTextMapPropagatorOnce sync.Once delegateMeterOnce sync.Once + delegateLoggerOnce sync.Once ) // GetErrorHandler returns the global ErrorHandler instance. @@ -150,6 +157,32 @@ func SetMeterProvider(mp metric.MeterProvider) { globalMeterProvider.Store(meterProviderHolder{mp: mp}) } +// LoggerProvider is the internal implementation for global.LoggerProvider. +func LoggerProvider() log.LoggerProvider { + return globalLoggerProvider.Load().(loggerProviderHolder).provider +} + +// SetLoggerProvider is the internal implementation for global.SetLoggerProvider. +func SetLoggerProvider(provider log.LoggerProvider) { + current := LoggerProvider() + if _, cOk := current.(*loggerProvider); cOk { + if _, lpOk := provider.(*loggerProvider); lpOk && current == provider { + Error( + errors.New("no delegate configured in logger provider"), + "Setting logger provider to its current value. No delegate will be configured", + ) + return + } + } + + delegateLoggerOnce.Do(func() { + if def, ok := current.(*loggerProvider); ok { + def.setDelegate(provider) + } + }) + globalLoggerProvider.Store(loggerProviderHolder{provider: provider}) +} + func defaultTracerValue() *atomic.Value { v := &atomic.Value{} v.Store(tracerProviderHolder{tp: &tracerProvider{}}) @@ -167,3 +200,9 @@ func defaultMeterProvider() *atomic.Value { v.Store(meterProviderHolder{mp: &meterProvider{}}) return v } + +func defaultLoggerProvider() *atomic.Value { + v := &atomic.Value{} + v.Store(loggerProviderHolder{provider: &loggerProvider{}}) + return v +} diff --git a/vendor/go.opentelemetry.io/otel/log.go b/vendor/go.opentelemetry.io/otel/log.go new file mode 100644 index 000000000..1758913fa --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log.go @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package otel + +import ( + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/log" +) + +// Logger returns a [log.Logger] configured with the provided name and options +// from the globally configured [log.LoggerProvider]. +// +// If this is called before a global LoggerProvider is configured, the returned +// Logger will be a No-Op implementation of a Logger. When a global +// LoggerProvider is registered for the first time, the returned Logger is +// updated in place to report to this new LoggerProvider. There is no need to +// call this function again for an updated instance. +// +// This is a convenience function. It is equivalent to: +// +// GetLoggerProvider().Logger(name, options...) +func Logger(name string, options ...log.LoggerOption) log.Logger { + return GetLoggerProvider().Logger(name, options...) +} + +// GetLoggerProvider returns the globally configured [log.LoggerProvider]. +// +// If a global LoggerProvider has not been configured with [SetLoggerProvider], +// the returned LoggerProvider will be a No-Op implementation. When +// a global LoggerProvider is registered for the first time, the returned +// LoggerProvider and all Loggers it has created are updated in place. There is +// no need to call this function again for an updated instance. +func GetLoggerProvider() log.LoggerProvider { + return global.LoggerProvider() +} + +// SetLoggerProvider configures provider as the global [log.LoggerProvider]. +func SetLoggerProvider(provider log.LoggerProvider) { + global.SetLoggerProvider(provider) +} diff --git a/vendor/go.opentelemetry.io/otel/log/DESIGN.md b/vendor/go.opentelemetry.io/otel/log/DESIGN.md new file mode 100644 index 000000000..d36c96773 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/DESIGN.md @@ -0,0 +1,566 @@ +# Logs API + +## Abstract + +`go.opentelemetry.io/otel/log` provides +[Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/). + +The prototype was created in +[#4725](https://github.com/open-telemetry/opentelemetry-go/pull/4725). + +## Background + +The key challenge is to create a performant API compliant with the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/) +with an intuitive and user friendly design. +Performance is seen as one of the most important characteristics of logging libraries in Go. + +## Design + +This proposed design aims to: + +- be specification compliant, +- be similar to Trace and Metrics API, +- take advantage of both OpenTelemetry and `slog` experience to achieve acceptable performance. + +### Module structure + +The API is published as a single `go.opentelemetry.io/otel/log` Go module. + +The package structure is similar to Trace API and Metrics API. +The Go module consists of the following packages: + +- `go.opentelemetry.io/otel/log` +- `go.opentelemetry.io/otel/log/embedded` +- `go.opentelemetry.io/otel/log/logtest` +- `go.opentelemetry.io/otel/log/noop` + +Rejected alternative: + +- [Reuse slog](#reuse-slog) + +### LoggerProvider + +The [`LoggerProvider` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#loggerprovider) +is defined as `LoggerProvider` interface in [provider.go](provider.go). + +The specification may add new operations to `LoggerProvider`. +The interface may have methods added without a package major version bump. +This embeds `embedded.LoggerProvider` to help inform an API implementation +author about this non-standard API evolution. +This approach is already used in Trace API and Metrics API. + +#### LoggerProvider.Logger + +The `Logger` method implements the [`Get a Logger` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#get-a-logger). + +The required `name` parameter is accepted as a `string` method argument. + +The `LoggerOption` options are defined to support optional parameters. + +Implementation requirements: + +- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements) + the method to be safe to be called concurrently. + +- If the passed name is empty, this should be reported as invalid as specified + by the [Logs SDK specification](https://opentelemetry.io/docs/specs/otel/logs/sdk/#logger-creation). + The method should still use it as the instrumentation scope name and return + a working logger. + +`Logger` can be extended by adding new `LoggerOption` options +and adding new exported fields to the `LoggerConfig` struct. +This design is already used in Trace API for getting tracers +and in Metrics API for getting meters. + +Rejected alternative: + +- [Passing struct as parameter to LoggerProvider.Logger](#passing-struct-as-parameter-to-loggerproviderlogger). + +### Logger + +The [`Logger` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#logger) +is defined as `Logger` interface in [logger.go](logger.go). + +The specification may add new operations to `Logger`. +The interface may have methods added without a package major version bump. +This embeds `embedded.Logger` to help inform an API implementation +author about this non-standard API evolution. +This approach is already used in Trace API and Metrics API. + +### Logger.Emit + +The `Emit` method implements the [`Emit a LogRecord` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord). + +[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/) +is accepted as a `context.Context` method argument. + +Calls to `Emit` are supposed to be on the hot path. +Therefore, in order to reduce the number of heap allocations, +the [`LogRecord` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord), +is defined as `Record` struct in [record.go](record.go). + +[`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp) +is accessed using following methods: + +```go +func (r *Record) Timestamp() time.Time +func (r *Record) SetTimestamp(t time.Time) +``` + +[`ObservedTimestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-observedtimestamp) +is accessed using following methods: + +```go +func (r *Record) ObservedTimestamp() time.Time +func (r *Record) SetObservedTimestamp(t time.Time) +``` + +[`EventName`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-eventname) +is accessed using following methods: + +```go +func (r *Record) EventName() string +func (r *Record) SetEventName(s string) +``` + +[`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber) +is accessed using following methods: + +```go +func (r *Record) Severity() Severity +func (r *Record) SetSeverity(s Severity) +``` + +`Severity` type is defined in [severity.go](severity.go). +The constants are are based on +[Displaying Severity recommendation](https://opentelemetry.io/docs/specs/otel/logs/data-model/#displaying-severity). +Additionally, `Severity[Level]` constants are defined to make the API more readable and user friendly. + +[`SeverityText`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext) +is accessed using following methods: + +```go +func (r *Record) SeverityText() string +func (r *Record) SetSeverityText(s string) +``` + +[`Body`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body) +is accessed using following methods: + +```go +func (r *Record) Body() attribute.Value +func (r *Record) SetBody(v attribute.Value) +``` + +[Log record attributes](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes) +are accessed using following methods: + +```go +func (r *Record) WalkAttributes(f func(attribute.KeyValue) bool) +func (r *Record) AddAttributes(attrs ...attribute.KeyValue) +``` + +`Record` has a `AttributesLen` method that returns +the number of attributes to allow slice preallocation +when converting records to a different representation: + +```go +func (r *Record) AttributesLen() int +``` + +The records attributes design and implementation is based on +[`slog.Record`](https://pkg.go.dev/log/slog#Record). +It allows achieving high-performance access and manipulation of the attributes +while keeping the API user friendly. +It relieves the user from making his own improvements +for reducing the number of allocations when passing attributes. + +Log body and attributes use the common +[`attribute.Value`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#Value) +and +[`attribute.KeyValue`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#KeyValue) +types. +These types cover the Logs Data Model `any` value shape, including empty +values, byte slices, generic slices, and maps. +Reusing the attribute package keeps the API consistent across signals and +avoids maintaining a second value model with conversion helpers. + +The zero value of `attribute.Value` represents an empty body. +Log maps use `attribute.MAP`, which may contain duplicate keys when callers +construct one that way. Duplicate-key normalization is an SDK policy, not an +API behavior. + +The caller must not subsequently mutate the record passed to `Emit`. +This would allow the implementation to not clone the record, +but simply retain, modify or discard it. +The implementation may still choose to clone the record or copy its attributes +if it needs to retain or modify it, +e.g. in case of asynchronous processing to eliminate the possibility of data races, +because the user can technically reuse the record and add new attributes +after the call (even when the documentation says that the caller must not do it). + +Implementation requirements: + +- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements) + the method to be safe to be called concurrently. + +- The method must not interrupt the record processing if the context is canceled + per ["ignoring context cancellation" guideline](../CONTRIBUTING.md#ignoring-context-cancellation). + +- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord) + use the current time as observed timestamp if the passed is empty. + +- The method should handle the trace context passed via `ctx` argument in order to meet the + [specification's SDK requirement](https://opentelemetry.io/docs/specs/otel/logs/sdk/#readablelogrecord) + to populate the trace context fields from the resolved context. + +`Emit` can be extended by adding new exported fields to the `Record` struct. + +Rejected alternatives: + +- [Record as interface](#record-as-interface) +- [Options as parameter to Logger.Emit](#options-as-parameter-to-loggeremit) +- [Passing record as pointer to Logger.Emit](#passing-record-as-pointer-to-loggeremit) +- [Logger.WithAttributes](#loggerwithattributes) +- [Record attributes as slice](#record-attributes-as-slice) +- [Use any instead of attribute.Value](#use-any-instead-of-attributevalue) +- [Severity type encapsulating number and text](#severity-type-encapsulating-number-and-text) +- [Define log-specific value types](#define-log-specific-value-types) +- [Mix receiver types for Record](#mix-receiver-types-for-record) +- [Add XYZ method to Logger](#add-xyz-method-to-logger) + +### Logger.Enabled + +The `Enabled` method implements the [`Enabled` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#enabled). + +[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/) +is accepted as a `context.Context` method argument. + +Calls to `Enabled` are supposed to be on the hot path and the list of arguments +can be extendend in future. Therefore, in order to reduce the number of heap +allocations and make it possible to handle new arguments, `Enabled` accepts +a `EnabledParameters` struct, defined in [logger.go](logger.go), as the second +method argument. + +The `EnabledParameters` uses fields, instead of getters and setters, to allow +simpler usage which allows configuring the `EnabledParameters` in the same line +where `Enabled` is called. + +### noop package + +The `go.opentelemetry.io/otel/log/noop` package provides +[Logs API No-Op Implementation](https://opentelemetry.io/docs/specs/otel/logs/noop/). + +### Trace context correlation + +The bridge implementation should do its best to pass +the `ctx` containing the trace context from the caller +so it can later be passed via `Logger.Emit`. + +It is not expected that users (caller or bridge implementation) reconstruct +a `context.Context`. Reconstructing a `context.Context` with +[`trace.ContextWithSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#ContextWithSpanContext) +and [`trace.NewSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#NewSpanContext) +would usually involve more memory allocations. + +The logging libraries which have recording methods that accepts `context.Context`, +such us [`slog`](https://pkg.go.dev/log/slog), +[`logrus`](https://pkg.go.dev/github.com/sirupsen/logrus), +[`zerolog`](https://pkg.go.dev/github.com/rs/zerolog), +makes passing the trace context trivial. + +However, some libraries do not accept a `context.Context` in their recording methods. +Structured logging libraries, +such as [`logr`](https://pkg.go.dev/github.com/go-logr/logr) +and [`zap`](https://pkg.go.dev/go.uber.org/zap), +offer passing `any` type as a log attribute/field. +Therefore, their bridge implementations can define a "special" log attributes/field +that will be used to capture the trace context. + +[The prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725) +has bridge implementations that handle trace context correlation efficiently. + +## Benchmarking + +The benchmarks take inspiration from [`slog`](https://pkg.go.dev/log/slog), +because for the Go team it was also critical to create API that would be fast +and interoperable with existing logging packages.[^2][^3] + +The benchmark results can be found in [the prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725). + +## Rejected alternatives + +### Reuse slog + +The API must not be coupled to [`slog`](https://pkg.go.dev/log/slog), +nor any other logging library. + +The API needs to evolve orthogonally to `slog`. + +`slog` is not compliant with the [Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/). +and we cannot expect the Go team to make `slog` compliant with it. + +The interoperability can be achieved using [a log bridge](https://opentelemetry.io/docs/specs/otel/glossary/#log-appender--bridge). + +You can read more about OpenTelemetry Logs design on [opentelemetry.io](https://opentelemetry.io/docs/concepts/signals/logs/). + +### Record as interface + +`Record` is defined as a `struct` because of the following reasons. + +Log record is a value object without any behavior. +It is used as data input for Logger methods. + +The log record resembles the instrument config structs like [metric.Float64CounterConfig](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Float64CounterConfig). + +Using `struct` instead of `interface` improves the performance as e.g. +indirect calls are less optimized, +usage of interfaces tend to increase heap allocations.[^3] + +### Options as parameter to Logger.Emit + +One of the initial ideas was to have: + +```go +type Logger interface{ + embedded.Logger + Emit(ctx context.Context, options ...RecordOption) +} +``` + +The main reason was that design would be similar +to the [Meter API](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Meter) +for creating instruments. + +However, passing `Record` directly, instead of using options, +is more performant as it reduces heap allocations.[^4] + +Another advantage of passing `Record` is that API would not have functions like `NewRecord(options...)`, +which would be used by the SDK and not by the users. + +Finally, the definition would be similar to [`slog.Handler.Handle`](https://pkg.go.dev/log/slog#Handler) +that was designed to provide optimization opportunities.[^2] + +### Passing record as pointer to Logger.Emit + +So far the benchmarks do not show differences that would +favor passing the record via pointer (and vice versa). + +Passing via value feels safer because of the following reasons. + +The user would not be able to pass `nil`. +Therefore, it reduces the possibility to have a nil pointer dereference. + +It should reduce the possibility of a heap allocation. + +It follows the design of [`slog.Handler`](https://pkg.go.dev/log/slog#Handler). + +If follows one of Google's Go Style Decisions +to prefer [passing values](https://google.github.io/styleguide/go/decisions#pass-values). + +### Passing struct as parameter to LoggerProvider.Logger + +Similarly to `Logger.Emit`, we could have something like: + +```go +type LoggerProvider interface{ + embedded.LoggerProvider + Logger(name string, config LoggerConfig) +} +``` + +The drawback of this idea would be that this would be +a different design from Trace and Metrics API. + +The performance of acquiring a logger is not as critical +as the performance of emitting a log record. While a single +HTTP/RPC handler could write hundreds of logs, it should not +create a new logger for each log entry. +The bridge implementation should reuse loggers whenever possible. + +### Logger.WithAttributes + +We could add `WithAttributes` to the `Logger` interface. +Then `Record` could be a simple struct with only exported fields. +The idea was that the SDK would implement the performance improvements +instead of doing it in the API. +This would allow having different optimization strategies. + +During the analysis[^5], it occurred that the main problem of this proposal +is that the variadic slice passed to an interface method is always heap allocated. + +Moreover, the logger returned by `WithAttribute` was allocated on the heap. + +Lastly, the proposal was not specification compliant. + +### Record attributes as slice + +One of the proposals[^6] was to have `Record` as a simple struct: + +```go +type Record struct { + Timestamp time.Time + ObservedTimestamp time.Time + EventName string + Severity Severity + SeverityText string + Body Value + Attributes []KeyValue +} +``` + +The bridge implementations could use [`sync.Pool`](https://pkg.go.dev/sync#Pool) +for reducing the number of allocations when passing attributes. + +The benchmarks results were better. + +In such a design, most bridges would have a `sync.Pool` +to reduce the number of heap allocations. +However, the `sync.Pool` will not work correctly with API implementations +that would take ownership of the record +(e.g. implementations that do not copy records for asynchronous processing). +The current design, even in case of improper API implementation, +has lower chances of encountering a bug as most bridges would +create a record, pass it, and forget about it. + +For reference, here is the reason why `slog` does not use `sync.Pool`[^3] +as well: + +> We can use a sync pool for records though we decided not to. +You can but it's a bad idea for us. Why? +Because users have control of Records. +Handler writers can get their hands on a record +and we'd have to ask them to free it +or try to free it magically at some some point. +But either way, they could get themselves in trouble by freeing it twice +or holding on to one after they free it. +That's a use after free bug and that's why `zerolog` was problematic for us. +`zerolog` as as part of its speed exposes a pool allocated value to users +if you use `zerolog` the normal way, that you'll see in all the examples, +you will never encounter a problem. +But if you do something a little out of the ordinary you can get +use after free bugs and we just didn't want to put that in the standard library. + +Therefore, we decided to not follow the proposal as it is +less user friendly (users and bridges would use e.g. a `sync.Pool` to reduce +the number of heap allocation), less safe (more prone to use after free bugs +and race conditions), and the benchmark differences were not significant. + +### Use any instead of attribute.Value + +[Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body) +defines Body to be `any`. +One could propose to define `Body` (and attribute values) as `any` +instead of using `attribute.Value`. + +First of all, [`any` type defined in the specification](https://opentelemetry.io/docs/specs/otel/logs/data-model/#type-any) +is not the same as `any` (`interface{}`) in Go. + +Moreover, using `any` as a field would decrease the performance.[^7] + +Using `attribute.Value` preserves a typed, allocation-conscious representation +of the Logs Data Model `any` values while avoiding unconstrained `interface{}` +handling in bridge implementations. + +### Severity type encapsulating number and text + +We could combine severity into a single field defining a type: + +```go +type Severity struct { + Number SeverityNumber + Text string +} +``` + +However, the [Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#log-and-event-record-definition) +define it as independent fields. +It should be more user friendly to have them separated. +Especially when having getter and setter methods, setting one value +when the other is already set would be unpleasant. + +### Define log-specific value types + +The original design defined `Kind`, `Value`, and `KeyValue` in +`go.opentelemetry.io/otel/log`. +That avoided coupling log bodies to the common attribute package while logs were +still exploring structured value support. + +The Logs Data Model and common attribute value model now share the structured +`any` shapes needed by Go: empty, bool, int64, float64, string, byte slice, +homogeneous slices, generic slices, and maps. +The specification direction is to reuse these value shapes across signals. +Keeping log-specific types would duplicate API surface, require conversion +helpers, and make bridge code choose between two equivalent value models. + +Therefore log records now use `attribute.Value` for body values and +`attribute.KeyValue` for attributes and map entries. + +### Mix receiver types for Record + +Methods of [`slog.Record`](https://pkg.go.dev/log/slog#Record) +have different receiver types. + +In `log/slog` GitHub issue we can only find that the reason is:[^8] + +>> some receiver of Record struct is by value +> Passing Records by value means they incur no heap allocation. +> That improves performance overall, even though they are copied. + +However, the benchmarks do not show any noticeable differences.[^9] + +The compiler is smart-enough to not make a heap allocation for any of these methods. +The use of a pointer receiver does not cause any heap allocation. +From Go FAQ:[^10] + +> In the current compilers, if a variable has its address taken, +> that variable is a candidate for allocation on the heap. +> However, a basic escape analysis recognizes some cases +> when such variables will not live past the return from the function +> and can reside on the stack. + +The [Understanding Allocations: the Stack and the Heap](https://www.youtube.com/watch?v=ZMZpH4yT7M0) +presentation by Jacob Walker describes the escape analysis with details. + +Moreover, also from Go FAQ:[^10] + +> Also, if a local variable is very large, +> it might make more sense to store it on the heap rather than the stack. + +Therefore, even if we use a value receiver and the value is very large +it may be heap allocated. + +Both [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments#receiver-type) +and [Google's Go Style Decisions](https://google.github.io/styleguide/go/decisions#receiver-type) +highly recommend making the methods for a type either all pointer methods +or all value methods. Google's Go Style Decisions even goes further and says: + +> There is a lot of misinformation about whether passing a value or a pointer +> to a function can affect performance. +> The compiler can choose to pass pointers to values on the stack +> as well as copying values on the stack, +> but these considerations should not outweigh the readability +> and correctness of the code in most circumstances. +> When the performance does matter, it is important to profile both approaches +> with a realistic benchmark before deciding that one approach outperforms the other. + +Because, the benchmarks[^9] do not proof any performance difference +and the general recommendation is to not mix receiver types, +we decided to use pointer receivers for all `Record` methods. + +### Add XYZ method to Logger + +The `Logger` does not have methods like `SetSeverity`, etc. +as the Logs API needs to follow (be compliant with) +the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/) + +[^1]: [Handle structured body and attributes](https://github.com/pellared/opentelemetry-go/pull/7) +[^2]: Jonathan Amsterdam, [The Go Blog: Structured Logging with slog](https://go.dev/blog/slog) +[^3]: Jonathan Amsterdam, [GopherCon Europe 2023: A Fast Structured Logging Package](https://www.youtube.com/watch?v=tC4Jt3i62ns) +[^4]: [Emit definition discussion with benchmarks](https://github.com/open-telemetry/opentelemetry-go/pull/4725#discussion_r1400869566) +[^5]: [Logger.WithAttributes analysis](https://github.com/pellared/opentelemetry-go/pull/3) +[^6]: [Record attributes as field and use sync.Pool for reducing allocations](https://github.com/pellared/opentelemetry-go/pull/4) and [Record attributes based on slog.Record](https://github.com/pellared/opentelemetry-go/pull/6) +[^7]: [Record.Body as any](https://github.com/pellared/opentelemetry-go/pull/5) +[^8]: [log/slog: structured, leveled logging](https://github.com/golang/go/issues/56345#issuecomment-1302563756) +[^9]: [Record with pointer receivers only](https://github.com/pellared/opentelemetry-go/pull/8) +[^10]: [Go FAQ: Stack or heap](https://go.dev/doc/faq#stack_or_heap) diff --git a/vendor/go.opentelemetry.io/otel/log/LICENSE b/vendor/go.opentelemetry.io/otel/log/LICENSE new file mode 100644 index 000000000..f1aee0f11 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/LICENSE @@ -0,0 +1,231 @@ + 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. + +-------------------------------------------------------------------------------- + +Copyright 2009 The Go Authors. + +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 LLC 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. \ No newline at end of file diff --git a/vendor/go.opentelemetry.io/otel/log/README.md b/vendor/go.opentelemetry.io/otel/log/README.md new file mode 100644 index 000000000..3f7142711 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/README.md @@ -0,0 +1,3 @@ +# Log API + +[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/log)](https://pkg.go.dev/go.opentelemetry.io/otel/log) diff --git a/vendor/go.opentelemetry.io/otel/log/doc.go b/vendor/go.opentelemetry.io/otel/log/doc.go new file mode 100644 index 000000000..211de35f5 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/doc.go @@ -0,0 +1,85 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +/* +Package log provides the OpenTelemetry Logs API. + +This API is separate from its implementation, so the instrumentation built +from it is reusable. See [go.opentelemetry.io/otel/sdk/log] for the official +OpenTelemetry implementation of this API. + +The log package provides the OpenTelemetry Logs API, which serves as a standard +interface for generating and managing log records within the OpenTelemetry ecosystem. +This package allows users to emit LogRecords, enabling structured, context-rich logging +that can be easily integrated with observability tools. It ensures that log data is captured +in a way that is consistent with OpenTelemetry's data model. + +This package can be used to create bridges between existing logging libraries and OpenTelemetry. +Log bridges allow existing logging setups to be integrated with OpenTelemetry. +Log bridges can be found in the [registry]. + +# API Implementations + +This package does not conform to the standard Go versioning policy; all of its +interfaces may have methods added to them without a package major version bump. +This non-standard API evolution could surprise an uninformed implementation +author. They could unknowingly build their implementation in a way that would +result in a runtime panic for their users who update to the new API. + +The API is designed to help inform an instrumentation author about this +non-standard API evolution. It requires them to choose a default behavior for +unimplemented interface methods. There are three behavior choices they can +make: + + - Compilation failure + - Panic + - Default to another implementation + +All interfaces in this API embed a corresponding interface from +[go.opentelemetry.io/otel/log/embedded]. If an author wants the default +behavior of their implementations to be a compilation failure, signaling to +their users that they need to update to the latest version of that implementation, +they need to embed the corresponding interface from +[go.opentelemetry.io/otel/log/embedded] in their implementation. For example, + + import "go.opentelemetry.io/otel/log/embedded" + + type LoggerProvider struct { + embedded.LoggerProvider + // ... + } + +If an author wants the default behavior of their implementations to panic, +they need to embed the API interface directly. + + import "go.opentelemetry.io/otel/log" + + type LoggerProvider struct { + log.LoggerProvider + // ... + } + +This is not a recommended behavior as it could lead to publishing packages that +contain runtime panics when users update other packages that use newer versions +of [go.opentelemetry.io/otel/log]. + +Finally, an author can embed another implementation in theirs. The embedded +implementation will be used for methods not defined by the author. For example, +an author who wants to default to silently dropping the call can use +[go.opentelemetry.io/otel/log/noop]: + + import "go.opentelemetry.io/otel/log/noop" + + type LoggerProvider struct { + noop.LoggerProvider + // ... + } + +It is strongly recommended that authors only embed +go.opentelemetry.io/otel/log/noop if they choose this default behavior. That +implementation is the only one OpenTelemetry authors can guarantee will fully +implement all the API interfaces when a user updates their API. + +[registry]: https://opentelemetry.io/ecosystem/registry/?language=go&component=log-bridge +*/ +package log diff --git a/vendor/go.opentelemetry.io/otel/log/embedded/README.md b/vendor/go.opentelemetry.io/otel/log/embedded/README.md new file mode 100644 index 000000000..bae4ac68f --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/embedded/README.md @@ -0,0 +1,3 @@ +# Log Embedded + +[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/log/embedded)](https://pkg.go.dev/go.opentelemetry.io/otel/log/embedded) diff --git a/vendor/go.opentelemetry.io/otel/log/embedded/embedded.go b/vendor/go.opentelemetry.io/otel/log/embedded/embedded.go new file mode 100644 index 000000000..3b97fcddc --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/embedded/embedded.go @@ -0,0 +1,36 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Package embedded provides interfaces embedded within the [OpenTelemetry Logs +// Bridge API]. +// +// Implementers of the [OpenTelemetry Logs API] can embed the relevant +// type from this package into their implementation directly. Doing so will +// result in a compilation error for users when the [OpenTelemetry Logs Bridge +// API] is extended (which is something that can happen without a major version +// bump of the API package). +// +// [OpenTelemetry Logs API]: https://pkg.go.dev/go.opentelemetry.io/otel/log +package embedded + +// LoggerProvider is embedded in the [Logs API LoggerProvider]. +// +// Embed this interface in your implementation of the [Logs API +// LoggerProvider] if you want users to experience a compilation error when the +// [Logs Bridge API LoggerProvider] interface is extended (which is something +// that can happen without a major version bump of the API package). This error +// signals that they need to update to your latest implementation. +// +// [Logs API LoggerProvider]: https://pkg.go.dev/go.opentelemetry.io/otel/log#LoggerProvider +type LoggerProvider interface{ loggerProvider() } + +// Logger is embedded in the [Logs API Logger]. +// +// Embed this interface in your implementation of the [Logs API Logger] +// if you want users to experience a compilation error when the [Logs API +// Logger] interface is extended (which is something that can happen without a +// major version bump of the API package). This error signals that they need to +// update to your latest implementation. +// +// [Logs API Logger]: https://pkg.go.dev/go.opentelemetry.io/otel/log#Logger +type Logger interface{ logger() } diff --git a/vendor/go.opentelemetry.io/otel/log/logger.go b/vendor/go.opentelemetry.io/otel/log/logger.go new file mode 100644 index 000000000..c0e4ca7ae --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/logger.go @@ -0,0 +1,197 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package log + +import ( + "context" + "slices" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/log/embedded" +) + +// Logger emits log records. +// +// Warning: Methods may be added to this interface in minor releases. See +// package documentation on API implementation for information on how to set +// the default behavior for unimplemented methods. +type Logger interface { + // Users of the interface can ignore this. This embedded type is only used + // by implementations of this interface. See the "API Implementations" + // section of the package documentation for more information. + embedded.Logger + + // Emit emits a log record. + // + // The record may be held by the implementation. Callers should not mutate + // the record after it is passed. + // + // Implementations of this method need to be safe for a user to call + // concurrently. + Emit(ctx context.Context, record Record) + + // Enabled reports whether the Logger emits for the given context and + // param. + // + // Calling Enabled is optional. It is not required before calling + // [Logger.Emit]. + // + // Enabled is useful when constructing a [Record] is expensive. A caller can + // call Enabled first and skip record construction when it returns false. + // When constructing the Record is inexpensive, a caller can emit it + // directly. + // + // The returned value is not static and may change over time. A cached value + // can become stale. + // + // The passed param is likely to contain only partial information about a + // record (e.g., a param with only the Severity set). + // If a Logger needs more information than is provided, it + // is said to be in an indeterminate state (see below). + // + // The returned value is true if the Logger emits for the provided context + // and param, and false if the Logger does not emit. The returned value may be + // true or false in an indeterminate state. + // An implementation should default to returning true for an indeterminate + // state, but may return false if there are valid reasons to do so in + // particular circumstances (e.g., performance or correctness). + // + // The param should not be held by the implementation. A copy should be + // made if the param needs to be held after the call returns. + // + // Implementations of this method need to be safe for a user to call + // concurrently. + Enabled(ctx context.Context, param EnabledParameters) bool +} + +// LoggerOption applies configuration options to a [Logger]. +type LoggerOption interface { + // applyLogger applies a LoggerOption to a LoggerConfig. + applyLogger(LoggerConfig) LoggerConfig +} + +// LoggerConfig contains options for a [Logger]. +type LoggerConfig struct { + // Ensure forward compatibility by explicitly making this not comparable. + noCmp [0]func() //nolint: unused // This is indeed used. + + version string + schemaURL string + attrs attribute.Set +} + +type experimentalOption interface { + Experimental() +} + +// NewLoggerConfig returns a new [LoggerConfig] with all the options applied. +func NewLoggerConfig(options ...LoggerOption) LoggerConfig { + var c LoggerConfig + for _, opt := range options { + if _, ok := opt.(experimentalOption); ok { + continue + } + c = opt.applyLogger(c) + } + return c +} + +// InstrumentationVersion returns the version of the library providing +// instrumentation. +func (cfg LoggerConfig) InstrumentationVersion() string { + return cfg.version +} + +// InstrumentationAttributes returns the attributes associated with the library +// providing instrumentation. +func (cfg LoggerConfig) InstrumentationAttributes() attribute.Set { + return cfg.attrs +} + +// SchemaURL returns the schema URL of the library providing instrumentation. +func (cfg LoggerConfig) SchemaURL() string { + return cfg.schemaURL +} + +type loggerOptionFunc func(LoggerConfig) LoggerConfig + +func (fn loggerOptionFunc) applyLogger(cfg LoggerConfig) LoggerConfig { + return fn(cfg) +} + +// WithInstrumentationVersion returns a [LoggerOption] that sets the +// instrumentation version of a [Logger]. +func WithInstrumentationVersion(version string) LoggerOption { + return loggerOptionFunc(func(config LoggerConfig) LoggerConfig { + config.version = version + return config + }) +} + +// mergeSets returns the union of the keys in a and b. For duplicate keys, the +// value associated with b is used. +func mergeSets(a, b attribute.Set) attribute.Set { + // NewMergeIterator uses the first value for any duplicates. + iter := attribute.NewMergeIterator(&b, &a) + merged := make([]attribute.KeyValue, 0, a.Len()+b.Len()) + for iter.Next() { + merged = append(merged, iter.Attribute()) + } + return attribute.NewSet(merged...) +} + +// WithInstrumentationAttributes returns a [LoggerOption] that sets the +// instrumentation attributes of a [Logger]. +// +// This is equivalent to calling WithInstrumentationAttributeSet with an +// [attribute.Set] created from a clone of the passed attributes. +// [WithInstrumentationAttributeSet] is recommended for more control. +// +// If multiple [WithInstrumentationAttributes] or [WithInstrumentationAttributeSet] +// options are passed, the attributes will be merged together in the order +// they are passed. For attributes with duplicate keys, the last value passed +// will be used. +func WithInstrumentationAttributes(attr ...attribute.KeyValue) LoggerOption { + set := attribute.NewSet(slices.Clone(attr)...) + return WithInstrumentationAttributeSet(set) +} + +// WithInstrumentationAttributeSet returns a [LoggerOption] that adds +// instrumentation attributes to a [Logger]. +// +// If multiple [WithInstrumentationAttributes] or [WithInstrumentationAttributeSet] +// options are passed, the attributes will be merged together in the order +// they are passed. For attributes with duplicate keys, the last value passed +// will be used. +func WithInstrumentationAttributeSet(set attribute.Set) LoggerOption { + if set.Len() == 0 { + return loggerOptionFunc(func(config LoggerConfig) LoggerConfig { + return config + }) + } + + return loggerOptionFunc(func(config LoggerConfig) LoggerConfig { + if config.attrs.Len() == 0 { + config.attrs = set + } else { + config.attrs = mergeSets(config.attrs, set) + } + return config + }) +} + +// WithSchemaURL returns a [LoggerOption] that sets the schema URL for a +// [Logger]. +func WithSchemaURL(schemaURL string) LoggerOption { + return loggerOptionFunc(func(config LoggerConfig) LoggerConfig { + config.schemaURL = schemaURL + return config + }) +} + +// EnabledParameters represents the payload for [Logger.Enabled]. +type EnabledParameters struct { + Severity Severity + EventName string +} diff --git a/vendor/go.opentelemetry.io/otel/log/provider.go b/vendor/go.opentelemetry.io/otel/log/provider.go new file mode 100644 index 000000000..10969b415 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/provider.go @@ -0,0 +1,38 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package log + +import "go.opentelemetry.io/otel/log/embedded" + +// LoggerProvider provides access to [Logger]. +// +// Warning: Methods may be added to this interface in minor releases. See +// package documentation on API implementation for information on how to set +// the default behavior for unimplemented methods. +type LoggerProvider interface { + // Users of the interface can ignore this. This embedded type is only used + // by implementations of this interface. See the "API Implementations" + // section of the package documentation for more information. + embedded.LoggerProvider + + // Logger returns a new [Logger] with the provided name and configuration. + // + // The name needs to uniquely identify the source of logged code. It is + // recommended that name be the Go package name of the library using a log + // bridge (note: this is not the name of the bridge package). Most + // commonly, this means a bridge will need to accept this value from its + // users. + // + // An empty name is invalid. Implementations should retain the empty value as the + // instrumentation scope name, return a working Logger, and report the invalid value. + // + // The version of the package using a bridge can be critical information + // to include when logging. The bridge should accept this version + // information and use the [WithInstrumentationVersion] option to configure + // the Logger appropriately. + // + // Implementations of this method need to be safe for a user to call + // concurrently. + Logger(name string, options ...LoggerOption) Logger +} diff --git a/vendor/go.opentelemetry.io/otel/log/record.go b/vendor/go.opentelemetry.io/otel/log/record.go new file mode 100644 index 000000000..351657e95 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/record.go @@ -0,0 +1,168 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package log + +import ( + "slices" + "time" + + "go.opentelemetry.io/otel/attribute" +) + +// attributesInlineCount is the number of attributes that are efficiently +// stored in an array within a Record. This value is borrowed from slog, which +// performed a quantitative survey of log library use and found that this value +// covers 95% of all use cases (https://go.dev/blog/slog#performance). +const attributesInlineCount = 5 + +// Record represents a log record. +// A log record with a non-empty event name is interpreted as an event record. +type Record struct { + // Ensure forward compatibility by explicitly making this not comparable. + noCmp [0]func() //nolint: unused // This is indeed used. + + eventName string + timestamp time.Time + observedTimestamp time.Time + severity Severity + severityText string + body attribute.Value + err error + + // The fields below are for optimizing the implementation of Attributes and + // AddAttributes. This design is borrowed from the slog Record type: + // https://cs.opensource.google/go/go/+/refs/tags/go1.22.0:src/log/slog/record.go;l=20 + + // Allocation optimization: an inline array sized to hold + // the majority of log calls (based on examination of open-source + // code). It holds the start of the list of attributes. + front [attributesInlineCount]attribute.KeyValue + + // The number of attributes in front. + nFront int + + // The list of attributes except for those in front. + // Invariants: + // - len(back) > 0 if nFront == len(front) + // - Unused array elements are zeroed to detect mistakes. + back []attribute.KeyValue +} + +// EventName returns the event name. +// A log record with a non-empty event name is interpreted as an event record. +func (r *Record) EventName() string { + return r.eventName +} + +// SetEventName sets the event name. +// A log record with a non-empty event name is interpreted as an event record. +// Event names should uniquely identify the structure of the event's attributes +// and body. +func (r *Record) SetEventName(s string) { + r.eventName = s +} + +// Timestamp returns the time when the log record occurred. +func (r *Record) Timestamp() time.Time { + return r.timestamp +} + +// SetTimestamp sets the time when the log record occurred. +func (r *Record) SetTimestamp(t time.Time) { + r.timestamp = t +} + +// ObservedTimestamp returns the time when the log record was observed. +func (r *Record) ObservedTimestamp() time.Time { + return r.observedTimestamp +} + +// SetObservedTimestamp sets the time when the log record was observed. +func (r *Record) SetObservedTimestamp(t time.Time) { + r.observedTimestamp = t +} + +// Severity returns the [Severity] of the log record. +func (r *Record) Severity() Severity { + return r.severity +} + +// SetSeverity sets the [Severity] level of the log record. +func (r *Record) SetSeverity(level Severity) { + r.severity = level +} + +// SeverityText returns the text of the severity (also known as the log level) +// as originally known at the source. +func (r *Record) SeverityText() string { + return r.severityText +} + +// SetSeverityText sets the text of the severity (also known as the log level) +// as originally known at the source. +func (r *Record) SetSeverityText(text string) { + r.severityText = text +} + +// Body returns the body of the log record. +func (r *Record) Body() attribute.Value { + return r.body +} + +// SetBody sets the body of the log record. +func (r *Record) SetBody(v attribute.Value) { + r.body = v +} + +// Err returns the associated error if one has been set. +func (r *Record) Err() error { + return r.err +} + +// SetErr sets the associated error. Passing nil clears the error. +func (r *Record) SetErr(err error) { + r.err = err +} + +// WalkAttributes walks all attributes in the log record by calling f for each +// [attribute.KeyValue] in the [Record]. Iteration stops if f returns false. +func (r *Record) WalkAttributes(f func(attribute.KeyValue) bool) { + for i := 0; i < r.nFront; i++ { + if !f(r.front[i]) { + return + } + } + for _, a := range r.back { + if !f(a) { + return + } + } +} + +// AddAttributes adds attributes to the log record. +func (r *Record) AddAttributes(attrs ...attribute.KeyValue) { + var i int + for i = 0; i < len(attrs) && r.nFront < len(r.front); i++ { + a := attrs[i] + r.front[r.nFront] = a + r.nFront++ + } + + r.back = slices.Grow(r.back, len(attrs[i:])) + r.back = append(r.back, attrs[i:]...) +} + +// AttributesLen returns the number of attributes in the log record. +func (r *Record) AttributesLen() int { + return r.nFront + len(r.back) +} + +// Clone returns a copy of the record with no shared state. +// The original record and the clone can both be modified without interfering +// with each other. +func (r *Record) Clone() Record { + res := *r + res.back = slices.Clone(r.back) + return res +} diff --git a/vendor/go.opentelemetry.io/otel/log/severity.go b/vendor/go.opentelemetry.io/otel/log/severity.go new file mode 100644 index 000000000..4f305be36 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/severity.go @@ -0,0 +1,69 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +//go:generate stringer -type=Severity -linecomment + +package log + +// Severity represents a log record's severity (also known as its log level). +// Smaller numerical values correspond to less severe log records (such as +// debug events); larger numerical values correspond to more severe log records +// (such as errors and critical events). +type Severity int + +// The following Severity values are defined by OpenTelemetry. +const ( + // SeverityUndefined represents an unset Severity. + SeverityUndefined Severity = 0 // UNDEFINED + + // The following are severity values for fine-grained debugging log records. + // They are typically disabled in default configurations. + SeverityTrace1 Severity = 1 // TRACE + SeverityTrace2 Severity = 2 // TRACE2 + SeverityTrace3 Severity = 3 // TRACE3 + SeverityTrace4 Severity = 4 // TRACE4 + + // The following are severity values for debugging log records. + SeverityDebug1 Severity = 5 // DEBUG + SeverityDebug2 Severity = 6 // DEBUG2 + SeverityDebug3 Severity = 7 // DEBUG3 + SeverityDebug4 Severity = 8 // DEBUG4 + + // The following are severity values for informational log records indicating + // that an event happened. + SeverityInfo1 Severity = 9 // INFO + SeverityInfo2 Severity = 10 // INFO2 + SeverityInfo3 Severity = 11 // INFO3 + SeverityInfo4 Severity = 12 // INFO4 + + // The following are severity values for warning log records. These records + // are not errors, but they are likely more important than informational + // events. + SeverityWarn1 Severity = 13 // WARN + SeverityWarn2 Severity = 14 // WARN2 + SeverityWarn3 Severity = 15 // WARN3 + SeverityWarn4 Severity = 16 // WARN4 + + // The following are severity values for error log records indicating that + // something went wrong. + SeverityError1 Severity = 17 // ERROR + SeverityError2 Severity = 18 // ERROR2 + SeverityError3 Severity = 19 // ERROR3 + SeverityError4 Severity = 20 // ERROR4 + + // The following are severity values for fatal log records, such as those + // associated with an application or system crash. + SeverityFatal1 Severity = 21 // FATAL + SeverityFatal2 Severity = 22 // FATAL2 + SeverityFatal3 Severity = 23 // FATAL3 + SeverityFatal4 Severity = 24 // FATAL4 + + // The following are convenience definitions for the base severity of each + // level. + SeverityTrace = SeverityTrace1 + SeverityDebug = SeverityDebug1 + SeverityInfo = SeverityInfo1 + SeverityWarn = SeverityWarn1 + SeverityError = SeverityError1 + SeverityFatal = SeverityFatal1 +) diff --git a/vendor/go.opentelemetry.io/otel/log/severity_string.go b/vendor/go.opentelemetry.io/otel/log/severity_string.go new file mode 100644 index 000000000..fb94caeab --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/log/severity_string.go @@ -0,0 +1,48 @@ +// Code generated by "stringer -type=Severity -linecomment"; DO NOT EDIT. + +package log + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[SeverityUndefined-0] + _ = x[SeverityTrace1-1] + _ = x[SeverityTrace2-2] + _ = x[SeverityTrace3-3] + _ = x[SeverityTrace4-4] + _ = x[SeverityDebug1-5] + _ = x[SeverityDebug2-6] + _ = x[SeverityDebug3-7] + _ = x[SeverityDebug4-8] + _ = x[SeverityInfo1-9] + _ = x[SeverityInfo2-10] + _ = x[SeverityInfo3-11] + _ = x[SeverityInfo4-12] + _ = x[SeverityWarn1-13] + _ = x[SeverityWarn2-14] + _ = x[SeverityWarn3-15] + _ = x[SeverityWarn4-16] + _ = x[SeverityError1-17] + _ = x[SeverityError2-18] + _ = x[SeverityError3-19] + _ = x[SeverityError4-20] + _ = x[SeverityFatal1-21] + _ = x[SeverityFatal2-22] + _ = x[SeverityFatal3-23] + _ = x[SeverityFatal4-24] +} + +const _Severity_name = "UNDEFINEDTRACETRACE2TRACE3TRACE4DEBUGDEBUG2DEBUG3DEBUG4INFOINFO2INFO3INFO4WARNWARN2WARN3WARN4ERRORERROR2ERROR3ERROR4FATALFATAL2FATAL3FATAL4" + +var _Severity_index = [...]uint8{0, 9, 14, 20, 26, 32, 37, 43, 49, 55, 59, 64, 69, 74, 78, 83, 88, 93, 98, 104, 110, 116, 121, 127, 133, 139} + +func (i Severity) String() string { + idx := int(i) - 0 + if i < 0 || idx >= len(_Severity_index)-1 { + return "Severity(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Severity_name[_Severity_index[idx]:_Severity_index[idx+1]] +} diff --git a/vendor/go.opentelemetry.io/otel/metric/meter.go b/vendor/go.opentelemetry.io/otel/metric/meter.go index 70ff4c731..971241572 100644 --- a/vendor/go.opentelemetry.io/otel/metric/meter.go +++ b/vendor/go.opentelemetry.io/otel/metric/meter.go @@ -320,7 +320,7 @@ type Observer interface { ObserveInt64(obsrv Int64Observable, value int64, opts ...ObserveOption) } -// Registration is an token representing the unique registration of a callback +// Registration is a token representing the unique registration of a callback // for a set of instruments with a Meter. // // Warning: Methods may be added to this interface in minor releases. See diff --git a/vendor/go.opentelemetry.io/otel/propagation/internal/hextable/hextable.go b/vendor/go.opentelemetry.io/otel/propagation/internal/hextable/hextable.go new file mode 100644 index 000000000..3d63244c2 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/propagation/internal/hextable/hextable.go @@ -0,0 +1,32 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Package hextable provides a lookup table for decoding lowercase +// hexadecimal. +package hextable + +// Rev is a reverse hex lookup table for lowercase hex digits. Valid +// hexadecimal characters are indexed at their respective values. All other +// characters, including the upper-case A-F disallowed by the W3C trace +// context specification, are represented with '\xff'. +// +// The '\xff' character is used as invalid because no valid character has the +// upper 4 bits set. Meaning, an efficient validation can be performed over +// multiple character parsing by checking these bits remain zero. +const Rev = "" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" diff --git a/vendor/go.opentelemetry.io/otel/propagation/trace_context.go b/vendor/go.opentelemetry.io/otel/propagation/trace_context.go index ffaa90303..1eb36b88e 100644 --- a/vendor/go.opentelemetry.io/otel/propagation/trace_context.go +++ b/vendor/go.opentelemetry.io/otel/propagation/trace_context.go @@ -9,6 +9,7 @@ import ( "fmt" "strings" + "go.opentelemetry.io/otel/propagation/internal/hextable" "go.opentelemetry.io/otel/trace" ) @@ -126,27 +127,23 @@ func (TraceContext) extract(carrier TextMapCarrier) trace.SpanContext { return sc } -// upperHex detect hex is upper case Unicode characters. -func upperHex(v string) bool { - for _, c := range v { - if c >= 'A' && c <= 'F' { - return true - } - } - return false -} - func extractPart(dst []byte, h *string, n int) bool { part, left, _ := strings.Cut(*h, delimiter) *h = left - // hex.Decode decodes unsupported upper-case characters, so exclude explicitly. - if len(part) != n || upperHex(part) { + if len(part) != n { return false } - if p, err := hex.Decode(dst, []byte(part)); err != nil || p != n/2 { - return false + // hextable.Rev maps every invalid character to 0xff, including the + // upper-case A-F the specification disallows. OR-ing every looked-up value + // together lets a single check detect any invalid character, because no + // valid value has the upper 4 bits set. + invalidMark := byte(0) + for i := 0; i < n; i += 2 { + hi, lo := hextable.Rev[part[i]], hextable.Rev[part[i+1]] + dst[i/2] = (hi << 4) | lo + invalidMark |= hi | lo } - return true + return invalidMark&0xf0 == 0 } // Fields returns the keys who's values are set with Inject. diff --git a/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/dedup.go b/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/dedup.go index fe9ddc96d..d72cfb3c9 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/dedup.go +++ b/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/dedup.go @@ -28,40 +28,142 @@ type rawValue struct { slice any } -// Value returns value with all map values deduplicated and whether it changed. +type valueChanges uint8 + +const ( + depthLimitChanged valueChanges = 1 << iota + deduplicationChanged +) + +// ValueDedup returns value with all map values deduplicated and whether +// it changed. // // Duplicate map keys are resolved using last-value-wins semantics. -func Value(value attribute.Value) (attribute.Value, bool) { +func ValueDedup(value attribute.Value) (attribute.Value, bool) { switch value.Type() { case attribute.SLICE: - return deduplicateSliceValue(value) + return sliceValueDedup(value) case attribute.MAP: - return deduplicateMapValue(value) + return mapValueDedup(value) default: return value, false } } -// KeyValue returns kv with all map values deduplicated and whether it changed. -func KeyValue(kv attribute.KeyValue) (attribute.KeyValue, bool) { - value, changed := Value(kv.Value) +// ValueDedupLimitDepth returns value with all map values +// deduplicated and all array and map values limited to depthLimit. The boolean +// results report depth limiting and deduplication changes, respectively. +// +// Duplicate map keys are resolved using last-value-wins semantics. Depth +// starts at one for value and increments when descending into an array element +// or map value. An array or map beyond a non-negative depthLimit is replaced by +// an empty value. A negative depthLimit disables depth limiting. +func ValueDedupLimitDepth( + value attribute.Value, + depthLimit int, +) (attribute.Value, bool, bool) { + if depthLimit < 0 { + value, deduplicated := ValueDedup(value) + return value, false, deduplicated + } + + // Keep the common scalar and primitive-array cases in this wrapper. Routing + // them through the recursive, multi-result transform adds measurable + // overhead to the dominant simple attribute path. + switch value.Type() { + case attribute.BOOLSLICE, + attribute.INT64SLICE, + attribute.FLOAT64SLICE, + attribute.STRINGSLICE, + attribute.BYTESLICE: + if depthLimit == 0 { + return attribute.Value{}, true, false + } + return value, false, false + case attribute.SLICE, attribute.MAP: + default: + return value, false, false + } + + value, changes := valueDedupLimitDepth(value, depthLimit) + return value, changes&depthLimitChanged != 0, changes&deduplicationChanged != 0 +} + +// ValueLimitDepth returns value with all array and map values limited to +// depthLimit. Map keys are not deduplicated. +// +// Depth starts at one for value and increments when descending into an array +// element or map value. An array or map beyond a non-negative depthLimit is +// replaced by an empty value. A negative depthLimit disables depth limiting. +func ValueLimitDepth(value attribute.Value, depthLimit int) (attribute.Value, bool) { + if depthLimit < 0 { + return value, false + } + + switch value.Type() { + case attribute.BOOLSLICE, + attribute.INT64SLICE, + attribute.FLOAT64SLICE, + attribute.STRINGSLICE, + attribute.BYTESLICE: + if depthLimit == 0 { + return attribute.Value{}, true + } + return value, false + case attribute.SLICE, attribute.MAP: + default: + return value, false + } + + return valueLimitDepth(value, depthLimit) +} + +// KeyValueDedup returns kv with all map values deduplicated and whether +// it changed. +func KeyValueDedup(kv attribute.KeyValue) (attribute.KeyValue, bool) { + value, changed := ValueDedup(kv.Value) if changed { kv.Value = value } return kv, changed } -// KeyValues returns kvs with all map values deduplicated and whether they changed. +// KeyValueDedupLimitDepth returns kv with all map values +// deduplicated and all array and map values limited to depthLimit. The boolean +// results report depth limiting and deduplication changes, respectively. +func KeyValueDedupLimitDepth( + kv attribute.KeyValue, + depthLimit int, +) (attribute.KeyValue, bool, bool) { + value, depthLimited, deduplicated := ValueDedupLimitDepth(kv.Value, depthLimit) + if depthLimited || deduplicated { + kv.Value = value + } + return kv, depthLimited, deduplicated +} + +// KeyValueLimitDepth returns kv with all array and map values limited to +// depthLimit. Map keys are not deduplicated. +func KeyValueLimitDepth(kv attribute.KeyValue, depthLimit int) (attribute.KeyValue, bool) { + value, changed := ValueLimitDepth(kv.Value, depthLimit) + if changed { + kv.Value = value + } + return kv, changed +} + +// KeyValuesDedup returns kvs with all map values deduplicated and whether +// they changed. // // The returned slice is the original kvs slice if no value needs // deduplication. Top-level keys in kvs are not deduplicated. -func KeyValues(kvs []attribute.KeyValue) ([]attribute.KeyValue, bool) { +func KeyValuesDedup(kvs []attribute.KeyValue) ([]attribute.KeyValue, bool) { // Preserve the caller's slice on the common no-op path. Once a changed // value is found, copy the prior values exactly once and fill the rest in // place as the scan continues. var normalized []attribute.KeyValue for i, kv := range kvs { - kv, changed := KeyValue(kv) + kv, changed := KeyValueDedup(kv) if normalized != nil { normalized[i] = kv continue @@ -80,22 +182,67 @@ func KeyValues(kvs []attribute.KeyValue) ([]attribute.KeyValue, bool) { return normalized, true } -// Set returns set with all map values deduplicated and whether it changed. +// KeyValuesDedupLimitDepth returns kvs with all map values +// deduplicated and all array and map values limited to depthLimit. The boolean +// results report depth limiting and deduplication changes, respectively. +// +// The returned slice is the original kvs slice if no value needs +// normalization. Top-level keys in kvs are not deduplicated. +func KeyValuesDedupLimitDepth( + kvs []attribute.KeyValue, + depthLimit int, +) ([]attribute.KeyValue, bool, bool) { + if depthLimit < 0 { + kvs, deduplicated := KeyValuesDedup(kvs) + return kvs, false, deduplicated + } + + var normalized []attribute.KeyValue + var allChanges valueChanges + for i, kv := range kvs { + value, changes := valueDedupLimitDepth(kv.Value, depthLimit) + allChanges |= changes + if changes != 0 { + kv.Value = value + } + if normalized != nil { + normalized[i] = kv + continue + } + if changes == 0 { + continue + } + + normalized = make([]attribute.KeyValue, len(kvs)) + copy(normalized, kvs[:i]) + normalized[i] = kv + } + if normalized == nil { + return kvs, false, false + } + return normalized, + allChanges&depthLimitChanged != 0, + allChanges&deduplicationChanged != 0 +} + +// SetDedup returns set with all map values deduplicated and whether it +// changed. // // The returned Set is the original set if no value needs deduplication. // Top-level key uniqueness remains attribute.Set's responsibility; this only // normalizes map attribute values. -func Set(set attribute.Set) (attribute.Set, bool) { - if set.Len() == 0 { +func SetDedup(set attribute.Set) (attribute.Set, bool) { + length := set.Len() + if length == 0 { return set, false } // Most attribute sets contain no duplicate map keys. Delay allocation until // the first changed value so the no-op path returns the original Set. var normalized []attribute.KeyValue - for i := range set.Len() { + for i := range length { kv, _ := set.Get(i) - kv, changed := KeyValue(kv) + kv, changed := KeyValueDedup(kv) if normalized != nil { normalized = append(normalized, kv) continue @@ -104,7 +251,7 @@ func Set(set attribute.Set) (attribute.Set, bool) { continue } - normalized = make([]attribute.KeyValue, 0, set.Len()) + normalized = make([]attribute.KeyValue, 0, length) for j := range i { prior, _ := set.Get(j) normalized = append(normalized, prior) @@ -118,7 +265,359 @@ func Set(set attribute.Set) (attribute.Set, bool) { return attribute.NewSet(normalized...), true } -func deduplicateSliceValue(value attribute.Value) (attribute.Value, bool) { +// SetDedupLimitDepth returns set with all map values deduplicated and +// all array and map values limited to depthLimit. The boolean results report +// depth limiting and deduplication changes, respectively. +// +// The returned Set is the original set if no value needs normalization. +// Top-level key uniqueness remains attribute.Set's responsibility; this only +// normalizes attribute values. +func SetDedupLimitDepth( + set attribute.Set, + depthLimit int, +) (attribute.Set, bool, bool) { + if depthLimit < 0 { + set, deduplicated := SetDedup(set) + return set, false, deduplicated + } + length := set.Len() + if length == 0 { + return set, false, false + } + + var normalized []attribute.KeyValue + var allChanges valueChanges + for i := range length { + kv, _ := set.Get(i) + value, changes := valueDedupLimitDepth(kv.Value, depthLimit) + allChanges |= changes + if changes != 0 { + kv.Value = value + } + if normalized != nil { + normalized = append(normalized, kv) + continue + } + if changes == 0 { + continue + } + + normalized = make([]attribute.KeyValue, 0, length) + for j := range i { + prior, _ := set.Get(j) + normalized = append(normalized, prior) + } + normalized = append(normalized, kv) + } + if normalized == nil { + return set, false, false + } + return attribute.NewSet(normalized...), + allChanges&depthLimitChanged != 0, + allChanges&deduplicationChanged != 0 +} + +// SetLimitDepth returns set with all array and map values limited to +// depthLimit. Map keys are not deduplicated. +// +// The returned Set is the original set if no value changes. +func SetLimitDepth(set attribute.Set, depthLimit int) (attribute.Set, bool) { + if depthLimit < 0 { + return set, false + } + length := set.Len() + if length == 0 { + return set, false + } + + var normalized []attribute.KeyValue + for i := range length { + kv, _ := set.Get(i) + value, changed := valueLimitDepth(kv.Value, depthLimit) + if changed { + kv.Value = value + } + if normalized != nil { + normalized = append(normalized, kv) + continue + } + if !changed { + continue + } + + normalized = make([]attribute.KeyValue, 0, length) + for j := range i { + prior, _ := set.Get(j) + normalized = append(normalized, prior) + } + normalized = append(normalized, kv) + } + if normalized == nil { + return set, false + } + return attribute.NewSet(normalized...), true +} + +// valueDedupLimitDepth combines depth limiting with recursive map +// deduplication. remainingDepth is non-negative. It checks the remaining +// budget before reading collection storage and lazily rebuilds only changed +// ancestry. +func valueDedupLimitDepth( + value attribute.Value, + remainingDepth int, +) (attribute.Value, valueChanges) { + switch value.Type() { + case attribute.BOOLSLICE, + attribute.INT64SLICE, + attribute.FLOAT64SLICE, + attribute.STRINGSLICE, + attribute.BYTESLICE: + if remainingDepth == 0 { + return attribute.Value{}, depthLimitChanged + } + case attribute.SLICE: + if remainingDepth == 0 { + return attribute.Value{}, depthLimitChanged + } + return sliceValueDedupLimitDepth(value, remainingDepth) + case attribute.MAP: + if remainingDepth == 0 { + return attribute.Value{}, depthLimitChanged + } + return mapValueDedupLimitDepth(value, remainingDepth) + } + return value, 0 +} + +// valueLimitDepth limits collection depth while preserving duplicate map keys. +func valueLimitDepth( + value attribute.Value, + remainingDepth int, +) (attribute.Value, bool) { + switch value.Type() { + case attribute.BOOLSLICE, + attribute.INT64SLICE, + attribute.FLOAT64SLICE, + attribute.STRINGSLICE, + attribute.BYTESLICE: + if remainingDepth == 0 { + return attribute.Value{}, true + } + case attribute.SLICE: + if remainingDepth == 0 { + return attribute.Value{}, true + } + return sliceValueLimitDepth(value, remainingDepth) + case attribute.MAP: + if remainingDepth == 0 { + return attribute.Value{}, true + } + return mapValueLimitDepth(value, remainingDepth) + } + return value, false +} + +func sliceValueDedupLimitDepth( + value attribute.Value, + remainingDepth int, +) (attribute.Value, valueChanges) { + storage := valueStorage(value) + length := valueLen(storage) + if length <= 1 { + if length == 1 { + elem := valueAt(storage, 0) + newElem, changes := valueDedupLimitDepth( + elem, + remainingDepth-1, + ) + if changes != 0 { + return attribute.SliceValue(newElem), changes + } + } + return value, 0 + } + + var normalized []attribute.Value + var allChanges valueChanges + for i := range length { + elem := valueAt(storage, i) + newElem, changes := valueDedupLimitDepth( + elem, + remainingDepth-1, + ) + allChanges |= changes + if normalized != nil { + normalized[i] = newElem + continue + } + if changes == 0 { + continue + } + + normalized = make([]attribute.Value, length) + for j := range i { + normalized[j] = valueAt(storage, j) + } + normalized[i] = newElem + } + if normalized == nil { + return value, 0 + } + return attribute.SliceValue(normalized...), allChanges +} + +func sliceValueLimitDepth( + value attribute.Value, + remainingDepth int, +) (attribute.Value, bool) { + storage := valueStorage(value) + length := valueLen(storage) + if length <= 1 { + if length == 1 { + elem := valueAt(storage, 0) + newElem, changed := valueLimitDepth(elem, remainingDepth-1) + if changed { + return attribute.SliceValue(newElem), true + } + } + return value, false + } + + var normalized []attribute.Value + for i := range length { + elem := valueAt(storage, i) + newElem, changed := valueLimitDepth(elem, remainingDepth-1) + if normalized != nil { + normalized[i] = newElem + continue + } + if !changed { + continue + } + + normalized = make([]attribute.Value, length) + for j := range i { + normalized[j] = valueAt(storage, j) + } + normalized[i] = newElem + } + if normalized == nil { + return value, false + } + return attribute.SliceValue(normalized...), true +} + +func mapValueDedupLimitDepth( + value attribute.Value, + remainingDepth int, +) (attribute.Value, valueChanges) { + storage := valueStorage(value) + length := keyValueLen(storage) + if length <= 1 { + if length == 1 { + kv := keyValueAt(storage, 0) + newValue, changes := valueDedupLimitDepth( + kv.Value, + remainingDepth-1, + ) + if changes != 0 { + kv.Value = newValue + return attribute.MapValue(kv), changes + } + } + return value, 0 + } + + var normalized []attribute.KeyValue + var allChanges valueChanges + for i := 0; i < length; { + // attribute.MapValue stores key-values sorted by key using a stable + // sort. Only the last entry in an equal-key run survives, so avoid + // traversing values that will be discarded. + first := keyValueAt(storage, i) + j := i + 1 + for j < length && keyValueAt(storage, j).Key == first.Key { + j++ + } + + kv := keyValueAt(storage, j-1) + newValue, changes := valueDedupLimitDepth( + kv.Value, + remainingDepth-1, + ) + if changes != 0 { + kv.Value = newValue + } + if j-i > 1 { + changes |= deduplicationChanged + } + allChanges |= changes + if normalized != nil { + normalized = append(normalized, kv) + } else if changes != 0 { + if i == 0 && j == length { + return attribute.MapValue(kv), allChanges + } + normalized = make([]attribute.KeyValue, 0, length-(j-i-1)) + for k := range i { + normalized = append(normalized, keyValueAt(storage, k)) + } + normalized = append(normalized, kv) + } + i = j + } + if normalized == nil { + return value, 0 + } + return attribute.MapValue(normalized...), allChanges +} + +func mapValueLimitDepth( + value attribute.Value, + remainingDepth int, +) (attribute.Value, bool) { + storage := valueStorage(value) + length := keyValueLen(storage) + if length <= 1 { + if length == 1 { + kv := keyValueAt(storage, 0) + newValue, changed := valueLimitDepth(kv.Value, remainingDepth-1) + if changed { + kv.Value = newValue + return attribute.MapValue(kv), true + } + } + return value, false + } + + var normalized []attribute.KeyValue + for i := range length { + kv := keyValueAt(storage, i) + newValue, changed := valueLimitDepth(kv.Value, remainingDepth-1) + if changed { + kv.Value = newValue + } + if normalized != nil { + normalized[i] = kv + continue + } + if !changed { + continue + } + + normalized = make([]attribute.KeyValue, length) + for j := range i { + normalized[j] = keyValueAt(storage, j) + } + normalized[i] = kv + } + if normalized == nil { + return value, false + } + return attribute.MapValue(normalized...), true +} + +func sliceValueDedup(value attribute.Value) (attribute.Value, bool) { storage := valueStorage(value) length := valueLen(storage) @@ -127,7 +626,7 @@ func deduplicateSliceValue(value attribute.Value) (attribute.Value, bool) { var normalized []attribute.Value for i := range length { elem := valueAt(storage, i) - elem, changed := Value(elem) + elem, changed := ValueDedup(elem) if normalized != nil { normalized[i] = elem continue @@ -148,14 +647,14 @@ func deduplicateSliceValue(value attribute.Value) (attribute.Value, bool) { return attribute.SliceValue(normalized...), true } -func deduplicateMapValue(value attribute.Value) (attribute.Value, bool) { +func mapValueDedup(value attribute.Value) (attribute.Value, bool) { storage := valueStorage(value) length := keyValueLen(storage) if length <= 1 { // A single map entry cannot duplicate its own key, but its value might // contain a map or slice that needs recursive normalization. if length == 1 { - kv, changed := KeyValue(keyValueAt(storage, 0)) + kv, changed := KeyValueDedup(keyValueAt(storage, 0)) if changed { return attribute.MapValue(kv), true } @@ -174,13 +673,16 @@ func deduplicateMapValue(value attribute.Value) (attribute.Value, bool) { j++ } - kv, nestedChanged := KeyValue(keyValueAt(storage, j-1)) + kv, nestedChanged := KeyValueDedup(keyValueAt(storage, j-1)) // j-i > 1 means the current key run contained duplicates. changed := nestedChanged || j-i > 1 if normalized != nil { normalized = append(normalized, kv) } else if changed { - normalized = make([]attribute.KeyValue, 0, length) + if i == 0 && j == length { + return attribute.MapValue(kv), true + } + normalized = make([]attribute.KeyValue, 0, length-(j-i-1)) for k := range i { normalized = append(normalized, keyValueAt(storage, k)) } diff --git a/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/truncate.go b/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/truncate.go index c8341599b..db7c5388c 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/truncate.go +++ b/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/truncate.go @@ -7,7 +7,7 @@ package attrnorm import ( - "slices" + "reflect" "strings" "unicode/utf8" @@ -26,43 +26,24 @@ func Truncate(limit int, attr attribute.KeyValue) attribute.KeyValue { if limit < 0 { return attr } + + // Keep scalar cases in this wrapper. Routing them through the recursive, + // multi-result transform adds measurable overhead to the dominant simple + // attribute path. switch attr.Value.Type() { case attribute.STRING: - v := attr.Value.AsString() - return attr.Key.String(truncate(limit, v)) - case attribute.STRINGSLICE: - v := attr.Value.AsStringSlice() - for i := range v { - v[i] = truncate(limit, v[i]) - } - return attr.Key.StringSlice(v) + attr.Value = attribute.StringValue(truncate(limit, attr.Value.AsString())) case attribute.BYTESLICE: - v := attr.Value.AsString() - if len(v) > limit { - return attr.Key.ByteSlice([]byte(v[:limit])) + s := attr.Value.AsString() + if len(s) > limit { + attr.Value = attribute.ByteSliceValue([]byte(s[:limit])) } - return attr + case attribute.STRINGSLICE: + attr.Value, _ = truncateStringSliceValue(limit, attr.Value) case attribute.SLICE: - v := attr.Value.AsSlice() - if !slices.ContainsFunc(v, func(e attribute.Value) bool { return needsTruncation(limit, e) }) { - return attr - } - newV := make([]attribute.Value, len(v)) - for i, elem := range v { - newV[i] = TruncateValue(limit, elem) - } - return attr.Key.Slice(newV...) + attr.Value, _ = truncateSliceValue(limit, attr.Value) case attribute.MAP: - v := attr.Value.AsMap() - if !slices.ContainsFunc(v, func(kv attribute.KeyValue) bool { return needsTruncation(limit, kv.Value) }) { - return attr - } - newV := make([]attribute.KeyValue, len(v)) - for i, elem := range v { - elem.Value = TruncateValue(limit, elem.Value) - newV[i] = elem - } - return attr.Key.Map(newV...) + attr.Value, _ = truncateMapValue(limit, attr.Value) } return attr } @@ -76,85 +57,275 @@ func TruncateValue(limit int, v attribute.Value) attribute.Value { return v } + // Match Truncate's direct scalar path to avoid paying for the recursive, + // multi-result transform when no composite traversal is needed. switch v.Type() { case attribute.STRING: return attribute.StringValue(truncate(limit, v.AsString())) - case attribute.STRINGSLICE: - ss := v.AsStringSlice() - for i := range ss { - ss[i] = truncate(limit, ss[i]) - } - return attribute.StringSliceValue(ss) case attribute.BYTESLICE: - // len(v.AsString()) is identical to len(v.AsByteSlice()) but - // avoids allocating the full slice before truncation. s := v.AsString() - if limit >= 0 && len(s) > limit { + if len(s) > limit { return attribute.ByteSliceValue([]byte(s[:limit])) } + case attribute.STRINGSLICE: + v, _ = truncateStringSliceValue(limit, v) case attribute.SLICE: - sl := v.AsSlice() - if !slices.ContainsFunc(sl, func(e attribute.Value) bool { return needsTruncation(limit, e) }) { - return v - } - newSl := make([]attribute.Value, len(sl)) - for i, elem := range sl { - newSl[i] = TruncateValue(limit, elem) - } - return attribute.SliceValue(newSl...) + v, _ = truncateSliceValue(limit, v) case attribute.MAP: - m := v.AsMap() - if !slices.ContainsFunc(m, func(kv attribute.KeyValue) bool { return needsTruncation(limit, kv.Value) }) { - return v - } - newM := make([]attribute.KeyValue, len(m)) - for i, elem := range m { - elem.Value = TruncateValue(limit, elem.Value) - newM[i] = elem - } - return attribute.MapValue(newM...) + v, _ = truncateMapValue(limit, v) } return v } -// stringNeedsTruncation reports whether s would be modified by truncate for the -// given limit. -func stringNeedsTruncation(limit int, s string) bool { - if limit < 0 || len(s) <= limit { - return false - } - return utf8.RuneCountInString(s) > limit || !utf8.ValidString(s) -} - -// needsTruncation reports whether v would be modified by TruncateValue for the -// given limit. -func needsTruncation(limit int, v attribute.Value) bool { +// truncateValue traverses composite values once and rebuilds them lazily on +// the first changed child. Recursion provides O(depth) temporary stack space +// without forcing a heap allocation on the common no-op path. +func truncateValue(limit int, v attribute.Value) (attribute.Value, bool) { switch v.Type() { case attribute.STRING: - return stringNeedsTruncation(limit, v.AsString()) - case attribute.BYTESLICE: - // len(v.AsString()) is identical to len(v.AsByteSlice()) but - // avoids memory allocation. - if limit >= 0 && len(v.AsString()) > limit { - return true + s := v.AsString() + truncated := truncate(limit, s) + if truncated != s { + return attribute.StringValue(truncated), true } case attribute.STRINGSLICE: - for _, s := range v.AsStringSlice() { - if stringNeedsTruncation(limit, s) { - return true - } + return truncateStringSliceValue(limit, v) + case attribute.BYTESLICE: + // len(v.AsString()) is identical to len(v.AsByteSlice()) but + // avoids allocating the full slice before truncation. + s := v.AsString() + if len(s) > limit { + return attribute.ByteSliceValue([]byte(s[:limit])), true } case attribute.SLICE: - return slices.ContainsFunc(v.AsSlice(), func(e attribute.Value) bool { return needsTruncation(limit, e) }) + return truncateSliceValue(limit, v) case attribute.MAP: - return slices.ContainsFunc( - v.AsMap(), - func(kv attribute.KeyValue) bool { return needsTruncation(limit, kv.Value) }, - ) + return truncateMapValue(limit, v) } - return false + return v, false } +func truncateStringSliceValue(limit int, value attribute.Value) (attribute.Value, bool) { + storage := valueStorage(value) + switch values := storage.(type) { + case [0]string: + return value, false + case [1]string: + return truncateStrings(limit, value, values[:]) + case [2]string: + return truncateStrings(limit, value, values[:]) + case [3]string: + return truncateStrings(limit, value, values[:]) + default: + array := reflect.ValueOf(storage) + if array.Kind() != reflect.Array || array.Type().Elem() != stringType { + return value, false + } + return truncateStringArray(limit, value, array) + } +} + +func truncateStrings(limit int, value attribute.Value, values []string) (attribute.Value, bool) { + var truncated []string + for i, s := range values { + newS := truncate(limit, s) + if truncated != nil { + truncated[i] = newS + continue + } + if newS == s { + continue + } + + truncated = make([]string, len(values)) + copy(truncated, values[:i]) + truncated[i] = newS + } + if truncated == nil { + return value, false + } + return attribute.StringSliceValue(truncated), true +} + +func truncateStringArray(limit int, value attribute.Value, values reflect.Value) (attribute.Value, bool) { + var truncated []string + for i := range values.Len() { + s := values.Index(i).String() + newS := truncate(limit, s) + if truncated != nil { + truncated[i] = newS + continue + } + if newS == s { + continue + } + + truncated = make([]string, values.Len()) + for j := range i { + truncated[j] = values.Index(j).String() + } + truncated[i] = newS + } + if truncated == nil { + return value, false + } + return attribute.StringSliceValue(truncated), true +} + +func truncateSliceValue(limit int, value attribute.Value) (attribute.Value, bool) { + storage := valueStorage(value) + switch values := storage.(type) { + case [0]attribute.Value: + return value, false + case [1]attribute.Value: + return truncateValueSlice(limit, value, values[:]) + case [2]attribute.Value: + return truncateValueSlice(limit, value, values[:]) + case [3]attribute.Value: + return truncateValueSlice(limit, value, values[:]) + case [4]attribute.Value: + return truncateValueSlice(limit, value, values[:]) + case [5]attribute.Value: + return truncateValueSlice(limit, value, values[:]) + default: + array := reflect.ValueOf(storage) + if array.Kind() != reflect.Array || array.Type().Elem() != valueType { + return value, false + } + return truncateValueArray(limit, value, array) + } +} + +func truncateValueSlice(limit int, value attribute.Value, values []attribute.Value) (attribute.Value, bool) { + var truncated []attribute.Value + for i, elem := range values { + newElem, changed := truncateValue(limit, elem) + if truncated != nil { + truncated[i] = newElem + continue + } + if !changed { + continue + } + + truncated = make([]attribute.Value, len(values)) + copy(truncated, values[:i]) + truncated[i] = newElem + } + if truncated == nil { + return value, false + } + return attribute.SliceValue(truncated...), true +} + +func truncateValueArray(limit int, value attribute.Value, values reflect.Value) (attribute.Value, bool) { + var truncated []attribute.Value + for i := range values.Len() { + elem := values.Index(i).Interface().(attribute.Value) + newElem, changed := truncateValue(limit, elem) + if truncated != nil { + truncated[i] = newElem + continue + } + if !changed { + continue + } + + truncated = make([]attribute.Value, values.Len()) + for j := range i { + truncated[j] = values.Index(j).Interface().(attribute.Value) + } + truncated[i] = newElem + } + if truncated == nil { + return value, false + } + return attribute.SliceValue(truncated...), true +} + +func truncateMapValue(limit int, value attribute.Value) (attribute.Value, bool) { + storage := valueStorage(value) + switch keyValues := storage.(type) { + case [0]attribute.KeyValue: + return value, false + case [1]attribute.KeyValue: + return truncateKeyValueSlice(limit, value, keyValues[:]) + case [2]attribute.KeyValue: + return truncateKeyValueSlice(limit, value, keyValues[:]) + case [3]attribute.KeyValue: + return truncateKeyValueSlice(limit, value, keyValues[:]) + case [4]attribute.KeyValue: + return truncateKeyValueSlice(limit, value, keyValues[:]) + case [5]attribute.KeyValue: + return truncateKeyValueSlice(limit, value, keyValues[:]) + default: + array := reflect.ValueOf(storage) + if array.Kind() != reflect.Array || array.Type().Elem() != keyValueType { + return value, false + } + return truncateKeyValueArray(limit, value, array) + } +} + +func truncateKeyValueSlice( + limit int, + value attribute.Value, + keyValues []attribute.KeyValue, +) (attribute.Value, bool) { + var truncated []attribute.KeyValue + for i, kv := range keyValues { + newValue, changed := truncateValue(limit, kv.Value) + if changed { + kv.Value = newValue + } + if truncated != nil { + truncated[i] = kv + continue + } + if !changed { + continue + } + + truncated = make([]attribute.KeyValue, len(keyValues)) + copy(truncated, keyValues[:i]) + truncated[i] = kv + } + if truncated == nil { + return value, false + } + return attribute.MapValue(truncated...), true +} + +func truncateKeyValueArray(limit int, value attribute.Value, keyValues reflect.Value) (attribute.Value, bool) { + var truncated []attribute.KeyValue + for i := range keyValues.Len() { + kv := keyValues.Index(i).Interface().(attribute.KeyValue) + newValue, changed := truncateValue(limit, kv.Value) + if changed { + kv.Value = newValue + } + if truncated != nil { + truncated[i] = kv + continue + } + if !changed { + continue + } + + truncated = make([]attribute.KeyValue, keyValues.Len()) + for j := range i { + truncated[j] = keyValues.Index(j).Interface().(attribute.KeyValue) + } + truncated[i] = kv + } + if truncated == nil { + return value, false + } + return attribute.MapValue(truncated...), true +} + +var stringType = reflect.TypeFor[string]() + // truncate returns a version of s truncated according to limit. // // If limit is negative, it returns the original string. @@ -168,7 +339,7 @@ func truncate(limit int, s string) string { // This prioritizes performance in the following order based on the most // common expected use cases. // - // - Values shorter than the default limit (128). + // - Values whose byte length does not exceed the limit. // - Strings with valid encodings that exceed the limit. // - No limit. // - Strings with invalid encodings that exceed the limit. @@ -188,14 +359,27 @@ func truncate(limit int, s string) string { continue } + // A zero limit also truncates a leading invalid byte or U+FFFD. + if limit == 0 { + return "" + } + // Range reports RuneError for both an invalid byte and a valid U+FFFD. + // Only a size-1 decoding indicates invalid UTF-8. _, size := utf8.DecodeRuneInString(s[i:]) if size == 1 { - // Invalid encoding. + // Removing this byte makes len(s)-1 an upper bound for a rebuilt + // result. Keep the valid prefix before rescanning s[i:]. b.Grow(len(s) - 1) _, _ = b.WriteString(s[:i]) s = s[i:] break } + + // A valid U+FFFD still consumes one character of the limit. + count++ + if count > limit { + return s[:i] + } } // Fast-path, no invalid input. @@ -203,7 +387,9 @@ func truncate(limit int, s string) string { return s } - // Truncate while validating UTF-8. + // The builder holds the valid prefix before the first invalid byte, and + // count includes its runes. Skip malformed bytes without counting them + // while copying the remaining valid runes up to the limit. for i := 0; i < len(s) && count < limit; { c := s[i] if c < utf8.RuneSelf { diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go b/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go index f52e7ea54..5c7e85904 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go @@ -79,7 +79,7 @@ func (l AggregationLastValue) copy() Aggregation { return l } func (AggregationLastValue) err() error { return nil } // AggregationExplicitBucketHistogram is an Aggregation that summarizes a set of -// measurements as an histogram with explicitly defined buckets. +// measurements as a histogram with explicitly defined buckets. type AggregationExplicitBucketHistogram struct { // Boundaries are the increasing bucket boundary values. Boundary values // define bucket upper bounds. Buckets are exclusive of their lower @@ -138,7 +138,7 @@ func (h AggregationExplicitBucketHistogram) copy() Aggregation { } // AggregationBase2ExponentialHistogram is an Aggregation that summarizes a set of -// measurements as an histogram with bucket widths that grow exponentially. +// measurements as a histogram with bucket widths that grow exponentially. type AggregationBase2ExponentialHistogram struct { // MaxSize is the maximum number of buckets to use for the histogram. MaxSize int32 diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/env.go b/vendor/go.opentelemetry.io/otel/sdk/metric/env.go index 132664a7e..090446d84 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/env.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/env.go @@ -4,6 +4,7 @@ package metric import ( + "errors" "os" "strconv" "time" @@ -11,6 +12,8 @@ import ( "go.opentelemetry.io/otel/internal/global" ) +var errDurationOverflow = errors.New("duration overflows time.Duration") + // Environment variable names. const ( // The time interval (in milliseconds) between the start of two export attempts. @@ -26,7 +29,7 @@ func envDuration(key string, defaultValue time.Duration) time.Duration { if v == "" { return defaultValue } - d, err := strconv.Atoi(v) + d, err := strconv.ParseInt(v, 10, 64) if err != nil { global.Error(err, "parse duration", "environment variable", key, "value", v) return defaultValue @@ -35,5 +38,9 @@ func envDuration(key string, defaultValue time.Duration) time.Duration { global.Error(errNonPositiveDuration, "non-positive duration", "environment variable", key, "value", v) return defaultValue } + if d > int64(time.Duration(1<<63-1)/time.Millisecond) { + global.Error(errDurationOverflow, "duration overflows time.Duration", "environment variable", key, "value", v) + return defaultValue + } return time.Duration(d) * time.Millisecond } diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go index 48f2b464c..64f5884d0 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go @@ -24,6 +24,12 @@ func FixedSizeReservoirProvider(k int) ReservoirProvider { // sample each one. If there are more than k, the Reservoir will then randomly // sample all additional measurement with a decreasing probability. func NewFixedSizeReservoir(k int) *FixedSizeReservoir { + // A negative size is invalid. The constructor cannot return an error, so + // clamp it to zero and treat it as an empty reservoir (consistent with the + // existing behavior for k == 0) rather than panicking in make below. + if k < 0 { + k = 0 + } r := &FixedSizeReservoir{ storage: make([]measurement, k), } diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/value.go b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/value.go index c7d1645b6..af045e276 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/value.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/value.go @@ -49,8 +49,8 @@ func (v Value) Int64() int64 { return 0 } -// Float64 returns the value of v as an float64. If the ValueType of v is not -// an Float64ValueType, 0 is returned. +// Float64 returns the value of v as a float64. If the ValueType of v is not +// a Float64ValueType, 0 is returned. func (v Value) Float64() float64 { if v.t == Float64ValueType { return math.Float64frombits(v.val) diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go b/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go index 31f7afef9..f08657314 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go @@ -142,6 +142,9 @@ type Stream struct { // the attribute will not be recorded, otherwise, if it returns true, it // will record the attribute. // + // If nil, the instrument's advisory attribute keys are used. If the + // instrument has no advisory attribute keys, all attributes are recorded. + // // Note that attributes filtered out by a View may still appear on Exemplars, // because Exemplars are recorded with the dropped measurement attributes // when View attribute filtering is applied. @@ -207,11 +210,11 @@ func extractRawKVs[T any](opts []T) []attribute.KeyValue { } func resolveAttributes(configAttrs attribute.Set, rawKVs []attribute.KeyValue) attribute.Set { - configAttrs, _ = attrnorm.Set(configAttrs) + configAttrs, _ = attrnorm.SetDedup(configAttrs) if len(rawKVs) == 0 { return configAttrs } - rawKVs, _ = attrnorm.KeyValues(rawKVs) + rawKVs, _ = attrnorm.KeyValuesDedup(rawKVs) merged := make([]attribute.KeyValue, 0, configAttrs.Len()+len(rawKVs)) merged = append(merged, configAttrs.ToSlice()...) // rawKVs are appended after configAttrs, meaning they will override any duplicate keys in configAttrs. diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/atomic.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/atomic.go index 604ee0d56..1e342420e 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/atomic.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/atomic.go @@ -27,10 +27,18 @@ type atomicCounter[N int64 | float64] struct { // load returns the current value. The caller must ensure all calls to add have // returned prior to calling load. -func (n *atomicCounter[N]) load() N { - fval := math.Float64frombits(n.nFloatBits.Load()) - ival := n.nInt.Load() - return N(fval + float64(ival)) +func (n *atomicCounter[N]) load() (value N) { + switch any(value).(type) { + case int64: + value = N(n.nInt.Load()) + case float64: + fval := math.Float64frombits(n.nFloatBits.Load()) + ival := n.nInt.Load() + value = N(fval + float64(ival)) + default: + panic("unsupported type") + } + return value } func (n *atomicCounter[N]) add(value N) { @@ -183,40 +191,53 @@ type hotColdWaitGroup struct { endedCounts [2]atomic.Uint64 } +// hotIdx represents an index (0 or 1) to the currently active "hot" buffer +// where concurrent writes are accepted. +// +// coldIdx represents an index (0 or 1) to the "cold" buffer where collection +// reads and resets occur after a swap. +// +// These distinct types enforce at compile time that hot (write) and cold (read) +// indices are not accidentally interchanged across call boundaries. +type ( + hotIdx uint64 + coldIdx uint64 +) + // start returns the hot index that the writer should write to. The returned // hot index is 0 or 1. The caller must call done(hot index) after it finishes // its operation. start() is safe to call concurrently with other methods. -func (l *hotColdWaitGroup) start() uint64 { +func (l *hotColdWaitGroup) start() hotIdx { // We increment h.startedCountAndHotIdx so that the counter in the lower // 63 bits gets incremented. At the same time, we get the new value // back, which we can use to return the currently-hot index. - return l.startedCountAndHotIdx.Add(1) >> 63 + return hotIdx(l.startedCountAndHotIdx.Add(1) >> 63) } // done signals to the reader that an operation has fully completed. // done is safe to call concurrently. -func (l *hotColdWaitGroup) done(hotIdx uint64) { +func (l *hotColdWaitGroup) done(hotIdx hotIdx) { l.endedCounts[hotIdx].Add(1) } // swapHotAndWait swaps the hot bit, waits for all start() calls to be done(), // and then returns the now-cold index for the reader to read from. The // returned index is 0 or 1. swapHotAndWait must not be called concurrently. -func (l *hotColdWaitGroup) swapHotAndWait() uint64 { +func (l *hotColdWaitGroup) swapHotAndWait() coldIdx { n := l.startedCountAndHotIdx.Load() - coldIdx := (^n) >> 63 + coldIdxVal := (^n) >> 63 // Swap the hot and cold index while resetting the started measurements // count to zero. - n = l.startedCountAndHotIdx.Swap((coldIdx << 63)) - hotIdx := n >> 63 + n = l.startedCountAndHotIdx.Swap((coldIdxVal << 63)) + hotIdxVal := n >> 63 startedCount := n & ((1 << 63) - 1) // Wait for all measurements to the previously-hot map to finish. - for startedCount != l.endedCounts[hotIdx].Load() { + for startedCount != l.endedCounts[hotIdxVal].Load() { runtime.Gosched() // Let measurements complete. } // reset the number of ended operations - l.endedCounts[hotIdx].Store(0) - return hotIdx + l.endedCounts[hotIdxVal].Store(0) + return coldIdx(hotIdxVal) } // limitedSyncMap is a sync.Map which enforces the aggregation limit on @@ -270,6 +291,49 @@ func (m *limitedSyncMap[V]) LoadOrStoreAttr(lazy lazyFilteredAttributes, newValu return actual.(V) } +// LoadOrStoreAttrReclaiming is equivalent to LoadOrStoreAttr, except that a +// slot released after overflow was created can be reused for a new attribute +// set. The shared overflow entry remains available for measurements made while +// all normal slots are occupied. It reports whether the value was loaded and +// whether this lookup was routed to the shared overflow entry. +func (m *limitedSyncMap[V]) LoadOrStoreAttrReclaiming( + lazy lazyFilteredAttributes, + newValue func(attribute.Set, bool) V, +) (value V, loaded, overflowed bool) { + distinct := lazy.Distinct() + actual, loaded := m.Load(distinct) + if loaded { + return actual.(V), true, false + } + + m.lenMux.Lock() + defer m.lenMux.Unlock() + + actual, loaded = m.Load(distinct) + if loaded { + return actual.(V), true, false + } + + overflow, hasOverflow := m.Load(overflowSet.Equivalent()) + if m.aggLimit > 0 && hasOverflow && m.len >= m.aggLimit { + return overflow.(V), true, true + } + + var attrs attribute.Set + overflowed = m.aggLimit > 0 && !hasOverflow && m.len >= m.aggLimit-1 + if overflowed { + attrs = overflowSet + distinct = overflowSet.Equivalent() + } else { + attrs = lazy.Set() + } + actual, loaded = m.LoadOrStore(distinct, newValue(attrs, overflowed)) + if !loaded { + m.len++ + } + return actual.(V), loaded, overflowed +} + func (m *limitedSyncMap[V]) Clear() { m.lenMux.Lock() defer m.lenMux.Unlock() @@ -277,8 +341,62 @@ func (m *limitedSyncMap[V]) Clear() { m.Map.Clear() } +// CompareAndDelete deletes the entry for key if its value is equal to old. +// It reports whether the entry was deleted. +func (m *limitedSyncMap[V]) CompareAndDelete(key attribute.Distinct, old V) bool { + m.lenMux.Lock() + defer m.lenMux.Unlock() + if !m.Map.CompareAndDelete(key, old) { + return false + } + m.len-- + return true +} + func (m *limitedSyncMap[V]) Len() int { m.lenMux.Lock() defer m.lenMux.Unlock() return m.len } + +// hotColdMap manages two [limitedSyncMap] instances so that measurement and +// collection operate on separate maps and do not lock each other out. +// +// Measurements write to the currently hot map returned by [hotColdMap.hot] +// using the index from [hotColdWaitGroup.start]. Collection is performed by +// calling [hotColdWaitGroup.swapHotAndWait] to atomically swap the hot and cold +// maps and wait for in-flight writes to the cold map to complete. The caller +// can then read the cold map via [hotColdMap.Range] and must call +// [hotColdMap.Clear] on the cold index so that unused attribute sets do not +// report in subsequent collection cycles and the cardinality limit budget is +// reset. +// +// swapHotAndWait must not be called concurrently. +type hotColdMap[V any] struct { + hotColdWaitGroup + hotColdValMap [2]limitedSyncMap[V] +} + +func (m *hotColdMap[V]) init(limit int) { + m.hotColdValMap[0].aggLimit = limit + m.hotColdValMap[1].aggLimit = limit +} + +func (m *hotColdMap[V]) hot(i hotIdx) *limitedSyncMap[V] { + return &m.hotColdValMap[i] +} + +// Len returns the length of the specified map. +func (m *hotColdMap[V]) Len(readIdx coldIdx) int { + return m.hotColdValMap[readIdx].Len() +} + +// Range calls f sequentially for each key and value present in the map at readIdx. +func (m *hotColdMap[V]) Range(readIdx coldIdx, f func(key, value any) bool) { + m.hotColdValMap[readIdx].Range(f) +} + +// Clear clears the map at readIdx. +func (m *hotColdMap[V]) Clear(readIdx coldIdx) { + m.hotColdValMap[readIdx].Clear() +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/finish_sum.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/finish_sum.go new file mode 100644 index 000000000..d167acdae --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/finish_sum.go @@ -0,0 +1,313 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package aggregate + +import ( + "context" + "sync" + "sync/atomic" + "time" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/metric/internal/finish" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +type finishSumValue[N int64 | float64] struct { + lifecycle finish.Lifecycle + value atomicCounter[N] + attrs attribute.Set + start time.Time + dropExemplars bool + reservoir FilteredExemplarReservoir[N] +} + +func newFinishSumValue[N int64 | float64]( + attrs attribute.Set, + reservoir func(attribute.Set) FilteredExemplarReservoir[N], +) *finishSumValue[N] { + r := reservoir(attrs) + _, drop := r.(*dropRes[N]) + point := &finishSumValue[N]{ + attrs: attrs, + start: now(), + dropExemplars: drop, + reservoir: r, + } + return point +} + +func (v *finishSumValue[N]) measure( + ctx context.Context, + value N, + lazy lazyFilteredAttributes, +) bool { + measurement, ok := v.lifecycle.AcquireMeasurement() + if !ok { + return false + } + v.measureAcquired(ctx, value, lazy, measurement) + return true +} + +func (v *finishSumValue[N]) measureOverflow( + ctx context.Context, + value N, + lazy lazyFilteredAttributes, +) bool { + measurement, ok := v.lifecycle.AcquireSharedMeasurement() + if !ok { + return false + } + v.measureAcquired(ctx, value, lazy, measurement) + return true +} + +func (v *finishSumValue[N]) measureAcquired( + ctx context.Context, + value N, + lazy lazyFilteredAttributes, + measurement finish.Measurement, +) { + v.value.add(value) + if v.dropExemplars { + measurement.Release() + return + } + defer measurement.Release() + v.reservoir.Offer(ctx, value, lazy) +} + +func (v *finishSumValue[N]) finish(t time.Time) { + v.lifecycle.Finish(t) +} + +func (v *finishSumValue[N]) collectCumulative( + t time.Time, +) (metricdata.DataPoint[N], bool, bool) { + collection, ok := v.lifecycle.BeginCumulativeCollection(t) + if !ok { + return metricdata.DataPoint[N]{}, false, false + } + dp, retire := v.collect(v.start, collection) + return dp, true, retire +} + +func (v *finishSumValue[N]) collectDelta( + start time.Time, + t time.Time, +) (metricdata.DataPoint[N], bool, bool) { + collection, ok := v.lifecycle.BeginDeltaCollection(t) + if !ok { + return metricdata.DataPoint[N]{}, false, false + } + dp, retire := v.collect(start, collection) + return dp, true, retire +} + +func (v *finishSumValue[N]) collect( + start time.Time, + collection finish.Collection, +) (metricdata.DataPoint[N], bool) { + defer collection.Complete() + + dp := metricdata.DataPoint[N]{ + Attributes: v.attrs, + StartTime: start, + Time: collection.Time(), + Value: v.value.load(), + } + collectExemplars(&dp.Exemplars, v.reservoir.Collect) + return dp, collection.ShouldRetire() +} + +func (v *finishSumValue[N]) shutdown() { + v.lifecycle.Retire() +} + +// FinishSum contains the operations of a finish-aware Sum aggregation. +type FinishSum[N int64 | float64] struct { + Measure Measure[N] + ComputeAggregation ComputeAggregation + Finish func(attribute.Distinct, time.Time) + Shutdown func() +} + +type finishSum[N int64 | float64] struct { + collectMu sync.Mutex + shutdownOnce sync.Once + stopped atomic.Bool + + values limitedSyncMap[*finishSumValue[N]] + start time.Time + temporality metricdata.Temporality + monotonic bool + reservoir func(attribute.Set) FilteredExemplarReservoir[N] +} + +func newFinishSum[N int64 | float64]( + monotonic bool, + temporality metricdata.Temporality, + limit int, + reservoir func(attribute.Set) FilteredExemplarReservoir[N], +) *finishSum[N] { + var start time.Time + if temporality != metricdata.DeltaTemporality { + temporality = metricdata.CumulativeTemporality + } else { + start = now() + } + return &finishSum[N]{ + values: limitedSyncMap[*finishSumValue[N]]{ + aggLimit: limit, + }, + start: start, + temporality: temporality, + monotonic: monotonic, + reservoir: reservoir, + } +} + +func (s *finishSum[N]) measure( + ctx context.Context, + value N, + lazy lazyFilteredAttributes, +) { + for { + if s.stopped.Load() { + return + } + var initial finish.Measurement + point, loaded, overflowed := s.values.LoadOrStoreAttrReclaiming(lazy, func( + attrs attribute.Set, + overflow bool, + ) *finishSumValue[N] { + point := newFinishSumValue(attrs, s.reservoir) + // The point has not been published, so its new lifecycle cannot be + // retired and this initial measurement admission cannot fail. + if overflow { + initial, _ = point.lifecycle.AcquireSharedMeasurement() + } else { + initial, _ = point.lifecycle.AcquireMeasurement() + } + return point + }) + if !loaded { + point.measureAcquired(ctx, value, lazy, initial) + if s.stopped.Load() { + s.retireAndDelete(point) + } + return + } + if overflowed { + if point.measureOverflow(ctx, value, lazy) { + if s.stopped.Load() { + s.retireAndDelete(point) + } + return + } + continue + } + if point.measure(ctx, value, lazy) { + if s.stopped.Load() { + s.retireAndDelete(point) + } + return + } + s.values.CompareAndDelete(lazy.Distinct(), point) + } +} + +func (s *finishSum[N]) retireAndDelete(point *finishSumValue[N]) { + point.shutdown() + s.values.CompareAndDelete(point.attrs.Equivalent(), point) +} + +func (s *finishSum[N]) finish( + distinct attribute.Distinct, + t time.Time, +) { + if s.stopped.Load() { + return + } + value, ok := s.values.Load(distinct) + if !ok { + return + } + point := value.(*finishSumValue[N]) + point.finish(t) +} + +func (s *finishSum[N]) collect( + dest *metricdata.Aggregation, //nolint:gocritic // Required by ComputeAggregation. +) int { + s.collectMu.Lock() + defer s.collectMu.Unlock() + if s.stopped.Load() { + return 0 + } + + t := now() + start := s.start + if s.temporality == metricdata.DeltaTemporality { + s.start = t + } + sData, _ := (*dest).(metricdata.Sum[N]) + sData.Temporality = s.temporality + sData.IsMonotonic = s.monotonic + points := reset(sData.DataPoints, 0, s.values.Len()) + + s.values.Range(func(key, raw any) bool { + point := raw.(*finishSumValue[N]) + var dp metricdata.DataPoint[N] + var emit, retire bool + if s.temporality == metricdata.DeltaTemporality { + dp, emit, retire = point.collectDelta(start, t) + } else { + dp, emit, retire = point.collectCumulative(t) + } + if !emit { + return true + } + points = append(points, dp) + + if retire { + s.values.CompareAndDelete(key.(attribute.Distinct), point) + } + return true + }) + + sData.DataPoints = points + *dest = sData + return len(points) +} + +func (s *finishSum[N]) shutdown() { + s.shutdownOnce.Do(func() { + s.stopped.Store(true) + s.collectMu.Lock() + defer s.collectMu.Unlock() + s.values.Range(func(_, raw any) bool { + raw.(*finishSumValue[N]).shutdown() + return true + }) + s.values.Clear() + }) +} + +// FinishSum returns a Sum aggregation with exact-attribute lifecycle support. +func (b Builder[N]) FinishSum(monotonic bool) FinishSum[N] { + store := newFinishSum( + monotonic, + b.Temporality, + b.AggregationLimit, + b.resFunc(), + ) + return FinishSum[N]{ + Measure: b.filter(store.measure), + ComputeAggregation: store.collect, + Finish: store.finish, + Shutdown: store.shutdown, + } +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go index 89770dc20..152ae46ea 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go @@ -85,18 +85,8 @@ func (b *histogramPointCounters[N]) mergeIntoAndReset( // nolint:revive // Inten // deltaHistogram is a histogram whose internal storage is reset when it is // collected. -// -// deltaHistogram's measure is implemented without locking, even when called -// concurrently with collect. This is done by maintaining two separate maps: -// one "hot" which is concurrently updated by measure(), and one "cold", which -// is read and reset by collect(). The [hotcoldWaitGroup] allows collect() to -// swap the hot and cold maps, and wait for updates to the cold map to complete -// prior to reading. deltaHistogram swaps ald clears complete maps so that -// unused attribute sets do not report in subsequent collect() calls. type deltaHistogram[N int64 | float64] struct { - hcwg hotColdWaitGroup - hotColdValMap [2]limitedSyncMap[*histogramPoint[N]] - + vals hotColdMap[*histogramPoint[N]] start time.Time noMinMax bool noSum bool @@ -109,12 +99,13 @@ func (s *deltaHistogram[N]) measure( value N, lazy lazyFilteredAttributes, ) { - hotIdx := s.hcwg.start() - defer s.hcwg.done(hotIdx) - h := s.hotColdValMap[hotIdx].LoadOrStoreAttr(lazy, func(attr attribute.Set) *histogramPoint[N] { + hotIdx := s.vals.start() + defer s.vals.done(hotIdx) + + h := s.vals.hot(hotIdx).LoadOrStoreAttr(lazy, func(attr attribute.Set) *histogramPoint[N] { r := s.newRes(attr) _, isDrop := r.(*dropRes[N]) - hPt := &histogramPoint[N]{ + return &histogramPoint[N]{ res: r, attrs: attr, dropExemplars: isDrop, @@ -127,7 +118,6 @@ func (s *deltaHistogram[N]) measure( // counts = (-∞, 0], (0, 5.0], (5.0, 10.0], (10.0, +∞) histogramPointCounters: histogramPointCounters[N]{counts: make([]atomic.Uint64, len(s.bounds)+1)}, } - return hPt }) // This search will return an index in the range [0, len(s.bounds)], where @@ -162,17 +152,15 @@ func newDeltaHistogram[N int64 | float64]( // complete control over the fix. b := slices.Clone(boundaries) slices.Sort(b) - return &deltaHistogram[N]{ + h := &deltaHistogram[N]{ start: now(), noMinMax: noMinMax, noSum: noSum, bounds: b, newRes: r, - hotColdValMap: [2]limitedSyncMap[*histogramPoint[N]]{ - {aggLimit: limit}, - {aggLimit: limit}, - }, } + h.vals.init(limit) + return h } func (s *deltaHistogram[N]) collect( @@ -186,20 +174,19 @@ func (s *deltaHistogram[N]) collect( h.Temporality = metricdata.DeltaTemporality // delta always clears values on collection - readIdx := s.hcwg.swapHotAndWait() + readIdx := s.vals.swapHotAndWait() // Do not allow modification of our copy of bounds. bounds := slices.Clone(s.bounds) // The len will not change while we iterate over values, since we waited // for all writes to finish to the cold values and len. - n := s.hotColdValMap[readIdx].Len() + n := s.vals.Len(readIdx) hDPts := reset(h.DataPoints, n, n) var i int - s.hotColdValMap[readIdx].Range(func(_, value any) bool { + s.vals.Range(readIdx, func(_, value any) bool { val := value.(*histogramPoint[N]) - count := val.loadCountsInto(&hDPts[i].BucketCounts) hDPts[i].Attributes = val.attrs hDPts[i].StartTime = s.start @@ -222,12 +209,12 @@ func (s *deltaHistogram[N]) collect( } collectExemplars(&hDPts[i].Exemplars, val.res.Collect) - i++ return true }) // Unused attribute sets do not report. - s.hotColdValMap[readIdx].Clear() + s.vals.Clear(readIdx) + // The delta collection cycle resets. s.start = t @@ -403,7 +390,7 @@ func (s *cumulativeHistogram[N]) collect( } // Once we've read the point, merge it back into the hot histogram // point since it is cumulative. - hotIdx := (readIdx + 1) % 2 + hotIdx := hotIdx((readIdx + 1) % 2) val.hotColdPoint[readIdx].mergeIntoAndReset(&val.hotColdPoint[hotIdx], s.noMinMax, s.noSum) collectExemplars(&dp.Exemplars, val.res.Collect) diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go index ad68fac8d..8c9014345 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go @@ -21,18 +21,35 @@ type lastValuePoint[N int64 | float64] struct { dropExemplars bool } -// lastValueMap summarizes a set of measurements as the last one made. -type lastValueMap[N int64 | float64] struct { - newRes func(attribute.Set) FilteredExemplarReservoir[N] - values limitedSyncMap[*lastValuePoint[N]] +func newDeltaLastValue[N int64 | float64]( + limit int, + r func(attribute.Set) FilteredExemplarReservoir[N], +) *deltaLastValue[N] { + s := &deltaLastValue[N]{ + newRes: r, + start: now(), + } + s.vals.init(limit) + return s } -func (s *lastValueMap[N]) measure( +// deltaLastValue summarizes a set of measurements as the last one made. +type deltaLastValue[N int64 | float64] struct { + newRes func(attribute.Set) FilteredExemplarReservoir[N] + start time.Time + + vals hotColdMap[*lastValuePoint[N]] +} + +func (s *deltaLastValue[N]) measure( ctx context.Context, value N, lazy lazyFilteredAttributes, ) { - lv := s.values.LoadOrStoreAttr(lazy, func(attr attribute.Set) *lastValuePoint[N] { + hotIdx := s.vals.start() + defer s.vals.done(hotIdx) + + lv := s.vals.hot(hotIdx).LoadOrStoreAttr(lazy, func(attr attribute.Set) *lastValuePoint[N] { r := s.newRes(attr) _, isDrop := r.(*dropRes[N]) p := &lastValuePoint[N]{ @@ -51,45 +68,6 @@ func (s *lastValueMap[N]) measure( } } -func newDeltaLastValue[N int64 | float64]( - limit int, - r func(attribute.Set) FilteredExemplarReservoir[N], -) *deltaLastValue[N] { - return &deltaLastValue[N]{ - newRes: r, - start: now(), - hotColdValMap: [2]lastValueMap[N]{ - { - newRes: r, - values: limitedSyncMap[*lastValuePoint[N]]{aggLimit: limit}, - }, - { - newRes: r, - values: limitedSyncMap[*lastValuePoint[N]]{aggLimit: limit}, - }, - }, - } -} - -// deltaLastValue summarizes a set of measurements as the last one made. -type deltaLastValue[N int64 | float64] struct { - newRes func(attribute.Set) FilteredExemplarReservoir[N] - start time.Time - - hcwg hotColdWaitGroup - hotColdValMap [2]lastValueMap[N] -} - -func (s *deltaLastValue[N]) measure( - ctx context.Context, - value N, - lazy lazyFilteredAttributes, -) { - hotIdx := s.hcwg.start() - defer s.hcwg.done(hotIdx) - s.hotColdValMap[hotIdx].measure(ctx, value, lazy) -} - func (s *deltaLastValue[N]) collect( dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface ) int { @@ -110,14 +88,14 @@ func (s *deltaLastValue[N]) copyAndClearDpts( // the DataPoints is missed (better luck next time). gData, _ := (*dest).(metricdata.Gauge[N]) // delta always clears values on collection - readIdx := s.hcwg.swapHotAndWait() + readIdx := s.vals.swapHotAndWait() // The len will not change while we iterate over values, since we waited // for all writes to finish to the cold values and len. - n := s.hotColdValMap[readIdx].values.Len() + n := s.vals.Len(readIdx) dPts := reset(gData.DataPoints, n, n) var i int - s.hotColdValMap[readIdx].values.Range(func(_, value any) bool { + s.vals.Range(readIdx, func(_, value any) bool { v := value.(*lastValuePoint[N]) dPts[i].Attributes = v.attrs dPts[i].StartTime = s.start @@ -127,17 +105,19 @@ func (s *deltaLastValue[N]) copyAndClearDpts( i++ return true }) - gData.DataPoints = dPts // Do not report stale values. - s.hotColdValMap[readIdx].values.Clear() + s.vals.Clear(readIdx) + + gData.DataPoints = dPts *dest = gData return i } // cumulativeLastValue summarizes a set of measurements as the last one made. type cumulativeLastValue[N int64 | float64] struct { - lastValueMap[N] - start time.Time + values limitedSyncMap[*lastValuePoint[N]] + newRes func(attribute.Set) FilteredExemplarReservoir[N] + start time.Time } func newCumulativeLastValue[N int64 | float64]( @@ -145,11 +125,33 @@ func newCumulativeLastValue[N int64 | float64]( r func(attribute.Set) FilteredExemplarReservoir[N], ) *cumulativeLastValue[N] { return &cumulativeLastValue[N]{ - lastValueMap: lastValueMap[N]{ - newRes: r, - values: limitedSyncMap[*lastValuePoint[N]]{aggLimit: limit}, - }, - start: now(), + values: limitedSyncMap[*lastValuePoint[N]]{aggLimit: limit}, + newRes: r, + start: now(), + } +} + +func (s *cumulativeLastValue[N]) measure( + ctx context.Context, + value N, + lazy lazyFilteredAttributes, +) { + lv := s.values.LoadOrStoreAttr(lazy, func(attr attribute.Set) *lastValuePoint[N] { + r := s.newRes(attr) + _, isDrop := r.(*dropRes[N]) + p := &lastValuePoint[N]{ + res: r, + attrs: attr, + startTime: now(), + dropExemplars: isDrop, + } + p.value.Store(value) + return p + }) + + lv.value.Store(value) + if !lv.dropExemplars { + lv.res.Offer(ctx, value, lazy) } } diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go index c9a67cad8..ed3530cff 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go @@ -20,17 +20,37 @@ type sumValue[N int64 | float64] struct { dropExemplars bool } -type sumValueMap[N int64 | float64] struct { - newRes func(attribute.Set) FilteredExemplarReservoir[N] - values limitedSyncMap[*sumValue[N]] +// newDeltaSum returns an aggregator that summarizes a set of measurements as +// their arithmetic sum. Each sum is scoped by attributes and the aggregation +// cycle the measurements were made in. +func newDeltaSum[N int64 | float64]( + monotonic bool, + limit int, + r func(attribute.Set) FilteredExemplarReservoir[N], +) *deltaSum[N] { + s := &deltaSum[N]{ + monotonic: monotonic, + start: now(), + newRes: r, + } + s.vals.init(limit) + return s } -func (s *sumValueMap[N]) measure( - ctx context.Context, - value N, - lazy lazyFilteredAttributes, -) { - sv := s.values.LoadOrStoreAttr(lazy, func(attr attribute.Set) *sumValue[N] { +// deltaSum is the storage for sums which resets every collection interval. +type deltaSum[N int64 | float64] struct { + monotonic bool + start time.Time + + vals hotColdMap[*sumValue[N]] + newRes func(attribute.Set) FilteredExemplarReservoir[N] +} + +func (s *deltaSum[N]) measure(ctx context.Context, value N, lazy lazyFilteredAttributes) { + hotIdx := s.vals.start() + defer s.vals.done(hotIdx) + + sv := s.vals.hot(hotIdx).LoadOrStoreAttr(lazy, func(attr attribute.Set) *sumValue[N] { r := s.newRes(attr) _, isDrop := r.(*dropRes[N]) return &sumValue[N]{ @@ -41,53 +61,11 @@ func (s *sumValueMap[N]) measure( } }) sv.n.add(value) - // It is possible for collection to race with measurement and observe the - // exemplar in the batch of metrics after the add() for cumulative sums. - // This is an accepted tradeoff to avoid locking during measurement. if !sv.dropExemplars { sv.res.Offer(ctx, value, lazy) } } -// newDeltaSum returns an aggregator that summarizes a set of measurements as -// their arithmetic sum. Each sum is scoped by attributes and the aggregation -// cycle the measurements were made in. -func newDeltaSum[N int64 | float64]( - monotonic bool, - limit int, - r func(attribute.Set) FilteredExemplarReservoir[N], -) *deltaSum[N] { - return &deltaSum[N]{ - monotonic: monotonic, - start: now(), - hotColdValMap: [2]sumValueMap[N]{ - { - newRes: r, - values: limitedSyncMap[*sumValue[N]]{aggLimit: limit}, - }, - { - newRes: r, - values: limitedSyncMap[*sumValue[N]]{aggLimit: limit}, - }, - }, - } -} - -// deltaSum is the storage for sums which resets every collection interval. -type deltaSum[N int64 | float64] struct { - monotonic bool - start time.Time - - hcwg hotColdWaitGroup - hotColdValMap [2]sumValueMap[N] -} - -func (s *deltaSum[N]) measure(ctx context.Context, value N, lazy lazyFilteredAttributes) { - hotIdx := s.hcwg.start() - defer s.hcwg.done(hotIdx) - s.hotColdValMap[hotIdx].measure(ctx, value, lazy) -} - func (s *deltaSum[N]) collect( dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface ) int { @@ -100,14 +78,14 @@ func (s *deltaSum[N]) collect( sData.IsMonotonic = s.monotonic // delta always clears values on collection - readIdx := s.hcwg.swapHotAndWait() + readIdx := s.vals.swapHotAndWait() // The len will not change while we iterate over values, since we waited // for all writes to finish to the cold values and len. - n := s.hotColdValMap[readIdx].values.Len() + n := s.vals.Len(readIdx) dPts := reset(sData.DataPoints, n, n) var i int - s.hotColdValMap[readIdx].values.Range(func(_, value any) bool { + s.vals.Range(readIdx, func(_, value any) bool { val := value.(*sumValue[N]) collectExemplars(&dPts[i].Exemplars, val.res.Collect) dPts[i].Attributes = val.attrs @@ -117,7 +95,9 @@ func (s *deltaSum[N]) collect( i++ return true }) - s.hotColdValMap[readIdx].values.Clear() + // Unused attribute sets do not report. + s.vals.Clear(readIdx) + // The delta collection cycle resets. s.start = t @@ -138,19 +118,38 @@ func newCumulativeSum[N int64 | float64]( return &cumulativeSum[N]{ monotonic: monotonic, start: now(), - sumValueMap: sumValueMap[N]{ - newRes: r, - values: limitedSyncMap[*sumValue[N]]{aggLimit: limit}, - }, + values: limitedSyncMap[*sumValue[N]]{aggLimit: limit}, + newRes: r, } } -// deltaSum is the storage for sums which never reset. +// cumulativeSum is the storage for sums which never reset. type cumulativeSum[N int64 | float64] struct { monotonic bool start time.Time - sumValueMap[N] + values limitedSyncMap[*sumValue[N]] + newRes func(attribute.Set) FilteredExemplarReservoir[N] +} + +func (s *cumulativeSum[N]) measure(ctx context.Context, value N, lazy lazyFilteredAttributes) { + sv := s.values.LoadOrStoreAttr(lazy, func(attr attribute.Set) *sumValue[N] { + r := s.newRes(attr) + _, isDrop := r.(*dropRes[N]) + return &sumValue[N]{ + res: r, + attrs: attr, + startTime: now(), + dropExemplars: isDrop, + } + }) + sv.n.add(value) + // It is possible for collection to race with measurement and observe the + // exemplar in the batch of metrics after the add() for cumulative sums. + // This is an accepted tradeoff to avoid locking during measurement. + if !sv.dropExemplars { + sv.res.Offer(ctx, value, lazy) + } } func (s *cumulativeSum[N]) collect( @@ -209,7 +208,7 @@ func newPrecomputedSum[N int64 | float64]( r func(attribute.Set) FilteredExemplarReservoir[N], ) *precomputedSum[N] { return &precomputedSum[N]{ - deltaSum: newDeltaSum(monotonic, limit, r), + deltaSum: newDeltaSum[N](monotonic, limit, r), } } @@ -233,14 +232,14 @@ func (s *precomputedSum[N]) delta( sData.IsMonotonic = s.monotonic // delta always clears values on collection - readIdx := s.hcwg.swapHotAndWait() + readIdx := s.vals.swapHotAndWait() // The len will not change while we iterate over values, since we waited // for all writes to finish to the cold values and len. - n := s.hotColdValMap[readIdx].values.Len() + n := s.vals.Len(readIdx) dPts := reset(sData.DataPoints, n, n) var i int - s.hotColdValMap[readIdx].values.Range(func(key, value any) bool { + s.vals.Range(readIdx, func(key, value any) bool { val := value.(*sumValue[N]) n := val.n.load() @@ -254,7 +253,8 @@ func (s *precomputedSum[N]) delta( i++ return true }) - s.hotColdValMap[readIdx].values.Clear() + // Unused attribute sets do not report. + s.vals.Clear(readIdx) s.reported = newReported // The delta collection cycle resets. s.start = t @@ -277,14 +277,14 @@ func (s *precomputedSum[N]) cumulative( sData.IsMonotonic = s.monotonic // cumulative precomputed always clears values on collection - readIdx := s.hcwg.swapHotAndWait() + readIdx := s.vals.swapHotAndWait() // The len will not change while we iterate over values, since we waited // for all writes to finish to the cold values and len. - n := s.hotColdValMap[readIdx].values.Len() + n := s.vals.Len(readIdx) dPts := reset(sData.DataPoints, n, n) var i int - s.hotColdValMap[readIdx].values.Range(func(_, value any) bool { + s.vals.Range(readIdx, func(_, value any) bool { val := value.(*sumValue[N]) collectExemplars(&dPts[i].Exemplars, val.res.Collect) dPts[i].Attributes = val.attrs @@ -294,7 +294,8 @@ func (s *precomputedSum[N]) cumulative( i++ return true }) - s.hotColdValMap[readIdx].values.Clear() + // Unused attribute sets do not report. + s.vals.Clear(readIdx) sData.DataPoints = dPts *dest = sData diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/dedup.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/dedup.go index fe9ddc96d..3e183f557 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/dedup.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/dedup.go @@ -28,40 +28,43 @@ type rawValue struct { slice any } -// Value returns value with all map values deduplicated and whether it changed. +// ValueDedup returns value with all map values deduplicated and whether +// it changed. // // Duplicate map keys are resolved using last-value-wins semantics. -func Value(value attribute.Value) (attribute.Value, bool) { +func ValueDedup(value attribute.Value) (attribute.Value, bool) { switch value.Type() { case attribute.SLICE: - return deduplicateSliceValue(value) + return sliceValueDedup(value) case attribute.MAP: - return deduplicateMapValue(value) + return mapValueDedup(value) default: return value, false } } -// KeyValue returns kv with all map values deduplicated and whether it changed. -func KeyValue(kv attribute.KeyValue) (attribute.KeyValue, bool) { - value, changed := Value(kv.Value) +// KeyValueDedup returns kv with all map values deduplicated and whether +// it changed. +func KeyValueDedup(kv attribute.KeyValue) (attribute.KeyValue, bool) { + value, changed := ValueDedup(kv.Value) if changed { kv.Value = value } return kv, changed } -// KeyValues returns kvs with all map values deduplicated and whether they changed. +// KeyValuesDedup returns kvs with all map values deduplicated and whether +// they changed. // // The returned slice is the original kvs slice if no value needs // deduplication. Top-level keys in kvs are not deduplicated. -func KeyValues(kvs []attribute.KeyValue) ([]attribute.KeyValue, bool) { +func KeyValuesDedup(kvs []attribute.KeyValue) ([]attribute.KeyValue, bool) { // Preserve the caller's slice on the common no-op path. Once a changed // value is found, copy the prior values exactly once and fill the rest in // place as the scan continues. var normalized []attribute.KeyValue for i, kv := range kvs { - kv, changed := KeyValue(kv) + kv, changed := KeyValueDedup(kv) if normalized != nil { normalized[i] = kv continue @@ -80,22 +83,24 @@ func KeyValues(kvs []attribute.KeyValue) ([]attribute.KeyValue, bool) { return normalized, true } -// Set returns set with all map values deduplicated and whether it changed. +// SetDedup returns set with all map values deduplicated and whether it +// changed. // // The returned Set is the original set if no value needs deduplication. // Top-level key uniqueness remains attribute.Set's responsibility; this only // normalizes map attribute values. -func Set(set attribute.Set) (attribute.Set, bool) { - if set.Len() == 0 { +func SetDedup(set attribute.Set) (attribute.Set, bool) { + length := set.Len() + if length == 0 { return set, false } // Most attribute sets contain no duplicate map keys. Delay allocation until // the first changed value so the no-op path returns the original Set. var normalized []attribute.KeyValue - for i := range set.Len() { + for i := range length { kv, _ := set.Get(i) - kv, changed := KeyValue(kv) + kv, changed := KeyValueDedup(kv) if normalized != nil { normalized = append(normalized, kv) continue @@ -104,7 +109,7 @@ func Set(set attribute.Set) (attribute.Set, bool) { continue } - normalized = make([]attribute.KeyValue, 0, set.Len()) + normalized = make([]attribute.KeyValue, 0, length) for j := range i { prior, _ := set.Get(j) normalized = append(normalized, prior) @@ -118,7 +123,7 @@ func Set(set attribute.Set) (attribute.Set, bool) { return attribute.NewSet(normalized...), true } -func deduplicateSliceValue(value attribute.Value) (attribute.Value, bool) { +func sliceValueDedup(value attribute.Value) (attribute.Value, bool) { storage := valueStorage(value) length := valueLen(storage) @@ -127,7 +132,7 @@ func deduplicateSliceValue(value attribute.Value) (attribute.Value, bool) { var normalized []attribute.Value for i := range length { elem := valueAt(storage, i) - elem, changed := Value(elem) + elem, changed := ValueDedup(elem) if normalized != nil { normalized[i] = elem continue @@ -148,14 +153,14 @@ func deduplicateSliceValue(value attribute.Value) (attribute.Value, bool) { return attribute.SliceValue(normalized...), true } -func deduplicateMapValue(value attribute.Value) (attribute.Value, bool) { +func mapValueDedup(value attribute.Value) (attribute.Value, bool) { storage := valueStorage(value) length := keyValueLen(storage) if length <= 1 { // A single map entry cannot duplicate its own key, but its value might // contain a map or slice that needs recursive normalization. if length == 1 { - kv, changed := KeyValue(keyValueAt(storage, 0)) + kv, changed := KeyValueDedup(keyValueAt(storage, 0)) if changed { return attribute.MapValue(kv), true } @@ -174,13 +179,16 @@ func deduplicateMapValue(value attribute.Value) (attribute.Value, bool) { j++ } - kv, nestedChanged := KeyValue(keyValueAt(storage, j-1)) + kv, nestedChanged := KeyValueDedup(keyValueAt(storage, j-1)) // j-i > 1 means the current key run contained duplicates. changed := nestedChanged || j-i > 1 if normalized != nil { normalized = append(normalized, kv) } else if changed { - normalized = make([]attribute.KeyValue, 0, length) + if i == 0 && j == length { + return attribute.MapValue(kv), true + } + normalized = make([]attribute.KeyValue, 0, length-(j-i-1)) for k := range i { normalized = append(normalized, keyValueAt(storage, k)) } diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/distinct.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/distinct.go new file mode 100644 index 000000000..2bfc243da --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/distinct.go @@ -0,0 +1,110 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package attrnorm + +import ( + "cmp" + "slices" + + "go.opentelemetry.io/otel/attribute" +) + +// stackAttributes is the maximum number of unordered attributes copied to a +// stack buffer for canonicalization. Larger inputs use an allocated copy to +// keep sorting time bounded without modifying caller-owned attributes. +const stackAttributes = 10 + +// NewDistinct returns the identity of kvs after normalization and filtering. +// It does not retain or modify kvs. Duplicate keys use the last value supplied. +// The filter is called once for each unique normalized attribute in ascending +// key order. +func NewDistinct(kvs []attribute.KeyValue, filter attribute.Filter) attribute.Distinct { + if filter == nil { + if distinct, ok := tryUnfilteredDistinct(kvs); ok { + return distinct + } + } else if ordered(kvs) { + return orderedDistinct(kvs, filter) + } + if len(kvs) <= stackAttributes { + return sortedDistinct(kvs, filter) + } + return allocatedDistinct(kvs, filter) +} + +// tryUnfilteredDistinct hashes kvs while verifying their keys are ordered. The +// partial hash is discarded if an out-of-order key is found. +func tryUnfilteredDistinct(kvs []attribute.KeyValue) (attribute.Distinct, bool) { + hasher := attribute.NewHasher() + if len(kvs) == 0 { + return hasher.Distinct(), true + } + + // pending identifies the last value seen for the current key. + pending := 0 + for i := 1; i < len(kvs); i++ { + if kvs[i].Key < kvs[pending].Key { + return attribute.Distinct{}, false + } + if kvs[i].Key == kvs[pending].Key { + pending = i + continue + } + + normalized, _ := KeyValueDedup(kvs[pending]) + hasher.Write(normalized) + pending = i + } + + normalized, _ := KeyValueDedup(kvs[pending]) + hasher.Write(normalized) + return hasher.Distinct(), true +} + +// Keep this direct loop instead of slices.IsSortedFunc. It only needs a +// greater-than comparison and benchmarks faster for typical attribute counts. +func ordered(kvs []attribute.KeyValue) bool { + for i := 1; i < len(kvs); i++ { + if kvs[i-1].Key > kvs[i].Key { + return false + } + } + return true +} + +// orderedDistinct hashes key-values whose keys are in ascending order. Equal +// keys remain in input order so selecting the last retains last-value-wins. +func orderedDistinct(kvs []attribute.KeyValue, filter attribute.Filter) attribute.Distinct { + hasher := attribute.NewHasher() + for i := 0; i < len(kvs); { + j := i + 1 + for j < len(kvs) && kvs[j].Key == kvs[i].Key { + j++ + } + kv, _ := KeyValueDedup(kvs[j-1]) + if filter == nil || filter(kv) { + hasher.Write(kv) + } + i = j + } + return hasher.Distinct() +} + +func sortedDistinct(kvs []attribute.KeyValue, filter attribute.Filter) attribute.Distinct { + var scratch [stackAttributes]attribute.KeyValue + cpy := scratch[:len(kvs)] + copy(cpy, kvs) + return sortDistinct(cpy, filter) +} + +func allocatedDistinct(kvs []attribute.KeyValue, filter attribute.Filter) attribute.Distinct { + return sortDistinct(slices.Clone(kvs), filter) +} + +func sortDistinct(kvs []attribute.KeyValue, filter attribute.Filter) attribute.Distinct { + slices.SortStableFunc(kvs, func(a, b attribute.KeyValue) int { + return cmp.Compare(a.Key, b.Key) + }) + return orderedDistinct(kvs, filter) +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/doc.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/doc.go new file mode 100644 index 000000000..7dcd37370 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/doc.go @@ -0,0 +1,5 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Package finish coordinates the lifecycle of finish-aware metric series. +package finish diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/lifecycle.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/lifecycle.go new file mode 100644 index 000000000..2638fc77d --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/lifecycle.go @@ -0,0 +1,253 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package finish + +import ( + "runtime" + "sync" + "sync/atomic" + "time" +) + +type lifecycleState uint32 + +const ( + lifecycleActive lifecycleState = iota + lifecycleShared + lifecycleFinishPending + lifecycleRetired + lifecycleCollecting +) + +// Lifecycle coordinates measurements, explicit finishes, collections, and +// retirement for one metric series. Its zero value is ready for use. +// +// Lifecycle methods are safe to call concurrently. A successful measurement +// acquisition and an emitted collection must each be completed exactly once. +// A Lifecycle must not be copied after first use. +// +// The valid transitions are active to finish-pending on Finish, active or +// finish-pending to shared on a shared measurement, finish-pending to active on +// an ordinary measurement, any non-retired state to collecting on collection, +// and collecting to its prior state or retired when collection completes. +// Shared lifetimes ignore Finish. Retired is terminal. +type Lifecycle struct { + control sync.Mutex + state atomic.Uint32 + writers atomic.Uint64 + // finished is meaningful only while a pending finish is being collected. + // Reactivation leaves the old value in place so measurements remain lock-free. + finished time.Time +} + +// Measurement represents admission to update one metric-series lifetime. A +// successful call to Lifecycle.AcquireMeasurement returns a Measurement, which +// must be released exactly once after the aggregate and exemplars are updated. +type Measurement struct { + lifecycle *Lifecycle +} + +// Release completes the admitted measurement. +func (m Measurement) Release() { + m.lifecycle.releaseMeasurement() +} + +// Collection describes an exclusive collection phase for a metric-series +// lifetime. A Collection returned with true by a Lifecycle collection method +// must be completed exactly once after the aggregate and exemplars are read. +type Collection struct { + lifecycle *Lifecycle + time time.Time + restore lifecycleState + retire bool +} + +// Time returns the timestamp to use for the collected point. +func (c Collection) Time() time.Time { + return c.time +} + +// ShouldRetire reports whether Complete will retire the series lifetime. +func (c Collection) ShouldRetire() bool { + return c.retire +} + +// Complete ends the exclusive collection phase. It must be called exactly once. +func (c Collection) Complete() { + state := c.restore + if c.retire { + state = lifecycleRetired + } + c.lifecycle.finished = time.Time{} + c.lifecycle.state.Store(uint32(state)) + c.lifecycle.control.Unlock() +} + +// AcquireMeasurement reserves this series lifetime for a measurement. It waits +// for an in-progress collection and returns false only if the lifetime is +// retired. A successful acquisition must be paired with exactly one call to +// Measurement.Release after the aggregate and exemplars are updated. +func (l *Lifecycle) AcquireMeasurement() (Measurement, bool) { + for { + // Increment before checking state so a collection either waits for this + // attempt or closes admission before the attempt can update the aggregate. + l.writers.Add(1) + switch lifecycleState(l.state.Load()) { + case lifecycleActive, lifecycleShared: + return Measurement{lifecycle: l}, true + case lifecycleFinishPending: + if l.state.CompareAndSwap( + uint32(lifecycleFinishPending), + uint32(lifecycleActive), + ) { + return Measurement{lifecycle: l}, true + } + l.releaseMeasurement() + case lifecycleCollecting: + l.releaseMeasurement() + l.waitForCollection() + case lifecycleRetired: + l.releaseMeasurement() + return Measurement{}, false + } + } +} + +// AcquireSharedMeasurement reserves this series lifetime for a measurement and +// atomically makes the lifetime shared. A shared lifetime cannot be finished. +// It waits for an in-progress collection and returns false only if the lifetime +// is retired. A successful acquisition must be paired with exactly one call to +// Measurement.Release after the aggregate and exemplars are updated. +func (l *Lifecycle) AcquireSharedMeasurement() (Measurement, bool) { + for { + // Increment before checking state so a collection either waits for this + // attempt or closes admission before the attempt can update the aggregate. + l.writers.Add(1) + switch lifecycleState(l.state.Load()) { + case lifecycleShared: + return Measurement{lifecycle: l}, true + case lifecycleActive: + if l.state.CompareAndSwap( + uint32(lifecycleActive), + uint32(lifecycleShared), + ) { + return Measurement{lifecycle: l}, true + } + l.releaseMeasurement() + case lifecycleFinishPending: + if l.state.CompareAndSwap( + uint32(lifecycleFinishPending), + uint32(lifecycleShared), + ) { + return Measurement{lifecycle: l}, true + } + l.releaseMeasurement() + case lifecycleCollecting: + l.releaseMeasurement() + l.waitForCollection() + case lifecycleRetired: + l.releaseMeasurement() + return Measurement{}, false + } + } +} + +func (l *Lifecycle) waitForCollection() { + l.control.Lock() + l.control.Unlock() //nolint:gocritic,staticcheck // Lock acquisition parks until collection completes. +} + +func (l *Lifecycle) releaseMeasurement() { + // atomic.Uint64 has no subtraction operation. Adding MaxUint64 decrements + // the writer count modulo 2^64. A matching acquisition guarantees the count + // is nonzero. + l.writers.Add(^uint64(0)) +} + +// Finish marks an active series lifetime to be retired by its next collection +// at the supplied time. It returns false if the lifetime is already pending, +// shared, collecting, or retired. A measurement admitted after Finish +// reactivates the lifetime. +func (l *Lifecycle) Finish(at time.Time) bool { + l.control.Lock() + defer l.control.Unlock() + if !l.state.CompareAndSwap( + uint32(lifecycleActive), + uint32(lifecycleFinishPending), + ) { + return false + } + // Collection also holds control, so it cannot observe finish-pending before + // its timestamp is available. A concurrent measurement may reactivate or + // share the lifetime; in that case the timestamp is intentionally ignored. + l.finished = at + return true +} + +// BeginCumulativeCollection closes measurement admission and waits for admitted +// measurements to complete. An active or shared lifetime returns to its prior +// state when the returned Collection is completed; a finish-pending lifetime is +// retired. It returns false without a Collection if the lifetime is retired. A +// returned Collection must be completed exactly once. +func (l *Lifecycle) BeginCumulativeCollection(at time.Time) (Collection, bool) { + l.control.Lock() + collection, ok := l.beginCollection(at) + if !ok { + l.control.Unlock() + } + return collection, ok +} + +// BeginDeltaCollection closes measurement admission and waits for admitted +// measurements to complete. Every emitted lifetime is retired when the returned +// Collection is completed. It returns false without a Collection if the +// lifetime is retired. A returned Collection must be completed exactly once. +func (l *Lifecycle) BeginDeltaCollection(at time.Time) (Collection, bool) { + l.control.Lock() + collection, ok := l.beginCollection(at) + if !ok { + l.control.Unlock() + return Collection{}, false + } + collection.retire = true + return collection, true +} + +func (l *Lifecycle) beginCollection(at time.Time) (Collection, bool) { + state := lifecycleState(l.state.Load()) + if state == lifecycleRetired { + return Collection{}, false + } + state = lifecycleState(l.state.Swap(uint32(lifecycleCollecting))) + for l.writers.Load() != 0 { + runtime.Gosched() + } + + if state == lifecycleFinishPending { + return Collection{ + lifecycle: l, + time: l.finished, + restore: state, + retire: true, + }, true + } + return Collection{lifecycle: l, time: at, restore: state}, true +} + +// Retire permanently closes the series lifetime. It waits for admitted +// measurements to complete and has no effect if the lifetime is already +// retired. +func (l *Lifecycle) Retire() { + l.control.Lock() + defer l.control.Unlock() + if lifecycleState(l.state.Load()) == lifecycleRetired { + return + } + l.state.Store(uint32(lifecycleCollecting)) + for l.writers.Load() != 0 { + runtime.Gosched() + } + l.finished = time.Time{} + l.state.Store(uint32(lifecycleRetired)) +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md deleted file mode 100644 index 41a4c2996..000000000 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Experimental Features - -The Metric SDK contains features that have not yet stabilized in the OpenTelemetry specification. -These features are added to the OpenTelemetry Go Metric SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback. - -These feature may change in backwards incompatible ways as feedback is applied. -See the [Compatibility and Stability](#compatibility-and-stability) section for more information. - -## Features - -- [Metric Export Batch Size](#metric-export-batch-size) - -### Metric Export Batch Size - -The metric export can be split into batches before exporting by specifying a maximum number of data points per batch. - -This experimental feature can be enabled by setting the `OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE` environment variable. -The value MUST be a positive integer. -All other values or an empty value will result in the default behavior of not batching. - -#### Examples - -Enable metrics to be batched by maximum export batch size of 200. - -```console -export OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE=200 -``` - -Disable metric export batching. - -```console -unset OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE -``` - -## Compatibility and Stability - -Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../VERSIONING.md). -These features may be removed or modified in successive version releases, including patch versions. - -When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release. -There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version. -If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support. diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/features.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/features.go deleted file mode 100644 index a8268702a..000000000 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/features.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package x - -import "strconv" - -// MetricExportBatchSize is an experimental feature flag that controls the -// max export batch size for metric data. -// -// To enable this feature set the OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE environment -// variable to a positive integer value. -var MetricExportBatchSize = newFeature( - []string{"METRIC_EXPORT_BATCH_SIZE"}, - func(v string) (int, bool) { - val, err := strconv.Atoi(v) - if err == nil && val > 0 { - return val, true - } - return 0, false - }, -) diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go deleted file mode 100644 index fdb75b818..000000000 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// DO NOT MODIFY. Generated by gotmpl. -// source: internal/shared/x/x.go.tmpl - -// Package x documents experimental features for [go.opentelemetry.io/otel/sdk/metric]. -package x - -import ( - "os" -) - -// Feature is an experimental feature control flag. It provides a uniform way -// to interact with these feature flags and parse their values. -type Feature[T any] struct { - keys []string - parse func(v string) (T, bool) -} - -func newFeature[T any](suffix []string, parse func(string) (T, bool)) Feature[T] { - const envKeyRoot = "OTEL_GO_X_" - keys := make([]string, 0, len(suffix)) - for _, s := range suffix { - keys = append(keys, envKeyRoot+s) - } - return Feature[T]{ - keys: keys, - parse: parse, - } -} - -// Keys returns the environment variable keys that can be set to enable the -// feature. -func (f Feature[T]) Keys() []string { return f.keys } - -// Lookup returns the user-configured value for the feature and true if the -// user has enabled the feature. Otherwise, if the feature is not enabled, a -// zero value and false are returned. -func (f Feature[T]) Lookup() (v T, ok bool) { - // https://github.com/open-telemetry/opentelemetry-specification/blob/62effed618589a0bec416a87e559c0a9d96289bb/specification/configuration/sdk-environment-variables.md#parsing-empty-value - // - // > The SDK MUST interpret an empty value of an environment variable the - // > same way as when the variable is unset. - for _, key := range f.keys { - vRaw := os.Getenv(key) - if vRaw != "" { - return f.parse(vRaw) - } - } - return v, ok -} - -// Enabled reports whether the feature is enabled. -func (f Feature[T]) Enabled() bool { - _, ok := f.Lookup() - return ok -} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go b/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go index 1caed336e..3155a22bb 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go @@ -190,7 +190,7 @@ type ExponentialHistogramDataPoint[N int64 | float64] struct { type ExponentialBucket struct { // Offset is the bucket index of the first entry in the Counts slice. Offset int32 - // Counts is an slice where Counts[i] carries the count of the bucket at + // Counts is a slice where Counts[i] carries the count of the bucket at // index (Offset+i). Counts[i] is the count of values greater than // base^(Offset+i) and less than or equal to base^(Offset+i+1). Counts []uint64 diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go b/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go index 9f7712bd5..9405959c6 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go @@ -14,7 +14,6 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/sdk/metric/internal/observ" - "go.opentelemetry.io/otel/sdk/metric/internal/x" "go.opentelemetry.io/otel/sdk/metric/metricdata" semconv "go.opentelemetry.io/otel/semconv/v1.43.0" ) @@ -29,6 +28,7 @@ const ( type periodicReaderConfig struct { interval time.Duration timeout time.Duration + maxExportBatchSize int producers []Producer cardinalityLimitSelector CardinalityLimitSelector } @@ -99,6 +99,21 @@ func WithInterval(d time.Duration) PeriodicReaderOption { }) } +// WithMaxExportBatchSize configures the maximum number of metric data points in +// a batch that are exported at once. +// +// If this option is not used or size is less than or equal to zero, no limit is +// applied. +func WithMaxExportBatchSize(size int) PeriodicReaderOption { + return periodicReaderOptionFunc(func(conf periodicReaderConfig) periodicReaderConfig { + if size <= 0 { + return conf + } + conf.maxExportBatchSize = size + return conf + }) +} + // NewPeriodicReader returns a Reader that collects and exports metric data to // the exporter at a defined interval. By default, the returned Reader will // collect and export data every 60 seconds, and will cancel any attempts that @@ -116,6 +131,7 @@ func NewPeriodicReader(exporter Exporter, options ...PeriodicReaderOption) *Peri r := &PeriodicReader{ interval: conf.interval, timeout: conf.timeout, + batcher: batcher{size: conf.maxExportBatchSize}, exporter: exporter, flushCh: make(chan chan error), cancel: cancel, @@ -127,16 +143,8 @@ func NewPeriodicReader(exporter Exporter, options ...PeriodicReaderOption) *Peri }, }, } - if val, ok := x.MetricExportBatchSize.Lookup(); ok { - r.batcher = batcher{size: val} - } r.externalProducers.Store(conf.producers) - go func() { - defer func() { close(r.done) }() - r.run(ctx, conf.interval) - }() - var err error r.inst, err = observ.NewInstrumentation( semconv.OTelComponentTypePeriodicMetricReader.Value.AsString(), @@ -146,6 +154,11 @@ func NewPeriodicReader(exporter Exporter, options ...PeriodicReaderOption) *Peri otel.Handle(err) } + go func() { + defer func() { close(r.done) }() + r.run(ctx, conf.interval) + }() + return r } diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go b/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go index f04c2ddce..af705ea91 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go @@ -255,7 +255,7 @@ func (i *inserter[N]) Instrument( continue } matched = true - in, id, e := i.cachedAggregator(inst.Scope, inst.Kind, stream, readerAggregation) + in, id, e := i.cachedAggregator(inst.Scope, inst.Kind, stream, allowedKeys, readerAggregation) if e != nil { err = errors.Join(err, e) } @@ -284,13 +284,7 @@ func (i *inserter[N]) Instrument( Description: inst.Description, Unit: inst.Unit, } - // allowedKeys == nil indicates that the WithDefaultAttributes option was not passed, - // and all keys are allowed. An empty (non-nil) slice indicates that the option was passed - // with an empty set of keys, and no keys are allowed. - if allowedKeys != nil { - stream.AttributeFilter = attribute.NewAllowKeysFilter(allowedKeys...) - } - in, _, e := i.cachedAggregator(inst.Scope, inst.Kind, stream, readerAggregation) + in, _, e := i.cachedAggregator(inst.Scope, inst.Kind, stream, allowedKeys, readerAggregation) if e != nil { if err == nil { err = errCreatingAggregators @@ -364,6 +358,7 @@ func (i *inserter[N]) cachedAggregator( scope instrumentation.Scope, kind InstrumentKind, stream Stream, + allowedKeys []attribute.Key, readerAggregation Aggregation, ) (meas aggregate.Measure[N], aggID uint64, err error) { switch stream.Aggregation.(type) { @@ -378,6 +373,14 @@ func (i *inserter[N]) cachedAggregator( if stream.ExemplarReservoirProviderSelector == nil { stream.ExemplarReservoirProviderSelector = DefaultExemplarReservoirProviderSelector } + // If attribute_keys is not provided on the view (AttributeFilter == nil), + // use the advisory Attributes configured on the instrument (allowedKeys). + // allowedKeys == nil indicates that the WithDefaultAttributes option was not passed, + // and all keys are allowed. An empty (non-nil) slice indicates that the option was passed + // with an empty set of keys, and no keys are allowed. + if stream.AttributeFilter == nil && allowedKeys != nil { + stream.AttributeFilter = attribute.NewAllowKeysFilter(allowedKeys...) + } if err := isAggregatorCompatible(kind, stream.Aggregation); err != nil { return nil, 0, fmt.Errorf( diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go b/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go index 9f9f01f43..2a9f29ac2 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go @@ -77,7 +77,7 @@ func (mp *MeterProvider) Meter(name string, options ...metric.MeterOption) metri } c := metric.NewMeterConfig(options...) - attrs, _ := attrnorm.Set(c.InstrumentationAttributes()) + attrs, _ := attrnorm.SetDedup(c.InstrumentationAttributes()) s := instrumentation.Scope{ Name: name, Version: c.InstrumentationVersion(), diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/version.go b/vendor/go.opentelemetry.io/otel/sdk/metric/version.go index 615db8225..231009680 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/version.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/version.go @@ -5,5 +5,5 @@ package metric // version is the current release version of the metric SDK in use. func version() string { - return "1.46.0" + return "1.47.0" } diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/view.go b/vendor/go.opentelemetry.io/otel/sdk/metric/view.go index 3f98928f9..62ee9727a 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/metric/view.go +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/view.go @@ -44,7 +44,7 @@ type View func(Instrument) (Stream, bool) // the Instrument the View matches against will be use for the Name, // Description, and Unit of the returned Stream and no Aggregation or // AttributeFilter are set. All non-zero-value fields of mask are used instead -// of the default. If you need to zero out an Stream field returned from a +// of the default. If you need to zero out a Stream field returned from a // View, create a View directly. func NewView(criteria Instrument, mask Stream) View { if criteria.IsEmpty() { diff --git a/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go b/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go index dcd7280ac..1ab929a3a 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go +++ b/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go @@ -90,7 +90,7 @@ func NewSchemaless(attrs ...attribute.KeyValue) *Resource { return &Resource{} } - attrs, _ = attrnorm.KeyValues(attrs) + attrs, _ = attrnorm.KeyValuesDedup(attrs) // Ensure attributes comply with the specification: // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/common/README.md#attribute diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/batch_span_processor.go b/vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/batch_span_processor.go index 896ed517f..b55750a84 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/batch_span_processor.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/batch_span_processor.go @@ -47,6 +47,8 @@ type BSP struct { processedQueueFullOpts []metric.AddOption } +// NewBSP creates new instrumentation for a BatchSpanProcessor. +// It returns nil if observability is not enabled. func NewBSP(id int64, qLen func() int64, qMax int64) (*BSP, error) { if !x.Observability.Enabled() { return nil, nil @@ -108,12 +110,16 @@ func NewBSP(id int64, qLen func() int64, qMax int64) (*BSP, error) { }, err } +// Shutdown unregisters the callbacks registered by NewBSP. func (b *BSP) Shutdown() error { return b.reg.Unregister() } +// Processed records n spans as having finished processing successfully. func (b *BSP) Processed(ctx context.Context, n int64) { b.processed.Add(ctx, n, b.processedOpts...) } +// ProcessedQueueFull records n spans as having finished processing with a +// queue-full error. func (b *BSP) ProcessedQueueFull(ctx context.Context, n int64) { b.processed.Add(ctx, n, b.processedQueueFullOpts...) } diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/tracer.go b/vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/tracer.go index 3428aa894..16fad3c43 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/tracer.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/tracer.go @@ -30,6 +30,8 @@ type Tracer struct { started metric.Int64Counter } +// NewTracer creates new instrumentation for a Tracer. +// It returns an empty, disabled Tracer if observability is not enabled. func NewTracer() (Tracer, error) { if !x.Observability.Enabled() { return Tracer{}, nil @@ -52,8 +54,11 @@ func NewTracer() (Tracer, error) { return Tracer{enabled: true, live: l.Inst(), started: s.Inst()}, err } +// Enabled returns whether observability is enabled for t. func (t Tracer) Enabled() bool { return t.enabled } +// SpanStarted records the start of span, which was created with psc as its +// parent span context. func (t Tracer) SpanStarted(ctx context.Context, psc trace.SpanContext, span trace.Span) { if !t.started.Enabled(ctx) { return @@ -84,10 +89,12 @@ func (t Tracer) SpanStarted(ctx context.Context, psc trace.SpanContext, span tra t.started.Add(ctx, 1, opts...) } +// SpanLive records span as a live span. func (t Tracer) SpanLive(ctx context.Context, span trace.Span) { t.spanLive(ctx, 1, span) } +// SpanEnded records span as no longer being live. func (t Tracer) SpanEnded(ctx context.Context, span trace.Span) { t.spanLive(ctx, -1, span) } diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go b/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go index 6b2368413..ce615a1b0 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go @@ -150,7 +150,10 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T return noop.NewTracerProvider().Tracer(name, opts...) } c := trace.NewTracerConfig(opts...) - attrs, _ := attrnorm.Set(c.InstrumentationAttributes()) + attrs, _, _ := attrnorm.SetDedupLimitDepth( + c.InstrumentationAttributes(), + p.spanLimits.AttributeValueDepthLimit, + ) if name == "" { name = defaultTracerName } @@ -255,13 +258,14 @@ func (p *TracerProvider) UnregisterSpanProcessor(sp SpanProcessor) { idx = i } } - if stopOnce != nil { - stopOnce.state.Do(func() { - if err := sp.Shutdown(context.Background()); err != nil { - otel.Handle(err) - } - }) + if stopOnce == nil { + return } + stopOnce.state.Do(func() { + if err := sp.Shutdown(context.Background()); err != nil { + otel.Handle(err) + } + }) if len(spss) > 1 { copy(spss[idx:], spss[idx+1:]) } @@ -429,6 +433,29 @@ func WithSampler(s Sampler) TracerProviderOption { }) } +// WithAttributeValueDepthLimit sets the maximum allowed depth for attribute +// values. Depth starts at one for the top-level value and increments when +// descending into an array element or map value. An array or map beyond this +// depth is replaced by an empty value. +// +// This limit applies to span, event, link, and instrumentation scope +// attributes processed by this TracerProvider. It does not apply to Resource +// attributes. +// +// Setting this to zero means the default limit of 64 is used. Setting this to +// a negative value means no limit is applied. +// +// There is no environment variable for this limit. +func WithAttributeValueDepthLimit(limit int) TracerProviderOption { + if limit == 0 { + limit = DefaultAttributeValueDepthLimit + } + return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig { + cfg.spanLimits.AttributeValueDepthLimit = limit + return cfg + }) +} + // WithSpanLimits returns a TracerProviderOption that configures a // TracerProvider to use the SpanLimits sl. These SpanLimits bound any Span // created by a Tracer from the TracerProvider. @@ -448,6 +475,9 @@ func WithSpanLimits(sl SpanLimits) TracerProviderOption { if sl.AttributeValueLengthLimit <= 0 { sl.AttributeValueLengthLimit = DefaultAttributeValueLengthLimit } + if sl.AttributeValueDepthLimit <= 0 { + sl.AttributeValueDepthLimit = DefaultAttributeValueDepthLimit + } if sl.AttributeCountLimit <= 0 { sl.AttributeCountLimit = DefaultAttributeCountLimit } @@ -473,13 +503,14 @@ func WithSpanLimits(sl SpanLimits) TracerProviderOption { // TracerProvider to use these limits. These limits bound any Span created by // a Tracer from the TracerProvider. // -// The limits will be used as-is. Zero or negative values will not be changed -// to the default value like WithSpanLimits does. Setting a limit to zero will -// effectively disable the related resource it limits and setting to a -// negative value will mean that resource is unlimited. Consequentially, this -// means that the zero-value SpanLimits will disable all span resources. -// Because of this, limits should be constructed using NewSpanLimits and -// updated accordingly. +// The limits will be used as-is, except that an AttributeValueDepthLimit of +// zero means the default limit is used. Other zero or negative values will not +// be changed to the default value like WithSpanLimits does. Setting a limit to +// zero will effectively disable the related resource it limits and setting to +// a negative value will mean that resource is unlimited. Consequentially, the +// zero-value SpanLimits will disable all span resources except the attribute +// value depth limit. Because of this, limits should be constructed using +// NewSpanLimits and updated accordingly. // // If this or WithSpanLimits are not provided, the TracerProvider will use the // limits defined by environment variables, or the defaults if unset. Refer to @@ -525,5 +556,8 @@ func ensureValidTracerProviderConfig(cfg tracerProviderConfig) tracerProviderCon if cfg.resource == nil { cfg.resource = resource.Default() } + if cfg.spanLimits.AttributeValueDepthLimit == 0 { + cfg.spanLimits.AttributeValueDepthLimit = DefaultAttributeValueDepthLimit + } return cfg } diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go b/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go index b0fa94ed2..76cca5cd5 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go @@ -46,14 +46,13 @@ func (e samplerArgParseError) Unwrap() error { } func samplerFromEnv() (Sampler, error) { - sampler, ok := os.LookupEnv(tracesSamplerKey) - if !ok { + sampler := strings.ToLower(strings.TrimSpace(os.Getenv(tracesSamplerKey))) + if sampler == "" { return nil, nil } - sampler = strings.ToLower(strings.TrimSpace(sampler)) - samplerArg, hasSamplerArg := os.LookupEnv(tracesSamplerArgKey) - samplerArg = strings.TrimSpace(samplerArg) + samplerArg := strings.TrimSpace(os.Getenv(tracesSamplerArgKey)) + hasSamplerArg := samplerArg != "" switch sampler { case samplerAlwaysOn: diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go b/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go index 97985c498..1e6be1248 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/simple_span_processor.go @@ -104,10 +104,15 @@ func (ssp *simpleSpanProcessor) Shutdown(ctx context.Context) error { // span would need to be exported. Meaning, OnEnd would be called and // try acquiring the lock that is held here. ssp.exporterMu.Lock() - done, shutdown := stopFunc(ssp.exporter) + exp := ssp.exporter ssp.exporter = nil ssp.exporterMu.Unlock() + if exp == nil { + return + } + + done, shutdown := stopFunc(exp) go shutdown() // Wait for the exporter to shut down or the deadline to expire. diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go b/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go index 8893dc39f..6e0c06be5 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/snapshot.go @@ -12,7 +12,7 @@ import ( "go.opentelemetry.io/otel/trace" ) -// snapshot is an record of a spans state at a particular checkpointed time. +// snapshot is a record of a span's state at a particular checkpointed time. // It is used as a read-only representation of that state. type snapshot struct { name string diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/span.go b/vendor/go.opentelemetry.io/otel/sdk/trace/span.go index aae977314..05920ab87 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/span.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/span.go @@ -278,8 +278,11 @@ func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) { s.addDroppedAttr(1) continue } - a = dedupAttr(a) - a = attrnorm.Truncate(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a) + a = normAttr( + a, + s.tracer.provider.spanLimits.AttributeValueDepthLimit, + s.tracer.provider.spanLimits.AttributeValueLengthLimit, + ) s.attributes = append(s.attributes, a) s.attributesDirty = true } @@ -353,8 +356,11 @@ func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) { if idx, ok := exists[a.Key]; ok { // Perform all updates before dropping, even when at capacity. - a = dedupAttr(a) - a = attrnorm.Truncate(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a) + a = normAttr( + a, + s.tracer.provider.spanLimits.AttributeValueDepthLimit, + s.tracer.provider.spanLimits.AttributeValueLengthLimit, + ) s.attributes[idx] = a continue } @@ -364,22 +370,27 @@ func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) { // updates are checked and performed. s.addDroppedAttr(1) } else { - a = dedupAttr(a) - a = attrnorm.Truncate(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a) + a = normAttr( + a, + s.tracer.provider.spanLimits.AttributeValueDepthLimit, + s.tracer.provider.spanLimits.AttributeValueLengthLimit, + ) s.attributes = append(s.attributes, a) exists[a.Key] = len(s.attributes) - 1 } } } -func dedupAttr(attr attribute.KeyValue) attribute.KeyValue { +func normAttr(attr attribute.KeyValue, depthLimit, lengthLimit int) attribute.KeyValue { switch attr.Value.Type() { case attribute.SLICE, attribute.MAP: - attr, _ = attrnorm.KeyValue(attr) - return attr - default: - return attr + if depthLimit < 0 { + attr, _ = attrnorm.KeyValueDedup(attr) + } else { + attr, _, _ = attrnorm.KeyValueDedupLimitDepth(attr, depthLimit) + } } + return attrnorm.Truncate(lengthLimit, attr) } // End ends the span. This method does nothing if the span is already ended or @@ -483,9 +494,7 @@ func (s *recordingSpan) RecordError(err error, opts ...trace.EventOption) { return } - s.mu.Lock() - defer s.mu.Unlock() - if !s.isRecording() { + if !s.IsRecording() { return } @@ -501,7 +510,7 @@ func (s *recordingSpan) RecordError(err error, opts ...trace.EventOption) { )) } - s.addEvent(semconv.ExceptionEventName, opts...) + s.AddEvent(semconv.ExceptionEventName, opts...) } func typeStr(i any) string { @@ -540,7 +549,10 @@ func (s *recordingSpan) AddEvent(name string, o ...trace.EventOption) { // This method assumes s.mu.Lock is held by the caller. func (s *recordingSpan) addEvent(name string, o ...trace.EventOption) { c := trace.NewEventConfig(o...) - attrs, _ := attrnorm.KeyValues(c.Attributes()) + attrs, _, _ := attrnorm.KeyValuesDedupLimitDepth( + c.Attributes(), + s.tracer.provider.spanLimits.AttributeValueDepthLimit, + ) e := Event{Name: name, Attributes: attrs, Time: c.Timestamp()} // Discard attributes over limit. @@ -580,7 +592,7 @@ func (s *recordingSpan) Name() string { return s.name } -// Name returns the SpanContext of this span's parent span. +// Parent returns the SpanContext of this span's parent span. func (s *recordingSpan) Parent() trace.SpanContext { s.mu.Lock() defer s.mu.Unlock() @@ -720,7 +732,10 @@ func (s *recordingSpan) AddLink(link trace.Link) { return } - attrs, _ := attrnorm.KeyValues(link.Attributes) + attrs, _, _ := attrnorm.KeyValuesDedupLimitDepth( + link.Attributes, + s.tracer.provider.spanLimits.AttributeValueDepthLimit, + ) l := Link{SpanContext: link.SpanContext, Attributes: attrs} // Discard attributes over limit. diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go b/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go index 5ee15a884..3069e2269 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/span_limits.go @@ -10,6 +10,10 @@ const ( // attribute value length, unlimited. DefaultAttributeValueLengthLimit = -1 + // DefaultAttributeValueDepthLimit is the default maximum allowed depth for + // nested attribute values. + DefaultAttributeValueDepthLimit = 64 + // DefaultAttributeCountLimit is the default maximum number of attributes // a span can have. DefaultAttributeCountLimit = 128 @@ -43,6 +47,20 @@ type SpanLimits struct { // Setting this to a negative value means no limit is applied. AttributeValueLengthLimit int + // AttributeValueDepthLimit is the maximum allowed depth for an attribute + // value. Depth starts at one for the top-level value and increments when + // descending into an array element or map value. An array or map beyond this + // depth is replaced by an empty value. + // + // This limit applies to span, event, link, and instrumentation scope + // attributes processed by a TracerProvider. It does not apply to Resource + // attributes. + // + // Setting this to zero means the default limit is used. + // + // Setting this to a negative value means no limit is applied. + AttributeValueDepthLimit int + // AttributeCountLimit is the maximum allowed span attribute count. Any // attribute added to a span once this limit is reached will be dropped. // @@ -88,12 +106,15 @@ type SpanLimits struct { AttributePerLinkCountLimit int } -// NewSpanLimits returns a SpanLimits with all limits set to the value their -// corresponding environment variable holds, or the default if unset. +// NewSpanLimits returns a SpanLimits with all limits set to their default. +// Limits with a corresponding environment variable are set from the +// environment when the variable is defined. // // • AttributeValueLengthLimit: OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT // (default: unlimited) // +// • AttributeValueDepthLimit: default 64 (no environment variable) +// // • AttributeCountLimit: OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT (default: 128) // // • EventCountLimit: OTEL_SPAN_EVENT_COUNT_LIMIT (default: 128) @@ -107,6 +128,7 @@ type SpanLimits struct { func NewSpanLimits() SpanLimits { return SpanLimits{ AttributeValueLengthLimit: env.SpanAttributeValueLength(DefaultAttributeValueLengthLimit), + AttributeValueDepthLimit: DefaultAttributeValueDepthLimit, AttributeCountLimit: env.SpanAttributeCount(DefaultAttributeCountLimit), EventCountLimit: env.SpanEventCount(DefaultEventCountLimit), LinkCountLimit: env.SpanLinkCount(DefaultLinkCountLimit), diff --git a/vendor/go.opentelemetry.io/otel/sdk/version.go b/vendor/go.opentelemetry.io/otel/sdk/version.go index 621d6d7e6..2335ebdd7 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/version.go +++ b/vendor/go.opentelemetry.io/otel/sdk/version.go @@ -6,5 +6,5 @@ package sdk // Version is the current release version of the OpenTelemetry SDK in use. func Version() string { - return "1.46.0" + return "1.47.0" } diff --git a/vendor/go.opentelemetry.io/otel/trace/auto.go b/vendor/go.opentelemetry.io/otel/trace/auto.go index 17cf898cd..be4a96445 100644 --- a/vendor/go.opentelemetry.io/otel/trace/auto.go +++ b/vendor/go.opentelemetry.io/otel/trace/auto.go @@ -372,7 +372,7 @@ func convAttrValue(value attribute.Value) telemetry.Value { return telemetry.Value{} } -// truncate returns a truncated version of s such that it contains less than +// truncate returns a truncated version of s such that it contains at most // the limit number of characters. Truncation is applied by returning the limit // number of valid characters contained in s. // @@ -381,7 +381,7 @@ func convAttrValue(value attribute.Value) telemetry.Value { // UTF-8 is supported. When truncating, all invalid characters are dropped // before applying truncation. // -// If s already contains less than the limit number of bytes, it is returned +// If s already contains at most the limit number of bytes, it is returned // unchanged. No invalid characters are removed. func truncate(limit int, s string) string { // This prioritize performance in the following order based on the most @@ -407,6 +407,10 @@ func truncate(limit int, s string) string { continue } + // A zero limit also truncates a leading invalid byte or U+FFFD. + if limit == 0 { + return "" + } _, size := utf8.DecodeRuneInString(s[i:]) if size == 1 { // Invalid encoding. @@ -415,6 +419,12 @@ func truncate(limit int, s string) string { s = s[i:] break } + + // A valid U+FFFD still consumes one character of the limit. + count++ + if count > limit { + return s[:i] + } } // Fast-path, no invalid input. diff --git a/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/number.go b/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/number.go index 29e629d66..5bb3b16c7 100644 --- a/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/number.go +++ b/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/number.go @@ -41,7 +41,7 @@ func (i *protoInt64) UnmarshalJSON(data []byte) error { // strings or integers. type protoUint64 uint64 -// Int64 returns the protoUint64 as a uint64. +// Uint64 returns the protoUint64 as a uint64. func (i *protoUint64) Uint64() uint64 { return uint64(*i) } // UnmarshalJSON decodes both strings and integers. diff --git a/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/value.go b/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/value.go index 9d2d68063..b7b0e8b58 100644 --- a/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/value.go +++ b/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/value.go @@ -327,7 +327,7 @@ func (v Value) String() string { // Try to handle this as gracefully as possible. // // Don't panic here. The goal here is to have developers find this - // first if a slog.Kind is is not handled. It is + // first if a slog.Kind is not handled. It is // preferable to have user's open issue asking why their attributes // have a "unhandled: " prefix than say that their code is panicking. return fmt.Sprintf("", v.Kind()) diff --git a/vendor/go.opentelemetry.io/otel/trace/trace.go b/vendor/go.opentelemetry.io/otel/trace/trace.go index c4c383819..66b967e7d 100644 --- a/vendor/go.opentelemetry.io/otel/trace/trace.go +++ b/vendor/go.opentelemetry.io/otel/trace/trace.go @@ -134,13 +134,49 @@ func TraceIDFromHex(h string) (TraceID, error) { if len(h) != 32 { return [16]byte{}, errInvalidTraceIDLength } - var b [16]byte - invalidMark := byte(0) - for i := 0; i < len(h); i += 4 { - b[i/2] = (hexRev[h[i]] << 4) | hexRev[h[i+1]] - b[i/2+1] = (hexRev[h[i+2]] << 4) | hexRev[h[i+3]] - invalidMark |= hexRev[h[i]] | hexRev[h[i+1]] | hexRev[h[i+2]] | hexRev[h[i+3]] + // Decoding every character at a constant index allows the compiler to + // eliminate the bounds checks a loop over h would retain. + n0, n1 := hexRev[h[0]], hexRev[h[1]] + n2, n3 := hexRev[h[2]], hexRev[h[3]] + n4, n5 := hexRev[h[4]], hexRev[h[5]] + n6, n7 := hexRev[h[6]], hexRev[h[7]] + n8, n9 := hexRev[h[8]], hexRev[h[9]] + n10, n11 := hexRev[h[10]], hexRev[h[11]] + n12, n13 := hexRev[h[12]], hexRev[h[13]] + n14, n15 := hexRev[h[14]], hexRev[h[15]] + n16, n17 := hexRev[h[16]], hexRev[h[17]] + n18, n19 := hexRev[h[18]], hexRev[h[19]] + n20, n21 := hexRev[h[20]], hexRev[h[21]] + n22, n23 := hexRev[h[22]], hexRev[h[23]] + n24, n25 := hexRev[h[24]], hexRev[h[25]] + n26, n27 := hexRev[h[26]], hexRev[h[27]] + n28, n29 := hexRev[h[28]], hexRev[h[29]] + n30, n31 := hexRev[h[30]], hexRev[h[31]] + + b := [16]byte{ + (n0 << 4) | n1, + (n2 << 4) | n3, + (n4 << 4) | n5, + (n6 << 4) | n7, + (n8 << 4) | n9, + (n10 << 4) | n11, + (n12 << 4) | n13, + (n14 << 4) | n15, + (n16 << 4) | n17, + (n18 << 4) | n19, + (n20 << 4) | n21, + (n22 << 4) | n23, + (n24 << 4) | n25, + (n26 << 4) | n27, + (n28 << 4) | n29, + (n30 << 4) | n31, } + + invalidMark := n0 | n1 | n2 | n3 | n4 | n5 | n6 | n7 | + n8 | n9 | n10 | n11 | n12 | n13 | n14 | n15 | + n16 | n17 | n18 | n19 | n20 | n21 | n22 | n23 | + n24 | n25 | n26 | n27 | n28 | n29 | n30 | n31 + // If the upper 4 bits of any byte are not zero, there was an invalid hex // character since invalid hex characters are 0xff in hexRev. if invalidMark&0xf0 != 0 { @@ -160,13 +196,31 @@ func SpanIDFromHex(h string) (SpanID, error) { if len(h) != 16 { return [8]byte{}, errInvalidSpanIDLength } - var b [8]byte - invalidMark := byte(0) - for i := 0; i < len(h); i += 4 { - b[i/2] = (hexRev[h[i]] << 4) | hexRev[h[i+1]] - b[i/2+1] = (hexRev[h[i+2]] << 4) | hexRev[h[i+3]] - invalidMark |= hexRev[h[i]] | hexRev[h[i+1]] | hexRev[h[i+2]] | hexRev[h[i+3]] + // Decoding every character at a constant index allows the compiler to + // eliminate the bounds checks a loop over h would retain. + n0, n1 := hexRev[h[0]], hexRev[h[1]] + n2, n3 := hexRev[h[2]], hexRev[h[3]] + n4, n5 := hexRev[h[4]], hexRev[h[5]] + n6, n7 := hexRev[h[6]], hexRev[h[7]] + n8, n9 := hexRev[h[8]], hexRev[h[9]] + n10, n11 := hexRev[h[10]], hexRev[h[11]] + n12, n13 := hexRev[h[12]], hexRev[h[13]] + n14, n15 := hexRev[h[14]], hexRev[h[15]] + + b := [8]byte{ + (n0 << 4) | n1, + (n2 << 4) | n3, + (n4 << 4) | n5, + (n6 << 4) | n7, + (n8 << 4) | n9, + (n10 << 4) | n11, + (n12 << 4) | n13, + (n14 << 4) | n15, } + + invalidMark := n0 | n1 | n2 | n3 | n4 | n5 | n6 | n7 | + n8 | n9 | n10 | n11 | n12 | n13 | n14 | n15 + // If the upper 4 bits of any byte are not zero, there was an invalid hex // character since invalid hex characters are 0xff in hexRev. if invalidMark&0xf0 != 0 { diff --git a/vendor/go.opentelemetry.io/otel/trace/tracestate.go b/vendor/go.opentelemetry.io/otel/trace/tracestate.go index 9ac78fa04..062ceb2ad 100644 --- a/vendor/go.opentelemetry.io/otel/trace/tracestate.go +++ b/vendor/go.opentelemetry.io/otel/trace/tracestate.go @@ -283,7 +283,7 @@ func (ts TraceState) Walk(f func(key, value string) bool) { // specification an error is returned with the original TraceState. // // If adding a new list-member means the TraceState would have more members -// then is allowed, the new list-member will be inserted and the right-most +// than is allowed, the new list-member will be inserted and the right-most // list-member will be dropped in the returned TraceState. func (ts TraceState) Insert(key, value string) (TraceState, error) { m, err := newMember(key, value) diff --git a/vendor/go.opentelemetry.io/otel/version.go b/vendor/go.opentelemetry.io/otel/version.go index f599bf285..29ff1801f 100644 --- a/vendor/go.opentelemetry.io/otel/version.go +++ b/vendor/go.opentelemetry.io/otel/version.go @@ -5,5 +5,5 @@ package otel // Version is the current release version of OpenTelemetry in use. func Version() string { - return "1.46.0" + return "1.47.0" } diff --git a/vendor/go.opentelemetry.io/otel/versions.yaml b/vendor/go.opentelemetry.io/otel/versions.yaml index f329d171d..a0cb35f4d 100644 --- a/vendor/go.opentelemetry.io/otel/versions.yaml +++ b/vendor/go.opentelemetry.io/otel/versions.yaml @@ -3,7 +3,7 @@ module-sets: stable-v1: - version: v1.46.0 + version: v1.47.0 modules: - go.opentelemetry.io/otel - go.opentelemetry.io/otel/bridge/opencensus @@ -17,25 +17,29 @@ module-sets: - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric - go.opentelemetry.io/otel/exporters/stdout/stdouttrace - go.opentelemetry.io/otel/exporters/zipkin + - go.opentelemetry.io/otel/log - go.opentelemetry.io/otel/metric - go.opentelemetry.io/otel/sdk + - go.opentelemetry.io/otel/sdk/log - go.opentelemetry.io/otel/sdk/metric - go.opentelemetry.io/otel/trace experimental-metrics: - version: v0.68.0 + version: v0.69.0 modules: - go.opentelemetry.io/otel/exporters/prometheus - go.opentelemetry.io/otel/metric/x experimental-logs: - version: v0.22.0 + version: v0.23.0 modules: - - go.opentelemetry.io/otel/log - go.opentelemetry.io/otel/log/logtest - - go.opentelemetry.io/otel/sdk/log - go.opentelemetry.io/otel/sdk/log/logtest - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp - go.opentelemetry.io/otel/exporters/stdout/stdoutlog + experimental-traces: + version: v0.1.0 + modules: + - go.opentelemetry.io/otel/sdk/trace/x experimental-schema: version: v0.0.19 modules: diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.go b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.go index 8e13d157c..eb7fbc67b 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.go +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.go @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.21.6 +// protoc-gen-go v1.36.11 +// protoc v7.35.0 // source: opentelemetry/proto/collector/metrics/v1/metrics_service.proto package v1 @@ -26,6 +26,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -36,25 +37,22 @@ const ( ) type ExportMetricsServiceRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // An array of ResourceMetrics. // For data coming from a single resource this array will typically contain one // element. Intermediary nodes (such as OpenTelemetry Collector) that receive // data from multiple origins typically batch the data before forwarding further and // in that case this array will contain multiple elements. ResourceMetrics []*v1.ResourceMetrics `protobuf:"bytes,1,rep,name=resource_metrics,json=resourceMetrics,proto3" json:"resource_metrics,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExportMetricsServiceRequest) Reset() { *x = ExportMetricsServiceRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExportMetricsServiceRequest) String() string { @@ -65,7 +63,7 @@ func (*ExportMetricsServiceRequest) ProtoMessage() {} func (x *ExportMetricsServiceRequest) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -88,10 +86,7 @@ func (x *ExportMetricsServiceRequest) GetResourceMetrics() []*v1.ResourceMetrics } type ExportMetricsServiceResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The details of a partially successful export request. // // If the request is only partially accepted @@ -108,15 +103,15 @@ type ExportMetricsServiceResponse struct { // `error_message` = "") is equivalent to it not being set/present. Senders // SHOULD interpret it the same way as in the full success case. PartialSuccess *ExportMetricsPartialSuccess `protobuf:"bytes,1,opt,name=partial_success,json=partialSuccess,proto3" json:"partial_success,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExportMetricsServiceResponse) Reset() { *x = ExportMetricsServiceResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExportMetricsServiceResponse) String() string { @@ -127,7 +122,7 @@ func (*ExportMetricsServiceResponse) ProtoMessage() {} func (x *ExportMetricsServiceResponse) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -150,10 +145,7 @@ func (x *ExportMetricsServiceResponse) GetPartialSuccess() *ExportMetricsPartial } type ExportMetricsPartialSuccess struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The number of rejected data points. // // A `rejected_` field holding a `0` value indicates that the @@ -166,16 +158,16 @@ type ExportMetricsPartialSuccess struct { // // error_message is an optional field. An error_message with an empty value // is equivalent to it not being set. - ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` + ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExportMetricsPartialSuccess) Reset() { *x = ExportMetricsPartialSuccess{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExportMetricsPartialSuccess) String() string { @@ -186,7 +178,7 @@ func (*ExportMetricsPartialSuccess) ProtoMessage() {} func (x *ExportMetricsPartialSuccess) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -217,79 +209,34 @@ func (x *ExportMetricsPartialSuccess) GetErrorMessage() string { var File_opentelemetry_proto_collector_metrics_v1_metrics_service_proto protoreflect.FileDescriptor -var file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc = []byte{ - 0x0a, 0x3e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2f, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x28, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x2c, 0x6f, 0x70, 0x65, 0x6e, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x79, 0x0a, 0x1b, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x1c, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, - 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x22, 0x74, 0x0a, 0x1b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, - 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x12, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xac, 0x01, 0x0a, 0x0e, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x99, 0x01, - 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x45, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x46, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, - 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xa4, 0x01, 0x0a, 0x2b, 0x69, 0x6f, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x13, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x33, 0x67, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x74, 0x6c, 0x70, - 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x2f, 0x76, 0x31, 0xaa, 0x02, 0x28, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, - 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x56, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc = "" + + "\n" + + ">opentelemetry/proto/collector/metrics/v1/metrics_service.proto\x12(opentelemetry.proto.collector.metrics.v1\x1a,opentelemetry/proto/metrics/v1/metrics.proto\"y\n" + + "\x1bExportMetricsServiceRequest\x12Z\n" + + "\x10resource_metrics\x18\x01 \x03(\v2/.opentelemetry.proto.metrics.v1.ResourceMetricsR\x0fresourceMetrics\"\x8e\x01\n" + + "\x1cExportMetricsServiceResponse\x12n\n" + + "\x0fpartial_success\x18\x01 \x01(\v2E.opentelemetry.proto.collector.metrics.v1.ExportMetricsPartialSuccessR\x0epartialSuccess\"t\n" + + "\x1bExportMetricsPartialSuccess\x120\n" + + "\x14rejected_data_points\x18\x01 \x01(\x03R\x12rejectedDataPoints\x12#\n" + + "\rerror_message\x18\x02 \x01(\tR\ferrorMessage2\xac\x01\n" + + "\x0eMetricsService\x12\x99\x01\n" + + "\x06Export\x12E.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest\x1aF.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse\"\x00B\xa4\x01\n" + + "+io.opentelemetry.proto.collector.metrics.v1B\x13MetricsServiceProtoP\x01Z3go.opentelemetry.io/proto/otlp/collector/metrics/v1\xaa\x02(OpenTelemetry.Proto.Collector.Metrics.V1b\x06proto3" var ( file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescOnce sync.Once - file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData = file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData []byte ) func file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescGZIP() []byte { file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescOnce.Do(func() { - file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData) + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc), len(file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc))) }) return file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData } var file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3) -var file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_goTypes = []interface{}{ +var file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_goTypes = []any{ (*ExportMetricsServiceRequest)(nil), // 0: opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest (*ExportMetricsServiceResponse)(nil), // 1: opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse (*ExportMetricsPartialSuccess)(nil), // 2: opentelemetry.proto.collector.metrics.v1.ExportMetricsPartialSuccess @@ -312,49 +259,11 @@ func file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_init() if File_opentelemetry_proto_collector_metrics_v1_metrics_service_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExportMetricsServiceRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExportMetricsServiceResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExportMetricsPartialSuccess); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc), len(file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc)), NumEnums: 0, NumMessages: 3, NumExtensions: 0, @@ -365,7 +274,6 @@ func file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_init() MessageInfos: file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes, }.Build() File_opentelemetry_proto_collector_metrics_v1_metrics_service_proto = out.File - file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc = nil file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_goTypes = nil file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_depIdxs = nil } diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.gw.go b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.gw.go index c42f1454e..3da3d6f5d 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.gw.go +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.gw.go @@ -10,6 +10,7 @@ package v1 import ( "context" + "errors" "io" "net/http" @@ -24,62 +25,56 @@ import ( ) // Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray -var _ = metadata.Join +var ( + _ codes.Code + _ io.Reader + _ status.Status + _ = errors.New + _ = runtime.String + _ = utilities.NewDoubleArray + _ = metadata.Join +) func request_MetricsService_Export_0(ctx context.Context, marshaler runtime.Marshaler, client MetricsServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ExportMetricsServiceRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + var ( + protoReq ExportMetricsServiceRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.Export(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err - } func local_request_MetricsService_Export_0(ctx context.Context, marshaler runtime.Marshaler, server MetricsServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ExportMetricsServiceRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + var ( + protoReq ExportMetricsServiceRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.Export(ctx, &protoReq) return msg, metadata, err - } // RegisterMetricsServiceHandlerServer registers the http handlers for service MetricsService to "mux". // UnaryRPC :call MetricsServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMetricsServiceHandlerFromEndpoint instead. +// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. func RegisterMetricsServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MetricsServiceServer) error { - - mux.Handle("POST", pattern_MetricsService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_MetricsService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", runtime.WithHTTPPathPattern("/v1/metrics")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", runtime.WithHTTPPathPattern("/v1/metrics")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -91,9 +86,7 @@ func RegisterMetricsServiceHandlerServer(ctx context.Context, mux *runtime.Serve runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_MetricsService_Export_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) return nil @@ -102,25 +95,24 @@ func RegisterMetricsServiceHandlerServer(ctx context.Context, mux *runtime.Serve // RegisterMetricsServiceHandlerFromEndpoint is same as RegisterMetricsServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterMetricsServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.Dial(endpoint, opts...) + conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() - return RegisterMetricsServiceHandler(ctx, mux, conn) } @@ -134,16 +126,13 @@ func RegisterMetricsServiceHandler(ctx context.Context, mux *runtime.ServeMux, c // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MetricsServiceClient". // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MetricsServiceClient" // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "MetricsServiceClient" to call the correct interceptors. +// "MetricsServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares. func RegisterMetricsServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MetricsServiceClient) error { - - mux.Handle("POST", pattern_MetricsService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_MetricsService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", runtime.WithHTTPPathPattern("/v1/metrics")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", runtime.WithHTTPPathPattern("/v1/metrics")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -154,11 +143,8 @@ func RegisterMetricsServiceHandlerClient(ctx context.Context, mux *runtime.Serve runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_MetricsService_Export_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - return nil } diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service_grpc.pb.go b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service_grpc.pb.go index fc668643c..328b74a12 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service_grpc.pb.go +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service_grpc.pb.go @@ -1,7 +1,21 @@ +// Copyright 2019, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.1.0 -// - protoc v3.21.6 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v7.35.0 // source: opentelemetry/proto/collector/metrics/v1/metrics_service.proto package v1 @@ -15,12 +29,20 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + MetricsService_Export_FullMethodName = "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export" +) // MetricsServiceClient is the client API for MetricsService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Service that can be used to push metrics between one Application +// instrumented with OpenTelemetry and a collector, or between a collector and a +// central collector. type MetricsServiceClient interface { Export(ctx context.Context, in *ExportMetricsServiceRequest, opts ...grpc.CallOption) (*ExportMetricsServiceResponse, error) } @@ -34,8 +56,9 @@ func NewMetricsServiceClient(cc grpc.ClientConnInterface) MetricsServiceClient { } func (c *metricsServiceClient) Export(ctx context.Context, in *ExportMetricsServiceRequest, opts ...grpc.CallOption) (*ExportMetricsServiceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ExportMetricsServiceResponse) - err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", in, out, opts...) + err := c.cc.Invoke(ctx, MetricsService_Export_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -44,20 +67,28 @@ func (c *metricsServiceClient) Export(ctx context.Context, in *ExportMetricsServ // MetricsServiceServer is the server API for MetricsService service. // All implementations must embed UnimplementedMetricsServiceServer -// for forward compatibility +// for forward compatibility. +// +// Service that can be used to push metrics between one Application +// instrumented with OpenTelemetry and a collector, or between a collector and a +// central collector. type MetricsServiceServer interface { Export(context.Context, *ExportMetricsServiceRequest) (*ExportMetricsServiceResponse, error) mustEmbedUnimplementedMetricsServiceServer() } -// UnimplementedMetricsServiceServer must be embedded to have forward compatible implementations. -type UnimplementedMetricsServiceServer struct { -} +// UnimplementedMetricsServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedMetricsServiceServer struct{} func (UnimplementedMetricsServiceServer) Export(context.Context, *ExportMetricsServiceRequest) (*ExportMetricsServiceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Export not implemented") } func (UnimplementedMetricsServiceServer) mustEmbedUnimplementedMetricsServiceServer() {} +func (UnimplementedMetricsServiceServer) testEmbeddedByValue() {} // UnsafeMetricsServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to MetricsServiceServer will @@ -67,6 +98,13 @@ type UnsafeMetricsServiceServer interface { } func RegisterMetricsServiceServer(s grpc.ServiceRegistrar, srv MetricsServiceServer) { + // If the following call pancis, it indicates UnimplementedMetricsServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&MetricsService_ServiceDesc, srv) } @@ -80,7 +118,7 @@ func _MetricsService_Export_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", + FullMethod: MetricsService_Export_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MetricsServiceServer).Export(ctx, req.(*ExportMetricsServiceRequest)) diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service.pb.go b/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service.pb.go index c1af04e84..2234be22d 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service.pb.go +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service.pb.go @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.21.6 +// protoc-gen-go v1.36.11 +// protoc v7.35.0 // source: opentelemetry/proto/collector/trace/v1/trace_service.proto package v1 @@ -26,6 +26,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -36,25 +37,22 @@ const ( ) type ExportTraceServiceRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // An array of ResourceSpans. // For data coming from a single resource this array will typically contain one // element. Intermediary nodes (such as OpenTelemetry Collector) that receive // data from multiple origins typically batch the data before forwarding further and // in that case this array will contain multiple elements. ResourceSpans []*v1.ResourceSpans `protobuf:"bytes,1,rep,name=resource_spans,json=resourceSpans,proto3" json:"resource_spans,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExportTraceServiceRequest) Reset() { *x = ExportTraceServiceRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExportTraceServiceRequest) String() string { @@ -65,7 +63,7 @@ func (*ExportTraceServiceRequest) ProtoMessage() {} func (x *ExportTraceServiceRequest) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -88,10 +86,7 @@ func (x *ExportTraceServiceRequest) GetResourceSpans() []*v1.ResourceSpans { } type ExportTraceServiceResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The details of a partially successful export request. // // If the request is only partially accepted @@ -108,15 +103,15 @@ type ExportTraceServiceResponse struct { // `error_message` = "") is equivalent to it not being set/present. Senders // SHOULD interpret it the same way as in the full success case. PartialSuccess *ExportTracePartialSuccess `protobuf:"bytes,1,opt,name=partial_success,json=partialSuccess,proto3" json:"partial_success,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExportTraceServiceResponse) Reset() { *x = ExportTraceServiceResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExportTraceServiceResponse) String() string { @@ -127,7 +122,7 @@ func (*ExportTraceServiceResponse) ProtoMessage() {} func (x *ExportTraceServiceResponse) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -150,10 +145,7 @@ func (x *ExportTraceServiceResponse) GetPartialSuccess() *ExportTracePartialSucc } type ExportTracePartialSuccess struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The number of rejected spans. // // A `rejected_` field holding a `0` value indicates that the @@ -166,16 +158,16 @@ type ExportTracePartialSuccess struct { // // error_message is an optional field. An error_message with an empty value // is equivalent to it not being set. - ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` + ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExportTracePartialSuccess) Reset() { *x = ExportTracePartialSuccess{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExportTracePartialSuccess) String() string { @@ -186,7 +178,7 @@ func (*ExportTracePartialSuccess) ProtoMessage() {} func (x *ExportTracePartialSuccess) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -217,75 +209,34 @@ func (x *ExportTracePartialSuccess) GetErrorMessage() string { var File_opentelemetry_proto_collector_trace_v1_trace_service_proto protoreflect.FileDescriptor -var file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc = []byte{ - 0x0a, 0x3a, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2f, - 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x26, 0x6f, 0x70, - 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x74, 0x72, 0x61, 0x63, - 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x28, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, - 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6f, - 0x0a, 0x19, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x52, 0x0a, 0x0e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, - 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x22, - 0x88, 0x01, 0x0a, 0x1a, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, - 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, 0x74, - 0x69, 0x61, 0x6c, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x74, - 0x69, 0x61, 0x6c, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x67, 0x0a, 0x19, 0x45, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, - 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x6a, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0d, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x12, 0x23, - 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x32, 0xa2, 0x01, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x91, 0x01, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, - 0x41, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, - 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x54, - 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x42, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x9c, 0x01, 0x0a, 0x29, 0x69, 0x6f, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x74, 0x72, - 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x11, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x6f, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x69, 0x6f, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x74, 0x6c, 0x70, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x31, 0xaa, 0x02, - 0x26, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x54, - 0x72, 0x61, 0x63, 0x65, 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc = "" + + "\n" + + ":opentelemetry/proto/collector/trace/v1/trace_service.proto\x12&opentelemetry.proto.collector.trace.v1\x1a(opentelemetry/proto/trace/v1/trace.proto\"o\n" + + "\x19ExportTraceServiceRequest\x12R\n" + + "\x0eresource_spans\x18\x01 \x03(\v2+.opentelemetry.proto.trace.v1.ResourceSpansR\rresourceSpans\"\x88\x01\n" + + "\x1aExportTraceServiceResponse\x12j\n" + + "\x0fpartial_success\x18\x01 \x01(\v2A.opentelemetry.proto.collector.trace.v1.ExportTracePartialSuccessR\x0epartialSuccess\"g\n" + + "\x19ExportTracePartialSuccess\x12%\n" + + "\x0erejected_spans\x18\x01 \x01(\x03R\rrejectedSpans\x12#\n" + + "\rerror_message\x18\x02 \x01(\tR\ferrorMessage2\xa2\x01\n" + + "\fTraceService\x12\x91\x01\n" + + "\x06Export\x12A.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest\x1aB.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse\"\x00B\x9c\x01\n" + + ")io.opentelemetry.proto.collector.trace.v1B\x11TraceServiceProtoP\x01Z1go.opentelemetry.io/proto/otlp/collector/trace/v1\xaa\x02&OpenTelemetry.Proto.Collector.Trace.V1b\x06proto3" var ( file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescOnce sync.Once - file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescData = file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc + file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescData []byte ) func file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescGZIP() []byte { file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescOnce.Do(func() { - file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescData) + file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc), len(file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc))) }) return file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDescData } var file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3) -var file_opentelemetry_proto_collector_trace_v1_trace_service_proto_goTypes = []interface{}{ +var file_opentelemetry_proto_collector_trace_v1_trace_service_proto_goTypes = []any{ (*ExportTraceServiceRequest)(nil), // 0: opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest (*ExportTraceServiceResponse)(nil), // 1: opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse (*ExportTracePartialSuccess)(nil), // 2: opentelemetry.proto.collector.trace.v1.ExportTracePartialSuccess @@ -308,49 +259,11 @@ func file_opentelemetry_proto_collector_trace_v1_trace_service_proto_init() { if File_opentelemetry_proto_collector_trace_v1_trace_service_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExportTraceServiceRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExportTraceServiceResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExportTracePartialSuccess); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc), len(file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc)), NumEnums: 0, NumMessages: 3, NumExtensions: 0, @@ -361,7 +274,6 @@ func file_opentelemetry_proto_collector_trace_v1_trace_service_proto_init() { MessageInfos: file_opentelemetry_proto_collector_trace_v1_trace_service_proto_msgTypes, }.Build() File_opentelemetry_proto_collector_trace_v1_trace_service_proto = out.File - file_opentelemetry_proto_collector_trace_v1_trace_service_proto_rawDesc = nil file_opentelemetry_proto_collector_trace_v1_trace_service_proto_goTypes = nil file_opentelemetry_proto_collector_trace_v1_trace_service_proto_depIdxs = nil } diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service.pb.gw.go b/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service.pb.gw.go index bb1bd261e..b2cf91e2f 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service.pb.gw.go +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service.pb.gw.go @@ -10,6 +10,7 @@ package v1 import ( "context" + "errors" "io" "net/http" @@ -24,62 +25,56 @@ import ( ) // Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray -var _ = metadata.Join +var ( + _ codes.Code + _ io.Reader + _ status.Status + _ = errors.New + _ = runtime.String + _ = utilities.NewDoubleArray + _ = metadata.Join +) func request_TraceService_Export_0(ctx context.Context, marshaler runtime.Marshaler, client TraceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ExportTraceServiceRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + var ( + protoReq ExportTraceServiceRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.Export(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err - } func local_request_TraceService_Export_0(ctx context.Context, marshaler runtime.Marshaler, server TraceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ExportTraceServiceRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + var ( + protoReq ExportTraceServiceRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.Export(ctx, &protoReq) return msg, metadata, err - } // RegisterTraceServiceHandlerServer registers the http handlers for service TraceService to "mux". // UnaryRPC :call TraceServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterTraceServiceHandlerFromEndpoint instead. +// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. func RegisterTraceServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server TraceServiceServer) error { - - mux.Handle("POST", pattern_TraceService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_TraceService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/opentelemetry.proto.collector.trace.v1.TraceService/Export", runtime.WithHTTPPathPattern("/v1/traces")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/opentelemetry.proto.collector.trace.v1.TraceService/Export", runtime.WithHTTPPathPattern("/v1/traces")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -91,9 +86,7 @@ func RegisterTraceServiceHandlerServer(ctx context.Context, mux *runtime.ServeMu runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_TraceService_Export_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) return nil @@ -102,25 +95,24 @@ func RegisterTraceServiceHandlerServer(ctx context.Context, mux *runtime.ServeMu // RegisterTraceServiceHandlerFromEndpoint is same as RegisterTraceServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterTraceServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.Dial(endpoint, opts...) + conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() - return RegisterTraceServiceHandler(ctx, mux, conn) } @@ -134,16 +126,13 @@ func RegisterTraceServiceHandler(ctx context.Context, mux *runtime.ServeMux, con // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "TraceServiceClient". // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "TraceServiceClient" // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "TraceServiceClient" to call the correct interceptors. +// "TraceServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares. func RegisterTraceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client TraceServiceClient) error { - - mux.Handle("POST", pattern_TraceService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_TraceService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/opentelemetry.proto.collector.trace.v1.TraceService/Export", runtime.WithHTTPPathPattern("/v1/traces")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/opentelemetry.proto.collector.trace.v1.TraceService/Export", runtime.WithHTTPPathPattern("/v1/traces")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -154,11 +143,8 @@ func RegisterTraceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_TraceService_Export_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - return nil } diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service_grpc.pb.go b/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service_grpc.pb.go index 892864ea6..0c93f2da4 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service_grpc.pb.go +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/trace/v1/trace_service_grpc.pb.go @@ -1,7 +1,21 @@ +// Copyright 2019, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.1.0 -// - protoc v3.21.6 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v7.35.0 // source: opentelemetry/proto/collector/trace/v1/trace_service.proto package v1 @@ -15,12 +29,20 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + TraceService_Export_FullMethodName = "/opentelemetry.proto.collector.trace.v1.TraceService/Export" +) // TraceServiceClient is the client API for TraceService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Service that can be used to push spans between one Application instrumented with +// OpenTelemetry and a collector, or between a collector and a central collector (in this +// case spans are sent/received to/from multiple Applications). type TraceServiceClient interface { Export(ctx context.Context, in *ExportTraceServiceRequest, opts ...grpc.CallOption) (*ExportTraceServiceResponse, error) } @@ -34,8 +56,9 @@ func NewTraceServiceClient(cc grpc.ClientConnInterface) TraceServiceClient { } func (c *traceServiceClient) Export(ctx context.Context, in *ExportTraceServiceRequest, opts ...grpc.CallOption) (*ExportTraceServiceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ExportTraceServiceResponse) - err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.trace.v1.TraceService/Export", in, out, opts...) + err := c.cc.Invoke(ctx, TraceService_Export_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -44,20 +67,28 @@ func (c *traceServiceClient) Export(ctx context.Context, in *ExportTraceServiceR // TraceServiceServer is the server API for TraceService service. // All implementations must embed UnimplementedTraceServiceServer -// for forward compatibility +// for forward compatibility. +// +// Service that can be used to push spans between one Application instrumented with +// OpenTelemetry and a collector, or between a collector and a central collector (in this +// case spans are sent/received to/from multiple Applications). type TraceServiceServer interface { Export(context.Context, *ExportTraceServiceRequest) (*ExportTraceServiceResponse, error) mustEmbedUnimplementedTraceServiceServer() } -// UnimplementedTraceServiceServer must be embedded to have forward compatible implementations. -type UnimplementedTraceServiceServer struct { -} +// UnimplementedTraceServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedTraceServiceServer struct{} func (UnimplementedTraceServiceServer) Export(context.Context, *ExportTraceServiceRequest) (*ExportTraceServiceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Export not implemented") } func (UnimplementedTraceServiceServer) mustEmbedUnimplementedTraceServiceServer() {} +func (UnimplementedTraceServiceServer) testEmbeddedByValue() {} // UnsafeTraceServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to TraceServiceServer will @@ -67,6 +98,13 @@ type UnsafeTraceServiceServer interface { } func RegisterTraceServiceServer(s grpc.ServiceRegistrar, srv TraceServiceServer) { + // If the following call pancis, it indicates UnimplementedTraceServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&TraceService_ServiceDesc, srv) } @@ -80,7 +118,7 @@ func _TraceService_Export_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/opentelemetry.proto.collector.trace.v1.TraceService/Export", + FullMethod: TraceService_Export_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(TraceServiceServer).Export(ctx, req.(*ExportTraceServiceRequest)) diff --git a/vendor/go.opentelemetry.io/proto/otlp/common/v1/common.pb.go b/vendor/go.opentelemetry.io/proto/otlp/common/v1/common.pb.go index cef358000..626d8c600 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/common/v1/common.pb.go +++ b/vendor/go.opentelemetry.io/proto/otlp/common/v1/common.pb.go @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.21.6 +// protoc-gen-go v1.36.11 +// protoc v7.35.0 // source: opentelemetry/proto/common/v1/common.proto package v1 @@ -25,6 +25,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -38,14 +39,12 @@ const ( // primitive value such as a string or integer or it may contain an arbitrary nested // object containing arrays, key-value lists and primitives. type AnyValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The value is one of the listed fields. It is valid for all values to be unspecified // in which case this AnyValue is considered to be "empty". // - // Types that are assignable to Value: + // Types that are valid to be assigned to Value: + // // *AnyValue_StringValue // *AnyValue_BoolValue // *AnyValue_IntValue @@ -54,16 +53,16 @@ type AnyValue struct { // *AnyValue_KvlistValue // *AnyValue_BytesValue // *AnyValue_StringValueStrindex - Value isAnyValue_Value `protobuf_oneof:"value"` + Value isAnyValue_Value `protobuf_oneof:"value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AnyValue) Reset() { *x = AnyValue{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AnyValue) String() string { @@ -74,7 +73,7 @@ func (*AnyValue) ProtoMessage() {} func (x *AnyValue) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -89,65 +88,81 @@ func (*AnyValue) Descriptor() ([]byte, []int) { return file_opentelemetry_proto_common_v1_common_proto_rawDescGZIP(), []int{0} } -func (m *AnyValue) GetValue() isAnyValue_Value { - if m != nil { - return m.Value +func (x *AnyValue) GetValue() isAnyValue_Value { + if x != nil { + return x.Value } return nil } func (x *AnyValue) GetStringValue() string { - if x, ok := x.GetValue().(*AnyValue_StringValue); ok { - return x.StringValue + if x != nil { + if x, ok := x.Value.(*AnyValue_StringValue); ok { + return x.StringValue + } } return "" } func (x *AnyValue) GetBoolValue() bool { - if x, ok := x.GetValue().(*AnyValue_BoolValue); ok { - return x.BoolValue + if x != nil { + if x, ok := x.Value.(*AnyValue_BoolValue); ok { + return x.BoolValue + } } return false } func (x *AnyValue) GetIntValue() int64 { - if x, ok := x.GetValue().(*AnyValue_IntValue); ok { - return x.IntValue + if x != nil { + if x, ok := x.Value.(*AnyValue_IntValue); ok { + return x.IntValue + } } return 0 } func (x *AnyValue) GetDoubleValue() float64 { - if x, ok := x.GetValue().(*AnyValue_DoubleValue); ok { - return x.DoubleValue + if x != nil { + if x, ok := x.Value.(*AnyValue_DoubleValue); ok { + return x.DoubleValue + } } return 0 } func (x *AnyValue) GetArrayValue() *ArrayValue { - if x, ok := x.GetValue().(*AnyValue_ArrayValue); ok { - return x.ArrayValue + if x != nil { + if x, ok := x.Value.(*AnyValue_ArrayValue); ok { + return x.ArrayValue + } } return nil } func (x *AnyValue) GetKvlistValue() *KeyValueList { - if x, ok := x.GetValue().(*AnyValue_KvlistValue); ok { - return x.KvlistValue + if x != nil { + if x, ok := x.Value.(*AnyValue_KvlistValue); ok { + return x.KvlistValue + } } return nil } func (x *AnyValue) GetBytesValue() []byte { - if x, ok := x.GetValue().(*AnyValue_BytesValue); ok { - return x.BytesValue + if x != nil { + if x, ok := x.Value.(*AnyValue_BytesValue); ok { + return x.BytesValue + } } return nil } func (x *AnyValue) GetStringValueStrindex() int32 { - if x, ok := x.GetValue().(*AnyValue_StringValueStrindex); ok { - return x.StringValueStrindex + if x != nil { + if x, ok := x.Value.(*AnyValue_StringValueStrindex); ok { + return x.StringValueStrindex + } } return 0 } @@ -195,6 +210,8 @@ type AnyValue_StringValueStrindex struct { // empty, ignoring its semantic content for the non-Profiling signal. // // Status: [Alpha] + // + // [Since v1.10.0] StringValueStrindex int32 `protobuf:"varint,8,opt,name=string_value_strindex,json=stringValueStrindex,proto3,oneof"` } @@ -217,21 +234,18 @@ func (*AnyValue_StringValueStrindex) isAnyValue_Value() {} // ArrayValue is a list of AnyValue messages. We need ArrayValue as a message // since oneof in AnyValue does not allow repeated fields. type ArrayValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Array of values. The array may be empty (contain 0 elements). - Values []*AnyValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + Values []*AnyValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ArrayValue) Reset() { *x = ArrayValue{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ArrayValue) String() string { @@ -242,7 +256,7 @@ func (*ArrayValue) ProtoMessage() {} func (x *ArrayValue) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -270,26 +284,23 @@ func (x *ArrayValue) GetValues() []*AnyValue { // avoid unnecessary extra wrapping (which slows down the protocol). The 2 approaches // are semantically equivalent. type KeyValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // A collection of key/value pairs of key-value pairs. The list may be empty (may // contain 0 elements). // // The keys MUST be unique (it is not allowed to have more than one // value with the same key). // The behavior of software that receives duplicated keys can be unpredictable. - Values []*KeyValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + Values []*KeyValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *KeyValueList) Reset() { *x = KeyValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *KeyValueList) String() string { @@ -300,7 +311,7 @@ func (*KeyValueList) ProtoMessage() {} func (x *KeyValueList) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -325,10 +336,7 @@ func (x *KeyValueList) GetValues() []*KeyValue { // Represents a key-value pair that is used to store Span attributes, Link // attributes, etc. type KeyValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The key name of the pair. // key_strindex MUST NOT be set if key is used. Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` @@ -345,16 +353,18 @@ type KeyValue struct { // empty, ignoring its semantic content for the non-Profiling signal. // // Status: [Alpha] - KeyStrindex int32 `protobuf:"varint,3,opt,name=key_strindex,json=keyStrindex,proto3" json:"key_strindex,omitempty"` + // + // [Since v1.10.0] + KeyStrindex int32 `protobuf:"varint,3,opt,name=key_strindex,json=keyStrindex,proto3" json:"key_strindex,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *KeyValue) Reset() { *x = KeyValue{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *KeyValue) String() string { @@ -365,7 +375,7 @@ func (*KeyValue) ProtoMessage() {} func (x *KeyValue) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -404,10 +414,7 @@ func (x *KeyValue) GetKeyStrindex() int32 { // InstrumentationScope is a message representing the instrumentation scope information // such as the fully qualified name and version. type InstrumentationScope struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // A name denoting the Instrumentation scope. // An empty instrumentation scope name means the name is unknown. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -423,15 +430,15 @@ type InstrumentationScope struct { // can be discarded because their keys are too long or because there are too many // attributes. If this value is 0, then no attributes were dropped. DroppedAttributesCount uint32 `protobuf:"varint,4,opt,name=dropped_attributes_count,json=droppedAttributesCount,proto3" json:"dropped_attributes_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *InstrumentationScope) Reset() { *x = InstrumentationScope{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *InstrumentationScope) String() string { @@ -442,7 +449,7 @@ func (*InstrumentationScope) ProtoMessage() {} func (x *InstrumentationScope) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -489,11 +496,10 @@ func (x *InstrumentationScope) GetDroppedAttributesCount() uint32 { // Entity represents an object of interest associated with produced telemetry: e.g spans, metrics, profiles, or logs. // // Status: [Development] +// +// [Since v1.6.0] type EntityRef struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The Schema URL, if known. This is the identifier of the Schema that the entity data // is recorded in. To learn more about Schema URL see // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url @@ -518,15 +524,15 @@ type EntityRef struct { // These attribute keys are not part of entity's identity. // These keys MUST exist in the containing {message}.attributes. DescriptionKeys []string `protobuf:"bytes,4,rep,name=description_keys,json=descriptionKeys,proto3" json:"description_keys,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EntityRef) Reset() { *x = EntityRef{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *EntityRef) String() string { @@ -537,7 +543,7 @@ func (*EntityRef) ProtoMessage() {} func (x *EntityRef) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_common_v1_common_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -582,101 +588,60 @@ func (x *EntityRef) GetDescriptionKeys() []string { var File_opentelemetry_proto_common_v1_common_proto protoreflect.FileDescriptor -var file_opentelemetry_proto_common_v1_common_proto_rawDesc = []byte{ - 0x0a, 0x2a, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x6f, 0x70, - 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x22, 0x96, 0x03, 0x0a, 0x08, - 0x41, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, - 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, - 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, - 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, - 0x0c, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x72, 0x72, 0x61, 0x79, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x72, 0x72, 0x61, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x50, 0x0a, 0x0c, 0x6b, 0x76, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, - 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, - 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x6b, 0x76, 0x6c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x13, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x07, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4d, 0x0a, 0x0a, 0x41, 0x72, 0x72, 0x61, 0x79, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x41, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x0c, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, - 0x69, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x22, 0x7e, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x3d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6b, 0x65, 0x79, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x22, 0xc7, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x0a, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x16, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x41, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x82, - 0x01, 0x0a, 0x09, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x66, 0x12, 0x1d, 0x0a, 0x0a, - 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x55, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x17, 0x0a, 0x07, 0x69, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x06, 0x69, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, - 0x65, 0x79, 0x73, 0x42, 0x7b, 0x0a, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x67, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x6f, 0x74, 0x6c, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, - 0xaa, 0x02, 0x1d, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_opentelemetry_proto_common_v1_common_proto_rawDesc = "" + + "\n" + + "*opentelemetry/proto/common/v1/common.proto\x12\x1dopentelemetry.proto.common.v1\"\x96\x03\n" + + "\bAnyValue\x12#\n" + + "\fstring_value\x18\x01 \x01(\tH\x00R\vstringValue\x12\x1f\n" + + "\n" + + "bool_value\x18\x02 \x01(\bH\x00R\tboolValue\x12\x1d\n" + + "\tint_value\x18\x03 \x01(\x03H\x00R\bintValue\x12#\n" + + "\fdouble_value\x18\x04 \x01(\x01H\x00R\vdoubleValue\x12L\n" + + "\varray_value\x18\x05 \x01(\v2).opentelemetry.proto.common.v1.ArrayValueH\x00R\n" + + "arrayValue\x12P\n" + + "\fkvlist_value\x18\x06 \x01(\v2+.opentelemetry.proto.common.v1.KeyValueListH\x00R\vkvlistValue\x12!\n" + + "\vbytes_value\x18\a \x01(\fH\x00R\n" + + "bytesValue\x124\n" + + "\x15string_value_strindex\x18\b \x01(\x05H\x00R\x13stringValueStrindexB\a\n" + + "\x05value\"M\n" + + "\n" + + "ArrayValue\x12?\n" + + "\x06values\x18\x01 \x03(\v2'.opentelemetry.proto.common.v1.AnyValueR\x06values\"O\n" + + "\fKeyValueList\x12?\n" + + "\x06values\x18\x01 \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\x06values\"~\n" + + "\bKeyValue\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12=\n" + + "\x05value\x18\x02 \x01(\v2'.opentelemetry.proto.common.v1.AnyValueR\x05value\x12!\n" + + "\fkey_strindex\x18\x03 \x01(\x05R\vkeyStrindex\"\xc7\x01\n" + + "\x14InstrumentationScope\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + + "\aversion\x18\x02 \x01(\tR\aversion\x12G\n" + + "\n" + + "attributes\x18\x03 \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x128\n" + + "\x18dropped_attributes_count\x18\x04 \x01(\rR\x16droppedAttributesCount\"\x82\x01\n" + + "\tEntityRef\x12\x1d\n" + + "\n" + + "schema_url\x18\x01 \x01(\tR\tschemaUrl\x12\x12\n" + + "\x04type\x18\x02 \x01(\tR\x04type\x12\x17\n" + + "\aid_keys\x18\x03 \x03(\tR\x06idKeys\x12)\n" + + "\x10description_keys\x18\x04 \x03(\tR\x0fdescriptionKeysB{\n" + + " io.opentelemetry.proto.common.v1B\vCommonProtoP\x01Z(go.opentelemetry.io/proto/otlp/common/v1\xaa\x02\x1dOpenTelemetry.Proto.Common.V1b\x06proto3" var ( file_opentelemetry_proto_common_v1_common_proto_rawDescOnce sync.Once - file_opentelemetry_proto_common_v1_common_proto_rawDescData = file_opentelemetry_proto_common_v1_common_proto_rawDesc + file_opentelemetry_proto_common_v1_common_proto_rawDescData []byte ) func file_opentelemetry_proto_common_v1_common_proto_rawDescGZIP() []byte { file_opentelemetry_proto_common_v1_common_proto_rawDescOnce.Do(func() { - file_opentelemetry_proto_common_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_opentelemetry_proto_common_v1_common_proto_rawDescData) + file_opentelemetry_proto_common_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_common_v1_common_proto_rawDesc), len(file_opentelemetry_proto_common_v1_common_proto_rawDesc))) }) return file_opentelemetry_proto_common_v1_common_proto_rawDescData } var file_opentelemetry_proto_common_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_opentelemetry_proto_common_v1_common_proto_goTypes = []interface{}{ +var file_opentelemetry_proto_common_v1_common_proto_goTypes = []any{ (*AnyValue)(nil), // 0: opentelemetry.proto.common.v1.AnyValue (*ArrayValue)(nil), // 1: opentelemetry.proto.common.v1.ArrayValue (*KeyValueList)(nil), // 2: opentelemetry.proto.common.v1.KeyValueList @@ -703,81 +668,7 @@ func file_opentelemetry_proto_common_v1_common_proto_init() { if File_opentelemetry_proto_common_v1_common_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_opentelemetry_proto_common_v1_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AnyValue); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_common_v1_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ArrayValue); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_common_v1_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*KeyValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_common_v1_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*KeyValue); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_common_v1_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InstrumentationScope); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_common_v1_common_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EntityRef); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_opentelemetry_proto_common_v1_common_proto_msgTypes[0].OneofWrappers = []interface{}{ + file_opentelemetry_proto_common_v1_common_proto_msgTypes[0].OneofWrappers = []any{ (*AnyValue_StringValue)(nil), (*AnyValue_BoolValue)(nil), (*AnyValue_IntValue)(nil), @@ -791,7 +682,7 @@ func file_opentelemetry_proto_common_v1_common_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_opentelemetry_proto_common_v1_common_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_common_v1_common_proto_rawDesc), len(file_opentelemetry_proto_common_v1_common_proto_rawDesc)), NumEnums: 0, NumMessages: 6, NumExtensions: 0, @@ -802,7 +693,6 @@ func file_opentelemetry_proto_common_v1_common_proto_init() { MessageInfos: file_opentelemetry_proto_common_v1_common_proto_msgTypes, }.Build() File_opentelemetry_proto_common_v1_common_proto = out.File - file_opentelemetry_proto_common_v1_common_proto_rawDesc = nil file_opentelemetry_proto_common_v1_common_proto_goTypes = nil file_opentelemetry_proto_common_v1_common_proto_depIdxs = nil } diff --git a/vendor/go.opentelemetry.io/proto/otlp/metrics/v1/metrics.pb.go b/vendor/go.opentelemetry.io/proto/otlp/metrics/v1/metrics.pb.go index e148ddd13..55b7d1bb2 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/metrics/v1/metrics.pb.go +++ b/vendor/go.opentelemetry.io/proto/otlp/metrics/v1/metrics.pb.go @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.21.6 +// protoc-gen-go v1.36.11 +// protoc v7.35.0 // source: opentelemetry/proto/metrics/v1/metrics.proto package v1 @@ -27,6 +27,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -56,18 +57,18 @@ const ( // it receives and reports the sum of these requests every second as a // DELTA metric: // - // 1. The system starts receiving at time=t_0. - // 2. A request is received, the system measures 1 request. - // 3. A request is received, the system measures 1 request. - // 4. A request is received, the system measures 1 request. - // 5. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_0 to - // t_0+1 with a value of 3. - // 6. A request is received, the system measures 1 request. - // 7. A request is received, the system measures 1 request. - // 8. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_0+1 to - // t_0+2 with a value of 2. + // 1. The system starts receiving at time=t_0. + // 2. A request is received, the system measures 1 request. + // 3. A request is received, the system measures 1 request. + // 4. A request is received, the system measures 1 request. + // 5. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+1 with a value of 3. + // 6. A request is received, the system measures 1 request. + // 7. A request is received, the system measures 1 request. + // 8. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0+1 to + // t_0+2 with a value of 2. AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA AggregationTemporality = 1 // CUMULATIVE is an AggregationTemporality for a metric aggregator which // reports changes since a fixed start time. This means that current values @@ -81,24 +82,24 @@ const ( // it receives and reports the sum of these requests every second as a // CUMULATIVE metric: // - // 1. The system starts receiving at time=t_0. - // 2. A request is received, the system measures 1 request. - // 3. A request is received, the system measures 1 request. - // 4. A request is received, the system measures 1 request. - // 5. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_0 to - // t_0+1 with a value of 3. - // 6. A request is received, the system measures 1 request. - // 7. A request is received, the system measures 1 request. - // 8. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_0 to - // t_0+2 with a value of 5. - // 9. The system experiences a fault and loses state. - // 10. The system recovers and resumes receiving at time=t_1. - // 11. A request is received, the system measures 1 request. - // 12. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_1 to - // t_0+1 with a value of 1. + // 1. The system starts receiving at time=t_0. + // 2. A request is received, the system measures 1 request. + // 3. A request is received, the system measures 1 request. + // 4. A request is received, the system measures 1 request. + // 5. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+1 with a value of 3. + // 6. A request is received, the system measures 1 request. + // 7. A request is received, the system measures 1 request. + // 8. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+2 with a value of 5. + // 9. The system experiences a fault and loses state. + // 10. The system recovers and resumes receiving at time=t_1. + // 11. A request is received, the system measures 1 request. + // 12. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_1 to + // t_0+1 with a value of 1. // // Note: Even though, when reporting changes since last report time, using // CUMULATIVE is valid, it is not recommended. This may cause problems for @@ -153,8 +154,7 @@ func (AggregationTemporality) EnumDescriptor() ([]byte, []int) { // enum is a bit-mask. To test the presence of a single flag in the flags of // a data point, for example, use an expression like: // -// (point.flags & DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK) == DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK -// +// (point.flags & DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK) == DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK type DataPointFlags int32 const ( @@ -212,21 +212,22 @@ func (DataPointFlags) EnumDescriptor() ([]byte, []int) { // // MetricsData // └─── ResourceMetrics -// ├── Resource -// ├── SchemaURL -// └── ScopeMetrics -// ├── Scope -// ├── SchemaURL -// └── Metric -// ├── Name -// ├── Description -// ├── Unit -// └── data -// ├── Gauge -// ├── Sum -// ├── Histogram -// ├── ExponentialHistogram -// └── Summary +// +// ├── Resource +// ├── SchemaURL +// └── ScopeMetrics +// ├── Scope +// ├── SchemaURL +// └── Metric +// ├── Name +// ├── Description +// ├── Unit +// └── data +// ├── Gauge +// ├── Sum +// ├── Histogram +// ├── ExponentialHistogram +// └── Summary // // The main difference between this message and collector protocol is that // in this message there will not be any "control" or "metadata" specific to @@ -235,25 +236,22 @@ func (DataPointFlags) EnumDescriptor() ([]byte, []int) { // When new fields are added into this message, the OTLP request MUST be updated // as well. type MetricsData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // An array of ResourceMetrics. // For data coming from a single resource this array will typically contain // one element. Intermediary nodes that receive data from multiple origins // typically batch the data before forwarding further and in that case this // array will contain multiple elements. ResourceMetrics []*ResourceMetrics `protobuf:"bytes,1,rep,name=resource_metrics,json=resourceMetrics,proto3" json:"resource_metrics,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MetricsData) Reset() { *x = MetricsData{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MetricsData) String() string { @@ -264,7 +262,7 @@ func (*MetricsData) ProtoMessage() {} func (x *MetricsData) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -288,10 +286,7 @@ func (x *MetricsData) GetResourceMetrics() []*ResourceMetrics { // A collection of ScopeMetrics from a Resource. type ResourceMetrics struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The resource for the metrics in this message. // If this field is not set then no resource info is known. Resource *v1.Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` @@ -303,16 +298,16 @@ type ResourceMetrics struct { // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url // This schema_url applies to the data in the "resource" field. It does not apply // to the data in the "scope_metrics" field which have their own schema_url field. - SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` + SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ResourceMetrics) Reset() { *x = ResourceMetrics{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ResourceMetrics) String() string { @@ -323,7 +318,7 @@ func (*ResourceMetrics) ProtoMessage() {} func (x *ResourceMetrics) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -361,10 +356,7 @@ func (x *ResourceMetrics) GetSchemaUrl() string { // A collection of Metrics produced by an Scope. type ScopeMetrics struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The instrumentation scope information for the metrics in this message. // Semantically when InstrumentationScope isn't set, it is equivalent with // an empty instrumentation scope name (unknown). @@ -377,16 +369,16 @@ type ScopeMetrics struct { // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url // This schema_url applies to the data in the "scope" field and all metrics in the // "metrics" field. - SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` + SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ScopeMetrics) Reset() { *x = ScopeMetrics{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ScopeMetrics) String() string { @@ -397,7 +389,7 @@ func (*ScopeMetrics) ProtoMessage() {} func (x *ScopeMetrics) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -436,65 +428,68 @@ func (x *ScopeMetrics) GetSchemaUrl() string { // Defines a Metric which has one or more timeseries. The following is a // brief summary of the Metric data model. For more details, see: // -// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md +// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md // // The data model and relation between entities is shown in the // diagram below. Here, "DataPoint" is the term used to refer to any // one of the specific data point value types, and "points" is the term used // to refer to any one of the lists of points contained in the Metric. // -// - Metric is composed of a metadata and data. -// - Metadata part contains a name, description, unit. -// - Data is one of the possible types (Sum, Gauge, Histogram, Summary). -// - DataPoint contains timestamps, attributes, and one of the possible value type -// fields. +// - Metric is composed of a metadata and data. // -// Metric -// +------------+ -// |name | -// |description | -// |unit | +------------------------------------+ -// |data |---> |Gauge, Sum, Histogram, Summary, ... | -// +------------+ +------------------------------------+ +// - Metadata part contains a name, description, unit. // -// Data [One of Gauge, Sum, Histogram, Summary, ...] -// +-----------+ -// |... | // Metadata about the Data. -// |points |--+ -// +-----------+ | -// | +---------------------------+ -// | |DataPoint 1 | -// v |+------+------+ +------+ | -// +-----+ ||label |label |...|label | | -// | 1 |-->||value1|value2|...|valueN| | -// +-----+ |+------+------+ +------+ | -// | . | |+-----+ | -// | . | ||value| | -// | . | |+-----+ | -// | . | +---------------------------+ -// | . | . -// | . | . -// | . | . -// | . | +---------------------------+ -// | . | |DataPoint M | -// +-----+ |+------+------+ +------+ | -// | M |-->||label |label |...|label | | -// +-----+ ||value1|value2|...|valueN| | -// |+------+------+ +------+ | -// |+-----+ | -// ||value| | -// |+-----+ | -// +---------------------------+ +// - Data is one of the possible types (Sum, Gauge, Histogram, Summary). +// +// - DataPoint contains timestamps, attributes, and one of the possible value type +// fields. +// +// Metric +// +------------+ +// |name | +// |description | +// |unit | +------------------------------------+ +// |data |---> |Gauge, Sum, Histogram, Summary, ... | +// +------------+ +------------------------------------+ +// +// Data [One of Gauge, Sum, Histogram, Summary, ...] +// +-----------+ +// |... | // Metadata about the Data. +// |points |--+ +// +-----------+ | +// | +---------------------------+ +// | |DataPoint 1 | +// v |+------+------+ +------+ | +// +-----+ ||label |label |...|label | | +// | 1 |-->||value1|value2|...|valueN| | +// +-----+ |+------+------+ +------+ | +// | . | |+-----+ | +// | . | ||value| | +// | . | |+-----+ | +// | . | +---------------------------+ +// | . | . +// | . | . +// | . | . +// | . | +---------------------------+ +// | . | |DataPoint M | +// +-----+ |+------+------+ +------+ | +// | M |-->||label |label |...|label | | +// +-----+ ||value1|value2|...|valueN| | +// |+------+------+ +------+ | +// |+-----+ | +// ||value| | +// |+-----+ | +// +---------------------------+ // // Each distinct type of DataPoint represents the output of a specific // aggregation function, the result of applying the DataPoint's // associated function of to one or more measurements. // // All DataPoint types have three common fields: -// - Attributes includes key-value pairs associated with the data point -// - TimeUnixNano is required, set to the end time of the aggregation -// - StartTimeUnixNano is optional, but strongly encouraged for DataPoints -// having an AggregationTemporality field, as discussed below. +// - Attributes includes key-value pairs associated with the data point +// - TimeUnixNano is required, set to the end time of the aggregation +// - StartTimeUnixNano is optional, but strongly encouraged for DataPoints +// having an AggregationTemporality field, as discussed below. // // Both TimeUnixNano and StartTimeUnixNano values are expressed as // UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. @@ -518,10 +513,7 @@ func (x *ScopeMetrics) GetSchemaUrl() string { // when the start time is truly unknown, setting StartTimeUnixNano is // strongly encouraged. type Metric struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The name of the metric. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // A description of the metric, which can be used in documentation. @@ -530,10 +522,11 @@ type Metric struct { // described by https://ucum.org/ucum and https://units-of-measurement.org/ Unit string `protobuf:"bytes,3,opt,name=unit,proto3" json:"unit,omitempty"` // Data determines the aggregation type (if any) of the metric, what is the - // reported value type for the data points, as well as the relatationship to + // reported value type for the data points, as well as the relationship to // the time interval over which they are reported. // - // Types that are assignable to Data: + // Types that are valid to be assigned to Data: + // // *Metric_Gauge // *Metric_Sum // *Metric_Histogram @@ -548,16 +541,18 @@ type Metric struct { // Attribute keys MUST be unique (it is not allowed to have more than one // attribute with the same key). // The behavior of software that receives duplicated keys can be unpredictable. - Metadata []*v11.KeyValue `protobuf:"bytes,12,rep,name=metadata,proto3" json:"metadata,omitempty"` + // + // [Since v1.2.0] + Metadata []*v11.KeyValue `protobuf:"bytes,12,rep,name=metadata,proto3" json:"metadata,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Metric) Reset() { *x = Metric{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Metric) String() string { @@ -568,7 +563,7 @@ func (*Metric) ProtoMessage() {} func (x *Metric) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -604,44 +599,54 @@ func (x *Metric) GetUnit() string { return "" } -func (m *Metric) GetData() isMetric_Data { - if m != nil { - return m.Data +func (x *Metric) GetData() isMetric_Data { + if x != nil { + return x.Data } return nil } func (x *Metric) GetGauge() *Gauge { - if x, ok := x.GetData().(*Metric_Gauge); ok { - return x.Gauge + if x != nil { + if x, ok := x.Data.(*Metric_Gauge); ok { + return x.Gauge + } } return nil } func (x *Metric) GetSum() *Sum { - if x, ok := x.GetData().(*Metric_Sum); ok { - return x.Sum + if x != nil { + if x, ok := x.Data.(*Metric_Sum); ok { + return x.Sum + } } return nil } func (x *Metric) GetHistogram() *Histogram { - if x, ok := x.GetData().(*Metric_Histogram); ok { - return x.Histogram + if x != nil { + if x, ok := x.Data.(*Metric_Histogram); ok { + return x.Histogram + } } return nil } func (x *Metric) GetExponentialHistogram() *ExponentialHistogram { - if x, ok := x.GetData().(*Metric_ExponentialHistogram); ok { - return x.ExponentialHistogram + if x != nil { + if x, ok := x.Data.(*Metric_ExponentialHistogram); ok { + return x.ExponentialHistogram + } } return nil } func (x *Metric) GetSummary() *Summary { - if x, ok := x.GetData().(*Metric_Summary); ok { - return x.Summary + if x != nil { + if x, ok := x.Data.(*Metric_Summary); ok { + return x.Summary + } } return nil } @@ -697,22 +702,19 @@ func (*Metric_Summary) isMetric_Data() {} // AggregationTemporality is not included. Consequently, this also means // "StartTimeUnixNano" is ignored for all data points. type Gauge struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The time series data points. // Note: Multiple time series may be included (same timestamp, different attributes). - DataPoints []*NumberDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` + DataPoints []*NumberDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Gauge) Reset() { *x = Gauge{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Gauge) String() string { @@ -723,7 +725,7 @@ func (*Gauge) ProtoMessage() {} func (x *Gauge) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -748,10 +750,7 @@ func (x *Gauge) GetDataPoints() []*NumberDataPoint { // Sum represents the type of a scalar metric that is calculated as a sum of all // reported measurements over a time interval. type Sum struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The time series data points. // Note: Multiple time series may be included (same timestamp, different attributes). DataPoints []*NumberDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` @@ -759,16 +758,16 @@ type Sum struct { // since last report time, or cumulative changes since a fixed start time. AggregationTemporality AggregationTemporality `protobuf:"varint,2,opt,name=aggregation_temporality,json=aggregationTemporality,proto3,enum=opentelemetry.proto.metrics.v1.AggregationTemporality" json:"aggregation_temporality,omitempty"` // Represents whether the sum is monotonic. - IsMonotonic bool `protobuf:"varint,3,opt,name=is_monotonic,json=isMonotonic,proto3" json:"is_monotonic,omitempty"` + IsMonotonic bool `protobuf:"varint,3,opt,name=is_monotonic,json=isMonotonic,proto3" json:"is_monotonic,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Sum) Reset() { *x = Sum{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Sum) String() string { @@ -779,7 +778,7 @@ func (*Sum) ProtoMessage() {} func (x *Sum) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -818,25 +817,22 @@ func (x *Sum) GetIsMonotonic() bool { // Histogram represents the type of a metric that is calculated by aggregating // as a Histogram of all reported measurements over a time interval. type Histogram struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The time series data points. // Note: Multiple time series may be included (same timestamp, different attributes). DataPoints []*HistogramDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` // aggregation_temporality describes if the aggregator reports delta changes // since last report time, or cumulative changes since a fixed start time. AggregationTemporality AggregationTemporality `protobuf:"varint,2,opt,name=aggregation_temporality,json=aggregationTemporality,proto3,enum=opentelemetry.proto.metrics.v1.AggregationTemporality" json:"aggregation_temporality,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Histogram) Reset() { *x = Histogram{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Histogram) String() string { @@ -847,7 +843,7 @@ func (*Histogram) ProtoMessage() {} func (x *Histogram) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -879,25 +875,22 @@ func (x *Histogram) GetAggregationTemporality() AggregationTemporality { // ExponentialHistogram represents the type of a metric that is calculated by aggregating // as a ExponentialHistogram of all reported double measurements over a time interval. type ExponentialHistogram struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The time series data points. // Note: Multiple time series may be included (same timestamp, different attributes). DataPoints []*ExponentialHistogramDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` // aggregation_temporality describes if the aggregator reports delta changes // since last report time, or cumulative changes since a fixed start time. AggregationTemporality AggregationTemporality `protobuf:"varint,2,opt,name=aggregation_temporality,json=aggregationTemporality,proto3,enum=opentelemetry.proto.metrics.v1.AggregationTemporality" json:"aggregation_temporality,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExponentialHistogram) Reset() { *x = ExponentialHistogram{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExponentialHistogram) String() string { @@ -908,7 +901,7 @@ func (*ExponentialHistogram) ProtoMessage() {} func (x *ExponentialHistogram) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -947,22 +940,19 @@ func (x *ExponentialHistogram) GetAggregationTemporality() AggregationTemporalit // because the count and sum fields of a SummaryDataPoint are assumed to be // cumulative values. type Summary struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The time series data points. // Note: Multiple time series may be included (same timestamp, different attributes). - DataPoints []*SummaryDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` + DataPoints []*SummaryDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Summary) Reset() { *x = Summary{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Summary) String() string { @@ -973,7 +963,7 @@ func (*Summary) ProtoMessage() {} func (x *Summary) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -998,10 +988,7 @@ func (x *Summary) GetDataPoints() []*SummaryDataPoint { // NumberDataPoint is a single data point in a timeseries that describes the // time-varying scalar value of a metric. type NumberDataPoint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The set of key/value pairs that uniquely identify the timeseries from // where this point belongs. The list may be empty (may contain 0 elements). // Attribute keys MUST be unique (it is not allowed to have more than one @@ -1022,7 +1009,8 @@ type NumberDataPoint struct { // The value itself. A point is considered invalid when one of the recognized // value fields is not present inside this oneof. // - // Types that are assignable to Value: + // Types that are valid to be assigned to Value: + // // *NumberDataPoint_AsDouble // *NumberDataPoint_AsInt Value isNumberDataPoint_Value `protobuf_oneof:"value"` @@ -1031,16 +1019,16 @@ type NumberDataPoint struct { Exemplars []*Exemplar `protobuf:"bytes,5,rep,name=exemplars,proto3" json:"exemplars,omitempty"` // Flags that apply to this specific data point. See DataPointFlags // for the available flags and their meaning. - Flags uint32 `protobuf:"varint,8,opt,name=flags,proto3" json:"flags,omitempty"` + Flags uint32 `protobuf:"varint,8,opt,name=flags,proto3" json:"flags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *NumberDataPoint) Reset() { *x = NumberDataPoint{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *NumberDataPoint) String() string { @@ -1051,7 +1039,7 @@ func (*NumberDataPoint) ProtoMessage() {} func (x *NumberDataPoint) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1087,23 +1075,27 @@ func (x *NumberDataPoint) GetTimeUnixNano() uint64 { return 0 } -func (m *NumberDataPoint) GetValue() isNumberDataPoint_Value { - if m != nil { - return m.Value +func (x *NumberDataPoint) GetValue() isNumberDataPoint_Value { + if x != nil { + return x.Value } return nil } func (x *NumberDataPoint) GetAsDouble() float64 { - if x, ok := x.GetValue().(*NumberDataPoint_AsDouble); ok { - return x.AsDouble + if x != nil { + if x, ok := x.Value.(*NumberDataPoint_AsDouble); ok { + return x.AsDouble + } } return 0 } func (x *NumberDataPoint) GetAsInt() int64 { - if x, ok := x.GetValue().(*NumberDataPoint_AsInt); ok { - return x.AsInt + if x != nil { + if x, ok := x.Value.(*NumberDataPoint_AsInt); ok { + return x.AsInt + } } return 0 } @@ -1149,10 +1141,7 @@ func (*NumberDataPoint_AsInt) isNumberDataPoint_Value() {} // "explicit_bounds" and "bucket_counts" must be omitted and only "count" and // "sum" are known. type HistogramDataPoint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The set of key/value pairs that uniquely identify the timeseries from // where this point belongs. The list may be empty (may contain 0 elements). // Attribute keys MUST be unique (it is not allowed to have more than one @@ -1219,16 +1208,16 @@ type HistogramDataPoint struct { // min is the minimum value over (start_time, end_time]. Min *float64 `protobuf:"fixed64,11,opt,name=min,proto3,oneof" json:"min,omitempty"` // max is the maximum value over (start_time, end_time]. - Max *float64 `protobuf:"fixed64,12,opt,name=max,proto3,oneof" json:"max,omitempty"` + Max *float64 `protobuf:"fixed64,12,opt,name=max,proto3,oneof" json:"max,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *HistogramDataPoint) Reset() { *x = HistogramDataPoint{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *HistogramDataPoint) String() string { @@ -1239,7 +1228,7 @@ func (*HistogramDataPoint) ProtoMessage() {} func (x *HistogramDataPoint) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1335,12 +1324,8 @@ func (x *HistogramDataPoint) GetMax() float64 { // time-varying values of a ExponentialHistogram of double values. A ExponentialHistogram contains // summary statistics for a population of values, it may optionally contain the // distribution of those values across a set of buckets. -// type ExponentialHistogramDataPoint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The set of key/value pairs that uniquely identify the timeseries from // where this point belongs. The list may be empty (may contain 0 elements). // Attribute keys MUST be unique (it is not allowed to have more than one @@ -1374,7 +1359,7 @@ type ExponentialHistogramDataPoint struct { // scale describes the resolution of the histogram. Boundaries are // located at powers of the base, where: // - // base = (2^(2^-scale)) + // base = (2^(2^-scale)) // // The histogram bucket identified by `index`, a signed integer, // contains values that are greater than (base^index) and @@ -1417,15 +1402,15 @@ type ExponentialHistogramDataPoint struct { // expressed using the standard exponential formula as well as values that // have been rounded to zero. ZeroThreshold float64 `protobuf:"fixed64,14,opt,name=zero_threshold,json=zeroThreshold,proto3" json:"zero_threshold,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExponentialHistogramDataPoint) Reset() { *x = ExponentialHistogramDataPoint{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExponentialHistogramDataPoint) String() string { @@ -1436,7 +1421,7 @@ func (*ExponentialHistogramDataPoint) ProtoMessage() {} func (x *ExponentialHistogramDataPoint) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1553,10 +1538,7 @@ func (x *ExponentialHistogramDataPoint) GetZeroThreshold() float64 { // time-varying values of a Summary metric. The count and sum fields represent // cumulative values. type SummaryDataPoint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The set of key/value pairs that uniquely identify the timeseries from // where this point belongs. The list may be empty (may contain 0 elements). // Attribute keys MUST be unique (it is not allowed to have more than one @@ -1590,16 +1572,16 @@ type SummaryDataPoint struct { QuantileValues []*SummaryDataPoint_ValueAtQuantile `protobuf:"bytes,6,rep,name=quantile_values,json=quantileValues,proto3" json:"quantile_values,omitempty"` // Flags that apply to this specific data point. See DataPointFlags // for the available flags and their meaning. - Flags uint32 `protobuf:"varint,8,opt,name=flags,proto3" json:"flags,omitempty"` + Flags uint32 `protobuf:"varint,8,opt,name=flags,proto3" json:"flags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SummaryDataPoint) Reset() { *x = SummaryDataPoint{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SummaryDataPoint) String() string { @@ -1610,7 +1592,7 @@ func (*SummaryDataPoint) ProtoMessage() {} func (x *SummaryDataPoint) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1679,10 +1661,7 @@ func (x *SummaryDataPoint) GetFlags() uint32 { // was recorded, for example the span and trace ID of the active span when the // exemplar was recorded. type Exemplar struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The set of key/value pairs that were filtered out by the aggregator, but // recorded alongside the original measurement. Only key/value pairs that were // filtered out by the aggregator should be included @@ -1696,7 +1675,8 @@ type Exemplar struct { // considered invalid when one of the recognized value fields is not present // inside this oneof. // - // Types that are assignable to Value: + // Types that are valid to be assigned to Value: + // // *Exemplar_AsDouble // *Exemplar_AsInt Value isExemplar_Value `protobuf_oneof:"value"` @@ -1707,16 +1687,16 @@ type Exemplar struct { // (Optional) Trace ID of the exemplar trace. // trace_id may be missing if the measurement is not recorded inside a trace // or if the trace is not sampled. - TraceId []byte `protobuf:"bytes,5,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` + TraceId []byte `protobuf:"bytes,5,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Exemplar) Reset() { *x = Exemplar{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Exemplar) String() string { @@ -1727,7 +1707,7 @@ func (*Exemplar) ProtoMessage() {} func (x *Exemplar) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1756,23 +1736,27 @@ func (x *Exemplar) GetTimeUnixNano() uint64 { return 0 } -func (m *Exemplar) GetValue() isExemplar_Value { - if m != nil { - return m.Value +func (x *Exemplar) GetValue() isExemplar_Value { + if x != nil { + return x.Value } return nil } func (x *Exemplar) GetAsDouble() float64 { - if x, ok := x.GetValue().(*Exemplar_AsDouble); ok { - return x.AsDouble + if x != nil { + if x, ok := x.Value.(*Exemplar_AsDouble); ok { + return x.AsDouble + } } return 0 } func (x *Exemplar) GetAsInt() int64 { - if x, ok := x.GetValue().(*Exemplar_AsInt); ok { - return x.AsInt + if x != nil { + if x, ok := x.Value.(*Exemplar_AsInt); ok { + return x.AsInt + } } return 0 } @@ -1810,10 +1794,7 @@ func (*Exemplar_AsInt) isExemplar_Value() {} // Buckets are a set of bucket counts, encoded in a contiguous array // of counts. type ExponentialHistogramDataPoint_Buckets struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The bucket index of the first entry in the bucket_counts array. // // Note: This uses a varint encoding as a simple form of compression. @@ -1827,16 +1808,16 @@ type ExponentialHistogramDataPoint_Buckets struct { // fixed64. This field is expected to have many buckets, // especially zeros, so uint64 has been selected to ensure // varint encoding. - BucketCounts []uint64 `protobuf:"varint,2,rep,packed,name=bucket_counts,json=bucketCounts,proto3" json:"bucket_counts,omitempty"` + BucketCounts []uint64 `protobuf:"varint,2,rep,packed,name=bucket_counts,json=bucketCounts,proto3" json:"bucket_counts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExponentialHistogramDataPoint_Buckets) Reset() { *x = ExponentialHistogramDataPoint_Buckets{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExponentialHistogramDataPoint_Buckets) String() string { @@ -1847,7 +1828,7 @@ func (*ExponentialHistogramDataPoint_Buckets) ProtoMessage() {} func (x *ExponentialHistogramDataPoint_Buckets) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1885,26 +1866,23 @@ func (x *ExponentialHistogramDataPoint_Buckets) GetBucketCounts() []uint64 { // See the following issue for more context: // https://github.com/open-telemetry/opentelemetry-proto/issues/125 type SummaryDataPoint_ValueAtQuantile struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The quantile of a distribution. Must be in the interval // [0.0, 1.0]. Quantile float64 `protobuf:"fixed64,1,opt,name=quantile,proto3" json:"quantile,omitempty"` // The value at the given quantile of a distribution. // // Quantile values must NOT be negative. - Value float64 `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"` + Value float64 `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SummaryDataPoint_ValueAtQuantile) Reset() { *x = SummaryDataPoint_ValueAtQuantile{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SummaryDataPoint_ValueAtQuantile) String() string { @@ -1915,7 +1893,7 @@ func (*SummaryDataPoint_ValueAtQuantile) ProtoMessage() {} func (x *SummaryDataPoint_ValueAtQuantile) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1946,321 +1924,151 @@ func (x *SummaryDataPoint_ValueAtQuantile) GetValue() float64 { var File_opentelemetry_proto_metrics_v1_metrics_proto protoreflect.FileDescriptor -var file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc = []byte{ - 0x0a, 0x2c, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76, 0x31, - 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x2a, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x69, 0x0a, 0x0b, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x44, 0x61, 0x74, 0x61, 0x12, 0x5a, 0x0a, 0x10, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xd2, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x45, 0x0a, 0x08, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x12, 0x51, 0x0a, 0x0d, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x0c, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x75, 0x72, - 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x55, - 0x72, 0x6c, 0x4a, 0x06, 0x08, 0xe8, 0x07, 0x10, 0xe9, 0x07, 0x22, 0xba, 0x01, 0x0a, 0x0c, 0x53, - 0x63, 0x6f, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x49, 0x0a, 0x05, 0x73, - 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x72, - 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, - 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x40, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, - 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x55, 0x72, 0x6c, 0x22, 0xa6, 0x04, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x12, 0x3d, 0x0a, 0x05, - 0x67, 0x61, 0x75, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x75, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x05, 0x67, 0x61, 0x75, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x03, 0x73, - 0x75, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x6d, 0x48, 0x00, 0x52, - 0x03, 0x73, 0x75, 0x6d, 0x12, 0x49, 0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, - 0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x48, 0x00, 0x52, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, - 0x6b, 0x0a, 0x15, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x68, - 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, - 0x67, 0x72, 0x61, 0x6d, 0x48, 0x00, 0x52, 0x14, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x43, 0x0a, 0x07, - 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x48, 0x00, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x12, 0x43, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x06, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, - 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, - 0x22, 0x59, 0x0a, 0x05, 0x47, 0x61, 0x75, 0x67, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, - 0x0a, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xeb, 0x01, 0x0a, 0x03, - 0x53, 0x75, 0x6d, 0x12, 0x50, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x6f, 0x0a, 0x17, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, - 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x16, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, - 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x6d, 0x6f, 0x6e, - 0x6f, 0x74, 0x6f, 0x6e, 0x69, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, - 0x4d, 0x6f, 0x6e, 0x6f, 0x74, 0x6f, 0x6e, 0x69, 0x63, 0x22, 0xd1, 0x01, 0x0a, 0x09, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x53, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x6f, 0x0a, 0x17, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x65, 0x6d, 0x70, - 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, - 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x16, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0xe7, 0x01, - 0x0a, 0x14, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, - 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x5e, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, - 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, - 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x6f, 0x0a, 0x17, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, - 0x16, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, - 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0x5c, 0x0a, 0x07, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x12, 0x51, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, - 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xd6, 0x02, 0x0a, 0x0f, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, - 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, - 0x52, 0x11, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, - 0x61, 0x6e, 0x6f, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, - 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, 0x74, 0x69, 0x6d, - 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x1d, 0x0a, 0x09, 0x61, 0x73, 0x5f, - 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x08, - 0x61, 0x73, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x06, 0x61, 0x73, 0x5f, 0x69, - 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x10, 0x48, 0x00, 0x52, 0x05, 0x61, 0x73, 0x49, 0x6e, - 0x74, 0x12, 0x46, 0x0a, 0x09, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, - 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x09, - 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, - 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x42, - 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xd9, - 0x03, 0x0a, 0x12, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, - 0x0a, 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, - 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, 0x52, 0x11, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, - 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, - 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, - 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x06, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x15, 0x0a, 0x03, 0x73, - 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x03, 0x73, 0x75, 0x6d, 0x88, - 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x06, 0x52, 0x0c, 0x62, 0x75, 0x63, 0x6b, 0x65, - 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x69, - 0x63, 0x69, 0x74, 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x01, - 0x52, 0x0e, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x73, - 0x12, 0x46, 0x0a, 0x09, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x18, 0x08, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x09, 0x65, - 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, - 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x15, - 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x48, 0x01, 0x52, 0x03, 0x6d, - 0x69, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x01, 0x48, 0x02, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x88, 0x01, 0x01, 0x42, 0x06, 0x0a, 0x04, - 0x5f, 0x73, 0x75, 0x6d, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6d, 0x69, 0x6e, 0x42, 0x06, 0x0a, 0x04, - 0x5f, 0x6d, 0x61, 0x78, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xfa, 0x05, 0x0a, 0x1d, 0x45, - 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0a, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x06, 0x52, 0x11, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, - 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, - 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, - 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x14, 0x0a, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x06, 0x52, 0x05, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x15, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x48, - 0x00, 0x52, 0x03, 0x73, 0x75, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x61, - 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x11, 0x52, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x06, 0x52, 0x09, 0x7a, 0x65, 0x72, 0x6f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x61, - 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x45, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, - 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x2e, - 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, - 0x65, 0x12, 0x61, 0x0a, 0x08, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, - 0x6e, 0x74, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x52, 0x08, 0x6e, 0x65, 0x67, 0x61, - 0x74, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x46, 0x0a, 0x09, 0x65, 0x78, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, - 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x09, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x72, 0x73, 0x12, 0x15, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x48, - 0x01, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x6d, 0x61, 0x78, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x48, 0x02, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x88, 0x01, 0x01, - 0x12, 0x25, 0x0a, 0x0e, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, - 0x6c, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0d, 0x7a, 0x65, 0x72, 0x6f, 0x54, 0x68, - 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x1a, 0x46, 0x0a, 0x07, 0x42, 0x75, 0x63, 0x6b, 0x65, - 0x74, 0x73, 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, 0x23, 0x0a, 0x0d, 0x62, 0x75, - 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x04, 0x52, 0x0c, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x42, - 0x06, 0x0a, 0x04, 0x5f, 0x73, 0x75, 0x6d, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6d, 0x69, 0x6e, 0x42, - 0x06, 0x0a, 0x04, 0x5f, 0x6d, 0x61, 0x78, 0x22, 0xa6, 0x03, 0x0a, 0x10, 0x53, 0x75, 0x6d, 0x6d, - 0x61, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0a, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x06, 0x52, 0x11, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, - 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, - 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, - 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x14, 0x0a, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x06, 0x52, 0x05, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, - 0x03, 0x73, 0x75, 0x6d, 0x12, 0x69, 0x0a, 0x0f, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x2e, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x41, 0x74, 0x51, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x52, - 0x0e, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, - 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, - 0x66, 0x6c, 0x61, 0x67, 0x73, 0x1a, 0x43, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x41, 0x74, - 0x51, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, - 0x74, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, - 0x74, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, - 0x22, 0x85, 0x02, 0x0a, 0x08, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x12, 0x58, 0x0a, - 0x13, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x12, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x41, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, 0x52, - 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x1d, 0x0a, - 0x09, 0x61, 0x73, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, - 0x48, 0x00, 0x52, 0x08, 0x61, 0x73, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x06, - 0x61, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x10, 0x48, 0x00, 0x52, 0x05, - 0x61, 0x73, 0x49, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x70, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x19, - 0x0a, 0x08, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x2a, 0x8c, 0x01, 0x0a, 0x16, 0x41, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, - 0x69, 0x74, 0x79, 0x12, 0x27, 0x0a, 0x23, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, - 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x45, 0x4d, 0x50, - 0x4f, 0x52, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x01, 0x12, - 0x26, 0x0a, 0x22, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, - 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x55, 0x4d, 0x55, 0x4c, - 0x41, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x2a, 0x5e, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x1f, 0x0a, 0x1b, 0x44, 0x41, 0x54, - 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x5f, 0x46, 0x4c, 0x41, 0x47, 0x53, 0x5f, 0x44, 0x4f, - 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x10, 0x00, 0x12, 0x2b, 0x0a, 0x27, 0x44, 0x41, - 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x5f, 0x46, 0x4c, 0x41, 0x47, 0x53, 0x5f, 0x4e, - 0x4f, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x52, 0x44, 0x45, 0x44, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, - 0x5f, 0x4d, 0x41, 0x53, 0x4b, 0x10, 0x01, 0x42, 0x7f, 0x0a, 0x21, 0x69, 0x6f, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x6f, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x69, - 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x74, 0x6c, 0x70, 0x2f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76, 0x31, 0xaa, 0x02, 0x1e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc = "" + + "\n" + + ",opentelemetry/proto/metrics/v1/metrics.proto\x12\x1eopentelemetry.proto.metrics.v1\x1a*opentelemetry/proto/common/v1/common.proto\x1a.opentelemetry/proto/resource/v1/resource.proto\"i\n" + + "\vMetricsData\x12Z\n" + + "\x10resource_metrics\x18\x01 \x03(\v2/.opentelemetry.proto.metrics.v1.ResourceMetricsR\x0fresourceMetrics\"\xd2\x01\n" + + "\x0fResourceMetrics\x12E\n" + + "\bresource\x18\x01 \x01(\v2).opentelemetry.proto.resource.v1.ResourceR\bresource\x12Q\n" + + "\rscope_metrics\x18\x02 \x03(\v2,.opentelemetry.proto.metrics.v1.ScopeMetricsR\fscopeMetrics\x12\x1d\n" + + "\n" + + "schema_url\x18\x03 \x01(\tR\tschemaUrlJ\x06\b\xe8\a\x10\xe9\a\"\xba\x01\n" + + "\fScopeMetrics\x12I\n" + + "\x05scope\x18\x01 \x01(\v23.opentelemetry.proto.common.v1.InstrumentationScopeR\x05scope\x12@\n" + + "\ametrics\x18\x02 \x03(\v2&.opentelemetry.proto.metrics.v1.MetricR\ametrics\x12\x1d\n" + + "\n" + + "schema_url\x18\x03 \x01(\tR\tschemaUrl\"\xa6\x04\n" + + "\x06Metric\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" + + "\vdescription\x18\x02 \x01(\tR\vdescription\x12\x12\n" + + "\x04unit\x18\x03 \x01(\tR\x04unit\x12=\n" + + "\x05gauge\x18\x05 \x01(\v2%.opentelemetry.proto.metrics.v1.GaugeH\x00R\x05gauge\x127\n" + + "\x03sum\x18\a \x01(\v2#.opentelemetry.proto.metrics.v1.SumH\x00R\x03sum\x12I\n" + + "\thistogram\x18\t \x01(\v2).opentelemetry.proto.metrics.v1.HistogramH\x00R\thistogram\x12k\n" + + "\x15exponential_histogram\x18\n" + + " \x01(\v24.opentelemetry.proto.metrics.v1.ExponentialHistogramH\x00R\x14exponentialHistogram\x12C\n" + + "\asummary\x18\v \x01(\v2'.opentelemetry.proto.metrics.v1.SummaryH\x00R\asummary\x12C\n" + + "\bmetadata\x18\f \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\bmetadataB\x06\n" + + "\x04dataJ\x04\b\x04\x10\x05J\x04\b\x06\x10\aJ\x04\b\b\x10\t\"Y\n" + + "\x05Gauge\x12P\n" + + "\vdata_points\x18\x01 \x03(\v2/.opentelemetry.proto.metrics.v1.NumberDataPointR\n" + + "dataPoints\"\xeb\x01\n" + + "\x03Sum\x12P\n" + + "\vdata_points\x18\x01 \x03(\v2/.opentelemetry.proto.metrics.v1.NumberDataPointR\n" + + "dataPoints\x12o\n" + + "\x17aggregation_temporality\x18\x02 \x01(\x0e26.opentelemetry.proto.metrics.v1.AggregationTemporalityR\x16aggregationTemporality\x12!\n" + + "\fis_monotonic\x18\x03 \x01(\bR\visMonotonic\"\xd1\x01\n" + + "\tHistogram\x12S\n" + + "\vdata_points\x18\x01 \x03(\v22.opentelemetry.proto.metrics.v1.HistogramDataPointR\n" + + "dataPoints\x12o\n" + + "\x17aggregation_temporality\x18\x02 \x01(\x0e26.opentelemetry.proto.metrics.v1.AggregationTemporalityR\x16aggregationTemporality\"\xe7\x01\n" + + "\x14ExponentialHistogram\x12^\n" + + "\vdata_points\x18\x01 \x03(\v2=.opentelemetry.proto.metrics.v1.ExponentialHistogramDataPointR\n" + + "dataPoints\x12o\n" + + "\x17aggregation_temporality\x18\x02 \x01(\x0e26.opentelemetry.proto.metrics.v1.AggregationTemporalityR\x16aggregationTemporality\"\\\n" + + "\aSummary\x12Q\n" + + "\vdata_points\x18\x01 \x03(\v20.opentelemetry.proto.metrics.v1.SummaryDataPointR\n" + + "dataPoints\"\xd6\x02\n" + + "\x0fNumberDataPoint\x12G\n" + + "\n" + + "attributes\x18\a \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x12/\n" + + "\x14start_time_unix_nano\x18\x02 \x01(\x06R\x11startTimeUnixNano\x12$\n" + + "\x0etime_unix_nano\x18\x03 \x01(\x06R\ftimeUnixNano\x12\x1d\n" + + "\tas_double\x18\x04 \x01(\x01H\x00R\basDouble\x12\x17\n" + + "\x06as_int\x18\x06 \x01(\x10H\x00R\x05asInt\x12F\n" + + "\texemplars\x18\x05 \x03(\v2(.opentelemetry.proto.metrics.v1.ExemplarR\texemplars\x12\x14\n" + + "\x05flags\x18\b \x01(\rR\x05flagsB\a\n" + + "\x05valueJ\x04\b\x01\x10\x02\"\xd9\x03\n" + + "\x12HistogramDataPoint\x12G\n" + + "\n" + + "attributes\x18\t \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x12/\n" + + "\x14start_time_unix_nano\x18\x02 \x01(\x06R\x11startTimeUnixNano\x12$\n" + + "\x0etime_unix_nano\x18\x03 \x01(\x06R\ftimeUnixNano\x12\x14\n" + + "\x05count\x18\x04 \x01(\x06R\x05count\x12\x15\n" + + "\x03sum\x18\x05 \x01(\x01H\x00R\x03sum\x88\x01\x01\x12#\n" + + "\rbucket_counts\x18\x06 \x03(\x06R\fbucketCounts\x12'\n" + + "\x0fexplicit_bounds\x18\a \x03(\x01R\x0eexplicitBounds\x12F\n" + + "\texemplars\x18\b \x03(\v2(.opentelemetry.proto.metrics.v1.ExemplarR\texemplars\x12\x14\n" + + "\x05flags\x18\n" + + " \x01(\rR\x05flags\x12\x15\n" + + "\x03min\x18\v \x01(\x01H\x01R\x03min\x88\x01\x01\x12\x15\n" + + "\x03max\x18\f \x01(\x01H\x02R\x03max\x88\x01\x01B\x06\n" + + "\x04_sumB\x06\n" + + "\x04_minB\x06\n" + + "\x04_maxJ\x04\b\x01\x10\x02\"\xfa\x05\n" + + "\x1dExponentialHistogramDataPoint\x12G\n" + + "\n" + + "attributes\x18\x01 \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x12/\n" + + "\x14start_time_unix_nano\x18\x02 \x01(\x06R\x11startTimeUnixNano\x12$\n" + + "\x0etime_unix_nano\x18\x03 \x01(\x06R\ftimeUnixNano\x12\x14\n" + + "\x05count\x18\x04 \x01(\x06R\x05count\x12\x15\n" + + "\x03sum\x18\x05 \x01(\x01H\x00R\x03sum\x88\x01\x01\x12\x14\n" + + "\x05scale\x18\x06 \x01(\x11R\x05scale\x12\x1d\n" + + "\n" + + "zero_count\x18\a \x01(\x06R\tzeroCount\x12a\n" + + "\bpositive\x18\b \x01(\v2E.opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.BucketsR\bpositive\x12a\n" + + "\bnegative\x18\t \x01(\v2E.opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.BucketsR\bnegative\x12\x14\n" + + "\x05flags\x18\n" + + " \x01(\rR\x05flags\x12F\n" + + "\texemplars\x18\v \x03(\v2(.opentelemetry.proto.metrics.v1.ExemplarR\texemplars\x12\x15\n" + + "\x03min\x18\f \x01(\x01H\x01R\x03min\x88\x01\x01\x12\x15\n" + + "\x03max\x18\r \x01(\x01H\x02R\x03max\x88\x01\x01\x12%\n" + + "\x0ezero_threshold\x18\x0e \x01(\x01R\rzeroThreshold\x1aF\n" + + "\aBuckets\x12\x16\n" + + "\x06offset\x18\x01 \x01(\x11R\x06offset\x12#\n" + + "\rbucket_counts\x18\x02 \x03(\x04R\fbucketCountsB\x06\n" + + "\x04_sumB\x06\n" + + "\x04_minB\x06\n" + + "\x04_max\"\xa6\x03\n" + + "\x10SummaryDataPoint\x12G\n" + + "\n" + + "attributes\x18\a \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x12/\n" + + "\x14start_time_unix_nano\x18\x02 \x01(\x06R\x11startTimeUnixNano\x12$\n" + + "\x0etime_unix_nano\x18\x03 \x01(\x06R\ftimeUnixNano\x12\x14\n" + + "\x05count\x18\x04 \x01(\x06R\x05count\x12\x10\n" + + "\x03sum\x18\x05 \x01(\x01R\x03sum\x12i\n" + + "\x0fquantile_values\x18\x06 \x03(\v2@.opentelemetry.proto.metrics.v1.SummaryDataPoint.ValueAtQuantileR\x0equantileValues\x12\x14\n" + + "\x05flags\x18\b \x01(\rR\x05flags\x1aC\n" + + "\x0fValueAtQuantile\x12\x1a\n" + + "\bquantile\x18\x01 \x01(\x01R\bquantile\x12\x14\n" + + "\x05value\x18\x02 \x01(\x01R\x05valueJ\x04\b\x01\x10\x02\"\x85\x02\n" + + "\bExemplar\x12X\n" + + "\x13filtered_attributes\x18\a \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\x12filteredAttributes\x12$\n" + + "\x0etime_unix_nano\x18\x02 \x01(\x06R\ftimeUnixNano\x12\x1d\n" + + "\tas_double\x18\x03 \x01(\x01H\x00R\basDouble\x12\x17\n" + + "\x06as_int\x18\x06 \x01(\x10H\x00R\x05asInt\x12\x17\n" + + "\aspan_id\x18\x04 \x01(\fR\x06spanId\x12\x19\n" + + "\btrace_id\x18\x05 \x01(\fR\atraceIdB\a\n" + + "\x05valueJ\x04\b\x01\x10\x02*\x8c\x01\n" + + "\x16AggregationTemporality\x12'\n" + + "#AGGREGATION_TEMPORALITY_UNSPECIFIED\x10\x00\x12!\n" + + "\x1dAGGREGATION_TEMPORALITY_DELTA\x10\x01\x12&\n" + + "\"AGGREGATION_TEMPORALITY_CUMULATIVE\x10\x02*^\n" + + "\x0eDataPointFlags\x12\x1f\n" + + "\x1bDATA_POINT_FLAGS_DO_NOT_USE\x10\x00\x12+\n" + + "'DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK\x10\x01B\x7f\n" + + "!io.opentelemetry.proto.metrics.v1B\fMetricsProtoP\x01Z)go.opentelemetry.io/proto/otlp/metrics/v1\xaa\x02\x1eOpenTelemetry.Proto.Metrics.V1b\x06proto3" var ( file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescOnce sync.Once - file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData = file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc + file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData []byte ) func file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP() []byte { file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescOnce.Do(func() { - file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData) + file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc), len(file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc))) }) return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData } var file_opentelemetry_proto_metrics_v1_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 16) -var file_opentelemetry_proto_metrics_v1_metrics_proto_goTypes = []interface{}{ +var file_opentelemetry_proto_metrics_v1_metrics_proto_goTypes = []any{ (AggregationTemporality)(0), // 0: opentelemetry.proto.metrics.v1.AggregationTemporality (DataPointFlags)(0), // 1: opentelemetry.proto.metrics.v1.DataPointFlags (*MetricsData)(nil), // 2: opentelemetry.proto.metrics.v1.MetricsData @@ -2326,214 +2134,20 @@ func file_opentelemetry_proto_metrics_v1_metrics_proto_init() { if File_opentelemetry_proto_metrics_v1_metrics_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MetricsData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResourceMetrics); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScopeMetrics); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Metric); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Gauge); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Sum); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Histogram); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExponentialHistogram); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Summary); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NumberDataPoint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HistogramDataPoint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExponentialHistogramDataPoint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SummaryDataPoint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Exemplar); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExponentialHistogramDataPoint_Buckets); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SummaryDataPoint_ValueAtQuantile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3].OneofWrappers = []interface{}{ + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3].OneofWrappers = []any{ (*Metric_Gauge)(nil), (*Metric_Sum)(nil), (*Metric_Histogram)(nil), (*Metric_ExponentialHistogram)(nil), (*Metric_Summary)(nil), } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9].OneofWrappers = []interface{}{ + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9].OneofWrappers = []any{ (*NumberDataPoint_AsDouble)(nil), (*NumberDataPoint_AsInt)(nil), } - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10].OneofWrappers = []interface{}{} - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11].OneofWrappers = []interface{}{} - file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13].OneofWrappers = []interface{}{ + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10].OneofWrappers = []any{} + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11].OneofWrappers = []any{} + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13].OneofWrappers = []any{ (*Exemplar_AsDouble)(nil), (*Exemplar_AsInt)(nil), } @@ -2541,7 +2155,7 @@ func file_opentelemetry_proto_metrics_v1_metrics_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc), len(file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc)), NumEnums: 2, NumMessages: 16, NumExtensions: 0, @@ -2553,7 +2167,6 @@ func file_opentelemetry_proto_metrics_v1_metrics_proto_init() { MessageInfos: file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes, }.Build() File_opentelemetry_proto_metrics_v1_metrics_proto = out.File - file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc = nil file_opentelemetry_proto_metrics_v1_metrics_proto_goTypes = nil file_opentelemetry_proto_metrics_v1_metrics_proto_depIdxs = nil } diff --git a/vendor/go.opentelemetry.io/proto/otlp/resource/v1/resource.pb.go b/vendor/go.opentelemetry.io/proto/otlp/resource/v1/resource.pb.go index 301247ddf..de95b8f21 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/resource/v1/resource.pb.go +++ b/vendor/go.opentelemetry.io/proto/otlp/resource/v1/resource.pb.go @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.21.6 +// protoc-gen-go v1.36.11 +// protoc v7.35.0 // source: opentelemetry/proto/resource/v1/resource.proto package v1 @@ -26,6 +26,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -37,10 +38,7 @@ const ( // Resource information. type Resource struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Set of attributes that describe the resource. // Attribute keys MUST be unique (it is not allowed to have more than one // attribute with the same key). @@ -54,16 +52,18 @@ type Resource struct { // Note: keys in the references MUST exist in attributes of this message. // // Status: [Development] - EntityRefs []*v1.EntityRef `protobuf:"bytes,3,rep,name=entity_refs,json=entityRefs,proto3" json:"entity_refs,omitempty"` + // + // [Since v1.6.0] + EntityRefs []*v1.EntityRef `protobuf:"bytes,3,rep,name=entity_refs,json=entityRefs,proto3" json:"entity_refs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Resource) Reset() { *x = Resource{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_resource_v1_resource_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_resource_v1_resource_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Resource) String() string { @@ -74,7 +74,7 @@ func (*Resource) ProtoMessage() {} func (x *Resource) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_resource_v1_resource_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -112,54 +112,32 @@ func (x *Resource) GetEntityRefs() []*v1.EntityRef { var File_opentelemetry_proto_resource_v1_resource_proto protoreflect.FileDescriptor -var file_opentelemetry_proto_resource_v1_resource_proto_rawDesc = []byte{ - 0x0a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x76, - 0x31, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x1f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x1a, 0x2a, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, - 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd8, 0x01, - 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, - 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x16, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x49, 0x0a, - 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x66, 0x52, 0x0a, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x66, 0x73, 0x42, 0x83, 0x01, 0x0a, 0x22, 0x69, 0x6f, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x42, - 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x2a, 0x67, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x74, 0x6c, 0x70, - 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x76, 0x31, 0xaa, 0x02, 0x1f, 0x4f, - 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x56, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_opentelemetry_proto_resource_v1_resource_proto_rawDesc = "" + + "\n" + + ".opentelemetry/proto/resource/v1/resource.proto\x12\x1fopentelemetry.proto.resource.v1\x1a*opentelemetry/proto/common/v1/common.proto\"\xd8\x01\n" + + "\bResource\x12G\n" + + "\n" + + "attributes\x18\x01 \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x128\n" + + "\x18dropped_attributes_count\x18\x02 \x01(\rR\x16droppedAttributesCount\x12I\n" + + "\ventity_refs\x18\x03 \x03(\v2(.opentelemetry.proto.common.v1.EntityRefR\n" + + "entityRefsB\x83\x01\n" + + "\"io.opentelemetry.proto.resource.v1B\rResourceProtoP\x01Z*go.opentelemetry.io/proto/otlp/resource/v1\xaa\x02\x1fOpenTelemetry.Proto.Resource.V1b\x06proto3" var ( file_opentelemetry_proto_resource_v1_resource_proto_rawDescOnce sync.Once - file_opentelemetry_proto_resource_v1_resource_proto_rawDescData = file_opentelemetry_proto_resource_v1_resource_proto_rawDesc + file_opentelemetry_proto_resource_v1_resource_proto_rawDescData []byte ) func file_opentelemetry_proto_resource_v1_resource_proto_rawDescGZIP() []byte { file_opentelemetry_proto_resource_v1_resource_proto_rawDescOnce.Do(func() { - file_opentelemetry_proto_resource_v1_resource_proto_rawDescData = protoimpl.X.CompressGZIP(file_opentelemetry_proto_resource_v1_resource_proto_rawDescData) + file_opentelemetry_proto_resource_v1_resource_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_resource_v1_resource_proto_rawDesc), len(file_opentelemetry_proto_resource_v1_resource_proto_rawDesc))) }) return file_opentelemetry_proto_resource_v1_resource_proto_rawDescData } var file_opentelemetry_proto_resource_v1_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_opentelemetry_proto_resource_v1_resource_proto_goTypes = []interface{}{ +var file_opentelemetry_proto_resource_v1_resource_proto_goTypes = []any{ (*Resource)(nil), // 0: opentelemetry.proto.resource.v1.Resource (*v1.KeyValue)(nil), // 1: opentelemetry.proto.common.v1.KeyValue (*v1.EntityRef)(nil), // 2: opentelemetry.proto.common.v1.EntityRef @@ -179,25 +157,11 @@ func file_opentelemetry_proto_resource_v1_resource_proto_init() { if File_opentelemetry_proto_resource_v1_resource_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_opentelemetry_proto_resource_v1_resource_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Resource); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_opentelemetry_proto_resource_v1_resource_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_resource_v1_resource_proto_rawDesc), len(file_opentelemetry_proto_resource_v1_resource_proto_rawDesc)), NumEnums: 0, NumMessages: 1, NumExtensions: 0, @@ -208,7 +172,6 @@ func file_opentelemetry_proto_resource_v1_resource_proto_init() { MessageInfos: file_opentelemetry_proto_resource_v1_resource_proto_msgTypes, }.Build() File_opentelemetry_proto_resource_v1_resource_proto = out.File - file_opentelemetry_proto_resource_v1_resource_proto_rawDesc = nil file_opentelemetry_proto_resource_v1_resource_proto_goTypes = nil file_opentelemetry_proto_resource_v1_resource_proto_depIdxs = nil } diff --git a/vendor/go.opentelemetry.io/proto/otlp/trace/v1/trace.pb.go b/vendor/go.opentelemetry.io/proto/otlp/trace/v1/trace.pb.go index d7bfca902..9a9daf44d 100644 --- a/vendor/go.opentelemetry.io/proto/otlp/trace/v1/trace.pb.go +++ b/vendor/go.opentelemetry.io/proto/otlp/trace/v1/trace.pb.go @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.21.6 +// protoc-gen-go v1.36.11 +// protoc v7.35.0 // source: opentelemetry/proto/trace/v1/trace.proto package v1 @@ -27,6 +27,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -42,7 +43,7 @@ const ( // a bit-mask. To extract the bit-field, for example, use an // expression like: // -// (span.flags & SPAN_FLAGS_TRACE_FLAGS_MASK) +// (span.flags & SPAN_FLAGS_TRACE_FLAGS_MASK) // // See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions. // @@ -50,6 +51,8 @@ const ( // OpenTelemetry protocol. Older Span producers do not set this // field, consequently consumers should not rely on the absence of a // particular flag bit to indicate the presence of a particular feature. +// +// [Since v1.1.0] type SpanFlags int32 const ( @@ -61,8 +64,11 @@ const ( // Bits 8 and 9 are used to indicate that the parent span or link span is remote. // Bit 8 (`HAS_IS_REMOTE`) indicates whether the value is known. // Bit 9 (`IS_REMOTE`) indicates whether the span or link is remote. + // + // [Since v1.2.0] SpanFlags_SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK SpanFlags = 256 - SpanFlags_SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK SpanFlags = 512 + // [Since v1.2.0] + SpanFlags_SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK SpanFlags = 512 ) // Enum value maps for SpanFlags. @@ -248,25 +254,22 @@ func (Status_StatusCode) EnumDescriptor() ([]byte, []int) { // When new fields are added into this message, the OTLP request MUST be updated // as well. type TracesData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // An array of ResourceSpans. // For data coming from a single resource this array will typically contain // one element. Intermediary nodes that receive data from multiple origins // typically batch the data before forwarding further and in that case this // array will contain multiple elements. ResourceSpans []*ResourceSpans `protobuf:"bytes,1,rep,name=resource_spans,json=resourceSpans,proto3" json:"resource_spans,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TracesData) Reset() { *x = TracesData{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TracesData) String() string { @@ -277,7 +280,7 @@ func (*TracesData) ProtoMessage() {} func (x *TracesData) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -301,10 +304,7 @@ func (x *TracesData) GetResourceSpans() []*ResourceSpans { // A collection of ScopeSpans from a Resource. type ResourceSpans struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The resource for the spans in this message. // If this field is not set then no resource info is known. Resource *v1.Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` @@ -316,16 +316,16 @@ type ResourceSpans struct { // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url // This schema_url applies to the data in the "resource" field. It does not apply // to the data in the "scope_spans" field which have their own schema_url field. - SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` + SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ResourceSpans) Reset() { *x = ResourceSpans{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ResourceSpans) String() string { @@ -336,7 +336,7 @@ func (*ResourceSpans) ProtoMessage() {} func (x *ResourceSpans) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -374,10 +374,7 @@ func (x *ResourceSpans) GetSchemaUrl() string { // A collection of Spans produced by an InstrumentationScope. type ScopeSpans struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The instrumentation scope information for the spans in this message. // Semantically when InstrumentationScope isn't set, it is equivalent with // an empty instrumentation scope name (unknown). @@ -390,16 +387,16 @@ type ScopeSpans struct { // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url // This schema_url applies to the data in the "scope" field and all spans and span // events in the "spans" field. - SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` + SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ScopeSpans) Reset() { *x = ScopeSpans{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ScopeSpans) String() string { @@ -410,7 +407,7 @@ func (*ScopeSpans) ProtoMessage() {} func (x *ScopeSpans) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -450,10 +447,7 @@ func (x *ScopeSpans) GetSchemaUrl() string { // // The next available field id is 17. type Span struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // A unique identifier for a trace. All spans from the same trace share // the same `trace_id`. The ID is a 16-byte array. An ID with all zeroes OR // of length other than 16 bytes is considered invalid (empty string in OTLP/JSON @@ -496,6 +490,8 @@ type Span struct { // Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero. // // [Optional]. + // + // [Since v1.1.0] Flags uint32 `protobuf:"fixed32,16,opt,name=flags,proto3" json:"flags,omitempty"` // A description of the span's operation. // @@ -528,12 +524,12 @@ type Span struct { // This field is semantically required and it is expected that end_time >= start_time. EndTimeUnixNano uint64 `protobuf:"fixed64,8,opt,name=end_time_unix_nano,json=endTimeUnixNano,proto3" json:"end_time_unix_nano,omitempty"` // A collection of key/value pairs. Note, global attributes - // like server name can be set using the resource API. Examples of attributes: + // like service name can be set using the resource API. Examples of attributes: // - // "/http/user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36" - // "/http/server_latency": 300 - // "example.com/myattribute": true - // "example.com/score": 10.239 + // "user_agent.original": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36" + // "http.response.status_code": 200 + // "com.example.myattribute": true + // "com.example.score": 10.239 // // Attribute keys MUST be unique (it is not allowed to have more than one // attribute with the same key). @@ -556,16 +552,16 @@ type Span struct { DroppedLinksCount uint32 `protobuf:"varint,14,opt,name=dropped_links_count,json=droppedLinksCount,proto3" json:"dropped_links_count,omitempty"` // An optional final status for this span. Semantically when Status isn't set, it means // span's status code is unset, i.e. assume STATUS_CODE_UNSET (code = 0). - Status *Status `protobuf:"bytes,15,opt,name=status,proto3" json:"status,omitempty"` + Status *Status `protobuf:"bytes,15,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Span) Reset() { *x = Span{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Span) String() string { @@ -576,7 +572,7 @@ func (*Span) ProtoMessage() {} func (x *Span) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -706,23 +702,20 @@ func (x *Span) GetStatus() *Status { // The Status type defines a logical error model that is suitable for different // programming environments, including REST APIs and RPC APIs. type Status struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // A developer-facing human readable error message. Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` // The status code. - Code Status_StatusCode `protobuf:"varint,3,opt,name=code,proto3,enum=opentelemetry.proto.trace.v1.Status_StatusCode" json:"code,omitempty"` + Code Status_StatusCode `protobuf:"varint,3,opt,name=code,proto3,enum=opentelemetry.proto.trace.v1.Status_StatusCode" json:"code,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Status) Reset() { *x = Status{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Status) String() string { @@ -733,7 +726,7 @@ func (*Status) ProtoMessage() {} func (x *Status) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -765,10 +758,7 @@ func (x *Status) GetCode() Status_StatusCode { // Event is a time-stamped annotation of the span, consisting of user-supplied // text description and key-value pairs. type Span_Event struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The time the event occurred. TimeUnixNano uint64 `protobuf:"fixed64,1,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"` // The name of the event. @@ -782,15 +772,15 @@ type Span_Event struct { // The number of dropped attributes. If the value is 0, // then no attributes were dropped. DroppedAttributesCount uint32 `protobuf:"varint,4,opt,name=dropped_attributes_count,json=droppedAttributesCount,proto3" json:"dropped_attributes_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Span_Event) Reset() { *x = Span_Event{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Span_Event) String() string { @@ -801,7 +791,7 @@ func (*Span_Event) ProtoMessage() {} func (x *Span_Event) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -849,10 +839,7 @@ func (x *Span_Event) GetDroppedAttributesCount() uint32 { // where a single batch handler processes multiple requests from different // traces or when the handler receives a request from a different project. type Span_Link struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // A unique identifier of a trace that this linked span is part of. The ID is a // 16-byte array. TraceId []byte `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` @@ -885,16 +872,18 @@ type Span_Link struct { // When creating new spans, bits 10-31 (most-significant 22-bits) MUST be zero. // // [Optional]. - Flags uint32 `protobuf:"fixed32,6,opt,name=flags,proto3" json:"flags,omitempty"` + // + // [Since v1.1.0] + Flags uint32 `protobuf:"fixed32,6,opt,name=flags,proto3" json:"flags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Span_Link) Reset() { *x = Span_Link{} - if protoimpl.UnsafeEnabled { - mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Span_Link) String() string { @@ -905,7 +894,7 @@ func (*Span_Link) ProtoMessage() {} func (x *Span_Link) ProtoReflect() protoreflect.Message { mi := &file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -964,179 +953,101 @@ func (x *Span_Link) GetFlags() uint32 { var File_opentelemetry_proto_trace_v1_trace_proto protoreflect.FileDescriptor -var file_opentelemetry_proto_trace_v1_trace_proto_rawDesc = []byte{ - 0x0a, 0x28, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x74, - 0x72, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x6f, 0x70, 0x65, 0x6e, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x2a, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x60, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x63, 0x65, 0x73, 0x44, 0x61, - 0x74, 0x61, 0x12, 0x52, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, - 0x70, 0x61, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x22, 0xc8, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x12, 0x45, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x49, 0x0a, 0x0b, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, - 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x52, 0x0a, - 0x73, 0x63, 0x6f, 0x70, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x55, 0x72, 0x6c, 0x4a, 0x06, 0x08, 0xe8, 0x07, 0x10, 0xe9, - 0x07, 0x22, 0xb0, 0x01, 0x0a, 0x0a, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, - 0x12, 0x49, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x33, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x49, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x63, 0x6f, 0x70, 0x65, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x73, - 0x70, 0x61, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x52, 0x05, - 0x73, 0x70, 0x61, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, - 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x55, 0x72, 0x6c, 0x22, 0xc8, 0x0a, 0x0a, 0x04, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x19, 0x0a, - 0x08, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x70, 0x61, 0x6e, 0x49, - 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, 0x61, 0x63, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x70, 0x61, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, - 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x07, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, - 0x69, 0x6e, 0x64, 0x12, 0x2f, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x06, 0x52, 0x11, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, - 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x2b, 0x0a, 0x12, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x06, - 0x52, 0x0f, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, - 0x6f, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, - 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, - 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x72, - 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x16, 0x64, 0x72, - 0x6f, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0b, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, - 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, - 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0c, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x6b, - 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, - 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, - 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x72, 0x6f, 0x70, 0x70, - 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x4c, 0x69, 0x6e, - 0x6b, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, - 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0xc4, 0x01, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, - 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, - 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, - 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, - 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x16, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0xf4, 0x01, 0x0a, - 0x04, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x17, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x73, 0x70, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x72, 0x61, - 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x74, 0x72, 0x61, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, - 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x16, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, - 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x07, 0x52, 0x05, 0x66, 0x6c, - 0x61, 0x67, 0x73, 0x22, 0x99, 0x01, 0x0a, 0x08, 0x53, 0x70, 0x61, 0x6e, 0x4b, 0x69, 0x6e, 0x64, - 0x12, 0x19, 0x0a, 0x15, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x53, - 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, - 0x4c, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, - 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x50, 0x41, - 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, - 0x16, 0x0a, 0x12, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x50, 0x52, 0x4f, - 0x44, 0x55, 0x43, 0x45, 0x52, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x50, 0x41, 0x4e, 0x5f, - 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45, 0x52, 0x10, 0x05, 0x22, - 0xbd, 0x01, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, - 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x4e, 0x0a, 0x0a, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x55, - 0x53, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x12, - 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x4f, 0x4b, - 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x44, - 0x45, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x2a, - 0x9c, 0x01, 0x0a, 0x09, 0x53, 0x70, 0x61, 0x6e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x19, 0x0a, - 0x15, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x46, 0x4c, 0x41, 0x47, 0x53, 0x5f, 0x44, 0x4f, 0x5f, 0x4e, - 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1b, 0x53, 0x50, 0x41, 0x4e, - 0x5f, 0x46, 0x4c, 0x41, 0x47, 0x53, 0x5f, 0x54, 0x52, 0x41, 0x43, 0x45, 0x5f, 0x46, 0x4c, 0x41, - 0x47, 0x53, 0x5f, 0x4d, 0x41, 0x53, 0x4b, 0x10, 0xff, 0x01, 0x12, 0x2a, 0x0a, 0x25, 0x53, 0x50, - 0x41, 0x4e, 0x5f, 0x46, 0x4c, 0x41, 0x47, 0x53, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x58, 0x54, - 0x5f, 0x48, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4d, - 0x41, 0x53, 0x4b, 0x10, 0x80, 0x02, 0x12, 0x26, 0x0a, 0x21, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x46, - 0x4c, 0x41, 0x47, 0x53, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x5f, 0x49, 0x53, 0x5f, - 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4d, 0x41, 0x53, 0x4b, 0x10, 0x80, 0x04, 0x42, 0x77, - 0x0a, 0x1f, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x42, 0x0a, 0x54, 0x72, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, - 0x27, 0x67, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x74, 0x6c, 0x70, 0x2f, - 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x31, 0xaa, 0x02, 0x1c, 0x4f, 0x70, 0x65, 0x6e, 0x54, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, - 0x72, 0x61, 0x63, 0x65, 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_opentelemetry_proto_trace_v1_trace_proto_rawDesc = "" + + "\n" + + "(opentelemetry/proto/trace/v1/trace.proto\x12\x1copentelemetry.proto.trace.v1\x1a*opentelemetry/proto/common/v1/common.proto\x1a.opentelemetry/proto/resource/v1/resource.proto\"`\n" + + "\n" + + "TracesData\x12R\n" + + "\x0eresource_spans\x18\x01 \x03(\v2+.opentelemetry.proto.trace.v1.ResourceSpansR\rresourceSpans\"\xc8\x01\n" + + "\rResourceSpans\x12E\n" + + "\bresource\x18\x01 \x01(\v2).opentelemetry.proto.resource.v1.ResourceR\bresource\x12I\n" + + "\vscope_spans\x18\x02 \x03(\v2(.opentelemetry.proto.trace.v1.ScopeSpansR\n" + + "scopeSpans\x12\x1d\n" + + "\n" + + "schema_url\x18\x03 \x01(\tR\tschemaUrlJ\x06\b\xe8\a\x10\xe9\a\"\xb0\x01\n" + + "\n" + + "ScopeSpans\x12I\n" + + "\x05scope\x18\x01 \x01(\v23.opentelemetry.proto.common.v1.InstrumentationScopeR\x05scope\x128\n" + + "\x05spans\x18\x02 \x03(\v2\".opentelemetry.proto.trace.v1.SpanR\x05spans\x12\x1d\n" + + "\n" + + "schema_url\x18\x03 \x01(\tR\tschemaUrl\"\xc8\n" + + "\n" + + "\x04Span\x12\x19\n" + + "\btrace_id\x18\x01 \x01(\fR\atraceId\x12\x17\n" + + "\aspan_id\x18\x02 \x01(\fR\x06spanId\x12\x1f\n" + + "\vtrace_state\x18\x03 \x01(\tR\n" + + "traceState\x12$\n" + + "\x0eparent_span_id\x18\x04 \x01(\fR\fparentSpanId\x12\x14\n" + + "\x05flags\x18\x10 \x01(\aR\x05flags\x12\x12\n" + + "\x04name\x18\x05 \x01(\tR\x04name\x12?\n" + + "\x04kind\x18\x06 \x01(\x0e2+.opentelemetry.proto.trace.v1.Span.SpanKindR\x04kind\x12/\n" + + "\x14start_time_unix_nano\x18\a \x01(\x06R\x11startTimeUnixNano\x12+\n" + + "\x12end_time_unix_nano\x18\b \x01(\x06R\x0fendTimeUnixNano\x12G\n" + + "\n" + + "attributes\x18\t \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x128\n" + + "\x18dropped_attributes_count\x18\n" + + " \x01(\rR\x16droppedAttributesCount\x12@\n" + + "\x06events\x18\v \x03(\v2(.opentelemetry.proto.trace.v1.Span.EventR\x06events\x120\n" + + "\x14dropped_events_count\x18\f \x01(\rR\x12droppedEventsCount\x12=\n" + + "\x05links\x18\r \x03(\v2'.opentelemetry.proto.trace.v1.Span.LinkR\x05links\x12.\n" + + "\x13dropped_links_count\x18\x0e \x01(\rR\x11droppedLinksCount\x12<\n" + + "\x06status\x18\x0f \x01(\v2$.opentelemetry.proto.trace.v1.StatusR\x06status\x1a\xc4\x01\n" + + "\x05Event\x12$\n" + + "\x0etime_unix_nano\x18\x01 \x01(\x06R\ftimeUnixNano\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12G\n" + + "\n" + + "attributes\x18\x03 \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x128\n" + + "\x18dropped_attributes_count\x18\x04 \x01(\rR\x16droppedAttributesCount\x1a\xf4\x01\n" + + "\x04Link\x12\x19\n" + + "\btrace_id\x18\x01 \x01(\fR\atraceId\x12\x17\n" + + "\aspan_id\x18\x02 \x01(\fR\x06spanId\x12\x1f\n" + + "\vtrace_state\x18\x03 \x01(\tR\n" + + "traceState\x12G\n" + + "\n" + + "attributes\x18\x04 \x03(\v2'.opentelemetry.proto.common.v1.KeyValueR\n" + + "attributes\x128\n" + + "\x18dropped_attributes_count\x18\x05 \x01(\rR\x16droppedAttributesCount\x12\x14\n" + + "\x05flags\x18\x06 \x01(\aR\x05flags\"\x99\x01\n" + + "\bSpanKind\x12\x19\n" + + "\x15SPAN_KIND_UNSPECIFIED\x10\x00\x12\x16\n" + + "\x12SPAN_KIND_INTERNAL\x10\x01\x12\x14\n" + + "\x10SPAN_KIND_SERVER\x10\x02\x12\x14\n" + + "\x10SPAN_KIND_CLIENT\x10\x03\x12\x16\n" + + "\x12SPAN_KIND_PRODUCER\x10\x04\x12\x16\n" + + "\x12SPAN_KIND_CONSUMER\x10\x05\"\xbd\x01\n" + + "\x06Status\x12\x18\n" + + "\amessage\x18\x02 \x01(\tR\amessage\x12C\n" + + "\x04code\x18\x03 \x01(\x0e2/.opentelemetry.proto.trace.v1.Status.StatusCodeR\x04code\"N\n" + + "\n" + + "StatusCode\x12\x15\n" + + "\x11STATUS_CODE_UNSET\x10\x00\x12\x12\n" + + "\x0eSTATUS_CODE_OK\x10\x01\x12\x15\n" + + "\x11STATUS_CODE_ERROR\x10\x02J\x04\b\x01\x10\x02*\x9c\x01\n" + + "\tSpanFlags\x12\x19\n" + + "\x15SPAN_FLAGS_DO_NOT_USE\x10\x00\x12 \n" + + "\x1bSPAN_FLAGS_TRACE_FLAGS_MASK\x10\xff\x01\x12*\n" + + "%SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK\x10\x80\x02\x12&\n" + + "!SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK\x10\x80\x04Bw\n" + + "\x1fio.opentelemetry.proto.trace.v1B\n" + + "TraceProtoP\x01Z'go.opentelemetry.io/proto/otlp/trace/v1\xaa\x02\x1cOpenTelemetry.Proto.Trace.V1b\x06proto3" var ( file_opentelemetry_proto_trace_v1_trace_proto_rawDescOnce sync.Once - file_opentelemetry_proto_trace_v1_trace_proto_rawDescData = file_opentelemetry_proto_trace_v1_trace_proto_rawDesc + file_opentelemetry_proto_trace_v1_trace_proto_rawDescData []byte ) func file_opentelemetry_proto_trace_v1_trace_proto_rawDescGZIP() []byte { file_opentelemetry_proto_trace_v1_trace_proto_rawDescOnce.Do(func() { - file_opentelemetry_proto_trace_v1_trace_proto_rawDescData = protoimpl.X.CompressGZIP(file_opentelemetry_proto_trace_v1_trace_proto_rawDescData) + file_opentelemetry_proto_trace_v1_trace_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_trace_v1_trace_proto_rawDesc), len(file_opentelemetry_proto_trace_v1_trace_proto_rawDesc))) }) return file_opentelemetry_proto_trace_v1_trace_proto_rawDescData } var file_opentelemetry_proto_trace_v1_trace_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_opentelemetry_proto_trace_v1_trace_proto_msgTypes = make([]protoimpl.MessageInfo, 7) -var file_opentelemetry_proto_trace_v1_trace_proto_goTypes = []interface{}{ +var file_opentelemetry_proto_trace_v1_trace_proto_goTypes = []any{ (SpanFlags)(0), // 0: opentelemetry.proto.trace.v1.SpanFlags (Span_SpanKind)(0), // 1: opentelemetry.proto.trace.v1.Span.SpanKind (Status_StatusCode)(0), // 2: opentelemetry.proto.trace.v1.Status.StatusCode @@ -1177,97 +1088,11 @@ func file_opentelemetry_proto_trace_v1_trace_proto_init() { if File_opentelemetry_proto_trace_v1_trace_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TracesData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResourceSpans); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScopeSpans); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Span); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Status); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Span_Event); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_opentelemetry_proto_trace_v1_trace_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Span_Link); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_opentelemetry_proto_trace_v1_trace_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_opentelemetry_proto_trace_v1_trace_proto_rawDesc), len(file_opentelemetry_proto_trace_v1_trace_proto_rawDesc)), NumEnums: 3, NumMessages: 7, NumExtensions: 0, @@ -1279,7 +1104,6 @@ func file_opentelemetry_proto_trace_v1_trace_proto_init() { MessageInfos: file_opentelemetry_proto_trace_v1_trace_proto_msgTypes, }.Build() File_opentelemetry_proto_trace_v1_trace_proto = out.File - file_opentelemetry_proto_trace_v1_trace_proto_rawDesc = nil file_opentelemetry_proto_trace_v1_trace_proto_goTypes = nil file_opentelemetry_proto_trace_v1_trace_proto_depIdxs = nil } diff --git a/vendor/go.yaml.in/yaml/v3/resolve.go b/vendor/go.yaml.in/yaml/v3/resolve.go index 64ae88805..d47f50e64 100644 --- a/vendor/go.yaml.in/yaml/v3/resolve.go +++ b/vendor/go.yaml.in/yaml/v3/resolve.go @@ -42,6 +42,7 @@ func init() { for _, c := range "yYnNtTfFoO~" { t[int(c)] = 'M' // In map } + t[int('<')] = 'M' // In map (merge key "<<") t[int('.')] = '.' // Float (potentially in map) var resolveMapList = []struct { diff --git a/vendor/google.golang.org/grpc/CONTRIBUTING.md b/vendor/google.golang.org/grpc/CONTRIBUTING.md index 2079de7b0..bd80b1f92 100644 --- a/vendor/google.golang.org/grpc/CONTRIBUTING.md +++ b/vendor/google.golang.org/grpc/CONTRIBUTING.md @@ -23,6 +23,29 @@ wanted"](https://github.com/grpc/grpc-go/issues?q=sort%3Aupdated-desc%20is%3Aiss are especially nice for first-time contributors, as they should be well-defined problems that already have agreed-upon solutions. +## Generative AI Policy + +AI tools have the ability to produce more code than is possible for the gRPC +team to read, understand, review, and accept into the repository. For this +reason, we request that all contributions adhere to the following rules: + +1. **No AI-Generated Interactions:** All communication in the repo must be + authored by a human. _Exception: AIs may be used for directed writing + assistance or translation._ Absolutely no automated agents are allowed to + directly publish to GitHub. + +2. **Author Ownership and Accountability:** Code contributions are expected to + be fully owned and understood by the human contributor. If the code was + produced by generative AI, the author is expected to have reviewed and + understood it in its entirety before submitting it for review. This includes + all content: production code, tests, examples, tools, etc. + +In addition to the above requirements, any AI-assisted contributions must also +comply with the [Linux Foundation Generative AI +Policy](https://www.linuxfoundation.org/legal/generative-ai). This includes +confirming that all contributions are legally allowed to be contributed to the +gRPC project under the applicable license terms. + ## Code Style We follow [Google's published Go style diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go index 6c249fdaf..d22d1c3f1 100644 --- a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go +++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go @@ -18,7 +18,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v5.27.1 // source: grpc/binlog/v1/binarylog.proto diff --git a/vendor/google.golang.org/grpc/call.go b/vendor/google.golang.org/grpc/call.go index 2079bf4ed..788c89c16 100644 --- a/vendor/google.golang.org/grpc/call.go +++ b/vendor/google.golang.org/grpc/call.go @@ -20,10 +20,6 @@ package grpc import ( "context" - "io" - - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // Invoke sends the RPC request on the wire and returns after response is @@ -71,27 +67,8 @@ func invoke(ctx context.Context, method string, req, reply any, cc *ClientConn, if err != nil { return err } - // In case of nil or io.EOF error, call RecvMsg. - if err := cs.SendMsg(req); err != nil && err != io.EOF { + if err := cs.SendMsg(req); err != nil { return err } - // CloseSend is needed because in some scenarios (e.g., xDS), the same - // interceptors are used to process both unary and streaming RPCs. Calling - // CloseSend signals to those interceptors that no more messages are on the - // way. - if err := cs.CloseSend(); err != nil && err != io.EOF { - return err - } - if err := cs.RecvMsg(reply); err != nil { - return err - } - // Call RecvMsg again to get the trailers. - err = cs.RecvMsg(reply) - if err == io.EOF { - return nil - } - if err == nil { - return status.Error(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message") - } - return err + return cs.RecvMsg(reply) } diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index f5ce07197..7a25d251e 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -553,7 +553,6 @@ func chainStreamClientInterceptors(cc *ClientConn) { if cc.dopts.streamInt != nil { interceptors = append([]StreamClientInterceptor{cc.dopts.streamInt}, interceptors...) } - interceptors = append(interceptors, defaultStreamInterceptor) var chainedInt StreamClientInterceptor if len(interceptors) == 0 { chainedInt = nil @@ -1212,6 +1211,12 @@ func (cc *ClientConn) Close() error { cc.mu.Unlock() cc.resolverWrapper.close() + // Swap in a default ConfigSelector so the resolver-provided one (which may + // transitively retain resolver-owned state such as parsed service configs + // and cluster maps) is released once in-flight RPCs finish selecting on + // it. Done after the resolver has closed so no further UpdateState calls + // race with this swap. + cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{nil}) // The order of closing matters here since the balancer wrapper assumes the // picker is closed before it is closed. cc.pickerWrapper.close() diff --git a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go index dcb98cdbc..35d4c8303 100644 --- a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go +++ b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v5.27.1 // source: grpc/health/v1/health.proto diff --git a/vendor/google.golang.org/grpc/health/server.go b/vendor/google.golang.org/grpc/health/server.go index d8eebe99d..0c0669dff 100644 --- a/vendor/google.golang.org/grpc/health/server.go +++ b/vendor/google.golang.org/grpc/health/server.go @@ -107,6 +107,9 @@ func (s *Server) Watch(in *healthpb.HealthCheckRequest, stream healthgrpc.Health defer func() { s.mu.Lock() delete(s.updates[service], stream) + if len(s.updates[service]) == 0 { + delete(s.updates, service) + } s.mu.Unlock() }() s.mu.Unlock() diff --git a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go index 966932891..ca0e586df 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go @@ -395,7 +395,7 @@ func (c *Cancel) toProto() *binlogpb.GrpcLogEntry { // omitted. func metadataKeyOmit(key string) bool { switch key { - case "lb-token", ":path", ":authority", "content-encoding", "content-type", "user-agent", "te": + case "lb-token", ":path", ":authority", "content-encoding", "content-type", "user-agent", "te", "authorization": return true case "grpc-trace-bin": // grpc-trace-bin is special because it's visible to users. return false diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go index dc6fc0c4c..2f4ae2fad 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -144,14 +144,14 @@ var ( // ControlBufferThrottleLimit is the maximum number of control frames that can // be queued in the control buffer before throttling is applied. The value - // must be between 1 and 10,000, and is set to 100 by default. + // must be between 1 and 100,000, and is set to 10,000 by default. // // This environment variable serves as an escape hatch to increase the // throttling limit if unforeseen issues arise, and it will be removed in a // future release. // - // TODO: Remove this env var once v1.83.0 is released. - ControlBufferThrottleLimit = uint64FromEnv("GRPC_GO_EXPERIMENTAL_CONTROL_BUFFER_THROTTLE_LIMIT", 100, 1, 10000) + // TODO: Remove this env var once v1.86.0 is released. + ControlBufferThrottleLimit = uint64FromEnv("GRPC_GO_EXPERIMENTAL_CONTROL_BUFFER_THROTTLE_LIMIT", 10000, 1, 100000) // ALTSMaxFrameSize is the maximum frame size for ALTS in bytes. // This can be overridden by setting the environment variable diff --git a/vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go b/vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go index 070680edb..4718576ed 100644 --- a/vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go +++ b/vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go @@ -47,10 +47,9 @@ const ( var bdpPing = &ping{data: [8]byte{2, 4, 16, 16, 9, 14, 7, 7}} type bdpEstimator struct { + mu sync.Mutex // sentAt is the time when the ping was sent. sentAt time.Time - - mu sync.Mutex // bdp is the current bdp estimate. bdp uint32 // sample is the number of bytes received in one measurement cycle. @@ -75,7 +74,9 @@ func (b *bdpEstimator) timesnap(d [8]byte) { if bdpPing.data != d { return } + b.mu.Lock() b.sentAt = time.Now() + b.mu.Unlock() } // add adds bytes to the current sample for calculating bdp. diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go index 89c938fdb..e33ac3a5f 100644 --- a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go +++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go @@ -26,6 +26,7 @@ import ( "runtime" "sync" "sync/atomic" + "time" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" @@ -97,22 +98,35 @@ func (il *itemList) isEmpty() bool { return il.head == nil } -// maxQueuedControlBufferItems is the maximum number of frames (other than -// HEADERS and DATA) that we will buffer before preventing new reads from -// occurring on the transport. These are control frames sent in response to -// client requests, or frames that result in work being scheduled, such as -// RST_STREAM due to bad headers or settings acks. -var maxQueuedControlBufferItems = int(envconfig.ControlBufferThrottleLimit) +// maxQueuedTransportResponseFrames is the maximum number of "transport +// response" frames that we will buffer before preventing new reads from +// occurring on the transport. See cbItem.isTransportResponseFrame for the +// items that count towards this limit. +var maxQueuedTransportResponseFrames = int(envconfig.ControlBufferThrottleLimit) type cbItem interface { - isThrottled() bool + // isTransportResponseFrame reports whether the item counts against the + // maxQueuedTransportResponseFrames limit, when queued in the + // controlBuffer of a transport on the given side. + // + // Items that the peer can make the transport queue in unbounded + // numbers, for example by sending PING or SETTINGS frames, must be + // counted, so that the transport stops reading from a peer that sends + // such frames without reading what the transport writes. Items whose + // number grows with the local application's load (for example, one + // per stream it creates) must not be counted. Otherwise, under high + // concurrency, both peers could stop reading at the same time and + // deadlock (see https://github.com/grpc/grpc-go/issues/9330). + isTransportResponseFrame(s side) bool } -// throttledItem represents every item in the controlBuffer to which the overall -// throttling limit applies, other than outgoing HEADERS and DATA frames. -type throttledItem struct{} +// nonTransportResponseFrame represents items in the controlBuffer that are not +// queued in response to peer control/reset frames (for example, +// locally-initiated or flow-controlled items). These items are not counted +// against the maxQueuedTransportResponseFrames limit. +type nonTransportResponseFrame struct{} -func (throttledItem) isThrottled() bool { return true } +func (nonTransportResponseFrame) isTransportResponseFrame(side) bool { return false } // The following defines various control items which could flow through // the control buffer of transport. They represent different aspects of @@ -120,12 +134,13 @@ func (throttledItem) isThrottled() bool { return true } // registerStream is used to register an incoming stream with loopy writer. type registerStream struct { - throttledItem + nonTransportResponseFrame streamID uint32 wq *writeQuota } type clientHeaders struct { + nonTransportResponseFrame streamID uint32 hf []hpack.HeaderField initStream func(uint32) error @@ -134,9 +149,8 @@ type clientHeaders struct { onOrphaned func(error) } -func (*clientHeaders) isThrottled() bool { return false } - type serverHeaders struct { + nonTransportResponseFrame streamID uint32 hf []hpack.HeaderField endStream bool @@ -144,24 +158,37 @@ type serverHeaders struct { cleanup *cleanupStream } -func (h *serverHeaders) isThrottled() bool { return false } - type cleanupStream struct { - throttledItem streamID uint32 rst bool rstCode http2.ErrCode onWrite func() } +// isTransportResponseFrame returns true on the server since cleanupStream +// either results in a RST_STREAM frame being sent on the wire or in +// non-trivial work being performed when under a Rapid Reset attack. +// +// It returns false on the client, where a cleanupStream is queued at most once +// per stream, and the number of streams is controlled by the client and not by +// the server. Counting them on the client makes the client stop reading under +// high concurrency, which deadlocks with a server that has also stopped +// reading (see https://github.com/grpc/grpc-go/issues/9330). +func (*cleanupStream) isTransportResponseFrame(s side) bool { return s == serverSide } + type earlyAbortStream struct { - throttledItem streamID uint32 rst bool hf []hpack.HeaderField // Pre-built header fields } +// isTransportResponseFrame returns true on the server since earlyAbortStream +// results in a HEADERS frame being sent on the wire, and possibly a RST_STREAM +// frame. It is never queued on the client. +func (*earlyAbortStream) isTransportResponseFrame(s side) bool { return s == serverSide } + type dataFrame struct { + nonTransportResponseFrame streamID uint32 endStream bool h []byte @@ -172,36 +199,40 @@ type dataFrame struct { onEachWrite func() } -func (*dataFrame) isThrottled() bool { return false } - type incomingWindowUpdate struct { - throttledItem streamID uint32 increment uint32 } +// isTransportResponseFrame returns true to protect against a WINDOW_UPDATE +// flood attack from the peer. +func (*incomingWindowUpdate) isTransportResponseFrame(side) bool { return true } + type outgoingWindowUpdate struct { - throttledItem + nonTransportResponseFrame streamID uint32 increment uint32 } type incomingSettings struct { - throttledItem ss []http2.Setting } +// isTransportResponseFrame returns true since incomingSettings results in a +// SETTINGS ACK frame being sent on the wire. +func (*incomingSettings) isTransportResponseFrame(side) bool { return true } + type outgoingSettings struct { - throttledItem + nonTransportResponseFrame ss []http2.Setting } type incomingGoAway struct { - throttledItem + nonTransportResponseFrame } type goAway struct { - throttledItem + nonTransportResponseFrame code http2.ErrCode debugData []byte headsUp bool @@ -209,13 +240,23 @@ type goAway struct { } type ping struct { - throttledItem ack bool data [8]byte } +// isTransportResponseFrame returns true for all pings, and not only for ping +// acks sent in response to pings from the peer. This is because a BDP ping is +// queued in response to a DATA frame (of any size) from the peer, whenever +// there is no BDP ping outstanding. And since the BDP ping's payload is fixed, +// the peer can make it look like the BDP ping was acked at any time, by +// sending a ping ack with that payload. A peer alternating between empty DATA +// frames and such ping acks would otherwise be able to queue an unbounded +// number of BDP pings. Pings initiated locally (keepalive and BDP) are rare +// enough to not cause throttling of well-behaved peers. +func (*ping) isTransportResponseFrame(side) bool { return true } + type outFlowControlSizeRequest struct { - throttledItem + nonTransportResponseFrame resp chan uint32 } @@ -225,7 +266,7 @@ type outFlowControlSizeRequest struct { // can inspect settled accounting values (such as bytesOutStanding) after loopyWriter // has run to completion without any data races. type outStreamRequestForTesting struct { - throttledItem + nonTransportResponseFrame streamID uint32 resp chan *outStream } @@ -235,7 +276,7 @@ type outStreamRequestForTesting struct { // (by the client or server). The transport itself will close after the reader // encounters the EOF caused by the connection closure. type closeConnection struct { - throttledItem + nonTransportResponseFrame } type outStreamState int @@ -316,8 +357,9 @@ func (l *outStreamList) dequeue() *outStream { // shouldn't be confused with an HTTP2 frame, although some of the control // frames like dataFrame and headerFrame do go out on wire as HTTP2 frames. type controlBuffer struct { - wakeupCh chan struct{} // Unblocks readers waiting for something to read. + wakeupCh chan struct{} // Unblocks readers waiting for new items. done <-chan struct{} // Closed when the transport is done. + side side // Side of the transport owning this buffer. // Mutex guards all the fields below, except trfChan which can be read // atomically without holding mu. @@ -326,26 +368,30 @@ type controlBuffer struct { closed bool // True when the controlbuf is finished. list *itemList // List of queued control frames. - // transportResponseFrames counts the number of queued items that represent - // the response of an action initiated by the peer. trfChan is created - // when transportResponseFrames >= maxQueuedTransportResponseFrames and is - // closed and nilled when transportResponseFrames drops below the - // threshold. Both fields are protected by mu. + // transportResponseFrames counts the number of queued items that + // represent the response of an action initiated by the peer (as + // determined by cbItem.isTransportResponseFrame for this side). + // trfChan is created when transportResponseFrames >= + // maxQueuedTransportResponseFrames and is closed and nilled when + // transportResponseFrames drops below the threshold. Both fields are + // protected by mu. transportResponseFrames int trfChan atomic.Pointer[chan struct{}] } -func newControlBuffer(done <-chan struct{}) *controlBuffer { +func newControlBuffer(done <-chan struct{}, s side) *controlBuffer { return &controlBuffer{ wakeupCh: make(chan struct{}, 1), list: &itemList{}, done: done, + side: s, } } -// throttle blocks if there are too many frames in the control buf that -// represent the response of an action initiated by the peer, like -// incomingSettings cleanupStreams etc. +// throttle blocks if there are too many items in the control buffer that count +// towards the maxQueuedTransportResponseFrames limit (see +// cbItem.isTransportResponseFrame), until their number drops below the limit, +// the control buffer is finished, or the transport is done. func (c *controlBuffer) throttle() { if ch := c.trfChan.Load(); ch != nil { select { @@ -355,6 +401,25 @@ func (c *controlBuffer) throttle() { } } +// throttleWithTimeout is like throttle, but it stops waiting and returns an +// error if the control buffer is still throttled after the given duration. +func (c *controlBuffer) throttleWithTimeout(timeout time.Duration) error { + ch := c.trfChan.Load() + if ch == nil { + return nil + } + timer := time.NewTimer(timeout) + defer timer.Stop() + select { + case <-(*ch): + return nil + case <-c.done: + return nil + case <-timer.C: + return fmt.Errorf("still throttled after %v, with at least %d queued frames", timeout, maxQueuedTransportResponseFrames) + } +} + // put adds an item to the controlbuf. func (c *controlBuffer) put(it cbItem) error { _, err := c.executeAndPut(nil, it) @@ -390,9 +455,9 @@ func (c *controlBuffer) executeAndPut(f func() bool, it cbItem) (bool, error) { c.consumerWaiting = false } c.list.enqueue(it) - if it.isThrottled() { + if it.isTransportResponseFrame(c.side) { c.transportResponseFrames++ - if c.transportResponseFrames == maxQueuedControlBufferItems { + if c.transportResponseFrames == maxQueuedTransportResponseFrames { // We are adding the frame that puts us over the threshold; create // a throttling channel. ch := make(chan struct{}) @@ -447,8 +512,8 @@ func (c *controlBuffer) getOnceLocked() (any, error) { return nil, nil } h := c.list.dequeue().(cbItem) - if h.isThrottled() { - if c.transportResponseFrames == maxQueuedControlBufferItems { + if h.isTransportResponseFrame(c.side) { + if c.transportResponseFrames == maxQueuedTransportResponseFrames { // We are removing the frame that put us over the // threshold; close and clear the throttling channel. ch := c.trfChan.Swap(nil) @@ -484,9 +549,10 @@ func (c *controlBuffer) finish() { } } - // In case throttle() is currently in flight, it needs to be unblocked. - // Otherwise, the transport may not close, since the transport is closed by - // the reader encountering the connection error. + // In case throttle() or throttleWithTimeout() is currently in flight, + // it needs to be unblocked. Otherwise, the transport may not close, + // since the transport is closed by the reader encountering the + // connection error. ch := c.trfChan.Swap(nil) if ch != nil { close(*ch) diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go index 9cd8d28d3..a701522b4 100644 --- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go @@ -268,7 +268,7 @@ func (ht *serverHandlerTransport) writeStatus(s *ServerStream, st *status.Status for _, v := range vv { // http2 ResponseWriter mechanism to send undeclared Trailers after // the headers have possibly been written. - h.Add(http2.TrailerPrefix+k, encodeMetadataHeader(k, v)) + h.Add(http.TrailerPrefix+k, encodeMetadataHeader(k, v)) } } } @@ -494,7 +494,8 @@ func mapRecvMsgError(err error) error { if err == io.EOF || err == io.ErrUnexpectedEOF { return err } - if se, ok := err.(http2.StreamError); ok { + var se http2.StreamError + if errors.As(err, &se) { if code, ok := http2ErrConvTab[se.Code]; ok { return status.Error(code, se.Error()) } diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 720fc4e5b..a198bafbd 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -65,6 +65,13 @@ var clientConnectionCounter uint64 var goAwayLoopyWriterTimeout = 5 * time.Second +// clientThrottleTimeout is the maximum amount of time for which the client +// stops reading from the connection because too many frames queued in +// response to the server (see maxQueuedTransportResponseFrames) are waiting +// to be written. After that, the client closes the connection instead of +// waiting forever, since the server is most likely not reading. +var clientThrottleTimeout = 10 * time.Second + var metadataFromOutgoingContextRaw = internal.FromOutgoingContextRaw.(func(context.Context) (metadata.MD, [][]string, bool)) // http2Client implements the ClientTransport interface with HTTP2. @@ -107,6 +114,12 @@ type http2Client struct { kp keepalive.ClientParameters keepaliveEnabled bool + // throttleTimeout is the maximum amount of time for which reads can + // stay throttled before the connection is closed. It is copied from + // clientThrottleTimeout on creation, so that tests can override the + // latter without racing with the readers of other transports. + throttleTimeout time.Duration + statsHandler stats.Handler initialWindowSize int32 @@ -359,6 +372,7 @@ func NewHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts streamQuota: defaultMaxStreamsClient, streamsQuotaAvailable: make(chan struct{}, 1), keepaliveEnabled: keepaliveEnabled, + throttleTimeout: clientThrottleTimeout, bufferPool: opts.BufferPool, onClose: onClose, } @@ -386,7 +400,7 @@ func NewHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts } else if md := imetadata.Get(addr); md != nil { t.md = md } - t.controlBuf = newControlBuffer(t.ctxDone) + t.controlBuf = newControlBuffer(t.ctxDone, clientSide) if opts.InitialWindowSize >= defaultWindowSize { t.initialWindowSize = opts.InitialWindowSize } @@ -952,6 +966,7 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr, handler s LocalAddr: t.localAddr, Compression: callHdr.SendCompress, Header: header, + Authority: callHdr.Host, }) } if transportDrainRequired { @@ -1726,9 +1741,19 @@ func (t *http2Client) reader(errCh chan<- error) { atomic.StoreInt64(&t.lastRead, time.Now().UnixNano()) } - // loop to keep reading incoming messages on this transport. + // Loop to keep reading incoming messages on this transport. for { - t.controlBuf.throttle() + // Stop reading while too many items that the server can make + // the client queue (see cbItem.isTransportResponseFrame) are + // waiting to be written, to bound the memory that a server + // can make the client use by flooding it without reading. If + // reads stay throttled for t.throttleTimeout, close the + // connection instead of waiting forever. + if err := t.controlBuf.throttleWithTimeout(t.throttleTimeout); err != nil { + t.logger.Warningf("Closing connection since the server is not reading: %v", err) + errClose = connectionErrorf(true, err, "closing connection since the server is not reading: %v", err) + return + } frame, err := t.framer.readFrame() if t.keepaliveEnabled { atomic.StoreInt64(&t.lastRead, time.Now().UnixNano()) diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index f11e88cc5..5c3fc7658 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -297,7 +297,7 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport, ) t.logger = prefixLoggerForServerTransport(t) - t.controlBuf = newControlBuffer(t.done) + t.controlBuf = newControlBuffer(t.done, serverSide) if !config.StaticWindowSize { t.bdpEst = &bdpEstimator{ bdp: initialWindowSize, @@ -380,6 +380,11 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade defer t.maxStreamMu.Unlock() streamID := frame.Header().StreamID + if streamID%2 != 1 || streamID <= t.maxStreamID { + // illegal gRPC stream id. + return fmt.Errorf("received an illegal stream id: %v. headers frame: %+v", streamID, frame) + } + t.maxStreamID = streamID // frame.Truncated is set to true when framer detects that the current header // list size hits MaxHeaderListSize limit. @@ -393,12 +398,6 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade return nil } - if streamID%2 != 1 || streamID <= t.maxStreamID { - // illegal gRPC stream id. - return fmt.Errorf("received an illegal stream id: %v. headers frame: %+v", streamID, frame) - } - t.maxStreamID = streamID - s := &ServerStream{ Stream: Stream{ id: streamID, @@ -1014,7 +1013,17 @@ func (t *http2Server) streamContextErr(s *ServerStream) error { return ErrConnClosing default: } - return ContextErr(s.ctx.Err()) + err := s.ctx.Err() + if err == nil { + // In closeStream and finishStream, the stream state is transitioned to + // streamDone before s.cancel() is invoked so that concurrent operations + // immediately observe the terminal state. A concurrent caller (such as + // write or writeHeader) can see streamDone and invoke streamContextErr + // before s.cancel() runs or propagates to s.ctx. Default to + // context.Canceled rather than passing nil to ContextErr. + err = context.Canceled + } + return ContextErr(err) } // WriteHeader sends the header metadata md back to the client. @@ -1336,10 +1345,6 @@ func (t *http2Server) deleteStream(s *ServerStream, eosReceived bool) { // finishStream closes the stream and puts the trailing headerFrame into controlbuf. func (t *http2Server) finishStream(s *ServerStream, rst bool, rstCode http2.ErrCode, hdr *serverHeaders, eosReceived bool) { - // In case stream sending and receiving are invoked in separate - // goroutines (e.g., bi-directional streaming), cancel needs to be - // called to interrupt the potential blocking on other goroutines. - s.cancel() oldState := s.swapState(streamDone) if oldState == streamDone { @@ -1347,6 +1352,11 @@ func (t *http2Server) finishStream(s *ServerStream, rst bool, rstCode http2.ErrC return } + // In case stream sending and receiving are invoked in separate + // goroutines (e.g., bi-directional streaming), cancel needs to be + // called to interrupt the potential blocking on other goroutines. + s.cancel() + hdr.cleanup = &cleanupStream{ streamID: s.id, rst: rst, @@ -1360,15 +1370,16 @@ func (t *http2Server) finishStream(s *ServerStream, rst bool, rstCode http2.ErrC // closeStream clears the footprint of a stream when the stream is not needed any more. func (t *http2Server) closeStream(s *ServerStream, rst bool, rstCode http2.ErrCode, eosReceived bool) { + // We can't return early even if the stream's state is "done" as the state + // might have been set by the `finishStream` method. Deleting the stream via + // `finishStream` can get blocked on flow control. + s.swapState(streamDone) + // In case stream sending and receiving are invoked in separate // goroutines (e.g., bi-directional streaming), cancel needs to be // called to interrupt the potential blocking on other goroutines. s.cancel() - // We can't return early even if the stream's state is "done" as the state - // might have been set by the `finishStream` method. Deleting the stream via - // `finishStream` can get blocked on flow control. - s.swapState(streamDone) t.deleteStream(s, eosReceived) t.controlBuf.put(&cleanupStream{ diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go index fc656b36c..f627adf68 100644 --- a/vendor/google.golang.org/grpc/internal/transport/transport.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport.go @@ -121,7 +121,9 @@ func (b *recvBuffer) put(r recvMsg) { if b.err != nil { // drop the buffer on the floor. Since b.err is not nil, any subsequent reads // will always return an error, making this buffer inaccessible. - r.buffer.Free() + if r.buffer != nil { + r.buffer.Free() + } // An error had occurred earlier, don't accept more // data or errors. return diff --git a/vendor/google.golang.org/grpc/metadata/metadata.go b/vendor/google.golang.org/grpc/metadata/metadata.go index 2b79204b4..a3090ff3d 100644 --- a/vendor/google.golang.org/grpc/metadata/metadata.go +++ b/vendor/google.golang.org/grpc/metadata/metadata.go @@ -360,6 +360,66 @@ func FromOutgoingContext(ctx context.Context) (MD, bool) { return out, ok } +// ValueFromOutgoingContext returns the metadata value corresponding to the +// metadata key from the outgoing metadata if it exists. Keys are matched in a +// case-insensitive manner. +// +// Unlike FromOutgoingContext, this does not copy the entire outgoing metadata. +func ValueFromOutgoingContext(ctx context.Context, key string) []string { + raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) + if !ok { + return nil + } + + key = strings.ToLower(key) + // Unlike ValueFromIncomingContext, this can't return as soon as raw.md is + // checked: raw.added still needs to be walked and accumulated regardless. + // The else below prevents that from overwriting an exact match with an + // unrelated case-insensitive one. + var matchedMD []string + if v, ok := raw.md[key]; ok { + matchedMD = v + } else { + for k, v := range raw.md { + // Case insensitive comparison: MD is a map, and there's no + // guarantee that the MD attached to the context is created using + // our helper functions. + if strings.EqualFold(k, key) { + matchedMD = v + break + } + } + } + + // Defer allocating vals until raw.added actually has a match, so a match + // found only in raw.md doesn't pay for both a copyOf and a growing + // append. + var vals []string + for _, added := range raw.added { + if len(added)%2 == 1 { + panic(fmt.Sprintf("metadata: ValueFromOutgoingContext got an odd number of input pairs for metadata: %d", len(added))) + } + + // Case insensitive, like FromOutgoingContext: added isn't guaranteed + // lowercase, though AppendToOutgoingContext already lowercases it in + // practice, so try the cheap exact match first. + for i := 0; i < len(added); i += 2 { + if added[i] == key || strings.EqualFold(added[i], key) { + if vals == nil { + vals = make([]string, 0, len(matchedMD)+1) + vals = append(vals, matchedMD...) + } + vals = append(vals, added[i+1]) + } + } + } + + if vals == nil && matchedMD != nil { + return copyOf(matchedMD) + } + return vals +} + type rawMD struct { md MD added [][]string diff --git a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1/reflection.pb.go b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1/reflection.pb.go index 556ab033d..c8772eb03 100644 --- a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1/reflection.pb.go +++ b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1/reflection.pb.go @@ -21,7 +21,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v5.27.1 // source: grpc/reflection/v1/reflection.proto diff --git a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go index 6a46bb51f..b927bd443 100644 --- a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go +++ b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go @@ -18,7 +18,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 +// protoc-gen-go v1.36.12 // protoc v5.27.1 // grpc/reflection/v1alpha/reflection.proto is a deprecated file. diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go index 52f4ea513..6f1bb2eae 100644 --- a/vendor/google.golang.org/grpc/rpc_util.go +++ b/vendor/google.golang.org/grpc/rpc_util.go @@ -179,7 +179,6 @@ type callInfo struct { contentSubtype string codec baseCodec maxRetryRPCBufferSize int - onFinish []func(err error) authority string acceptedResponseCompressors []string } @@ -394,8 +393,7 @@ type OnFinishCallOption struct { OnFinish func(error) } -func (o OnFinishCallOption) before(c *callInfo) error { - c.onFinish = append(c.onFinish, o.OnFinish) +func (o OnFinishCallOption) before(*callInfo) error { return nil } diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 4ab54115b..5c1659729 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go @@ -1400,7 +1400,7 @@ func (s *Server) processRPC(ctx context.Context, stream *transport.ServerStream, ss.decompressorV1 = encoding.GetCompressor(rc) if ss.decompressorV1 == nil { st := status.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", rc) - ss.writeStatus(st) + ss.s.WriteStatus(st) return st.Err() } } @@ -1491,7 +1491,7 @@ func (s *Server) processRPC(ctx context.Context, stream *transport.ServerStream, binlog.Log(ctx, st) } } - if err := ss.writeStatus(appStatus); err != nil { + if err := ss.s.WriteStatus(appStatus); err != nil { channelz.Warningf(logger, s.channelz, "grpc: Server.processRPC failed to write status: %v", err) } return appErr @@ -1510,7 +1510,7 @@ func (s *Server) processRPC(ctx context.Context, stream *transport.ServerStream, binlog.Log(ctx, st) } } - if err := ss.writeStatus(statusOK); err != nil { + if err := ss.s.WriteStatus(statusOK); err != nil { channelz.Warningf(logger, s.channelz, "grpc: Server.processRPC failed to write status: %v", err) } return err @@ -1719,7 +1719,13 @@ func (s *Server) stop(graceful bool) { } if graceful || s.opts.waitForHandlers { + // Release the lock while waiting for handlers to finish. Holding it + // here would deadlock a concurrent Stop() (the recommended way to abort + // a GracefulStop that is taking too long), because Stop() must acquire + // s.mu before it can force the server to shut down. + s.mu.Unlock() s.handlersWG.Wait() + s.mu.Lock() } if s.events != nil { diff --git a/vendor/google.golang.org/grpc/stats/stats.go b/vendor/google.golang.org/grpc/stats/stats.go index 10bf998aa..c6996724c 100644 --- a/vendor/google.golang.org/grpc/stats/stats.go +++ b/vendor/google.golang.org/grpc/stats/stats.go @@ -190,6 +190,9 @@ type OutHeader struct { Compression string // Header contains the header metadata sent. Header metadata.MD + // Authority is the :authority pseudo-header sent for the RPC. + // It is valid only if Client is true. + Authority string // The following fields are valid only if Client is true. // FullMethod is the full RPC method string, i.e., /package.service/method. diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index 52e59f2c5..9fd628b8d 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go @@ -201,9 +201,9 @@ func (w *clientStreamWrapper) SendMsg(m any) error { } -// RecvMsg receives message m from the stream. For RPCs that call RecvMsg only -// once i.e. only client streaming RPCs, it calls the underlying RecvMsg a -// second time after receiving the first message to get the trailers. +// RecvMsg receives message m from the stream. For non-server-streaming RPCs +// (unary and client-streaming), it calls the underlying RecvMsg a second time +// after receiving the first message to get the trailers. func (w *clientStreamWrapper) RecvMsg(m any) error { err := w.ClientStream.RecvMsg(m) if err != nil { @@ -224,19 +224,6 @@ func (w *clientStreamWrapper) RecvMsg(m any) error { return err } -// defaultStreamInterceptor is a StreamClientInterceptor which wraps the -// ClientStream and is always invoked as the first interceptor. It consolidates -// behavior for different RPC types at the level closest to the application, -// which simplifies the underlying stream implementation and other interceptors -// by avoiding duplicate or scattered handling. -func defaultStreamInterceptor(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, streamer Streamer, opts ...CallOption) (ClientStream, error) { - cs, err := streamer(ctx, desc, cc, method, opts...) - if err != nil { - return nil, err - } - return &clientStreamWrapper{ClientStream: cs, desc: desc}, nil -} - // NewStream creates a new Stream for the client side. This is typically // called by generated code. ctx is used for the lifetime of the stream. // @@ -392,7 +379,11 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth } } - return newStream(ctx, opts...) + cs, err := newStream(ctx, opts...) + if err != nil { + return nil, err + } + return &clientStreamWrapper{ClientStream: cs, desc: desc}, nil } func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc *serviceconfig.MethodConfig, onCommit func(), nameResolutionDelayed bool, opts ...CallOption) (_ ClientStream, err error) { @@ -632,7 +623,12 @@ func (a *csAttempt) getTransport() error { func (a *csAttempt) newStream() error { cs := a.cs - cs.callHdr.PreviousAttempts = cs.numRetries + // The header is copied because the fields set below, notably the authority + // override taken from the pick result, describe the endpoint picked for + // this attempt only. Mutating the clientStream's header would carry them + // into a later attempt. + callHdr := *cs.callHdr + callHdr.PreviousAttempts = cs.numRetries // Merge metadata stored in PickResult, if any, with existing call metadata. // It is safe to overwrite the csAttempt's context here, since all state @@ -659,11 +655,11 @@ func (a *csAttempt) newStream() error { // apply it, as specified in gRFC A81. if cs.callInfo.authority == "" { if authMD := a.pickResult.Metadata.Get(":authority"); len(authMD) > 0 { - cs.callHdr.Authority = authMD[0] + callHdr.Authority = authMD[0] } } } - s, err := a.transport.NewStream(a.ctx, cs.callHdr, a.statsHandler) + s, err := a.transport.NewStream(a.ctx, &callHdr, a.statsHandler) if err != nil { nse, ok := err.(*transport.NewStreamError) if !ok { @@ -698,10 +694,6 @@ type clientStream struct { cancel context.CancelFunc // cancels all attempts - sentLast bool // sent an end stream - - receivedFirstMsg bool // set after the first message is received - methodConfig *MethodConfig ctx context.Context // the application's context, wrapped by stats/tracing @@ -709,19 +701,10 @@ type clientStream struct { retryThrottler *retryThrottler // The throttler active when the RPC began. binlogs []binarylog.MethodLogger - // serverHeaderBinlogged is a boolean for whether server header has been - // logged. Server header will be logged when the first time one of those - // happens: stream.Header(), stream.Recv(). - // - // It's only read and used by Recv() and Header(), so it doesn't need to be - // synchronized. - serverHeaderBinlogged bool mu sync.Mutex - firstAttempt bool // if true, transparent retry is valid - numRetries int // exclusive of transparent retry attempt(s) - numRetriesSincePushback int // retries since pushback; to reset backoff - finished bool // TODO: replace with atomic cmpxchg or sync.Once? + numRetries int // exclusive of transparent retry attempt(s) + numRetriesSincePushback int // retries since pushback; to reset backoff // attempt is the active client stream attempt. // The only place where it is written is the newAttemptLocked method and this method never writes nil. // So, attempt can be nil only inside newClientStream function when clientStream is first created. @@ -731,13 +714,33 @@ type clientStream struct { // place where we need to check if the attempt is nil. attempt *csAttempt // TODO(hedging): hedging will have multiple attempts simultaneously. - committed bool // active attempt committed for retry? onCommit func() replayBuffer []replayOp // operations to replay on retry replayBufferSize int // current size of replayBuffer + + // Bool fields are grouped at the tail to eliminate the alignment padding + // that would otherwise follow each bool when the next field is pointer- or + // int-sized. See https://github.com/grpc/grpc-go/issues/9280 for benchmarks. + // Add new bool fields here, not inline above. + + // Not guarded by mu. + sentLast bool // sent an end stream + receivedFirstMsg bool // set after the first message is received + // serverHeaderBinlogged is a boolean for whether server header has been + // logged. Server header will be logged when the first time one of those + // happens: stream.Header(), stream.Recv(). + // + // It's only read and used by Recv() and Header(), so it doesn't need to be + // synchronized. + serverHeaderBinlogged bool // nameResolutionDelay indicates if there was a delay in the name resolution. // This field is only valid on client side, it's always false on server side. nameResolutionDelay bool + + // Guarded by mu. + firstAttempt bool // if true, transparent retry is valid + finished bool // TODO: replace with atomic cmpxchg or sync.Once? + committed bool // active attempt committed for retry? } type replayOp struct { @@ -755,10 +758,8 @@ type csAttempt struct { parser parser pickResult balancer.PickResult - finished bool - decompressorV0 Decompressor - decompressorV1 encoding.Compressor - decompressorSet bool + decompressorV0 Decompressor + decompressorV1 encoding.Compressor mu sync.Mutex // guards trInfo.tr // trInfo may be nil (if EnableTracing is false). @@ -769,10 +770,18 @@ type csAttempt struct { statsHandler stats.Handler beginTime time.Time - // set for newStream errors that may be transparently retried - allowTransparentRetry bool - // set for pick errors that are returned as a status - drop bool + // Bool fields are grouped at the tail to eliminate the alignment padding + // that would otherwise follow each bool when the next field is pointer- or + // int-sized. See https://github.com/grpc/grpc-go/issues/9347 for benchmarks. + // Add new bool fields here, not inline above. + + // Not guarded by mu. + decompressorSet bool + allowTransparentRetry bool // set for newStream errors that may be transparently retried + drop bool // set for pick errors that are returned as a status + + // Guarded by mu. + finished bool } func (cs *clientStream) commitAttemptLocked() { @@ -1500,20 +1509,28 @@ type addrConnStream struct { callInfo *callInfo transport transport.ClientTransport ctx context.Context - sentLast bool - receivedFirstMsg bool desc *StreamDesc codec baseCodec sendCompressorV0 Compressor sendCompressorV1 encoding.Compressor - decompressorSet bool decompressorV0 Decompressor decompressorV1 encoding.Compressor - parser parser // mu guards finished and is held for the entire finish method. - mu sync.Mutex - finished bool + mu sync.Mutex + parser parser + + // Bool fields are grouped at the tail to eliminate the alignment padding + // that would otherwise follow each bool when the next field is pointer- or + // int-sized. See https://github.com/grpc/grpc-go/issues/9348 for benchmarks. + // Add new bool fields here, not inline above. + + // Not guarded by mu. + sentLast bool + receivedFirstMsg bool + decompressorSet bool + + finished bool // guarded by mu } func (as *addrConnStream) Header() (metadata.MD, error) { @@ -1728,15 +1745,23 @@ type serverStream struct { sendCompressorName string - recvFirstMsg bool // set after the first message is received - maxReceiveMessageSize int maxSendMessageSize int - trInfo *traceInfo + + // mu guards trInfo.tr after the service handler runs. + mu sync.Mutex + trInfo *traceInfo statsHandler stats.Handler binlogs []binarylog.MethodLogger + + // Bool fields are grouped at the tail to eliminate the alignment padding + // that would otherwise follow each bool when the next field is pointer- or + // int-sized. See https://github.com/grpc/grpc-go/issues/9349 for benchmarks. + // Add new bool fields here, not inline above. + + recvFirstMsg bool // set after the first message is received // serverHeaderBinlogged indicates whether server header has been logged. It // will happen when one of the following two happens: stream.SendHeader(), // stream.Send(). @@ -1744,10 +1769,6 @@ type serverStream struct { // It's only checked in send and sendHeader, doesn't need to be // synchronized. serverHeaderBinlogged bool - - statusWritten atomic.Bool // True if status has been written to the transport. - - mu sync.Mutex // protects trInfo.tr after the service handler runs. } func (ss *serverStream) Context() context.Context { @@ -1795,16 +1816,6 @@ func (ss *serverStream) SetTrailer(md metadata.MD) { ss.s.SetTrailer(md) } -// writeStatus sends the status of a stream to the client. It uses an atomic -// CAS to guarantee that the status is written to the transport exactly once, -// even if called concurrently. -func (ss *serverStream) writeStatus(st *status.Status) error { - if !ss.statusWritten.CompareAndSwap(false, true) { - return nil - } - return ss.s.WriteStatus(st) -} - func (ss *serverStream) SendMsg(m any) (err error) { defer func() { if ss.trInfo != nil { @@ -1821,7 +1832,7 @@ func (ss *serverStream) SendMsg(m any) (err error) { } if err != nil && err != io.EOF { st, _ := status.FromError(toRPCErr(err)) - ss.writeStatus(st) + ss.s.WriteStatus(st) // Non-user specified status was sent out. This should be an error // case (as a server side Cancel maybe). // @@ -1904,7 +1915,7 @@ func (ss *serverStream) RecvMsg(m any) (err error) { } if err != nil && err != io.EOF { st, _ := status.FromError(toRPCErr(err)) - ss.writeStatus(st) + ss.s.WriteStatus(st) // Non-user specified status was sent out. This should be an error // case (as a server side Cancel maybe). // diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index 75f8ef50d..d41341bcf 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.84.0" +const Version = "1.85.0" diff --git a/vendor/modules.txt b/vendor/modules.txt index ab825cb46..d4b7c95a5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -88,8 +88,8 @@ github.com/Microsoft/go-winio/internal/stringbuffer github.com/Microsoft/go-winio/pkg/bindfilter github.com/Microsoft/go-winio/pkg/guid github.com/Microsoft/go-winio/vhd -# github.com/Microsoft/hcsshim v0.15.0-rc.4 -## explicit; go 1.26.3 +# github.com/Microsoft/hcsshim v0.15.0 +## explicit; go 1.26.8 github.com/Microsoft/hcsshim github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options github.com/Microsoft/hcsshim/computestorage @@ -186,7 +186,7 @@ github.com/aws/aws-sdk-go-v2/internal/strings github.com/aws/aws-sdk-go-v2/internal/sync/singleflight github.com/aws/aws-sdk-go-v2/internal/timeconv github.com/aws/aws-sdk-go-v2/internal/timeouts -# github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.20 +# github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.25 ## explicit; go 1.24 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi @@ -609,8 +609,8 @@ github.com/go-logr/logr/funcr # github.com/go-logr/stdr v1.2.2 ## explicit; go 1.16 github.com/go-logr/stdr -# github.com/go-openapi/analysis v0.25.5 -## explicit; go 1.25.0 +# github.com/go-openapi/analysis v1.0.0 +## explicit; go 1.26.0 github.com/go-openapi/analysis github.com/go-openapi/analysis/internal/debug github.com/go-openapi/analysis/internal/flatten/normalize @@ -618,22 +618,22 @@ github.com/go-openapi/analysis/internal/flatten/operations github.com/go-openapi/analysis/internal/flatten/replace github.com/go-openapi/analysis/internal/flatten/schutils github.com/go-openapi/analysis/internal/flatten/sortref -# github.com/go-openapi/errors v0.22.8 -## explicit; go 1.25.0 +# github.com/go-openapi/errors v0.22.9 +## explicit; go 1.26.0 github.com/go-openapi/errors -# github.com/go-openapi/jsonpointer v1.0.0 -## explicit; go 1.25.0 +# github.com/go-openapi/jsonpointer v1.0.1 +## explicit; go 1.26.0 github.com/go-openapi/jsonpointer github.com/go-openapi/jsonpointer/jsonname -# github.com/go-openapi/jsonreference v1.0.0 +# github.com/go-openapi/jsonreference v1.0.1 ## explicit; go 1.25.0 github.com/go-openapi/jsonreference github.com/go-openapi/jsonreference/internal -# github.com/go-openapi/loads v0.25.0 +# github.com/go-openapi/loads v0.25.2 ## explicit; go 1.25.0 github.com/go-openapi/loads -# github.com/go-openapi/runtime v0.33.0 -## explicit; go 1.25.0 +# github.com/go-openapi/runtime v0.33.2 +## explicit; go 1.26.0 github.com/go-openapi/runtime github.com/go-openapi/runtime/client github.com/go-openapi/runtime/client/internal/request @@ -643,61 +643,61 @@ github.com/go-openapi/runtime/middleware/denco github.com/go-openapi/runtime/middleware/untyped github.com/go-openapi/runtime/security github.com/go-openapi/runtime/yamlpc -# github.com/go-openapi/runtime/server-middleware v0.30.0 -## explicit; go 1.25.0 +# github.com/go-openapi/runtime/server-middleware v0.33.2 +## explicit; go 1.26.0 github.com/go-openapi/runtime/server-middleware/docui github.com/go-openapi/runtime/server-middleware/mediatype github.com/go-openapi/runtime/server-middleware/negotiate github.com/go-openapi/runtime/server-middleware/negotiate/header -# github.com/go-openapi/spec v0.22.9 +# github.com/go-openapi/spec v1.0.0 ## explicit; go 1.25.0 github.com/go-openapi/spec -# github.com/go-openapi/strfmt v0.27.0 -## explicit; go 1.25.0 +# github.com/go-openapi/strfmt v0.27.2 +## explicit; go 1.26.0 github.com/go-openapi/strfmt github.com/go-openapi/strfmt/internal/bsonlite github.com/go-openapi/strfmt/internal/countries -# github.com/go-openapi/swag v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag -# github.com/go-openapi/swag/cmdutils v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/cmdutils v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/cmdutils -# github.com/go-openapi/swag/conv v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/conv v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/conv -# github.com/go-openapi/swag/fileutils v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/fileutils v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/fileutils -# github.com/go-openapi/swag/jsonutils v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/jsonutils v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/jsonutils github.com/go-openapi/swag/jsonutils/adapters github.com/go-openapi/swag/jsonutils/adapters/ifaces github.com/go-openapi/swag/jsonutils/adapters/stdlib/json -# github.com/go-openapi/swag/loading v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/loading v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/loading -# github.com/go-openapi/swag/mangling v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/mangling v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/mangling -# github.com/go-openapi/swag/netutils v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/netutils v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/netutils -# github.com/go-openapi/swag/pools v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/pools v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/pools -# github.com/go-openapi/swag/stringutils v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/stringutils v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/stringutils -# github.com/go-openapi/swag/typeutils v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/typeutils v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/typeutils -# github.com/go-openapi/swag/yamlutils v0.28.0 -## explicit; go 1.25.0 +# github.com/go-openapi/swag/yamlutils v0.29.2 +## explicit; go 1.26.0 github.com/go-openapi/swag/yamlutils -# github.com/go-openapi/validate v0.26.1 -## explicit; go 1.25.0 +# github.com/go-openapi/validate v1.0.0 +## explicit; go 1.26.0 github.com/go-openapi/validate # github.com/go-viper/mapstructure/v2 v2.5.0 ## explicit; go 1.18 @@ -736,7 +736,7 @@ github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/function github.com/google/go-cmp/cmp/internal/value -# github.com/google/go-containerregistry v0.21.7 +# github.com/google/go-containerregistry v0.22.0 ## explicit; go 1.25.0 github.com/google/go-containerregistry/pkg/name # github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 @@ -748,8 +748,8 @@ github.com/google/shlex # github.com/google/uuid v1.6.0 ## explicit github.com/google/uuid -# github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 -## explicit; go 1.25.0 +# github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0 +## explicit; go 1.26.0 github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options github.com/grpc-ecosystem/grpc-gateway/v2/runtime @@ -864,7 +864,7 @@ github.com/morikuni/aec # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 ## explicit github.com/munnerz/goautoneg -# github.com/oklog/ulid/v2 v2.1.1 +# github.com/oklog/ulid/v2 v2.1.2 ## explicit; go 1.15 github.com/oklog/ulid/v2 # github.com/opencontainers/go-digest v1.0.0 @@ -920,8 +920,8 @@ github.com/planetscale/vtprotobuf/generator/pattern github.com/planetscale/vtprotobuf/protohelpers github.com/planetscale/vtprotobuf/types/known/timestamppb github.com/planetscale/vtprotobuf/vtproto -# github.com/prometheus/client_golang v1.24.1 -## explicit; go 1.25.0 +# github.com/prometheus/client_golang v1.25.0 +## explicit; go 1.26.0 github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header github.com/prometheus/client_golang/prometheus @@ -931,18 +931,18 @@ github.com/prometheus/client_golang/prometheus/promhttp/internal # github.com/prometheus/client_model v0.6.3 ## explicit; go 1.23 github.com/prometheus/client_model/go -# github.com/prometheus/common v0.71.0 -## explicit; go 1.25.0 +# github.com/prometheus/common v0.72.0 +## explicit; go 1.26.0 github.com/prometheus/common/expfmt github.com/prometheus/common/model # github.com/prometheus/otlptranslator v1.0.0 ## explicit; go 1.23.0 github.com/prometheus/otlptranslator -# github.com/prometheus/procfs v0.21.1 +# github.com/prometheus/procfs v0.22.0 ## explicit; go 1.25.0 github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs -github.com/prometheus/procfs/internal/util +github.com/prometheus/procfs/internal/parsers # github.com/sasha-s/go-deadlock v0.3.5 ## explicit github.com/sasha-s/go-deadlock @@ -1107,21 +1107,21 @@ go.etcd.io/bbolt/internal/freelist ## explicit; go 1.24.0 go.opentelemetry.io/auto/sdk go.opentelemetry.io/auto/sdk/internal/telemetry -# go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0 +## explicit; go 1.26.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/internal -# go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.71.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.72.0 +## explicit; go 1.26.0 go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/internal/semconv -# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0 +## explicit; go 1.26.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv -# go.opentelemetry.io/otel v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel go.opentelemetry.io/otel/attribute go.opentelemetry.io/otel/attribute/internal @@ -1132,6 +1132,7 @@ go.opentelemetry.io/otel/internal/baggage go.opentelemetry.io/otel/internal/errorhandler go.opentelemetry.io/otel/internal/global go.opentelemetry.io/otel/propagation +go.opentelemetry.io/otel/propagation/internal/hextable go.opentelemetry.io/otel/semconv/internal/metricpool go.opentelemetry.io/otel/semconv/v1.21.0 go.opentelemetry.io/otel/semconv/v1.37.0 @@ -1147,8 +1148,8 @@ go.opentelemetry.io/otel/exporters/jaeger/internal/gen-go/agent go.opentelemetry.io/otel/exporters/jaeger/internal/gen-go/jaeger go.opentelemetry.io/otel/exporters/jaeger/internal/gen-go/zipkincore go.opentelemetry.io/otel/exporters/jaeger/internal/third_party/thrift/lib/go/thrift -# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/counter @@ -1158,8 +1159,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/x -# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/counter @@ -1169,12 +1170,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/x -# go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform -# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/counter @@ -1183,8 +1184,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/observ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/x -# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/counter @@ -1194,20 +1195,24 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpcon go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpjson go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/x -# go.opentelemetry.io/otel/exporters/prometheus v0.68.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/exporters/prometheus v0.69.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/exporters/prometheus go.opentelemetry.io/otel/exporters/prometheus/internal go.opentelemetry.io/otel/exporters/prometheus/internal/counter go.opentelemetry.io/otel/exporters/prometheus/internal/observ go.opentelemetry.io/otel/exporters/prometheus/internal/x -# go.opentelemetry.io/otel/metric v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/log v1.47.0 +## explicit; go 1.26.0 +go.opentelemetry.io/otel/log +go.opentelemetry.io/otel/log/embedded +# go.opentelemetry.io/otel/metric v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/metric go.opentelemetry.io/otel/metric/embedded go.opentelemetry.io/otel/metric/noop -# go.opentelemetry.io/otel/sdk v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/sdk v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/sdk go.opentelemetry.io/otel/sdk/instrumentation go.opentelemetry.io/otel/sdk/internal/attrnorm @@ -1217,32 +1222,32 @@ go.opentelemetry.io/otel/sdk/trace go.opentelemetry.io/otel/sdk/trace/internal/env go.opentelemetry.io/otel/sdk/trace/internal/observ go.opentelemetry.io/otel/sdk/trace/tracetest -# go.opentelemetry.io/otel/sdk/metric v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/sdk/metric v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/sdk/metric go.opentelemetry.io/otel/sdk/metric/exemplar go.opentelemetry.io/otel/sdk/metric/internal go.opentelemetry.io/otel/sdk/metric/internal/aggregate go.opentelemetry.io/otel/sdk/metric/internal/attrnorm +go.opentelemetry.io/otel/sdk/metric/internal/finish go.opentelemetry.io/otel/sdk/metric/internal/observ go.opentelemetry.io/otel/sdk/metric/internal/reservoir -go.opentelemetry.io/otel/sdk/metric/internal/x go.opentelemetry.io/otel/sdk/metric/metricdata -# go.opentelemetry.io/otel/trace v1.46.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/otel/trace v1.47.0 +## explicit; go 1.26.0 go.opentelemetry.io/otel/trace go.opentelemetry.io/otel/trace/embedded go.opentelemetry.io/otel/trace/internal/telemetry go.opentelemetry.io/otel/trace/noop -# go.opentelemetry.io/proto/otlp v1.11.0 -## explicit; go 1.25.0 +# go.opentelemetry.io/proto/otlp v1.11.1 +## explicit; go 1.26.0 go.opentelemetry.io/proto/otlp/collector/metrics/v1 go.opentelemetry.io/proto/otlp/collector/trace/v1 go.opentelemetry.io/proto/otlp/common/v1 go.opentelemetry.io/proto/otlp/metrics/v1 go.opentelemetry.io/proto/otlp/resource/v1 go.opentelemetry.io/proto/otlp/trace/v1 -# go.yaml.in/yaml/v3 v3.0.5 +# go.yaml.in/yaml/v3 v3.0.6 ## explicit; go 1.16 go.yaml.in/yaml/v3 # golang.org/x/crypto v0.58.0 @@ -1270,8 +1275,8 @@ golang.org/x/crypto/sha3 golang.org/x/crypto/ssh golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/internal/bcrypt_pbkdf -# golang.org/x/exp v0.0.0-20260603202125-055de637280b -## explicit; go 1.25.0 +# golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba +## explicit; go 1.26.0 golang.org/x/exp/trace golang.org/x/exp/trace/internal/tracev1 golang.org/x/exp/trace/internal/tracev2 @@ -1280,7 +1285,7 @@ golang.org/x/exp/trace/internal/version ## explicit; go 1.26.0 golang.org/x/mod/semver golang.org/x/mod/sumdb/note -# golang.org/x/net v0.61.0 +# golang.org/x/net v0.62.0 ## explicit; go 1.26.0 golang.org/x/net/http/httpguts golang.org/x/net/http2 @@ -1324,17 +1329,17 @@ golang.org/x/text/unicode/norm # golang.org/x/time v0.16.0 ## explicit; go 1.26.0 golang.org/x/time/rate -# google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 -## explicit; go 1.25.0 +# google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941 +## explicit; go 1.26.0 google.golang.org/genproto/googleapis/api google.golang.org/genproto/googleapis/api/annotations google.golang.org/genproto/googleapis/api/httpbody -# google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 -## explicit; go 1.25.0 +# google.golang.org/genproto/googleapis/rpc v0.0.0-20261012220534-4341edf3f941 +## explicit; go 1.26.0 google.golang.org/genproto/googleapis/rpc/errdetails google.golang.org/genproto/googleapis/rpc/status -# google.golang.org/grpc v1.84.0 -## explicit; go 1.25.0 +# google.golang.org/grpc v1.85.0 +## explicit; go 1.26.0 google.golang.org/grpc google.golang.org/grpc/attributes google.golang.org/grpc/backoff