From 551ac0c5b9a48fd760ab98cda4315119b641da74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Nov 2026 21:13:56 +0000 Subject: [PATCH] chore(deps): Bump google.golang.org/api Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.308.0 to 0.310.0. - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.308.0...v0.310.0) --- updated-dependencies: - dependency-name: google.golang.org/api dependency-version: 0.310.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- ci/resources/stemcell-version-bump/go.mod | 23 +- ci/resources/stemcell-version-bump/go.sum | 58 +- .../vendor/cloud.google.com/go/iam/CHANGES.md | 14 + .../gax-go/v2/.release-please-manifest.json | 2 +- .../googleapis/gax-go/v2/CHANGES.md | 7 + .../googleapis/gax-go/v2/internal/version.go | 2 +- .../googleapis/gax-go/v2/validator.go | 53 ++ .../go.opentelemetry.io/otel/.golangci.yml | 15 +- .../go.opentelemetry.io/otel/CHANGELOG.md | 121 +++- .../vendor/go.opentelemetry.io/otel/CLAUDE.md | 3 - .../go.opentelemetry.io/otel/CODEOWNERS | 2 +- .../go.opentelemetry.io/otel/CONTRIBUTING.md | 20 +- .../vendor/go.opentelemetry.io/otel/Makefile | 30 +- .../vendor/go.opentelemetry.io/otel/README.md | 28 +- .../go.opentelemetry.io/otel/VERSIONING.md | 6 + .../otel/attribute/hash.go | 70 ++- .../otel/attribute/internal/xxhash/xxhash.go | 8 + .../go.opentelemetry.io/otel/attribute/kv.go | 10 + .../go.opentelemetry.io/otel/attribute/set.go | 18 + .../otel/baggage/baggage.go | 235 +++++--- .../go.opentelemetry.io/otel/codes/codes.go | 2 +- .../otel/dependencies.Dockerfile | 2 +- .../otel/internal/baggage/baggage.go | 29 +- .../internal/errorhandler/errorhandler.go | 5 + .../otel/internal/global/logger.go | 96 +++ .../otel/internal/global/state.go | 45 +- .../vendor/go.opentelemetry.io/otel/log.go | 41 ++ .../go.opentelemetry.io/otel/log/DESIGN.md | 566 ++++++++++++++++++ .../go.opentelemetry.io/otel/log/LICENSE | 231 +++++++ .../go.opentelemetry.io/otel/log/README.md | 3 + .../go.opentelemetry.io/otel/log/doc.go | 85 +++ .../otel/log/embedded/README.md | 3 + .../otel/log/embedded/embedded.go | 36 ++ .../go.opentelemetry.io/otel/log/logger.go | 197 ++++++ .../go.opentelemetry.io/otel/log/provider.go | 38 ++ .../go.opentelemetry.io/otel/log/record.go | 168 ++++++ .../go.opentelemetry.io/otel/log/severity.go | 69 +++ .../otel/log/severity_string.go | 48 ++ .../go.opentelemetry.io/otel/metric/meter.go | 2 +- .../propagation/internal/hextable/hextable.go | 32 + .../otel/propagation/trace_context.go | 27 +- .../go.opentelemetry.io/otel/renovate.json | 7 + .../otel/sdk/internal/attrnorm/dedup.go | 546 ++++++++++++++++- .../otel/sdk/internal/attrnorm/truncate.go | 384 ++++++++---- .../otel/sdk/internal/x/x.go | 4 +- .../otel/sdk/metric/aggregation.go | 4 +- .../otel/sdk/metric/env.go | 9 +- .../metric/exemplar/fixed_size_reservoir.go | 6 + .../otel/sdk/metric/exemplar/value.go | 4 +- .../otel/sdk/metric/instrument.go | 7 +- .../metric/internal/aggregate/aggregate.go | 7 +- .../sdk/metric/internal/aggregate/atomic.go | 163 ++++- .../sdk/metric/internal/aggregate/drop.go | 2 +- .../aggregate/exponential_histogram.go | 19 +- .../internal/aggregate/filtered_reservoir.go | 9 +- .../metric/internal/aggregate/finish_sum.go | 313 ++++++++++ .../metric/internal/aggregate/histogram.go | 55 +- .../metric/internal/aggregate/lastvalue.go | 120 ++-- .../internal/aggregate/lazy_attributes.go | 146 +++++ .../otel/sdk/metric/internal/aggregate/sum.go | 132 ++-- .../sdk/metric/internal/attrnorm/dedup.go | 52 +- .../sdk/metric/internal/attrnorm/distinct.go | 110 ++++ .../otel/sdk/metric/internal/finish/doc.go | 5 + .../sdk/metric/internal/finish/lifecycle.go | 253 ++++++++ .../otel/sdk/metric/internal/x/README.md | 42 -- .../otel/sdk/metric/internal/x/features.go | 22 - .../otel/sdk/metric/internal/x/x.go | 58 -- .../otel/sdk/metric/metricdata/data.go | 2 +- .../otel/sdk/metric/periodic_reader.go | 31 +- .../otel/sdk/metric/pipeline.go | 19 +- .../otel/sdk/metric/provider.go | 2 +- .../otel/sdk/metric/version.go | 2 +- .../otel/sdk/metric/view.go | 2 +- .../otel/sdk/resource/resource.go | 5 +- .../go.opentelemetry.io/otel/sdk/version.go | 2 +- .../go.opentelemetry.io/otel/trace/auto.go | 14 +- .../otel/trace/internal/telemetry/number.go | 2 +- .../otel/trace/internal/telemetry/value.go | 2 +- .../go.opentelemetry.io/otel/trace/trace.go | 78 ++- .../otel/trace/tracestate.go | 2 +- .../go.opentelemetry.io/otel/version.go | 2 +- .../go.opentelemetry.io/otel/versions.yaml | 16 +- .../google.golang.org/api/internal/version.go | 2 +- .../stemcell-version-bump/vendor/modules.txt | 45 +- 84 files changed, 4428 insertions(+), 729 deletions(-) create mode 100644 ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/validator.go delete mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CLAUDE.md create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/global/logger.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/DESIGN.md create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/LICENSE create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/README.md create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/doc.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/embedded/README.md create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/embedded/embedded.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/logger.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/provider.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/record.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/severity.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/severity_string.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/propagation/internal/hextable/hextable.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/finish_sum.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lazy_attributes.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/distinct.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/doc.go create mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/lifecycle.go delete mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md delete mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/features.go delete mode 100644 ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go diff --git a/ci/resources/stemcell-version-bump/go.mod b/ci/resources/stemcell-version-bump/go.mod index a2bea826e..11c27c122 100644 --- a/ci/resources/stemcell-version-bump/go.mod +++ b/ci/resources/stemcell-version-bump/go.mod @@ -5,7 +5,7 @@ go 1.26.0 require ( cloud.google.com/go/storage v1.70.0 github.com/stretchr/testify v1.12.1 - google.golang.org/api v0.308.0 + google.golang.org/api v0.310.0 ) require ( @@ -14,7 +14,7 @@ require ( cloud.google.com/go/auth v0.24.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.3.0 // indirect cloud.google.com/go/compute/metadata v0.10.0 // indirect - cloud.google.com/go/iam v1.12.0 // indirect + cloud.google.com/go/iam v1.14.0 // indirect cloud.google.com/go/monitoring v1.30.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.35.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 // indirect @@ -29,19 +29,20 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/google/s2a-go v0.1.11 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.23 // indirect - github.com/googleapis/gax-go/v2 v2.26.2 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.24 // indirect + github.com/googleapis/gax-go/v2 v2.27.0 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/spiffe/go-spiffe/v2 v2.8.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.45.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect - go.opentelemetry.io/otel v1.45.0 // indirect - go.opentelemetry.io/otel/metric v1.45.0 // indirect - go.opentelemetry.io/otel/sdk v1.45.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.45.0 // indirect - go.opentelemetry.io/otel/trace v1.45.0 // indirect + go.opentelemetry.io/otel v1.47.0 // indirect + go.opentelemetry.io/otel/log v1.47.0 // indirect + go.opentelemetry.io/otel/metric v1.47.0 // indirect + go.opentelemetry.io/otel/sdk v1.47.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.47.0 // indirect + go.opentelemetry.io/otel/trace v1.47.0 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect golang.org/x/crypto v0.58.0 // indirect golang.org/x/net v0.61.0 // indirect @@ -50,8 +51,8 @@ require ( golang.org/x/sys v0.49.0 // indirect golang.org/x/text v0.43.0 // indirect golang.org/x/time v0.16.0 // indirect - google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d // indirect + google.golang.org/genproto v0.0.0-20261012220534-4341edf3f941 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20261012220534-4341edf3f941 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20261019180522-ce908d29299b // indirect google.golang.org/grpc v1.84.0 // indirect google.golang.org/protobuf v1.36.12 // indirect diff --git a/ci/resources/stemcell-version-bump/go.sum b/ci/resources/stemcell-version-bump/go.sum index 65a83c79a..e8468ed25 100644 --- a/ci/resources/stemcell-version-bump/go.sum +++ b/ci/resources/stemcell-version-bump/go.sum @@ -8,12 +8,12 @@ cloud.google.com/go/auth/oauth2adapt v0.3.0 h1:FY8oSZpCYoUNv6QxVODuMjQz4IlSOVeiQ cloud.google.com/go/auth/oauth2adapt v0.3.0/go.mod h1:7+2uCm7++XFO+/lN06c2HXpDXb/NMNn2/UwyBPbTnkk= cloud.google.com/go/compute/metadata v0.10.0 h1:pyKMUQSwchgkIBBJGdILqQbs/BNJXqwSA7Ej6LAvvtY= cloud.google.com/go/compute/metadata v0.10.0/go.mod h1:rGFHRrIif570kSibjFTMbt6/4/tzgJWFGI/HVol4GIk= -cloud.google.com/go/iam v1.12.0 h1:Aki3bX9aHUDKPHfnRJfDcTdVedvy6quGBQcTqx3DRXk= -cloud.google.com/go/iam v1.12.0/go.mod h1:FEZ4lXpADAC2AIpQY7LANNjjwyQ2jK439CI2VaD+sLY= -cloud.google.com/go/logging v1.19.0 h1:NCqhdVUg3wQ8Cobdf16FDSuTGi3+6+hdSBHrY5TsR6Q= -cloud.google.com/go/logging v1.19.0/go.mod h1:i40NZCHC9Gqvod4yE+yQfDWwlgwW/SrshkkGibCHxcA= -cloud.google.com/go/longrunning v1.2.0 h1:WjYH3YHBGCxGJP9M4dWGHBfXr/cFIjMkNgWcJj7/iMM= -cloud.google.com/go/longrunning v1.2.0/go.mod h1:5KMQALFGOCtFoi2xSOA1u3H7WKlhmckgiyFw7+LGQp0= +cloud.google.com/go/iam v1.14.0 h1:YRIB1/4xxwJ+NfI6RQr1WaOoHHeV0MizJEj940nBXJA= +cloud.google.com/go/iam v1.14.0/go.mod h1:JTPZfbHdGXJrOYREtkRoFzCDGaBdbA7ILLKO/DDuav0= +cloud.google.com/go/logging v1.20.0 h1:l7yzCB8/JSY5PHT9RsaqdT1jaBGbM6KlSJDX210HlXM= +cloud.google.com/go/logging v1.20.0/go.mod h1:ALUaJQZM691Eeujy9kFx0xREq3AMPuGd+pTRZuTYv+w= +cloud.google.com/go/longrunning v1.3.0 h1:lZ6c8SJJBmILp/Wnr3vGnBLa0q+cYfSHRCcUfVI2hpI= +cloud.google.com/go/longrunning v1.3.0/go.mod h1:wpgLxCn+UA3/TZ1bj/fW39mfDpwVlMPu1xKJyoMt7V0= cloud.google.com/go/monitoring v1.30.0 h1:r/d+JUbyKmJ8b07iznuKfzVzrIXTWxHQ3lBRm3x2LlY= cloud.google.com/go/monitoring v1.30.0/go.mod h1:htlUR0QWVMrjFzZmN4LGnMAve9xB/eduwjmINxVZ8RM= cloud.google.com/go/storage v1.70.0 h1:LQNHn0rRF94jVFfF3e416IzdQqIufa5GfF6HilQxb80= @@ -59,10 +59,10 @@ github.com/google/s2a-go v0.1.11 h1:7v1V1TraNGP63WptsAkNqr2w8jgm4vM6A6qx6Lsw9iM= github.com/google/s2a-go v0.1.11/go.mod h1:pz4tyvwXvJLLbyrkh6FW1eS2zPUXMaTmyNhYtyP2tNw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.23 h1:J+VGF1wjAM2dU2kKUXZxJdDppRLReWP7KWcclfngQhc= -github.com/googleapis/enterprise-certificate-proxy v0.3.23/go.mod h1:Y8NO/15GNLkrXI3OR5xOFmeU3XLX1sLSdtlXgJ0zmIw= -github.com/googleapis/gax-go/v2 v2.26.2 h1:ydkmNXxj7bEmmeK5AihkKnWxyOyBR9TDebvp5L5izk8= -github.com/googleapis/gax-go/v2 v2.26.2/go.mod h1:sMKqnMesnKH+3wiRJROcttA+cJoZoGbZl1vDQ8XYtGk= +github.com/googleapis/enterprise-certificate-proxy v0.3.24 h1:G9iCJIY+AYVmUskKdjX8FVy7sG+nbzjOQ41cvlmhcvg= +github.com/googleapis/enterprise-certificate-proxy v0.3.24/go.mod h1:hEjCmnoakQzv5ImLUp6alkY7XgLlNoAxwTXmhHHNIsI= +github.com/googleapis/gax-go/v2 v2.27.0 h1:qe2iQOUzxb3fd6x6ewpIEixPQhJ+0Ihc/RRZhKA/2g0= +github.com/googleapis/gax-go/v2 v2.27.0/go.mod h1:RofiqDw3ehcG4L0H1zO3D2Itpwd3/uS/7wdmbNDF1DE= 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/spiffe/go-spiffe/v2 v2.8.1 h1:eXZMLsu+3MLEPJyGJkolqtVrteZfQdUpOWj6LTiDl/E= @@ -77,20 +77,22 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0/go.mod h1:Sje3i3MjSPKTSPvVWCaL8ugBzJwik3u4smCjUeuupqg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= -go.opentelemetry.io/otel v1.45.0 h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU= -go.opentelemetry.io/otel v1.45.0/go.mod h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ= +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/stdout/stdoutmetric v1.45.0 h1:dm9iyzn6tioYZtwqaiBSU0TSI8Yu/8dTIbfG0+B49DY= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.45.0/go.mod h1:xAvxYjYK28qvt+yu4BYZ/zMmAjwMXINXD6JiMyeB8iI= -go.opentelemetry.io/otel/metric v1.45.0 h1:7Eg1uH7CJ5cXv9is6tnBe1FI6rj1nwUdbFypRm3br/M= -go.opentelemetry.io/otel/metric v1.45.0/go.mod h1:HAPbm1nd3p1PmFH7v2dR+6BjXxw+Lq4a2+pndMAm08s= -go.opentelemetry.io/otel/metric/x v0.67.0 h1:PcicCNZFkZ4bXfSooXdo3WN7RBOVOtjVdo1wD358Uns= -go.opentelemetry.io/otel/metric/x v0.67.0/go.mod h1:FBjCWZe6wgcqxcMtjdGiClDKXb2YxxXii0CXftE4QtI= -go.opentelemetry.io/otel/sdk v1.45.0 h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw= -go.opentelemetry.io/otel/sdk v1.45.0/go.mod h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA= -go.opentelemetry.io/otel/sdk/metric v1.45.0 h1:oVFszMfyj1Am6s24Vtc7wBb8BKLcwepJjNEYILuiE3o= -go.opentelemetry.io/otel/sdk/metric v1.45.0/go.mod h1:vUWUxDZvu1WVRj8JA8S0AdhsPrZoDpA2DdZauIh4mDA= -go.opentelemetry.io/otel/trace v1.45.0 h1:l/mP6Uv7oNO7/TblbhpbgMidxhq1uO/rPsikOyVhxag= -go.opentelemetry.io/otel/trace v1.45.0/go.mod h1:qoJJA2xNMnxRrdISU/kLtfUH2wNeQbiv+jhs/CxI8bc= +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.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= golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54= @@ -109,12 +111,12 @@ golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE= golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.308.0 h1:iGb+4qT3nVb3uuIzwor3yP2nyu+rMZr31PvLFiRNJQk= -google.golang.org/api v0.308.0/go.mod h1:4XMH+b/ZEfuTbK7FnrFRY9c4xfFHVflGTKuy/i5wUmE= -google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d h1:C9v1o0/4quuhOAfmRXA2j+we0PqZIp8traLdeogF3Ms= -google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d/go.mod h1:Wz2wFJntZFmLGo7pLDXZ3wYk5hyc0Mb+SkHhDDXT+lU= -google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d h1:QwnJwPte4XXAkhPu26LTDIahnsMSUV0kK8HkxbC+Pc4= -google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d/go.mod h1:WRrQ7/7N19PypuT0fxLOL5Lq0waoiRri4FbtHDEKrGE= +google.golang.org/api v0.310.0 h1:537ccDDmbwuwX1iof3Vtdz9vow6uJCgrSZJWedAWM0I= +google.golang.org/api v0.310.0/go.mod h1:5NUthU+LmGMKzYgRaScb+TTe1Lo7x4A+J7g+Yj8BRzA= +google.golang.org/genproto v0.0.0-20261012220534-4341edf3f941 h1:CXq2XEi5aEyLjjPZIwqrmQH8ZY4ctUwK7uyAx3mjX/U= +google.golang.org/genproto v0.0.0-20261012220534-4341edf3f941/go.mod h1:3gK0ehnhP0V7/x3ypGoLyT3d0n6TSi/EcsphIjHrcz4= +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-20261019180522-ce908d29299b h1:6WNWHZk91dp4gZ25642OALkuG1UVNZbwENJD19DnB8k= google.golang.org/genproto/googleapis/rpc v0.0.0-20261019180522-ce908d29299b/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc= google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0= diff --git a/ci/resources/stemcell-version-bump/vendor/cloud.google.com/go/iam/CHANGES.md b/ci/resources/stemcell-version-bump/vendor/cloud.google.com/go/iam/CHANGES.md index 16ff67290..9bcf933de 100644 --- a/ci/resources/stemcell-version-bump/vendor/cloud.google.com/go/iam/CHANGES.md +++ b/ci/resources/stemcell-version-bump/vendor/cloud.google.com/go/iam/CHANGES.md @@ -1,6 +1,20 @@ # Changes +## [1.14.0](https://github.com/googleapis/google-cloud-go/compare/iam/v1.13.0...iam/v1.14.0) (2026-09-23) + + +### Features + +* **all:** Update supported go versions ([#20520](https://github.com/googleapis/google-cloud-go/issues/20520)) ([90413d3](https://github.com/googleapis/google-cloud-go/commit/90413d3e9d381ef4b92e3c496d98b023c5b2d8cc)) + +## [1.13.0](https://github.com/googleapis/google-cloud-go/compare/iam/v1.12.0...iam/v1.13.0) (2026-08-07) + + +### Features + +* Update API sources and regenerate ([#20326](https://github.com/googleapis/google-cloud-go/issues/20326)) ([a25826f](https://github.com/googleapis/google-cloud-go/commit/a25826f05527527005b7868284df86df4d46ce05)) + ## [1.12.0](https://github.com/googleapis/google-cloud-go/compare/iam/v1.11.0...iam/v1.12.0) (2026-07-13) diff --git a/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/.release-please-manifest.json b/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/.release-please-manifest.json index c955a3b15..0798120da 100644 --- a/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/.release-please-manifest.json +++ b/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/.release-please-manifest.json @@ -1,3 +1,3 @@ { - "v2": "2.26.2" + "v2": "2.27.0" } diff --git a/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/CHANGES.md b/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/CHANGES.md index 03a7df68c..00354d08f 100644 --- a/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/CHANGES.md +++ b/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/CHANGES.md @@ -1,5 +1,12 @@ # Changes +## [2.27.0](https://github.com/googleapis/gax-go/compare/v2.26.2...v2.27.0) (2026-10-21) + + +### Features + +* add a path expression helper ([#568](https://github.com/googleapis/gax-go/issues/568)) ([7d7373f](https://github.com/googleapis/gax-go/commit/7d7373f69b2a10796449f9ef1971ebea643c0c3a)) + ## [2.26.2](https://github.com/googleapis/gax-go/compare/v2.26.1...v2.26.2) (2026-09-26) diff --git a/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/internal/version.go b/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/internal/version.go index 325b895de..ab9fb352b 100644 --- a/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/internal/version.go +++ b/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/internal/version.go @@ -17,4 +17,4 @@ package internal // Version is the current tagged release of the library. -const Version = "2.26.2" +const Version = "2.27.0" diff --git a/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/validator.go b/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/validator.go new file mode 100644 index 000000000..4f618f32a --- /dev/null +++ b/ci/resources/stemcell-version-bump/vendor/github.com/googleapis/gax-go/v2/validator.go @@ -0,0 +1,53 @@ +// Copyright 2026, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package gax + +import ( + "errors" + "fmt" + "slices" +) + +var PathExpressionError = errors.New("invalid values present in values used to construct an HTTP URL") + +// This function ensure values being used to construct an HTTP URL path +// for REST-based SDK transports do not contain problematic values. +// +// It will return PathExpressionError if validation fails. +func ValidatePathExpressions(vals ...any) error { + disallowedStringValues := []string{".", ".."} + for _, v := range vals { + s := fmt.Sprint(v) + if slices.Contains(disallowedStringValues, s) { + return PathExpressionError + } + } + return nil +} diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/.golangci.yml b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/.golangci.yml index 8a7f1ec5d..1fef8520b 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/.golangci.yml +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/.golangci.yml @@ -143,8 +143,7 @@ linters: - name: constant-logical-expr - name: context-as-argument arguments: - - allow-types-before: '*testing.T' - disabled: true + - allow-types-before: '*testing.T,*testing.B' - name: context-keys-type - name: deep-exit - name: defer @@ -231,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 @@ -273,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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CHANGELOG.md index 2db588ea2..18903c889 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CHANGELOG.md +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CHANGELOG.md @@ -11,6 +11,121 @@ 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]. +The next release will require at least [Go 1.26]. + +### Added + +- Support testing of [Go 1.27]. (#8811) +- Support `http/json` protocol in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#8273, #8775, #8831) +- Add `Hasher` struct and methods in `go.opentelemetry.io/otel/attribute` to compute authoritative `Distinct` hashes incrementally for attribute filtering and deduplication. (#8598) + +### Changed + +- Lazily evaluate filtered and dropped attributes on measurement hot paths in `go.opentelemetry.io/otel/sdk/metric` to avoid unnecessary attribute set allocations. (#8598) +- Add `ErrExporterShutdown` to `go.opentelemetry.io/otel/sdk/log` and return it from the `go.opentelemetry.io/otel/exporters/stdout/stdoutlog`, `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`, and `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` exporters when `Export` is called after `Shutdown`. (#8773) +- Clarify in `go.opentelemetry.io/otel/log` that calling `Logger.Enabled` is optional and that cached results can become stale. (#8764) + +### Fixed + +- Export dropped attribute counts in OTLP log records from `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#8829) +- Name span events created from OpenTracing logs after the `event` log field, falling back to `log`, instead of always using an empty name in `go.opentelemetry.io/otel/bridge/opentracing`. (#8648) +- Count exception attributes omitted due to the attribute count limit as dropped in `go.opentelemetry.io/otel/sdk/log`. (#8796) +- Prevent log record and instrumentation scope attributes with empty keys from reaching processors and exporters in `go.opentelemetry.io/otel/sdk/log`. (#8797) +- Fix a data race when span attributes are read concurrently in `go.opentelemetry.io/otel/sdk/trace`. (#8706) +- Prevent a panic in `(*Set).Filter` when called on a nil receiver in `go.opentelemetry.io/otel/attribute`. (#8792) +- The simple span and log processors record `otel.sdk.processor.{span,log}.processed` when the record is submitted to the exporter instead of after the export completes, and no longer set `error.type` from the export outcome, in `go.opentelemetry.io/otel/sdk/trace` and `go.opentelemetry.io/otel/sdk/log`. (#8705) +- Prevent `Resource.MarshalLog` from panicking on nil resources in `go.opentelemetry.io/otel/sdk/resource`. (#8758) + ## [1.45.0/0.67.0/0.21.0/0.0.18] - 2026-08-03 ### Added @@ -3782,7 +3897,10 @@ 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.45.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 [1.43.0/0.65.0/0.19.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.43.0 @@ -3887,6 +4005,7 @@ It contains api and sdk for trace and meter. +[Go 1.27]: https://go.dev/doc/go1.27 [Go 1.26]: https://go.dev/doc/go1.26 [Go 1.25]: https://go.dev/doc/go1.25 [Go 1.24]: https://go.dev/doc/go1.24 diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CLAUDE.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CLAUDE.md deleted file mode 100644 index dd3c4594f..000000000 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CLAUDE.md +++ /dev/null @@ -1,3 +0,0 @@ -# Instructions for Claude Code - -@AGENTS.md diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CODEOWNERS b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CODEOWNERS index 26a03aed1..41937a389 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CODEOWNERS +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md index 2aba71e19..958a698db 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/Makefile b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/Makefile index d4711257d..c674ef8a1 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/Makefile +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/Makefile @@ -69,8 +69,13 @@ $(GORELEASE): PACKAGE=golang.org/x/exp/cmd/gorelease GOVULNCHECK = $(TOOLS)/govulncheck $(TOOLS)/govulncheck: PACKAGE=golang.org/x/vuln/cmd/govulncheck +AFFECTEDMODS = $(TOOLS)/affectedmods +AFFECTEDMODS_FILES := $(sort $(shell find $(TOOLS_MOD_DIR)/affectedmods -type f)) +$(TOOLS)/affectedmods: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/affectedmods +$(TOOLS)/affectedmods: $(AFFECTEDMODS_FILES) + .PHONY: tools -tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(VERIFYREADMES) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE) +tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(VERIFYREADMES) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE) $(AFFECTEDMODS) # Virtualized python tools via docker @@ -125,9 +130,11 @@ go-work: $(CROSSLINK) # Build -.PHONY: build +.PHONY: build cross-build build: $(OTEL_GO_MOD_DIRS:%=build/%) $(OTEL_GO_MOD_DIRS:%=build-tests/%) +# Cross-platform builds cannot execute the binaries produced by build-tests (go test), so use a compile-only target. +cross-build: $(OTEL_GO_MOD_DIRS:%=build/%) build/%: DIR=$* build/%: @echo "$(GO) build $(DIR)/..." \ @@ -163,6 +170,9 @@ test/%: | grep -v third_party \ | xargs $(GO) test -timeout $(TIMEOUT)s $(ARGS) +.PHONY: test-tools +test-tools: test/$(TOOLS_MOD_DIR) + COVERAGE_MODE = atomic COVERAGE_PROFILE = coverage.out .PHONY: test-coverage @@ -187,15 +197,23 @@ benchmark/%: # sdk/metric is split into two shards to work around CodSpeed limitations. # See https://github.com/CodSpeedHQ/codspeed-go/issues/56 -BENCHMARK_SHARDS := $(filter-out ./sdk/metric,$(OTEL_GO_MOD_DIRS)) ./sdk/metric/root ./sdk/metric/internal -benchmark/./sdk/metric/root: +BENCHMARK_SHARDS := $(filter-out ./sdk/metric,$(OTEL_GO_MOD_DIRS)) ./sdk/metric/. ./sdk/metric/internal +benchmark/./sdk/metric/.: cd ./sdk/metric && $(GO) test -run='^$$' -bench=. $(ARGS) . ./exemplar/... -benchmark/./sdk/metric/internal: - cd ./sdk/metric && $(GO) test -run='^$$' -bench=. $(ARGS) ./internal/... print-sharded-benchmarks: @echo $(BENCHMARK_SHARDS) | jq -cR 'split(" ")' +# Print the JSON list of benchmark shards whose code changed since +# BASE_REF (default: main). Filters print-sharded-benchmarks +# down to shards whose underlying module contains a changed *.go file. +# Non-Go changes (docs, workflows, Makefile, go.mod/go.sum, tooling) emit []. +# Override the diff base via BASE_REF, or pass ARGS=-all to emit the full list. +BASE_REF ?= main +.PHONY: print-affected-benchmarks +print-affected-benchmarks: + @$(MAKE) -s print-sharded-benchmarks | $(GO) -C $(TOOLS_MOD_DIR) run ./affectedmods $(if $(strip $(BASE_REF)),-base=$(BASE_REF),) $(ARGS) + .PHONY: golangci-lint golangci-lint-fix golangci-lint-fix: ARGS=--fix golangci-lint-fix: golangci-lint diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/README.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/README.md index ce97e9a25..bcdb73e01 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/README.md +++ b/ci/resources/stemcell-version-bump/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 @@ -53,20 +50,20 @@ Currently, this project supports the following environments. | OS | Go Version | Architecture | |----------|------------|--------------| +| 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. @@ -113,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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/VERSIONING.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/VERSIONING.md index b27c9e84f..56eaa7d22 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/VERSIONING.md +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/VERSIONING.md @@ -12,6 +12,12 @@ is designed so the following goals can be achieved. * [Semantic import versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning) will be used. + * Stable module compatibility is understood in terms of the [Go 1 + compatibility guidelines](https://go.dev/doc/go1compat). Code that + compiled against an older version of a package should continue to compile + against newer versions of that package, subject to the exceptions in the + Go 1 compatibility guidelines and any additional exceptions documented + below. * Versions will comply with [semver 2.0](https://semver.org/spec/v2.0.0.html) with the following exceptions. * New methods may be added to exported API interfaces. All exported diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/hash.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/hash.go index f651eb13d..54c26e67a 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/hash.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/hash.go @@ -33,19 +33,71 @@ const ( emptyID uint64 = 7305809155345288421 // "__empty_" (little endian) ) +// Hasher computes a Distinct value from KeyValue attributes supplied with +// Write. +// +// A Hasher must be obtained from [NewHasher]. The zero value is not usable and +// its methods will panic. +type Hasher struct { + h xxhash.Hash +} + +// NewHasher returns a new Hasher. +func NewHasher() *Hasher { + return &Hasher{h: xxhash.New()} +} + +// Reset resets h to its initial state so it can be reused. +func (h *Hasher) Reset() { + h.h.Reset() +} + +// Write adds kv to the hash. +// +// Write requires attributes to be supplied in ascending key order with no +// duplicate keys. To produce the same Distinct as Set.Equivalent, write +// attributes in ascending key order, with no more than one value for each key. +// If the source contains duplicate keys, retain the last value for each key +// before calling Write. +func (h *Hasher) Write(kv KeyValue) { + // hashKV mutates the digest h.h refers to in place and returns the same + // Hash value it was passed. Discarding the result keeps the digest pointer + // from flowing back into h, which would force the digest to be heap + // allocated for every Hasher. Keeping Write this small also keeps it within + // the inlining budget, which matters because hashKVs calls it per attribute. + _ = hashKV(h.h, kv) +} + +// Distinct returns the identifier for the attributes written to h. When Write +// is called as described above, it returns the same value as [Set.Equivalent]. +func (h *Hasher) Distinct() Distinct { + // No count of written attributes is needed to detect the empty case. The + // sum of a digest with nothing written to it is emptyHash, which is + // non-zero (0xef46db3751d8e999), so it passes through remapZeroHash + // unchanged and matches emptySet.Equivalent. + return Distinct{hash: remapZeroHash(h.h.Sum64())} +} + +// remapZeroHash remaps a 0 sum to a non-zero value, because hash == 0 is a +// reserved sentinel (treated as empty/invalid). +func remapZeroHash(sum uint64) uint64 { + if sum == 0 { + return 1 + } + return sum +} + // hashKVs returns a new xxHash64 hash of kvs. +// +// This routes through [Hasher] so that Set hashing and Hasher cannot disagree: +// there is exactly one implementation of how attributes are mixed and how the +// final sum is framed. func hashKVs(kvs []KeyValue) uint64 { - h := xxhash.New() + h := NewHasher() for _, kv := range kvs { - h = hashKV(h, kv) + h.Write(kv) } - sum := h.Sum64() - // Remap 0 to a non-zero value for non-empty input because hash == 0 is a reserved sentinel (treated as empty/invalid). - const remappedZeroHash uint64 = 1 - if sum == 0 && len(kvs) > 0 { - return remappedZeroHash - } - return sum + return h.Distinct().hash } // hashKV returns the xxHash64 hash of kv with h as the base. diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go index c851179cc..499aa3318 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go +++ b/ci/resources/stemcell-version-bump/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. } @@ -62,3 +65,8 @@ func (h Hash) String(val string) Hash { func (h Hash) Sum64() uint64 { return h.d.Sum64() } + +// Reset resets the hash to its initial state. +func (h Hash) Reset() { + h.d.Reset() +} diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/kv.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/kv.go index c4f0dd928..60d49739a 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/kv.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/set.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/set.go index 87d6f9620..d3b2e240b 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/set.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/attribute/set.go @@ -313,6 +313,9 @@ func filteredToFront(slice []KeyValue, keep Filter) int { // Filter returns a filtered copy of this Set. See the documentation for // NewSetWithSortableFiltered for more details. func (l *Set) Filter(re Filter) (Set, []KeyValue) { + if l == nil { + return emptySet, nil + } if re == nil { return *l, nil } @@ -406,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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/baggage/baggage.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/baggage/baggage.go index 25c739d08..72a58c1b6 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/baggage/baggage.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/codes/codes.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/codes/codes.go index 9355545a8..1502de350 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/codes/codes.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile index 20eecba40..82653bca9 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/dependencies.Dockerfile +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go index cbeb14fcd..d682f8c81 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go index de294461c..1234ead63 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/global/logger.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/global/logger.go new file mode 100644 index 000000000..e4328daa9 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/global/state.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/global/state.go index f8fcb82bc..bd388d834 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/internal/global/state.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log.go new file mode 100644 index 000000000..1758913fa --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/DESIGN.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/DESIGN.md new file mode 100644 index 000000000..d36c96773 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/LICENSE b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/LICENSE new file mode 100644 index 000000000..f1aee0f11 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/README.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/README.md new file mode 100644 index 000000000..3f7142711 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/doc.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/doc.go new file mode 100644 index 000000000..211de35f5 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/embedded/README.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/embedded/README.md new file mode 100644 index 000000000..bae4ac68f --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/embedded/embedded.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/embedded/embedded.go new file mode 100644 index 000000000..3b97fcddc --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/logger.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/logger.go new file mode 100644 index 000000000..c0e4ca7ae --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/provider.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/provider.go new file mode 100644 index 000000000..10969b415 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/record.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/record.go new file mode 100644 index 000000000..351657e95 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/severity.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/severity.go new file mode 100644 index 000000000..4f305be36 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/severity_string.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/log/severity_string.go new file mode 100644 index 000000000..fb94caeab --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/metric/meter.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/metric/meter.go index 70ff4c731..971241572 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/metric/meter.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/propagation/internal/hextable/hextable.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/propagation/internal/hextable/hextable.go new file mode 100644 index 000000000..3d63244c2 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/propagation/trace_context.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/propagation/trace_context.go index ffaa90303..1eb36b88e 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/propagation/trace_context.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/renovate.json b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/renovate.json index fa5acf2d3..5008ab2bf 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/renovate.json +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/renovate.json @@ -15,6 +15,13 @@ "matchDepTypes": ["indirect"], "enabled": true }, + { + "description": "Disable Go module major updates to v2+", + "matchManagers": ["gomod"], + "matchUpdateTypes": ["major"], + "matchNewValue": "/^v?([2-9]|[1-9][0-9]+)\\./", + "enabled": false + }, { "matchPackageNames": ["go.opentelemetry.io/build-tools/**"], "groupName": "build-tools" diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/dedup.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/dedup.go index fe9ddc96d..d72cfb3c9 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/dedup.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/truncate.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/truncate.go index 9955e9072..db7c5388c 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/truncate.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/attrnorm/truncate.go @@ -7,7 +7,7 @@ package attrnorm import ( - "slices" + "reflect" "strings" "unicode/utf8" @@ -16,53 +16,34 @@ import ( // Truncate returns a truncated version of attr. Only string, string slice, // byte slice, slice, and map attribute values are truncated. String values are -// truncated to at most a length of limit. Each string slice value is truncated -// in this fashion (the slice length itself is unaffected), and byte slice -// values are truncated to at most limit bytes. For slice and map attribute -// values, the limit is applied recursively to contained values. +// truncated according to limit. Each string slice value is truncated in this +// fashion (the slice length itself is unaffected), and byte slice values are +// truncated to at most limit bytes. For slice and map attribute values, the +// limit is applied recursively to contained values. // // No truncation is performed for a negative limit. 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,101 +57,289 @@ 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.BYTESLICE: + s := v.AsString() + if len(s) > limit { + return attribute.ByteSliceValue([]byte(s[:limit])) + } case attribute.STRINGSLICE: - ss := v.AsStringSlice() - for i := range ss { - ss[i] = truncate(limit, ss[i]) + v, _ = truncateStringSliceValue(limit, v) + case attribute.SLICE: + v, _ = truncateSliceValue(limit, v) + case attribute.MAP: + v, _ = truncateMapValue(limit, v) + } + return v +} + +// 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: + s := v.AsString() + truncated := truncate(limit, s) + if truncated != s { + return attribute.StringValue(truncated), true } - return attribute.StringSliceValue(ss) + case attribute.STRINGSLICE: + 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 limit >= 0 && len(s) > limit { - return attribute.ByteSliceValue([]byte(s[:limit])) + if len(s) > limit { + return attribute.ByteSliceValue([]byte(s[:limit])), true } case attribute.SLICE: - sl := v.AsSlice() - if !slices.ContainsFunc(sl, func(e attribute.Value) bool { return needsTruncation(limit, e) }) { - return v + return truncateSliceValue(limit, v) + case attribute.MAP: + return truncateMapValue(limit, v) + } + 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 } - newSl := make([]attribute.Value, len(sl)) - for i, elem := range sl { - newSl[i] = TruncateValue(limit, elem) + 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 } - return attribute.SliceValue(newSl...) - case attribute.MAP: - m := v.AsMap() - if !slices.ContainsFunc(m, func(kv attribute.KeyValue) bool { return needsTruncation(limit, kv.Value) }) { - return v + if newS == s { + continue } - newM := make([]attribute.KeyValue, len(m)) - for i, elem := range m { - elem.Value = TruncateValue(limit, elem.Value) - newM[i] = elem + + 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() } - return attribute.MapValue(newM...) + truncated[i] = newS } - return v + if truncated == nil { + return value, false + } + return attribute.StringSliceValue(truncated), true } -// 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 +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) } - 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 { - 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 +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 } - case attribute.STRINGSLICE: - for _, s := range v.AsStringSlice() { - if stringNeedsTruncation(limit, s) { - return true - } + if !changed { + continue } - case attribute.SLICE: - return slices.ContainsFunc(v.AsSlice(), func(e attribute.Value) bool { return needsTruncation(limit, e) }) - case attribute.MAP: - return slices.ContainsFunc( - v.AsMap(), - func(kv attribute.KeyValue) bool { return needsTruncation(limit, kv.Value) }, - ) + + 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 false + return attribute.MapValue(truncated...), true } -// truncate returns a truncated version of s such that it contains less than -// the limit number of characters. Truncation is applied by returning the limit -// number of valid characters contained in s. +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. // -// UTF-8 is supported. When truncating, all invalid characters are dropped +// UTF-8 is supported. When truncating, all invalid UTF-8 bytes are dropped // before applying truncation. // -// If s already contains less than the limit number of bytes, it is returned -// unchanged. No invalid characters are removed. +// If s already contains at most limit 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 - // common expected use-cases. + // This prioritizes performance in the following order based on the most + // common expected use cases. // - // - Short values less 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. @@ -190,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. @@ -205,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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go index e829d1794..67eea20a7 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go @@ -34,9 +34,9 @@ func newFeature[T any](suffix []string, parse func(string) (T, bool)) Feature[T] // feature. func (f Feature[T]) Keys() []string { return f.keys } -// Lookup returns the user configured value for the feature and true if the +// 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. +// 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 // diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go index f52e7ea54..5c7e85904 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/env.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/env.go index 132664a7e..090446d84 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/env.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go index 48f2b464c..64f5884d0 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/fixed_size_reservoir.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/value.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/value.go index c7d1645b6..af045e276 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/value.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go index 31f7afef9..f08657314 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/aggregate.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/aggregate.go index 696fc21ca..98916ae76 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/aggregate.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/aggregate.go @@ -57,18 +57,17 @@ func (b Builder[N]) resFunc() func(attribute.Set) FilteredExemplarReservoir[N] { return DropReservoir } -type fltrMeasure[N int64 | float64] func(ctx context.Context, value N, fltrAttr attribute.Set, droppedAttr []attribute.KeyValue) +type fltrMeasure[N int64 | float64] func(ctx context.Context, value N, lazy lazyFilteredAttributes) func (b Builder[N]) filter(f fltrMeasure[N]) Measure[N] { if b.Filter != nil { fltr := b.Filter // Copy to make it immutable after assignment. return func(ctx context.Context, n N, a attribute.Set) { - fAttr, dropped := a.Filter(fltr) - f(ctx, n, fAttr, dropped) + f(ctx, n, newLazyFilteredAttributes(a, fltr)) } } return func(ctx context.Context, n N, a attribute.Set) { - f(ctx, n, a, nil) + f(ctx, n, newLazyFilteredAttributes(a, nil)) } } diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/atomic.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/atomic.go index 675c23fc3..1e342420e 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/atomic.go +++ b/ci/resources/stemcell-version-bump/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 @@ -228,8 +249,13 @@ type limitedSyncMap[V any] struct { lenMux sync.Mutex } -func (m *limitedSyncMap[V]) LoadOrStoreAttr(fltrAttr attribute.Set, newValue func(attribute.Set) V) V { - actual, loaded := m.Load(fltrAttr.Equivalent()) +// LoadOrStoreAttr performs lookup using lazy.Distinct() on the hot path without +// constructing a Set. If the entry is not found and the aggregation limit has not +// been exceeded, lazy.Set() is called to construct the attribute.Set for storage. +// If the aggregation limit is exceeded, overflowSet is used instead without calling lazy.Set(). +func (m *limitedSyncMap[V]) LoadOrStoreAttr(lazy lazyFilteredAttributes, newValue func(attribute.Set) V) V { + distinct := lazy.Distinct() + actual, loaded := m.Load(distinct) if loaded { return actual.(V) } @@ -246,21 +272,68 @@ func (m *limitedSyncMap[V]) LoadOrStoreAttr(fltrAttr attribute.Set, newValue fun // re-fetch now that we hold the lock to ensure we don't use the overflow // set unless we are sure the attribute set isn't being written // concurrently. - actual, loaded = m.Load(fltrAttr.Equivalent()) + actual, loaded = m.Load(distinct) if loaded { return actual.(V) } + var fltrAttr attribute.Set if m.aggLimit > 0 && m.len >= m.aggLimit-1 { fltrAttr = overflowSet + distinct = overflowSet.Equivalent() + } else { + fltrAttr = lazy.Set() } - actual, loaded = m.LoadOrStore(fltrAttr.Equivalent(), newValue(fltrAttr)) + actual, loaded = m.LoadOrStore(distinct, newValue(fltrAttr)) if !loaded { m.len++ } 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() @@ -268,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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go index 47ec26dba..c78bdc671 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/drop.go @@ -18,7 +18,7 @@ func DropReservoir[N int64 | float64](attribute.Set) FilteredExemplarReservoir[N type dropRes[N int64 | float64] struct{} // Offer does nothing, all measurements offered will be dropped. -func (*dropRes[N]) Offer(context.Context, N, []attribute.KeyValue) {} +func (*dropRes[N]) Offer(context.Context, N, lazyFilteredAttributes) {} // Collect resets dest. No exemplars will ever be returned. func (*dropRes[N]) Collect(dest *[]exemplar.Exemplar) { diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go index 77c20a315..f539be942 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go @@ -331,8 +331,7 @@ type expoHistogram[N int64 | float64] struct { func (e *expoHistogram[N]) measure( ctx context.Context, value N, - fltrAttr attribute.Set, - droppedAttr []attribute.KeyValue, + lazy lazyFilteredAttributes, ) { // Ignore NaN and infinity. if math.IsInf(float64(value), 0) || math.IsNaN(float64(value)) { @@ -342,13 +341,17 @@ func (e *expoHistogram[N]) measure( e.valuesMu.Lock() defer e.valuesMu.Unlock() - v, ok := e.values[fltrAttr.Equivalent()] + distinct := lazy.Distinct() + v, ok := e.values[distinct] if !ok { - fltrAttr = e.limit.Attributes(fltrAttr, e.values) - // If we overflowed, make sure we add to the existing overflow series - // if it already exists. - v, ok = e.values[fltrAttr.Equivalent()] + v, ok = e.values[overflowSet.Equivalent()] if !ok { + var fltrAttr attribute.Set + if e.limit.aggLimit > 0 && len(e.values) >= e.limit.aggLimit-1 { + fltrAttr = overflowSet + } else { + fltrAttr = lazy.Set() + } v = newExpoHistogramDataPoint[N](fltrAttr, e.maxSize, e.maxScale, e.noMinMax, e.noSum) r := e.newRes(fltrAttr) _, isDrop := r.(*dropRes[N]) @@ -360,7 +363,7 @@ func (e *expoHistogram[N]) measure( } v.record(value) if !v.dropExemplars { - v.res.Offer(ctx, value, droppedAttr) + v.res.Offer(ctx, value, lazy) } } diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/filtered_reservoir.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/filtered_reservoir.go index 9aac90f03..20e26c57d 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/filtered_reservoir.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/filtered_reservoir.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/exemplar" "go.opentelemetry.io/otel/sdk/metric/internal/reservoir" ) @@ -22,7 +21,10 @@ type FilteredExemplarReservoir[N int64 | float64] interface { // The passed ctx needs to contain any baggage or span that were active // when the measurement was made. This information may be used by the // Reservoir in making a sampling decision. - Offer(ctx context.Context, val N, attr []attribute.KeyValue) + // + // The lazy parameter provides filtered attribute details when sampled, + // allowing dropped attributes to be computed only if the measurement is sampled. + Offer(ctx context.Context, val N, lazy lazyFilteredAttributes) // Collect returns all the held exemplars in the reservoir. Collect(dest *[]exemplar.Exemplar) } @@ -52,10 +54,11 @@ func NewFilteredExemplarReservoir[N int64 | float64]( } } -func (f *filteredExemplarReservoir[N]) Offer(ctx context.Context, val N, attr []attribute.KeyValue) { +func (f *filteredExemplarReservoir[N]) Offer(ctx context.Context, val N, lazy lazyFilteredAttributes) { if f.filter(ctx) { // only record the current time if we are sampling this measurement. ts := time.Now() + attr := lazy.Dropped() if !f.concurrentSafe { f.reservoirMux.Lock() defer f.reservoirMux.Unlock() diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/finish_sum.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/finish_sum.go new file mode 100644 index 000000000..d167acdae --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go index 17807e11e..152ae46ea 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go +++ b/ci/resources/stemcell-version-bump/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 @@ -107,15 +97,15 @@ type deltaHistogram[N int64 | float64] struct { func (s *deltaHistogram[N]) measure( ctx context.Context, value N, - fltrAttr attribute.Set, - droppedAttr []attribute.KeyValue, + lazy lazyFilteredAttributes, ) { - hotIdx := s.hcwg.start() - defer s.hcwg.done(hotIdx) - h := s.hotColdValMap[hotIdx].LoadOrStoreAttr(fltrAttr, 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, @@ -128,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 @@ -145,7 +134,7 @@ func (s *deltaHistogram[N]) measure( h.total.add(value) } if !h.dropExemplars { - h.res.Offer(ctx, value, droppedAttr) + h.res.Offer(ctx, value, lazy) } } @@ -163,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( @@ -187,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 @@ -223,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 @@ -286,10 +272,9 @@ func newCumulativeHistogram[N int64 | float64]( func (s *cumulativeHistogram[N]) measure( ctx context.Context, value N, - fltrAttr attribute.Set, - droppedAttr []attribute.KeyValue, + lazy lazyFilteredAttributes, ) { - h := s.values.LoadOrStoreAttr(fltrAttr, func(attr attribute.Set) *hotColdHistogramPoint[N] { + h := s.values.LoadOrStoreAttr(lazy, func(attr attribute.Set) *hotColdHistogramPoint[N] { r := s.newRes(attr) _, isDrop := r.(*dropRes[N]) hPt := &hotColdHistogramPoint[N]{ @@ -334,7 +319,7 @@ func (s *cumulativeHistogram[N]) measure( h.hotColdPoint[hotIdx].total.add(value) } if !h.dropExemplars { - h.res.Offer(ctx, value, droppedAttr) + h.res.Offer(ctx, value, lazy) } } @@ -405,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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go index 0fddc9dcc..8c9014345 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go @@ -21,19 +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 { +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 +} + +// deltaLastValue summarizes a set of measurements as the last one made. +type deltaLastValue[N int64 | float64] struct { newRes func(attribute.Set) FilteredExemplarReservoir[N] - values limitedSyncMap[*lastValuePoint[N]] + start time.Time + + vals hotColdMap[*lastValuePoint[N]] } -func (s *lastValueMap[N]) measure( +func (s *deltaLastValue[N]) measure( ctx context.Context, value N, - fltrAttr attribute.Set, - droppedAttr []attribute.KeyValue, + lazy lazyFilteredAttributes, ) { - lv := s.values.LoadOrStoreAttr(fltrAttr, 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]{ @@ -48,50 +64,10 @@ func (s *lastValueMap[N]) measure( lv.value.Store(value) if !lv.dropExemplars { - lv.res.Offer(ctx, value, droppedAttr) + lv.res.Offer(ctx, value, lazy) } } -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, - fltrAttr attribute.Set, - droppedAttr []attribute.KeyValue, -) { - hotIdx := s.hcwg.start() - defer s.hcwg.done(hotIdx) - s.hotColdValMap[hotIdx].measure(ctx, value, fltrAttr, droppedAttr) -} - func (s *deltaLastValue[N]) collect( dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface ) int { @@ -112,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 @@ -129,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]( @@ -147,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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lazy_attributes.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lazy_attributes.go new file mode 100644 index 000000000..2fe886247 --- /dev/null +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lazy_attributes.go @@ -0,0 +1,146 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package aggregate + +import ( + "math/bits" + + "go.opentelemetry.io/otel/attribute" +) + +type lazyFilteredAttributes struct { + orig attribute.Set + distinct attribute.Distinct + mask uint64 // bitmask of kept attributes (bit i == 1 if kept) for len <= 64 + bigMask []bool // fallback decision slice for len > 64 + hasDropped bool +} + +// newLazyFilteredAttributes filters orig using filter and computes the distinct +// hash of the resulting attributes. The filter function is evaluated once per +// attribute during initialization, and kept attribute indices are recorded in a +// bitmask so subsequent Set and Dropped calls do not re-evaluate filter. +func newLazyFilteredAttributes(orig attribute.Set, filter attribute.Filter) lazyFilteredAttributes { + if filter == nil { + return lazyFilteredAttributes{ + orig: orig, + distinct: orig.Equivalent(), + } + } + l := lazyFilteredAttributes{orig: orig, hasDropped: true} + + n := orig.Len() + hasher := attribute.NewHasher() + keptCount := 0 + for i := range n { + kv, _ := orig.Get(i) + if filter(kv) { + hasher.Write(kv) + l.recordKept(i, keptCount, n) + keptCount++ + } + } + if keptCount == n { + l.hasDropped = false + l.mask = 0 + l.bigMask = nil + l.distinct = orig.Equivalent() + return l + } + keptBefore64 := bits.OnesCount64(l.mask) + if keptCount-keptBefore64 > 0 { + l.ensureBigMask(n, keptCount) + } + l.distinct = hasher.Distinct() + return l +} + +// recordKept marks index i as kept in the bitmask or fallback slice. +func (l *lazyFilteredAttributes) recordKept(i, keptCount, total int) { + if i < 64 { + l.mask |= uint64(1) << i + return + } + if l.bigMask == nil && keptCount < i { + l.ensureBigMask(total, keptCount) + } + if l.bigMask != nil { + l.bigMask[i] = true + } +} + +// ensureBigMask initializes the bigMask slice and backfills any attributes past +// index 63 that were kept before attributes were dropped. +func (l *lazyFilteredAttributes) ensureBigMask(total, keptCount int) { + if l.bigMask != nil { + return + } + l.bigMask = make([]bool, total) + keptBefore64 := bits.OnesCount64(l.mask) + for j := 64; j < 64+(keptCount-keptBefore64); j++ { + l.bigMask[j] = true + } +} + +// isKept reports whether the attribute at index i was kept by the filter. +func (l lazyFilteredAttributes) isKept(i int) bool { + if i < 64 { + return (l.mask & (uint64(1) << i)) != 0 + } + return i < len(l.bigMask) && l.bigMask[i] +} + +// Distinct returns the precomputed Distinct hash of the filtered attributes. +func (l lazyFilteredAttributes) Distinct() attribute.Distinct { + return l.distinct +} + +// HasDroppedAttributes reports whether the filter dropped any attributes. +func (l lazyFilteredAttributes) HasDroppedAttributes() bool { + return l.hasDropped +} + +// Set constructs the filtered attribute Set using the recorded bitmask. +func (l lazyFilteredAttributes) Set() attribute.Set { + if !l.hasDropped { + return l.orig + } + if l.mask == 0 && l.bigMask == nil { + return attribute.NewSet() + } + n := l.orig.Len() + var kept []attribute.KeyValue + for i := range n { + if l.isKept(i) { + if kept == nil { + kept = make([]attribute.KeyValue, 0, n) + } + kv, _ := l.orig.Get(i) + kept = append(kept, kv) + } + } + return attribute.NewSet(kept...) +} + +// Dropped constructs the dropped attribute slice using the recorded bitmask. +func (l lazyFilteredAttributes) Dropped() []attribute.KeyValue { + if !l.hasDropped { + return nil + } + if l.mask == 0 && l.bigMask == nil { + return l.orig.ToSlice() + } + n := l.orig.Len() + var dropped []attribute.KeyValue + for i := range n { + if !l.isKept(i) { + if dropped == nil { + dropped = make([]attribute.KeyValue, 0, n) + } + kv, _ := l.orig.Get(i) + dropped = append(dropped, kv) + } + } + return dropped +} diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go index bee5ca370..ed3530cff 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go @@ -20,36 +20,6 @@ type sumValue[N int64 | float64] struct { dropExemplars bool } -type sumValueMap[N int64 | float64] struct { - newRes func(attribute.Set) FilteredExemplarReservoir[N] - values limitedSyncMap[*sumValue[N]] -} - -func (s *sumValueMap[N]) measure( - ctx context.Context, - value N, - fltrAttr attribute.Set, - droppedAttr []attribute.KeyValue, -) { - sv := s.values.LoadOrStoreAttr(fltrAttr, 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, droppedAttr) - } -} - // 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. @@ -58,20 +28,13 @@ func newDeltaSum[N int64 | float64]( limit int, r func(attribute.Set) FilteredExemplarReservoir[N], ) *deltaSum[N] { - return &deltaSum[N]{ + s := &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}, - }, - }, + newRes: r, } + s.vals.init(limit) + return s } // deltaSum is the storage for sums which resets every collection interval. @@ -79,14 +42,28 @@ type deltaSum[N int64 | float64] struct { monotonic bool start time.Time - hcwg hotColdWaitGroup - hotColdValMap [2]sumValueMap[N] + vals hotColdMap[*sumValue[N]] + newRes func(attribute.Set) FilteredExemplarReservoir[N] } -func (s *deltaSum[N]) measure(ctx context.Context, value N, fltrAttr attribute.Set, droppedAttr []attribute.KeyValue) { - hotIdx := s.hcwg.start() - defer s.hcwg.done(hotIdx) - s.hotColdValMap[hotIdx].measure(ctx, value, fltrAttr, droppedAttr) +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]{ + res: r, + attrs: attr, + startTime: now(), + dropExemplars: isDrop, + } + }) + sv.n.add(value) + if !sv.dropExemplars { + sv.res.Offer(ctx, value, lazy) + } } func (s *deltaSum[N]) collect( @@ -101,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 @@ -118,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 @@ -139,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( @@ -210,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), } } @@ -234,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() @@ -255,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 @@ -278,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 @@ -295,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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/dedup.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/dedup.go index fe9ddc96d..3e183f557 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/dedup.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/distinct.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/attrnorm/distinct.go new file mode 100644 index 000000000..2bfc243da --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/doc.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/doc.go new file mode 100644 index 000000000..7dcd37370 --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/lifecycle.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/finish/lifecycle.go new file mode 100644 index 000000000..2638fc77d --- /dev/null +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md deleted file mode 100644 index 41a4c2996..000000000 --- a/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/features.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/features.go deleted file mode 100644 index a8268702a..000000000 --- a/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/x.go deleted file mode 100644 index f501984ae..000000000 --- a/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go index 1caed336e..3155a22bb 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go index 9f7712bd5..9405959c6 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go index f04c2ddce..af705ea91 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go index 9f9f01f43..2a9f29ac2 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/version.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/version.go index 4c1cd75e2..231009680 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/version.go +++ b/ci/resources/stemcell-version-bump/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.45.0" + return "1.47.0" } diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/view.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/view.go index 3f98928f9..62ee9727a 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/metric/view.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go index 68ab274d2..1ab929a3a 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/resource/resource.go +++ b/ci/resources/stemcell-version-bump/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 @@ -120,6 +120,9 @@ func (r *Resource) String() string { // MarshalLog is the marshaling function used by the logging system to represent this Resource. func (r *Resource) MarshalLog() any { + if r == nil { + r = Empty() + } return struct { Attributes attribute.Set SchemaURL string diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/version.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/version.go index 1619fb3fa..2335ebdd7 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/sdk/version.go +++ b/ci/resources/stemcell-version-bump/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.45.0" + return "1.47.0" } diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/auto.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/auto.go index 17cf898cd..be4a96445 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/auto.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/number.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/number.go index 29e629d66..5bb3b16c7 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/number.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/value.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/value.go index 9d2d68063..b7b0e8b58 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/internal/telemetry/value.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/trace.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/trace.go index c4c383819..66b967e7d 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/trace.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/tracestate.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/tracestate.go index 9ac78fa04..062ceb2ad 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/trace/tracestate.go +++ b/ci/resources/stemcell-version-bump/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/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/version.go b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/version.go index ea7903096..29ff1801f 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/version.go +++ b/ci/resources/stemcell-version-bump/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.45.0" + return "1.47.0" } diff --git a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/versions.yaml b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/versions.yaml index 3b1ad7301..a0cb35f4d 100644 --- a/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/versions.yaml +++ b/ci/resources/stemcell-version-bump/vendor/go.opentelemetry.io/otel/versions.yaml @@ -3,7 +3,7 @@ module-sets: stable-v1: - version: v1.45.0 + version: v1.47.0 modules: - go.opentelemetry.io/otel - go.opentelemetry.io/otel/bridge/opencensus @@ -17,27 +17,31 @@ 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.67.0 + version: v0.69.0 modules: - go.opentelemetry.io/otel/exporters/prometheus - go.opentelemetry.io/otel/metric/x experimental-logs: - version: v0.21.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.18 + version: v0.0.19 modules: - go.opentelemetry.io/otel/schema excluded-modules: diff --git a/ci/resources/stemcell-version-bump/vendor/google.golang.org/api/internal/version.go b/ci/resources/stemcell-version-bump/vendor/google.golang.org/api/internal/version.go index cd8bbb5ac..fd163d013 100644 --- a/ci/resources/stemcell-version-bump/vendor/google.golang.org/api/internal/version.go +++ b/ci/resources/stemcell-version-bump/vendor/google.golang.org/api/internal/version.go @@ -5,4 +5,4 @@ package internal // Version is the current tagged release of the library. -const Version = "0.308.0" +const Version = "0.310.0" diff --git a/ci/resources/stemcell-version-bump/vendor/modules.txt b/ci/resources/stemcell-version-bump/vendor/modules.txt index 034a2b230..6d48604df 100644 --- a/ci/resources/stemcell-version-bump/vendor/modules.txt +++ b/ci/resources/stemcell-version-bump/vendor/modules.txt @@ -34,8 +34,8 @@ cloud.google.com/go/auth/oauth2adapt # cloud.google.com/go/compute/metadata v0.10.0 ## explicit; go 1.26.0 cloud.google.com/go/compute/metadata -# cloud.google.com/go/iam v1.12.0 -## explicit; go 1.25.0 +# cloud.google.com/go/iam v1.14.0 +## explicit; go 1.26.0 cloud.google.com/go/iam cloud.google.com/go/iam/apiv1/iampb # cloud.google.com/go/monitoring v1.30.0 @@ -161,11 +161,11 @@ github.com/google/s2a-go/stream # github.com/google/uuid v1.6.0 ## explicit github.com/google/uuid -# github.com/googleapis/enterprise-certificate-proxy v0.3.23 +# github.com/googleapis/enterprise-certificate-proxy v0.3.24 ## explicit; go 1.25.0 github.com/googleapis/enterprise-certificate-proxy/client github.com/googleapis/enterprise-certificate-proxy/client/util -# github.com/googleapis/gax-go/v2 v2.26.2 +# github.com/googleapis/gax-go/v2 v2.27.0 ## explicit; go 1.26.0 github.com/googleapis/gax-go/v2 github.com/googleapis/gax-go/v2/apierror @@ -219,8 +219,8 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/inte 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.45.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 @@ -231,6 +231,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.37.0 go.opentelemetry.io/otel/semconv/v1.37.0/rpcconv @@ -240,31 +241,35 @@ go.opentelemetry.io/otel/semconv/v1.41.0 go.opentelemetry.io/otel/semconv/v1.41.0/httpconv go.opentelemetry.io/otel/semconv/v1.43.0 go.opentelemetry.io/otel/semconv/v1.43.0/otelconv -# go.opentelemetry.io/otel/metric v1.45.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.45.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 go.opentelemetry.io/otel/sdk/internal/x go.opentelemetry.io/otel/sdk/resource -# go.opentelemetry.io/otel/sdk/metric v1.45.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.45.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 @@ -322,7 +327,7 @@ 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/api v0.308.0 +# google.golang.org/api v0.310.0 ## explicit; go 1.26.0 google.golang.org/api/googleapi google.golang.org/api/googleapi/transport @@ -340,14 +345,14 @@ google.golang.org/api/storage/v1 google.golang.org/api/transport google.golang.org/api/transport/grpc google.golang.org/api/transport/http -# google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d -## explicit; go 1.25.0 +# google.golang.org/genproto v0.0.0-20261012220534-4341edf3f941 +## explicit; go 1.26.0 google.golang.org/genproto/googleapis/type/calendarperiod google.golang.org/genproto/googleapis/type/date google.golang.org/genproto/googleapis/type/expr google.golang.org/genproto/googleapis/type/timeofday -# google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d -## 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/distribution