mirror of
https://github.com/containerd/containerd.git
synced 2026-10-28 17:45:13 +08:00
Merge pull request #14058 from thaJeztah/bump_otels
chore(deps): go.opentelemetry.io/otel v1.46.0, contrib v0.71.0
This commit is contained in:
44 files changed
+1244
-265
No files matched your search
@@ -66,20 +66,20 @@ require (
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/vishvananda/netns v0.0.5
|
||||
go.etcd.io/bbolt v1.5.0
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0
|
||||
go.opentelemetry.io/contrib/propagators/envcar v0.70.0
|
||||
go.opentelemetry.io/otel v1.45.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0
|
||||
go.opentelemetry.io/otel/sdk v1.45.0
|
||||
go.opentelemetry.io/otel/trace v1.45.0
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0
|
||||
go.opentelemetry.io/contrib/propagators/envcar v0.71.0
|
||||
go.opentelemetry.io/otel v1.46.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0
|
||||
go.opentelemetry.io/otel/sdk v1.46.0
|
||||
go.opentelemetry.io/otel/trace v1.46.0
|
||||
golang.org/x/mod v0.40.0
|
||||
golang.org/x/sync v0.22.0
|
||||
golang.org/x/sys v0.47.0
|
||||
golang.org/x/time v0.15.0
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5
|
||||
google.golang.org/grpc v1.83.2
|
||||
google.golang.org/protobuf v1.36.12
|
||||
k8s.io/apimachinery v0.37.0
|
||||
@@ -115,7 +115,7 @@ require (
|
||||
github.com/google/deck v0.0.0-20230104221208-105ad94aa8ae // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/knqyf263/go-plugin v0.9.0 // indirect
|
||||
github.com/mdlayher/socket v0.6.0 // indirect
|
||||
@@ -137,7 +137,7 @@ require (
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.45.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.46.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||
@@ -146,7 +146,7 @@ require (
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/term v0.45.0 // indirect
|
||||
golang.org/x/text v0.41.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/api v0.37.0 // indirect
|
||||
k8s.io/component-base v0.37.0 // indirect
|
||||
|
||||
@@ -117,30 +117,30 @@ github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxg
|
||||
github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y=
|
||||
github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY=
|
||||
github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0=
|
||||
github.com/go-openapi/swag v0.27.1 h1:VotvOLWW8q/EAxB0YdsBBGC8XYyeL1YwBj2ungAGPNg=
|
||||
github.com/go-openapi/swag v0.27.1/go.mod h1:GTkJPwHfhJp6MWr4/rCh64HVI3Ofu+tcsbfjfHmTxpE=
|
||||
github.com/go-openapi/swag/cmdutils v0.27.1 h1:I7sYqaWVl5mq0NEmNQkAmFDyNin9ufvMX/p2zwtQaOE=
|
||||
github.com/go-openapi/swag/cmdutils v0.27.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
|
||||
github.com/go-openapi/swag/conv v0.27.1 h1:8wi9ZG+olmY1wXphl93EWniPtbSPkXM/feH7FgjsvrU=
|
||||
github.com/go-openapi/swag/conv v0.27.1/go.mod h1:QbqMivkpKhC3g1B1GGGOJ6ANewI3S62dbzYu3Duowqs=
|
||||
github.com/go-openapi/swag/fileutils v0.27.1 h1:QQqBSoi5mW4XpU85nS0mLcA+zAE6vLzrb0QkmLKf9oM=
|
||||
github.com/go-openapi/swag/fileutils v0.27.1/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8=
|
||||
github.com/go-openapi/swag/jsonutils v0.27.1 h1:SVgK3i4USzCU5mibOOS/l4ea2h9UQXy7J7RNLTjuXjU=
|
||||
github.com/go-openapi/swag/jsonutils v0.27.1/go.mod h1:tdlEpZqdcQ17uj6J4YdK9vd8It5qWMwjWXOs0tjpRlk=
|
||||
github.com/go-openapi/swag/loading v0.27.1 h1:/DxUgDXKbBX4bcn7r9uEXfJyzN5XpiJmZplzQTjrRCY=
|
||||
github.com/go-openapi/swag/loading v0.27.1/go.mod h1:jvGh3iA2+zyUUycB5fgJWzeHnhrpvGnJJM0RVE9ZShE=
|
||||
github.com/go-openapi/swag/mangling v0.27.1 h1:yC9D0HyUE8gbP+BfmGx9+AA89ikwZTMjESK3OnnoaqA=
|
||||
github.com/go-openapi/swag/mangling v0.27.1/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w=
|
||||
github.com/go-openapi/swag/netutils v0.27.1 h1:mICMFoS82F5TZ4Zy3cqmcQk+BFeCp3Uyq3Np7GI0/qU=
|
||||
github.com/go-openapi/swag/netutils v0.27.1/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ=
|
||||
github.com/go-openapi/swag/pools v0.27.1 h1:9LeadcMyb2GJCbXX5hVQDbZ2Lq9TL4dCs/nx1j5DO0E=
|
||||
github.com/go-openapi/swag/pools v0.27.1/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE=
|
||||
github.com/go-openapi/swag/stringutils v0.27.1 h1:ZXePZ0r2p1qSjo8tD3Un4vFj8+FqlCkczxDrJIhYUp8=
|
||||
github.com/go-openapi/swag/stringutils v0.27.1/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM=
|
||||
github.com/go-openapi/swag/typeutils v0.27.1 h1:KSTdFlfnse4r6dP9IrEnwMldjE+zs71UeEB3//PtVXc=
|
||||
github.com/go-openapi/swag/typeutils v0.27.1/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ=
|
||||
github.com/go-openapi/swag/yamlutils v0.27.1 h1:ftxv6xvXb1E3zohUc+okZ9nSqNb9StQX/FXnKZ98sQA=
|
||||
github.com/go-openapi/swag/yamlutils v0.27.1/go.mod h1:bnxFIB1qewGRiZHypXGZ3fNgf13/0HfRgnS/iZBDrOo=
|
||||
github.com/go-openapi/swag v0.28.0 h1:xkgbOSKj6DZziNpyqRRAOt3GJGtgjgsd2RoyT30VWuw=
|
||||
github.com/go-openapi/swag v0.28.0/go.mod h1:4qYnT3Cqr1p1VknOdPo70evN4rgQnAg6jwApHyxSGIg=
|
||||
github.com/go-openapi/swag/cmdutils v0.28.0 h1:7TOeNtkYru1SG8Y34tDh9WBbLsMqGnptuxWiHREPZ4Q=
|
||||
github.com/go-openapi/swag/cmdutils v0.28.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
|
||||
github.com/go-openapi/swag/conv v0.28.0 h1:GtqqbyFe7vR5Y7ehxG9W6/OvrSFdf1OLeTGp40TqxH8=
|
||||
github.com/go-openapi/swag/conv v0.28.0/go.mod h1:mbUE+mzctnhxi864m0Q07SpN8OowD9JhxmxuYvZZD/k=
|
||||
github.com/go-openapi/swag/fileutils v0.28.0 h1:Z04XWQD7R8Eq+7GnOrjovBxPPmZzsS4gt2H2GPGIViU=
|
||||
github.com/go-openapi/swag/fileutils v0.28.0/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8=
|
||||
github.com/go-openapi/swag/jsonutils v0.28.0 h1:YIch6FwO7RXzeAnbO8Tu7dWBZeUEH+4nA0HXltVTnv4=
|
||||
github.com/go-openapi/swag/jsonutils v0.28.0/go.mod h1:CYM3WlTUcagR2ZoHdz54di/cbBqt82tuxuXgAjxw+mg=
|
||||
github.com/go-openapi/swag/loading v0.28.0 h1:td8QZdZC9MIYGGSnSPKShKiK22I2tU5UQvuUhIBPRLU=
|
||||
github.com/go-openapi/swag/loading v0.28.0/go.mod h1:rXB0QiQX5mMveXEA7ouM4KiiM9jVJe4K6BVbwhD1M4k=
|
||||
github.com/go-openapi/swag/mangling v0.28.0 h1:pH8eyeNO9SLYsTMWJrurnNfKmDa28XrlA+HePVD53VM=
|
||||
github.com/go-openapi/swag/mangling v0.28.0/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w=
|
||||
github.com/go-openapi/swag/netutils v0.28.0 h1:YXN6TALEi2pzts8/8GNm6T61HTAZsieukGZidap989k=
|
||||
github.com/go-openapi/swag/netutils v0.28.0/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ=
|
||||
github.com/go-openapi/swag/pools v0.28.0 h1:HPMZWSAfce3rdVTFcjFiCIBtDg9h4x2QlRrHipwhxeU=
|
||||
github.com/go-openapi/swag/pools v0.28.0/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE=
|
||||
github.com/go-openapi/swag/stringutils v0.28.0 h1:ixsc9iYgDPubHL/8nSkbnryEHpD2VRlBMLKpQyPXcDU=
|
||||
github.com/go-openapi/swag/stringutils v0.28.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM=
|
||||
github.com/go-openapi/swag/typeutils v0.28.0 h1:nRBKSBXjDgf01VDPB3fWeD9nQuhCOVeIYAkUx2tbkyY=
|
||||
github.com/go-openapi/swag/typeutils v0.28.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ=
|
||||
github.com/go-openapi/swag/yamlutils v0.28.0 h1:TV3JXH6DS46KUroDtMLAYHGkdWf5VDq3wVWFirmzROY=
|
||||
github.com/go-openapi/swag/yamlutils v0.28.0/go.mod h1:x0q/yndZHEgk9Rx3DyDqzFUmHy55KTvIZldvF2dTJXs=
|
||||
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
||||
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
@@ -170,8 +170,8 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY=
|
||||
github.com/intel/goresctrl v0.13.0 h1:5fhKjNq4V5MYDFHa//6M6x0jP6Iq5EXwZc6/eYxdEtQ=
|
||||
github.com/intel/goresctrl v0.13.0/go.mod h1:KFHS91JGOmeeuEog+nTQcsGjLC81nRqdsdhcqf69fjU=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
@@ -251,8 +251,8 @@ github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi
|
||||
github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc=
|
||||
github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI=
|
||||
github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY=
|
||||
github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc=
|
||||
github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=
|
||||
@@ -290,28 +290,28 @@ go.etcd.io/bbolt v1.5.0 h1:S7GAl7Fxv12yohbwFfIbQCGDWbQbtDGPET4P/bD4lxU=
|
||||
go.etcd.io/bbolt v1.5.0/go.mod h1:mkltfYE5aUHQxUct9N9V+Kp7aSjFqjgrhcXIS70Lrdk=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0 h1:oECp5f+hN7nkwjU/8BxQ/q23bGPb8FIrD839owX222E=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0/go.mod h1:DqEFwLumhzMBDQv9PcWbyoDxHI/4lAk6CM4nJBH39sc=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0 h1:LMuyCAyfalSjDyjdC65nK6N0zoTT63+E/u95X0JovZI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0/go.mod h1:085m8qbm4hgc8rZWGDEa4vmyyo2c3nPxUslYUKUIU04=
|
||||
go.opentelemetry.io/contrib/propagators/envcar v0.70.0 h1:ff/FI6f/ZRgcFluGTATyhGjVOuCGeWV2tg35kKvjie0=
|
||||
go.opentelemetry.io/contrib/propagators/envcar v0.70.0/go.mod h1:5AvLH2mk5oz7vcmpd6LZ4FJs+NGe13hX1ad24c3OxLI=
|
||||
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/exporters/otlp/otlptrace v1.45.0 h1:QRefszxJmfPdjXUUm3j6iDzY03mTPXMjqErFqQ67vUg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0/go.mod h1:Tiz03lTBVBrm7eWZBOidzEaYaJa8tjwGUGv6d8mlTyk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 h1:fG5MCxGz8+2VtrN/WgqSpJFctVz24gpxj8CxkKmc8Ww=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0/go.mod h1:BmAYTn+3ysbRe+IU2msxmf5Rx3g6DHvex+tWI3LdhYI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0 h1:QBajQ2SrwQijzHyZbQlPsuIzpl/ll8DY6wPWsajeGcI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0/go.mod h1:08ZQLjrPLQ6R4kAXvuOvODEer5Yh4CoFvll5qB2BCI8=
|
||||
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/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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0 h1:B2h3uqicet1CT2N5TOFhS+Gq++9i0/CLmaxvhmhtP5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0/go.mod h1:dylvB+ZiiwMvsDij9O84Uy7SijLgHMX4mbkncds+4Sw=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90UzBltIDKq1/5mrTGxTnOFDV0ICOhLoxiZ8jlg=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU=
|
||||
go.opentelemetry.io/contrib/propagators/envcar v0.71.0 h1:r7TFdi1B3O5ai64tONEuBTyxeQaLKVYf75vLiV7ZsDc=
|
||||
go.opentelemetry.io/contrib/propagators/envcar v0.71.0/go.mod h1:uAnx0mCFm63a47qI4f/hcoI72gVYrGdxEBL+6c500Ns=
|
||||
go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
|
||||
go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 h1:OFnwLJr+pF3iHrlGSzbxyuo6/6HyBlnlN1CWEJmBVcw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0/go.mod h1:716wFneO0ov19A2beH5hjfh9AK5z/VWNAtDijp1Y0/g=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0 h1:w53CDeOA/Kurp7yRsegSr6pbbr759dOvJ+yNmWM6Hxs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0/go.mod h1:BOmGMCbAtvcJiSJ+hLuhgPLdDbimnraSl8irz3iY8sY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0 h1:KrC1YrQeSt46ITMWAbgQx1M1eV1/1TKzttrBzymPmss=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0/go.mod h1:zDSEzoEqsOrgBeGvH66KRgxh90VonFyJqBHA0Pk3+rM=
|
||||
go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
|
||||
go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
|
||||
go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
|
||||
go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
|
||||
go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
|
||||
go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
|
||||
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
|
||||
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
@@ -410,10 +410,10 @@ golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d h1:FarXi840EJWSHYTN3ERkADbPWjl307+FGrA22KAVjjc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d/go.mod h1:K/+WGbmBY7aNW1HDw1fJnKYo10i0DkAX6pows00dLig=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 h1:izFU9hz7aeLI/Mi1J0991ae+xcwRLr7hTqWnB/9aIIU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5/go.mod h1:3LhxRw4YYkf+ylAfgaY9JlVLFKhokkCV8duhLLe7+t0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 h1:1VUiZAXyC+zmiFYi+WLtBzr68Cj8wOofHjjrA/kkizc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA=
|
||||
google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU=
|
||||
google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8=
|
||||
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
||||
|
||||
Generated
Vendored
+23
-7
@@ -407,22 +407,38 @@ func (*config) handleRPC(
|
||||
// Don't use gctx.metricAttrSet here, because it requires passing
|
||||
// multiple RecordOptions, which would call metric.mergeSets and
|
||||
// allocate a new set for each Record call.
|
||||
metricAttrs = make([]attribute.KeyValue, 0, len(gctx.metricAttrs)+1)
|
||||
metricAttrs = make([]attribute.KeyValue, 0, len(gctx.metricAttrs)+2)
|
||||
metricAttrs = append(metricAttrs, gctx.metricAttrs...)
|
||||
}
|
||||
metricAttrs = append(metricAttrs, rpcStatusAttr)
|
||||
// Allocate vararg slice once.
|
||||
recordOpts := []metric.RecordOption{metric.WithAttributeSet(attribute.NewSet(metricAttrs...))}
|
||||
|
||||
// error.type is Conditionally Required on the stable rpc.*.call.duration
|
||||
// metrics when the RPC failed, and SHOULD be set to the returned status
|
||||
// code. The failure classification is role-specific: clients treat every
|
||||
// non-OK status as an error, while servers only classify Unknown,
|
||||
// DeadlineExceeded, Unimplemented, Internal, Unavailable and DataLoss
|
||||
// as errors. Use recordStatus so the client and server rules are applied
|
||||
// independently (e.g. a client cancellation is not a server error).
|
||||
// The legacy v1.37 rpc.*.duration conventions did not define error.type,
|
||||
// so the compatibility instruments keep the unmodified attribute set.
|
||||
// Build each record option only in its enabled branch: single-mode
|
||||
// configurations (rpc, rpc/old) must not allocate the other set, and
|
||||
// error.type is only appended after the legacy instruments recorded.
|
||||
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
// Measure right before calling Record() to capture as much elapsed time as possible.
|
||||
elapsedTime := float64(rs.EndTime.Sub(rs.BeginTime)) / float64(time.Second)
|
||||
|
||||
if durationEnabled {
|
||||
duration.Record(ctx, elapsedTime, recordOpts...)
|
||||
}
|
||||
if oldDurationEnabled {
|
||||
oldDuration.Record(ctx, elapsedTime*1000.0, recordOpts...)
|
||||
oldDuration.Record(ctx, elapsedTime*1000.0, metric.WithAttributeSet(attribute.NewSet(metricAttrs...)))
|
||||
}
|
||||
if durationEnabled {
|
||||
if s != nil {
|
||||
if c, _ := recordStatus(s); c == codes.Error {
|
||||
metricAttrs = append(metricAttrs, semconv.ErrorTypeKey.String(canonicalString(s.Code())))
|
||||
}
|
||||
}
|
||||
duration.Record(ctx, elapsedTime, metric.WithAttributeSet(attribute.NewSet(metricAttrs...)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -4,4 +4,4 @@
|
||||
package otelgrpc
|
||||
|
||||
// Version is the current release version of the gRPC instrumentation.
|
||||
const Version = "0.70.0"
|
||||
const Version = "0.71.0"
|
||||
+1
-1
@@ -4,4 +4,4 @@
|
||||
package otelhttp
|
||||
|
||||
// Version is the current release version of the otelhttp instrumentation.
|
||||
const Version = "0.70.0"
|
||||
const Version = "0.71.0"
|
||||
+1
-1
@@ -5,6 +5,6 @@ package envcar
|
||||
|
||||
// Version is the current release version of the envcar propagator.
|
||||
func Version() string {
|
||||
return "0.70.0"
|
||||
return "0.71.0"
|
||||
// This string is updated by the pre_release.sh script during release
|
||||
}
|
||||
+1
-2
@@ -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
|
||||
|
||||
+31
-1
@@ -11,6 +11,34 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
<!-- Released section -->
|
||||
<!-- Don't change this section unless doing release -->
|
||||
|
||||
## [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 +3810,8 @@ 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.46.0...HEAD
|
||||
[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 +3916,7 @@ It contains api and sdk for trace and meter.
|
||||
|
||||
<!-- Released section ended -->
|
||||
|
||||
[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
|
||||
|
||||
+24
-6
@@ -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
|
||||
|
||||
+7
@@ -53,18 +53,25 @@ 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 |
|
||||
|
||||
|
||||
+6
@@ -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
|
||||
|
||||
+63
-11
@@ -33,21 +33,73 @@ const (
|
||||
emptyID uint64 = 7305809155345288421 // "__empty_" (little endian)
|
||||
)
|
||||
|
||||
// hashKVs returns a new xxHash64 hash of kvs.
|
||||
func hashKVs(kvs []KeyValue) uint64 {
|
||||
h := xxhash.New()
|
||||
for _, kv := range kvs {
|
||||
h = hashKV(h, 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
|
||||
// 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 := NewHasher()
|
||||
for _, kv := range kvs {
|
||||
h.Write(kv)
|
||||
}
|
||||
return h.Distinct().hash
|
||||
}
|
||||
|
||||
// hashKV returns the xxHash64 hash of kv with h as the base.
|
||||
func hashKV(h xxhash.Hash, kv KeyValue) xxhash.Hash {
|
||||
h = h.String(string(kv.Key))
|
||||
|
||||
+5
@@ -62,3 +62,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()
|
||||
}
|
||||
+3
@@ -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
|
||||
}
|
||||
|
||||
Generated
Vendored
+9
-9
@@ -21,13 +21,13 @@ const (
|
||||
)
|
||||
|
||||
// ParseCanonicalTarget parses a target string and returns the extracted host
|
||||
// (domain address or IP), the target port, or an error.
|
||||
// (domain name or IP address), the target port, or an error.
|
||||
//
|
||||
// If no port is specified, -1 is returned.
|
||||
//
|
||||
// If no host is specified, an empty string is returned.
|
||||
//
|
||||
// The target string is expected to always have the form
|
||||
// The target string must have the form
|
||||
// "<scheme>://[authority]/<endpoint>". For example:
|
||||
// - "dns:///example.com:42"
|
||||
// - "dns://8.8.8.8/example.com:42"
|
||||
@@ -35,8 +35,8 @@ const (
|
||||
// - "unix-abstract:///socket-name"
|
||||
// - "passthrough:///192.34.2.1:42"
|
||||
//
|
||||
// The target is expected to come from the CanonicalTarget method of a gRPC
|
||||
// Client.
|
||||
// The target is expected to be returned by gRPC's ClientConn.CanonicalTarget
|
||||
// method.
|
||||
func ParseCanonicalTarget(target string) (string, int, error) {
|
||||
const sep = "://"
|
||||
|
||||
@@ -60,7 +60,7 @@ func ParseCanonicalTarget(target string) (string, int, error) {
|
||||
return parseEndpoint(endpoint)
|
||||
}
|
||||
|
||||
// parseUnix parses unix socket targets.
|
||||
// parseUnix parses Unix socket targets.
|
||||
func parseUnix(endpoint string) (string, int, error) {
|
||||
// Format: unix[-abstract]://path
|
||||
//
|
||||
@@ -70,8 +70,8 @@ func parseUnix(endpoint string) (string, int, error) {
|
||||
return endpoint, -1, nil
|
||||
}
|
||||
|
||||
// If there's no leading slash, it means there might be an authority
|
||||
// Check for authority case (should error): "authority/path"
|
||||
// If there is no leading slash, an authority might be present, which is
|
||||
// invalid. Check for this case: "authority/path".
|
||||
if slashIdx := strings.Index(endpoint, "/"); slashIdx > 0 {
|
||||
return "", -1, fmt.Errorf("invalid (non-empty) authority: %s", endpoint[:slashIdx])
|
||||
}
|
||||
@@ -97,8 +97,8 @@ func parseUnix(endpoint string) (string, int, error) {
|
||||
// - "[ipv6]:port"
|
||||
// - "[ipv6%zone]:port"
|
||||
//
|
||||
// It returns the host or host%zone (domain address or IP), the port (or -1 if
|
||||
// not specified), or an error if the input is not a valid.
|
||||
// It returns the host or host%zone (domain name or IP address), the port (or
|
||||
// -1 if not specified), or an error if the input is invalid.
|
||||
func parseEndpoint(endpoint string) (string, int, error) {
|
||||
// First check if the endpoint is just an IP address.
|
||||
if ip := parseIP(endpoint); ip != "" {
|
||||
|
||||
Generated
Vendored
+21
@@ -100,6 +100,8 @@ func getOptionsFromEnv() []GenericOption {
|
||||
envconfig.WithHeaders("TRACES_HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }),
|
||||
WithEnvCompression("COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
|
||||
WithEnvCompression("TRACES_COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
|
||||
WithEnvProtocol("PROTOCOL", func(p Protocol) { opts = append(opts, WithProtocol(p)) }),
|
||||
WithEnvProtocol("TRACES_PROTOCOL", func(p Protocol) { opts = append(opts, WithProtocol(p)) }),
|
||||
envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
|
||||
envconfig.WithDuration("TRACES_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
|
||||
)
|
||||
@@ -139,6 +141,25 @@ func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOpt
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnvProtocol retrieves the specified config and passes it to ConfigFn as a Protocol.
|
||||
func WithEnvProtocol(n string, fn func(Protocol)) func(e *envconfig.EnvOptionsReader) {
|
||||
return func(e *envconfig.EnvOptionsReader) {
|
||||
if v, ok := e.GetEnvValue(n); ok {
|
||||
protocol := ProtocolHTTPProtobuf
|
||||
switch v {
|
||||
case "grpc":
|
||||
protocol = ProtocolGRPC
|
||||
case "http/protobuf":
|
||||
protocol = ProtocolHTTPProtobuf
|
||||
case "http/json":
|
||||
protocol = ProtocolHTTPJSON
|
||||
}
|
||||
|
||||
fn(protocol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// revive:disable-next-line:flag-parameter
|
||||
func withInsecure(b bool) GenericOption {
|
||||
if b {
|
||||
|
||||
Generated
Vendored
+25
@@ -50,6 +50,7 @@ type (
|
||||
TLSCfg *tls.Config
|
||||
Headers map[string]string
|
||||
Compression Compression
|
||||
Protocol Protocol
|
||||
MaxRequestSize int
|
||||
Timeout time.Duration
|
||||
URLPath string
|
||||
@@ -84,6 +85,7 @@ func NewHTTPConfig(opts ...HTTPOption) Config {
|
||||
Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort),
|
||||
URLPath: DefaultTracesPath,
|
||||
Compression: NoCompression,
|
||||
Protocol: ProtocolHTTPProtobuf,
|
||||
MaxRequestSize: DefaultMaxRequestSize,
|
||||
Timeout: DefaultTimeout,
|
||||
},
|
||||
@@ -119,6 +121,7 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
|
||||
Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort),
|
||||
URLPath: DefaultTracesPath,
|
||||
Compression: NoCompression,
|
||||
Protocol: ProtocolGRPC,
|
||||
MaxRequestSize: DefaultMaxRequestSize,
|
||||
Timeout: DefaultTimeout,
|
||||
},
|
||||
@@ -376,3 +379,25 @@ func WithHTTPClient(c *http.Client) GenericOption {
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
func WithProtocol(protocol Protocol) GenericOption {
|
||||
return newSplitOption(
|
||||
// For OTLP/HTTP endpoints, this is the encoding format of the payloads sent to the collector.
|
||||
func(cfg Config) Config {
|
||||
if protocol == ProtocolGRPC {
|
||||
global.Warn("grpc is not a valid protocol for OTLP/HTTP, defaulting to http/protobuf")
|
||||
protocol = ProtocolHTTPProtobuf
|
||||
}
|
||||
cfg.Traces.Protocol = protocol
|
||||
return cfg
|
||||
},
|
||||
// For OTLP/gRPC endpoints, it's always "grpc".
|
||||
func(cfg Config) Config {
|
||||
if protocol != ProtocolGRPC {
|
||||
global.Debug("protocol option is ignored for OTLP/gRPC and is set to grpc")
|
||||
}
|
||||
cfg.Traces.Protocol = ProtocolGRPC
|
||||
return cfg
|
||||
},
|
||||
)
|
||||
}
|
||||
Generated
Vendored
+12
@@ -38,3 +38,15 @@ const (
|
||||
// MarshalJSON tells the driver to send using json format.
|
||||
MarshalJSON
|
||||
)
|
||||
|
||||
// Protocol describes the transport protocol used to send data to the collector.
|
||||
type Protocol int
|
||||
|
||||
const (
|
||||
// ProtocolGRPC describes the "grpc" protocol.
|
||||
ProtocolGRPC Protocol = iota
|
||||
// ProtocolHTTPProtobuf describes the "http/protobuf" protocol.
|
||||
ProtocolHTTPProtobuf
|
||||
// ProtocolHTTPJSON describes the "http/json" protocol.
|
||||
ProtocolHTTPJSON
|
||||
)
|
||||
Generated
Vendored
+24
-26
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/cenkalti/backoff/v5"
|
||||
)
|
||||
|
||||
// DefaultConfig are the recommended defaults to use.
|
||||
// DefaultConfig is the recommended default configuration.
|
||||
var DefaultConfig = Config{
|
||||
Enabled: true,
|
||||
InitialInterval: 5 * time.Second,
|
||||
@@ -25,42 +25,40 @@ var DefaultConfig = Config{
|
||||
MaxElapsedTime: time.Minute,
|
||||
}
|
||||
|
||||
// Config defines configuration for retrying batches in case of export failure
|
||||
// using an exponential backoff.
|
||||
// Config defines configuration for retrying batches after an export failure
|
||||
// using exponential backoff.
|
||||
type Config struct {
|
||||
// Enabled indicates whether to not retry sending batches in case of
|
||||
// export failure.
|
||||
// Enabled indicates whether to retry sending batches after an export
|
||||
// failure.
|
||||
Enabled bool
|
||||
// InitialInterval the time to wait after the first failure before
|
||||
// InitialInterval is the time to wait after the first failure before
|
||||
// retrying.
|
||||
InitialInterval time.Duration
|
||||
// MaxInterval is the upper bound on backoff interval. Once this value is
|
||||
// reached the delay between consecutive retries will always be
|
||||
// `MaxInterval`.
|
||||
// MaxInterval is the upper bound on the backoff interval before
|
||||
// randomization. Once this value is reached, the base interval remains at
|
||||
// MaxInterval.
|
||||
MaxInterval time.Duration
|
||||
// MaxElapsedTime is the maximum amount of time (including retries) spent
|
||||
// trying to send a request/batch. Once this value is reached, the data
|
||||
// is discarded.
|
||||
// trying to send a request/batch. Once this value is reached, retrying stops.
|
||||
MaxElapsedTime time.Duration
|
||||
}
|
||||
|
||||
// RequestFunc wraps a request with retry logic.
|
||||
type RequestFunc func(context.Context, func(context.Context) error) error
|
||||
|
||||
// EvaluateFunc returns if an error is retry-able and if an explicit throttle
|
||||
// duration should be honored that was included in the error.
|
||||
// EvaluateFunc reports whether an error is retryable and returns any explicit
|
||||
// throttle duration to honor.
|
||||
//
|
||||
// The function must return true if the error argument is retry-able,
|
||||
// otherwise it must return false for the first return parameter.
|
||||
// The function must return true as its first return value if the error
|
||||
// argument is retryable; otherwise, it must return false.
|
||||
//
|
||||
// The function must return a non-zero time.Duration if the error contains
|
||||
// explicit throttle duration that should be honored, otherwise it must return
|
||||
// a zero valued time.Duration.
|
||||
// The function must return a nonzero time.Duration if the error contains an
|
||||
// explicit throttle duration that should be honored; otherwise, it must return
|
||||
// the zero value for time.Duration.
|
||||
type EvaluateFunc func(error) (bool, time.Duration)
|
||||
|
||||
// RequestFunc returns a RequestFunc using the evaluate function to determine
|
||||
// if requests can be retried and based on the exponential backoff
|
||||
// configuration of c.
|
||||
// RequestFunc returns a RequestFunc that uses evaluate to determine whether
|
||||
// requests can be retried and uses c to configure exponential backoff.
|
||||
func (c Config) RequestFunc(evaluate EvaluateFunc) RequestFunc {
|
||||
if !c.Enabled {
|
||||
return func(ctx context.Context, fn func(context.Context) error) error {
|
||||
@@ -96,7 +94,7 @@ func (c Config) RequestFunc(evaluate EvaluateFunc) RequestFunc {
|
||||
|
||||
// Check if context is canceled before attempting to wait and retry.
|
||||
if ctx.Err() != nil {
|
||||
return fmt.Errorf("%w: %w", ctx.Err(), err)
|
||||
return fmt.Errorf("%w: %w", context.Cause(ctx), err)
|
||||
}
|
||||
|
||||
if maxElapsedTime != 0 && time.Since(startTime) > maxElapsedTime {
|
||||
@@ -119,12 +117,12 @@ func (c Config) RequestFunc(evaluate EvaluateFunc) RequestFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// Allow override for testing.
|
||||
// waitFunc can be overridden for testing.
|
||||
var waitFunc = wait
|
||||
|
||||
// wait takes the caller's context, and the amount of time to wait. It will
|
||||
// return nil if the timer fires before or at the same time as the context's
|
||||
// deadline. This indicates that the call can be retried.
|
||||
// wait blocks until delay elapses or ctx is done. If both happen
|
||||
// simultaneously, wait favors the elapsed delay and returns nil to indicate
|
||||
// that the call can be retried.
|
||||
func wait(ctx context.Context, delay time.Duration) error {
|
||||
timer := time.NewTimer(delay)
|
||||
defer timer.Stop()
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -5,4 +5,4 @@ package internal
|
||||
|
||||
// Version is the current release version of the OpenTelemetry OTLP gRPC trace
|
||||
// exporter in use.
|
||||
const Version = "1.45.0"
|
||||
const Version = "1.46.0"
|
||||
Generated
Vendored
+2
-2
@@ -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
|
||||
//
|
||||
|
||||
+52
-20
@@ -27,10 +27,14 @@ import (
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/counter"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/observ"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpjson"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry"
|
||||
)
|
||||
|
||||
const contentTypeProto = "application/x-protobuf"
|
||||
const (
|
||||
contentTypeProto = "application/x-protobuf"
|
||||
contentTypeJSON = "application/json"
|
||||
)
|
||||
|
||||
// maxResponseBodySize is the maximum number of bytes to read from a response
|
||||
// body. It is set to 4 MiB per the OTLP specification recommendation to
|
||||
@@ -160,19 +164,11 @@ func (c *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
|
||||
pbRequest := &coltracepb.ExportTraceServiceRequest{
|
||||
ResourceSpans: protoSpans,
|
||||
}
|
||||
rawRequest, err := proto.Marshal(pbRequest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := c.contextWithStop(ctx)
|
||||
defer cancel()
|
||||
|
||||
if maxSize := c.cfg.MaxRequestSize; maxSize > 0 && len(rawRequest) > maxSize {
|
||||
return fmt.Errorf("request body too large: exceeded %d bytes", maxSize)
|
||||
}
|
||||
|
||||
request, err := c.newRequest(rawRequest)
|
||||
request, err := c.newRequest(pbRequest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -232,19 +228,26 @@ func (c *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
|
||||
return nil
|
||||
}
|
||||
|
||||
if resp.Header.Get("Content-Type") == "application/x-protobuf" {
|
||||
var respProto coltracepb.ExportTraceServiceResponse
|
||||
var respProto coltracepb.ExportTraceServiceResponse
|
||||
switch resp.Header.Get("Content-Type") {
|
||||
case contentTypeProto:
|
||||
if err := proto.Unmarshal(respData.Bytes(), &respProto); err != nil {
|
||||
return err
|
||||
}
|
||||
case contentTypeJSON:
|
||||
if err := otlpjson.UnmarshalExportTraceServiceResponse(respData.Bytes(), &respProto); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
if respProto.PartialSuccess != nil {
|
||||
msg := respProto.PartialSuccess.GetErrorMessage()
|
||||
n := respProto.PartialSuccess.GetRejectedSpans()
|
||||
if n != 0 || msg != "" {
|
||||
err := internal.TracePartialSuccessError(n, msg)
|
||||
uploadErr = errors.Join(uploadErr, err)
|
||||
}
|
||||
if respProto.PartialSuccess != nil {
|
||||
msg := respProto.PartialSuccess.GetErrorMessage()
|
||||
n := respProto.PartialSuccess.GetRejectedSpans()
|
||||
if n != 0 || msg != "" {
|
||||
err := internal.TracePartialSuccessError(n, msg)
|
||||
uploadErr = errors.Join(uploadErr, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -283,7 +286,24 @@ func (c *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
|
||||
}))
|
||||
}
|
||||
|
||||
func (c *client) newRequest(body []byte) (request, error) {
|
||||
func (c *client) marshalRequest(pbRequest *coltracepb.ExportTraceServiceRequest) ([]byte, error) {
|
||||
if c.cfg.Protocol == otlpconfig.ProtocolHTTPJSON {
|
||||
rawRequest, err := otlpjson.MarshalExportTraceServiceRequest(pbRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request body in json: %w", err)
|
||||
}
|
||||
return rawRequest, nil
|
||||
}
|
||||
|
||||
rawRequest, err := proto.Marshal(pbRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request body in protobuf: %w", err)
|
||||
}
|
||||
|
||||
return rawRequest, nil
|
||||
}
|
||||
|
||||
func (c *client) newRequest(pbRequest *coltracepb.ExportTraceServiceRequest) (request, error) {
|
||||
u := url.URL{Scheme: c.getScheme(), Host: c.cfg.Endpoint, Path: c.cfg.URLPath}
|
||||
r, err := http.NewRequestWithContext(context.Background(), http.MethodPost, u.String(), http.NoBody)
|
||||
if err != nil {
|
||||
@@ -297,6 +317,18 @@ func (c *client) newRequest(body []byte) (request, error) {
|
||||
r.Header.Set(k, v)
|
||||
}
|
||||
r.Header.Set("Content-Type", contentTypeProto)
|
||||
if c.cfg.Protocol == otlpconfig.ProtocolHTTPJSON {
|
||||
r.Header.Set("Content-Type", contentTypeJSON)
|
||||
}
|
||||
|
||||
body, err := c.marshalRequest(pbRequest)
|
||||
if err != nil {
|
||||
return request{Request: r}, err
|
||||
}
|
||||
|
||||
if maxSize := c.cfg.MaxRequestSize; maxSize > 0 && len(body) > maxSize {
|
||||
return request{Request: r}, fmt.Errorf("request body too large: exceeded %d bytes", maxSize)
|
||||
}
|
||||
|
||||
req := request{Request: r}
|
||||
switch Compression(c.cfg.Compression) {
|
||||
|
||||
+7
-1
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
Package otlptracehttp provides an OTLP span exporter using HTTP with protobuf payloads.
|
||||
Package otlptracehttp provides an OTLP span exporter using HTTP with protobuf or JSON payloads.
|
||||
By default the telemetry is sent to https://localhost:4318/v1/traces.
|
||||
|
||||
Exporter should be created using [New].
|
||||
@@ -63,6 +63,12 @@ the filepath to the client's private key to use in mTLS communication in PEM for
|
||||
OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY takes precedence over OTEL_EXPORTER_OTLP_CLIENT_KEY.
|
||||
The configuration can be overridden by [WithTLSClientConfig] option.
|
||||
|
||||
OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_TRACES_PROTOCOL (default: "http/protobuf") -
|
||||
the transport protocol the exporter uses. For OTLP/HTTP exporters, it indicates the encoding format of the payloads sent to the collector.
|
||||
Supported value: "http/protobuf", "http/json".
|
||||
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL takes precedence over OTEL_EXPORTER_OTLP_PROTOCOL.
|
||||
The configuration can be overridden by [WithEncoding] option.
|
||||
|
||||
[W3C Baggage HTTP Header Content Format]: https://www.w3.org/TR/baggage/#header-content
|
||||
*/
|
||||
package otlptracehttp
|
||||
Generated
Vendored
+21
@@ -100,6 +100,8 @@ func getOptionsFromEnv() []GenericOption {
|
||||
envconfig.WithHeaders("TRACES_HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }),
|
||||
WithEnvCompression("COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
|
||||
WithEnvCompression("TRACES_COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
|
||||
WithEnvProtocol("PROTOCOL", func(p Protocol) { opts = append(opts, WithProtocol(p)) }),
|
||||
WithEnvProtocol("TRACES_PROTOCOL", func(p Protocol) { opts = append(opts, WithProtocol(p)) }),
|
||||
envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
|
||||
envconfig.WithDuration("TRACES_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
|
||||
)
|
||||
@@ -139,6 +141,25 @@ func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOpt
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnvProtocol retrieves the specified config and passes it to ConfigFn as a Protocol.
|
||||
func WithEnvProtocol(n string, fn func(Protocol)) func(e *envconfig.EnvOptionsReader) {
|
||||
return func(e *envconfig.EnvOptionsReader) {
|
||||
if v, ok := e.GetEnvValue(n); ok {
|
||||
protocol := ProtocolHTTPProtobuf
|
||||
switch v {
|
||||
case "grpc":
|
||||
protocol = ProtocolGRPC
|
||||
case "http/protobuf":
|
||||
protocol = ProtocolHTTPProtobuf
|
||||
case "http/json":
|
||||
protocol = ProtocolHTTPJSON
|
||||
}
|
||||
|
||||
fn(protocol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// revive:disable-next-line:flag-parameter
|
||||
func withInsecure(b bool) GenericOption {
|
||||
if b {
|
||||
|
||||
Generated
Vendored
+25
@@ -50,6 +50,7 @@ type (
|
||||
TLSCfg *tls.Config
|
||||
Headers map[string]string
|
||||
Compression Compression
|
||||
Protocol Protocol
|
||||
MaxRequestSize int
|
||||
Timeout time.Duration
|
||||
URLPath string
|
||||
@@ -84,6 +85,7 @@ func NewHTTPConfig(opts ...HTTPOption) Config {
|
||||
Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort),
|
||||
URLPath: DefaultTracesPath,
|
||||
Compression: NoCompression,
|
||||
Protocol: ProtocolHTTPProtobuf,
|
||||
MaxRequestSize: DefaultMaxRequestSize,
|
||||
Timeout: DefaultTimeout,
|
||||
},
|
||||
@@ -119,6 +121,7 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
|
||||
Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort),
|
||||
URLPath: DefaultTracesPath,
|
||||
Compression: NoCompression,
|
||||
Protocol: ProtocolGRPC,
|
||||
MaxRequestSize: DefaultMaxRequestSize,
|
||||
Timeout: DefaultTimeout,
|
||||
},
|
||||
@@ -376,3 +379,25 @@ func WithHTTPClient(c *http.Client) GenericOption {
|
||||
return cfg
|
||||
})
|
||||
}
|
||||
|
||||
func WithProtocol(protocol Protocol) GenericOption {
|
||||
return newSplitOption(
|
||||
// For OTLP/HTTP endpoints, this is the encoding format of the payloads sent to the collector.
|
||||
func(cfg Config) Config {
|
||||
if protocol == ProtocolGRPC {
|
||||
global.Warn("grpc is not a valid protocol for OTLP/HTTP, defaulting to http/protobuf")
|
||||
protocol = ProtocolHTTPProtobuf
|
||||
}
|
||||
cfg.Traces.Protocol = protocol
|
||||
return cfg
|
||||
},
|
||||
// For OTLP/gRPC endpoints, it's always "grpc".
|
||||
func(cfg Config) Config {
|
||||
if protocol != ProtocolGRPC {
|
||||
global.Debug("protocol option is ignored for OTLP/gRPC and is set to grpc")
|
||||
}
|
||||
cfg.Traces.Protocol = ProtocolGRPC
|
||||
return cfg
|
||||
},
|
||||
)
|
||||
}
|
||||
Generated
Vendored
+12
@@ -38,3 +38,15 @@ const (
|
||||
// MarshalJSON tells the driver to send using json format.
|
||||
MarshalJSON
|
||||
)
|
||||
|
||||
// Protocol describes the transport protocol used to send data to the collector.
|
||||
type Protocol int
|
||||
|
||||
const (
|
||||
// ProtocolGRPC describes the "grpc" protocol.
|
||||
ProtocolGRPC Protocol = iota
|
||||
// ProtocolHTTPProtobuf describes the "http/protobuf" protocol.
|
||||
ProtocolHTTPProtobuf
|
||||
// ProtocolHTTPJSON describes the "http/json" protocol.
|
||||
ProtocolHTTPJSON
|
||||
)
|
||||
Generated
Vendored
+642
@@ -0,0 +1,642 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package otlpjson implements OTLP JSON Protobuf encoding for trace data.
|
||||
//
|
||||
// The encoding conforms to the OTLP specs
|
||||
// (https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding):
|
||||
// - trace ID and span ID byte arrays are encoded as case-insensitive hex-encoded strings
|
||||
// - enum values encoded as integers
|
||||
// - field names in lowerCamelCase
|
||||
// - 64-bit integers encoded as quoted decimal strings (ProtoJSON specs)
|
||||
package otlpjson
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1"
|
||||
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
|
||||
resourcepb "go.opentelemetry.io/proto/otlp/resource/v1"
|
||||
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
|
||||
)
|
||||
|
||||
// ExportTraceServiceRequest corresponds to coltracepb.ExportTraceServiceRequest.
|
||||
type ExportTraceServiceRequest struct {
|
||||
ResourceSpans []*ResourceSpans `json:"resourceSpans,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceSpans corresponds to tracepb.ResourceSpans.
|
||||
type ResourceSpans struct {
|
||||
Resource *Resource `json:"resource,omitempty"`
|
||||
ScopeSpans []*ScopeSpans `json:"scopeSpans,omitempty"`
|
||||
SchemaURL string `json:"schemaUrl,omitempty"`
|
||||
}
|
||||
|
||||
// Resource corresponds to resourcepb.Resource.
|
||||
type Resource struct {
|
||||
Attributes []*KeyValue `json:"attributes,omitempty"`
|
||||
DroppedAttributesCount uint32 `json:"droppedAttributesCount,omitempty"`
|
||||
EntityRefs []*EntityRef `json:"entityRefs,omitempty"`
|
||||
}
|
||||
|
||||
// ScopeSpans corresponds to tracepb.ScopeSpans.
|
||||
type ScopeSpans struct {
|
||||
Scope *InstrumentationScope `json:"scope,omitempty"`
|
||||
Spans []*Span `json:"spans,omitempty"`
|
||||
SchemaURL string `json:"schemaUrl,omitempty"`
|
||||
}
|
||||
|
||||
// InstrumentationScope corresponds to tracepb.InstrumentationScope.
|
||||
type InstrumentationScope struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Attributes []*KeyValue `json:"attributes,omitempty"`
|
||||
DroppedAttributesCount uint32 `json:"droppedAttributesCount,omitempty"`
|
||||
}
|
||||
|
||||
// EntityRef corresponds to resourcepb.EntityRef.
|
||||
type EntityRef struct {
|
||||
SchemaURL string `json:"schemaUrl,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
IdKeys []string `json:"idKeys,omitempty"`
|
||||
DescriptionKeys []string `json:"descriptionKeys,omitempty"`
|
||||
}
|
||||
|
||||
// KeyValue corresponds to commonpb.KeyValue.
|
||||
type KeyValue struct {
|
||||
Key string `json:"key"`
|
||||
Value *AnyValue `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// AnyValue corresponds to commonpb.AnyValue.
|
||||
type AnyValue struct {
|
||||
StringValue *string `json:"stringValue,omitempty"`
|
||||
BoolValue *bool `json:"boolValue,omitempty"`
|
||||
IntValue *Int64 `json:"intValue,omitempty"`
|
||||
DoubleValue *Float64 `json:"doubleValue,omitempty"`
|
||||
ArrayValue *ArrayValue `json:"arrayValue,omitempty"`
|
||||
KvlistValue *KvlistValue `json:"kvlistValue,omitempty"`
|
||||
BytesValue []byte `json:"bytesValue,omitempty"`
|
||||
}
|
||||
|
||||
// ArrayValue corresponds to commonpb.ArrayValue.
|
||||
type ArrayValue struct {
|
||||
Values []*AnyValue `json:"values,omitempty"`
|
||||
}
|
||||
|
||||
// KvlistValue corresponds to commonpb.KeyValueList.
|
||||
type KvlistValue struct {
|
||||
Values []*KeyValue `json:"values,omitempty"`
|
||||
}
|
||||
|
||||
// Span corresponds to tracepb.Span.
|
||||
type Span struct {
|
||||
TraceID TraceID `json:"traceId"`
|
||||
SpanID SpanID `json:"spanId"`
|
||||
TraceState string `json:"traceState,omitempty"`
|
||||
ParentSpanID *SpanID `json:"parentSpanId,omitempty"`
|
||||
Flags uint32 `json:"flags,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Kind int32 `json:"kind,omitempty"`
|
||||
StartTimeUnixNano Uint64 `json:"startTimeUnixNano,omitempty"`
|
||||
EndTimeUnixNano Uint64 `json:"endTimeUnixNano,omitempty"`
|
||||
Attributes []*KeyValue `json:"attributes,omitempty"`
|
||||
DroppedAttributesCount uint32 `json:"droppedAttributesCount,omitempty"`
|
||||
Events []*Event `json:"events,omitempty"`
|
||||
DroppedEventsCount uint32 `json:"droppedEventsCount,omitempty"`
|
||||
Links []*Link `json:"links,omitempty"`
|
||||
DroppedLinksCount uint32 `json:"droppedLinksCount,omitempty"`
|
||||
Status *Status `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// Event corresponds to tracepb.Span_Event.
|
||||
type Event struct {
|
||||
TimeUnixNano Uint64 `json:"timeUnixNano,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Attributes []*KeyValue `json:"attributes,omitempty"`
|
||||
DroppedAttributesCount uint32 `json:"droppedAttributesCount,omitempty"`
|
||||
}
|
||||
|
||||
// Link corresponds to tracepb.Span_Link.
|
||||
type Link struct {
|
||||
TraceID TraceID `json:"traceId"`
|
||||
SpanID SpanID `json:"spanId"`
|
||||
TraceState string `json:"traceState,omitempty"`
|
||||
Attributes []*KeyValue `json:"attributes,omitempty"`
|
||||
DroppedAttributesCount uint32 `json:"droppedAttributesCount,omitempty"`
|
||||
Flags uint32 `json:"flags,omitempty"`
|
||||
}
|
||||
|
||||
// Status corresponds to tracepb.Status.
|
||||
type Status struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
Code int32 `json:"code,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalExportTraceServiceRequest encodes an ExportTraceServiceRequest as JSON Protobuf encoded bytes.
|
||||
func MarshalExportTraceServiceRequest(req *coltracepb.ExportTraceServiceRequest) ([]byte, error) {
|
||||
if req == nil {
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
r := &ExportTraceServiceRequest{}
|
||||
for _, rs := range req.ResourceSpans {
|
||||
r.ResourceSpans = append(r.ResourceSpans, encodeResourceSpans(rs))
|
||||
}
|
||||
return json.Marshal(r)
|
||||
}
|
||||
|
||||
func encodeResourceSpans(rs *tracepb.ResourceSpans) *ResourceSpans {
|
||||
if rs == nil {
|
||||
return nil
|
||||
}
|
||||
out := &ResourceSpans{SchemaURL: rs.SchemaUrl}
|
||||
if rs.Resource != nil {
|
||||
out.Resource = &Resource{
|
||||
Attributes: encodeKeyValues(rs.Resource.Attributes),
|
||||
DroppedAttributesCount: rs.Resource.DroppedAttributesCount,
|
||||
EntityRefs: encodeEntityRefs(rs.Resource.EntityRefs),
|
||||
}
|
||||
}
|
||||
for _, ss := range rs.ScopeSpans {
|
||||
out.ScopeSpans = append(out.ScopeSpans, encodeScopeSpans(ss))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func encodeEntityRefs(ers []*commonpb.EntityRef) []*EntityRef {
|
||||
if len(ers) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]*EntityRef, len(ers))
|
||||
for i, er := range ers {
|
||||
if er == nil {
|
||||
continue
|
||||
}
|
||||
out[i] = &EntityRef{
|
||||
SchemaURL: er.SchemaUrl,
|
||||
Type: er.Type,
|
||||
IdKeys: er.IdKeys,
|
||||
DescriptionKeys: er.DescriptionKeys,
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func encodeScopeSpans(ss *tracepb.ScopeSpans) *ScopeSpans {
|
||||
if ss == nil {
|
||||
return nil
|
||||
}
|
||||
out := &ScopeSpans{SchemaURL: ss.SchemaUrl}
|
||||
if ss.Scope != nil {
|
||||
out.Scope = &InstrumentationScope{
|
||||
Name: ss.Scope.Name,
|
||||
Version: ss.Scope.Version,
|
||||
Attributes: encodeKeyValues(ss.Scope.Attributes),
|
||||
DroppedAttributesCount: ss.Scope.DroppedAttributesCount,
|
||||
}
|
||||
}
|
||||
for _, s := range ss.Spans {
|
||||
out.Spans = append(out.Spans, encodeSpan(s))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func encodeSpan(s *tracepb.Span) *Span {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
out := &Span{
|
||||
TraceState: s.TraceState,
|
||||
Flags: s.Flags,
|
||||
Name: s.Name,
|
||||
Kind: int32(s.Kind),
|
||||
StartTimeUnixNano: Uint64(s.StartTimeUnixNano),
|
||||
EndTimeUnixNano: Uint64(s.EndTimeUnixNano),
|
||||
Attributes: encodeKeyValues(s.Attributes),
|
||||
DroppedAttributesCount: s.DroppedAttributesCount,
|
||||
DroppedEventsCount: s.DroppedEventsCount,
|
||||
DroppedLinksCount: s.DroppedLinksCount,
|
||||
}
|
||||
|
||||
copy(out.TraceID[:], s.TraceId)
|
||||
copy(out.SpanID[:], s.SpanId)
|
||||
|
||||
if len(s.ParentSpanId) > 0 {
|
||||
var psid SpanID
|
||||
copy(psid[:], s.ParentSpanId)
|
||||
if psid != (SpanID{}) {
|
||||
out.ParentSpanID = &psid
|
||||
}
|
||||
}
|
||||
|
||||
for _, e := range s.Events {
|
||||
if e == nil {
|
||||
continue
|
||||
}
|
||||
out.Events = append(out.Events, &Event{
|
||||
TimeUnixNano: Uint64(e.TimeUnixNano),
|
||||
Name: e.Name,
|
||||
Attributes: encodeKeyValues(e.Attributes),
|
||||
DroppedAttributesCount: e.DroppedAttributesCount,
|
||||
})
|
||||
}
|
||||
for _, l := range s.Links {
|
||||
out.Links = append(out.Links, encodeLink(l))
|
||||
}
|
||||
if s.Status != nil {
|
||||
out.Status = &Status{
|
||||
Message: s.Status.Message,
|
||||
Code: int32(s.Status.Code),
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func encodeLink(l *tracepb.Span_Link) *Link {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
out := &Link{
|
||||
TraceState: l.TraceState,
|
||||
Attributes: encodeKeyValues(l.Attributes),
|
||||
DroppedAttributesCount: l.DroppedAttributesCount,
|
||||
Flags: l.Flags,
|
||||
}
|
||||
copy(out.TraceID[:], l.TraceId)
|
||||
copy(out.SpanID[:], l.SpanId)
|
||||
return out
|
||||
}
|
||||
|
||||
func encodeKeyValues(kvs []*commonpb.KeyValue) []*KeyValue {
|
||||
if len(kvs) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]*KeyValue, len(kvs))
|
||||
for i, kv := range kvs {
|
||||
if kv == nil {
|
||||
continue
|
||||
}
|
||||
out[i] = &KeyValue{
|
||||
Key: kv.Key,
|
||||
Value: encodeAnyValue(kv.Value),
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func encodeAnyValue(av *commonpb.AnyValue) *AnyValue {
|
||||
if av == nil {
|
||||
return nil
|
||||
}
|
||||
out := &AnyValue{}
|
||||
switch v := av.Value.(type) {
|
||||
case *commonpb.AnyValue_StringValue:
|
||||
out.StringValue = &v.StringValue
|
||||
case *commonpb.AnyValue_BoolValue:
|
||||
out.BoolValue = &v.BoolValue
|
||||
case *commonpb.AnyValue_IntValue:
|
||||
iv := Int64(v.IntValue)
|
||||
out.IntValue = &iv
|
||||
case *commonpb.AnyValue_DoubleValue:
|
||||
dv := Float64(v.DoubleValue)
|
||||
out.DoubleValue = &dv
|
||||
case *commonpb.AnyValue_ArrayValue:
|
||||
if v.ArrayValue != nil {
|
||||
arr := &ArrayValue{}
|
||||
for _, val := range v.ArrayValue.Values {
|
||||
arr.Values = append(arr.Values, encodeAnyValue(val))
|
||||
}
|
||||
out.ArrayValue = arr
|
||||
}
|
||||
case *commonpb.AnyValue_KvlistValue:
|
||||
if v.KvlistValue != nil {
|
||||
out.KvlistValue = &KvlistValue{
|
||||
Values: encodeKeyValues(v.KvlistValue.Values),
|
||||
}
|
||||
}
|
||||
case *commonpb.AnyValue_BytesValue:
|
||||
out.BytesValue = v.BytesValue
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// UnmarshalExportTraceServiceRequest decodes JSON Protobuf encoded payload into an ExportTraceServiceRequest.
|
||||
func UnmarshalExportTraceServiceRequest(data []byte, req *coltracepb.ExportTraceServiceRequest) error {
|
||||
var jr ExportTraceServiceRequest
|
||||
if err := json.Unmarshal(data, &jr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, rs := range jr.ResourceSpans {
|
||||
req.ResourceSpans = append(req.ResourceSpans, decodeResourceSpans(rs))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeResourceSpans(jrs *ResourceSpans) *tracepb.ResourceSpans {
|
||||
rs := &tracepb.ResourceSpans{SchemaUrl: jrs.SchemaURL}
|
||||
if jrs.Resource != nil {
|
||||
rs.Resource = &resourcepb.Resource{
|
||||
Attributes: decodeKeyValues(jrs.Resource.Attributes),
|
||||
DroppedAttributesCount: jrs.Resource.DroppedAttributesCount,
|
||||
EntityRefs: decodeEntityRefs(jrs.Resource.EntityRefs),
|
||||
}
|
||||
}
|
||||
for _, ss := range jrs.ScopeSpans {
|
||||
rs.ScopeSpans = append(rs.ScopeSpans, decodeScopeSpans(ss))
|
||||
}
|
||||
return rs
|
||||
}
|
||||
|
||||
func decodeEntityRefs(jers []*EntityRef) []*commonpb.EntityRef {
|
||||
if len(jers) == 0 {
|
||||
return nil
|
||||
}
|
||||
ers := make([]*commonpb.EntityRef, len(jers))
|
||||
for i, jer := range jers {
|
||||
if jer == nil {
|
||||
continue
|
||||
}
|
||||
ers[i] = &commonpb.EntityRef{
|
||||
SchemaUrl: jer.SchemaURL,
|
||||
Type: jer.Type,
|
||||
IdKeys: jer.IdKeys,
|
||||
DescriptionKeys: jer.DescriptionKeys,
|
||||
}
|
||||
}
|
||||
return ers
|
||||
}
|
||||
|
||||
func decodeScopeSpans(jss *ScopeSpans) *tracepb.ScopeSpans {
|
||||
ss := &tracepb.ScopeSpans{SchemaUrl: jss.SchemaURL}
|
||||
if jss.Scope != nil {
|
||||
ss.Scope = &commonpb.InstrumentationScope{
|
||||
Name: jss.Scope.Name,
|
||||
Version: jss.Scope.Version,
|
||||
Attributes: decodeKeyValues(jss.Scope.Attributes),
|
||||
DroppedAttributesCount: jss.Scope.DroppedAttributesCount,
|
||||
}
|
||||
}
|
||||
for _, s := range jss.Spans {
|
||||
ss.Spans = append(ss.Spans, decodeSpan(s))
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
func decodeSpan(js *Span) *tracepb.Span {
|
||||
s := &tracepb.Span{
|
||||
TraceId: js.TraceID[:],
|
||||
SpanId: js.SpanID[:],
|
||||
TraceState: js.TraceState,
|
||||
Flags: js.Flags,
|
||||
Name: js.Name,
|
||||
Kind: tracepb.Span_SpanKind(js.Kind),
|
||||
StartTimeUnixNano: uint64(js.StartTimeUnixNano),
|
||||
EndTimeUnixNano: uint64(js.EndTimeUnixNano),
|
||||
Attributes: decodeKeyValues(js.Attributes),
|
||||
DroppedAttributesCount: js.DroppedAttributesCount,
|
||||
DroppedEventsCount: js.DroppedEventsCount,
|
||||
DroppedLinksCount: js.DroppedLinksCount,
|
||||
}
|
||||
if js.ParentSpanID != nil {
|
||||
s.ParentSpanId = js.ParentSpanID[:]
|
||||
}
|
||||
for _, e := range js.Events {
|
||||
s.Events = append(s.Events, &tracepb.Span_Event{
|
||||
TimeUnixNano: uint64(e.TimeUnixNano),
|
||||
Name: e.Name,
|
||||
Attributes: decodeKeyValues(e.Attributes),
|
||||
DroppedAttributesCount: e.DroppedAttributesCount,
|
||||
})
|
||||
}
|
||||
for _, l := range js.Links {
|
||||
s.Links = append(s.Links, decodeLink(l))
|
||||
}
|
||||
if js.Status != nil {
|
||||
s.Status = &tracepb.Status{
|
||||
Message: js.Status.Message,
|
||||
Code: tracepb.Status_StatusCode(js.Status.Code),
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func decodeLink(jl *Link) *tracepb.Span_Link {
|
||||
return &tracepb.Span_Link{
|
||||
TraceId: jl.TraceID[:],
|
||||
SpanId: jl.SpanID[:],
|
||||
TraceState: jl.TraceState,
|
||||
Attributes: decodeKeyValues(jl.Attributes),
|
||||
DroppedAttributesCount: jl.DroppedAttributesCount,
|
||||
Flags: jl.Flags,
|
||||
}
|
||||
}
|
||||
|
||||
func decodeKeyValues(jkvs []*KeyValue) []*commonpb.KeyValue {
|
||||
if len(jkvs) == 0 {
|
||||
return nil
|
||||
}
|
||||
kvs := make([]*commonpb.KeyValue, len(jkvs))
|
||||
for i, jkv := range jkvs {
|
||||
kvs[i] = &commonpb.KeyValue{
|
||||
Key: jkv.Key,
|
||||
Value: decodeAnyValue(jkv.Value),
|
||||
}
|
||||
}
|
||||
return kvs
|
||||
}
|
||||
|
||||
func decodeAnyValue(jav *AnyValue) *commonpb.AnyValue {
|
||||
if jav == nil {
|
||||
return nil
|
||||
}
|
||||
av := &commonpb.AnyValue{}
|
||||
switch {
|
||||
case jav.StringValue != nil:
|
||||
av.Value = &commonpb.AnyValue_StringValue{StringValue: *jav.StringValue}
|
||||
case jav.BoolValue != nil:
|
||||
av.Value = &commonpb.AnyValue_BoolValue{BoolValue: *jav.BoolValue}
|
||||
case jav.IntValue != nil:
|
||||
av.Value = &commonpb.AnyValue_IntValue{IntValue: int64(*jav.IntValue)}
|
||||
case jav.DoubleValue != nil:
|
||||
av.Value = &commonpb.AnyValue_DoubleValue{DoubleValue: float64(*jav.DoubleValue)}
|
||||
case jav.ArrayValue != nil:
|
||||
arr := &commonpb.ArrayValue{}
|
||||
for _, v := range jav.ArrayValue.Values {
|
||||
arr.Values = append(arr.Values, decodeAnyValue(v))
|
||||
}
|
||||
av.Value = &commonpb.AnyValue_ArrayValue{ArrayValue: arr}
|
||||
case jav.KvlistValue != nil:
|
||||
av.Value = &commonpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &commonpb.KeyValueList{
|
||||
Values: decodeKeyValues(jav.KvlistValue.Values),
|
||||
},
|
||||
}
|
||||
case jav.BytesValue != nil:
|
||||
av.Value = &commonpb.AnyValue_BytesValue{BytesValue: jav.BytesValue}
|
||||
}
|
||||
return av
|
||||
}
|
||||
|
||||
// Float64 encodes non-finite values as strings per ProtoJSON specs.
|
||||
type Float64 float64
|
||||
|
||||
func (f Float64) MarshalJSON() ([]byte, error) {
|
||||
switch value := float64(f); {
|
||||
case math.IsNaN(value):
|
||||
return []byte(`"NaN"`), nil
|
||||
case math.IsInf(value, 1):
|
||||
return []byte(`"Infinity"`), nil
|
||||
case math.IsInf(value, -1):
|
||||
return []byte(`"-Infinity"`), nil
|
||||
default:
|
||||
return strconv.AppendFloat(nil, value, 'g', -1, 64), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Float64) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err == nil {
|
||||
switch str {
|
||||
case "NaN":
|
||||
*f = Float64(math.NaN())
|
||||
case "Infinity":
|
||||
*f = Float64(math.Inf(1))
|
||||
case "-Infinity":
|
||||
*f = Float64(math.Inf(-1))
|
||||
default:
|
||||
var value *float64
|
||||
if str != strings.TrimSpace(str) || json.Unmarshal([]byte(str), &value) != nil || value == nil {
|
||||
return fmt.Errorf("invalid float value %q", str)
|
||||
}
|
||||
*f = Float64(*value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var value float64
|
||||
if err := json.Unmarshal(data, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
*f = Float64(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int64 encodes int64 as a quoted decimal string per ProtoJSON specs.
|
||||
type Int64 int64
|
||||
|
||||
func (i Int64) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"` + strconv.FormatInt(int64(i), 10) + `"`), nil
|
||||
}
|
||||
|
||||
func (i *Int64) UnmarshalJSON(data []byte) error {
|
||||
// expects either a string representation or a number
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err == nil {
|
||||
v, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*i = Int64(v)
|
||||
return nil
|
||||
}
|
||||
var v int64
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
*i = Int64(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Uint64 encodes uint64 as a quoted decimal string per ProtoJSON specs.
|
||||
type Uint64 uint64
|
||||
|
||||
func (i Uint64) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"` + strconv.FormatUint(uint64(i), 10) + `"`), nil
|
||||
}
|
||||
|
||||
func (i *Uint64) UnmarshalJSON(data []byte) error {
|
||||
// expects either a string representation or a number
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err == nil {
|
||||
v, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*i = Uint64(v)
|
||||
return nil
|
||||
}
|
||||
var v uint64
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
*i = Uint64(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
const base16Alphabets = "0123456789ABCDEF"
|
||||
|
||||
// TraceID encodes a 16-byte trace ID as a case-insensitive hex-encoded string.
|
||||
type TraceID [16]byte
|
||||
|
||||
func (t TraceID) MarshalJSON() ([]byte, error) {
|
||||
var b [34]byte
|
||||
b[0] = '"'
|
||||
for i, v := range t {
|
||||
b[1+i*2] = base16Alphabets[v>>4]
|
||||
b[2+i*2] = base16Alphabets[v&0x0f]
|
||||
}
|
||||
b[33] = '"'
|
||||
return b[:], nil
|
||||
}
|
||||
|
||||
func (t *TraceID) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := hex.DecodeString(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(b) != len(t) {
|
||||
return fmt.Errorf("invalid trace ID length: got %d, want %d", len(b), len(t))
|
||||
}
|
||||
copy(t[:], b)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SpanID encodes an 8-byte span ID as a case-insensitive hex-encoded string.
|
||||
type SpanID [8]byte
|
||||
|
||||
func (s SpanID) MarshalJSON() ([]byte, error) {
|
||||
var b [18]byte
|
||||
b[0] = '"'
|
||||
for i, v := range s {
|
||||
b[1+i*2] = base16Alphabets[v>>4]
|
||||
b[2+i*2] = base16Alphabets[v&0x0f]
|
||||
}
|
||||
b[17] = '"'
|
||||
return b[:], nil
|
||||
}
|
||||
|
||||
func (s *SpanID) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := hex.DecodeString(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(b) != len(s) {
|
||||
return fmt.Errorf("invalid span ID length: got %d, want %d", len(b), len(s))
|
||||
}
|
||||
copy(s[:], b)
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package otlpjson
|
||||
|
||||
import (
|
||||
coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
|
||||
// MarshalExportTraceServiceResponse encodes an ExportTraceServiceResponse as JSON Protobuf encoded bytes.
|
||||
func MarshalExportTraceServiceResponse(resp *coltracepb.ExportTraceServiceResponse) ([]byte, error) {
|
||||
return protojson.Marshal(resp)
|
||||
}
|
||||
|
||||
// UnmarshalExportTraceServiceResponse decodes JSON Protobuf encoded payload into an ExportTraceServiceResponse.
|
||||
func UnmarshalExportTraceServiceResponse(data []byte, resp *coltracepb.ExportTraceServiceResponse) error {
|
||||
// ignore message fields with unknown names per OTLP specs.
|
||||
var unmarshaler protojson.UnmarshalOptions
|
||||
unmarshaler.DiscardUnknown = true
|
||||
return unmarshaler.Unmarshal(data, resp)
|
||||
}
|
||||
Generated
Vendored
+24
-26
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/cenkalti/backoff/v5"
|
||||
)
|
||||
|
||||
// DefaultConfig are the recommended defaults to use.
|
||||
// DefaultConfig is the recommended default configuration.
|
||||
var DefaultConfig = Config{
|
||||
Enabled: true,
|
||||
InitialInterval: 5 * time.Second,
|
||||
@@ -25,42 +25,40 @@ var DefaultConfig = Config{
|
||||
MaxElapsedTime: time.Minute,
|
||||
}
|
||||
|
||||
// Config defines configuration for retrying batches in case of export failure
|
||||
// using an exponential backoff.
|
||||
// Config defines configuration for retrying batches after an export failure
|
||||
// using exponential backoff.
|
||||
type Config struct {
|
||||
// Enabled indicates whether to not retry sending batches in case of
|
||||
// export failure.
|
||||
// Enabled indicates whether to retry sending batches after an export
|
||||
// failure.
|
||||
Enabled bool
|
||||
// InitialInterval the time to wait after the first failure before
|
||||
// InitialInterval is the time to wait after the first failure before
|
||||
// retrying.
|
||||
InitialInterval time.Duration
|
||||
// MaxInterval is the upper bound on backoff interval. Once this value is
|
||||
// reached the delay between consecutive retries will always be
|
||||
// `MaxInterval`.
|
||||
// MaxInterval is the upper bound on the backoff interval before
|
||||
// randomization. Once this value is reached, the base interval remains at
|
||||
// MaxInterval.
|
||||
MaxInterval time.Duration
|
||||
// MaxElapsedTime is the maximum amount of time (including retries) spent
|
||||
// trying to send a request/batch. Once this value is reached, the data
|
||||
// is discarded.
|
||||
// trying to send a request/batch. Once this value is reached, retrying stops.
|
||||
MaxElapsedTime time.Duration
|
||||
}
|
||||
|
||||
// RequestFunc wraps a request with retry logic.
|
||||
type RequestFunc func(context.Context, func(context.Context) error) error
|
||||
|
||||
// EvaluateFunc returns if an error is retry-able and if an explicit throttle
|
||||
// duration should be honored that was included in the error.
|
||||
// EvaluateFunc reports whether an error is retryable and returns any explicit
|
||||
// throttle duration to honor.
|
||||
//
|
||||
// The function must return true if the error argument is retry-able,
|
||||
// otherwise it must return false for the first return parameter.
|
||||
// The function must return true as its first return value if the error
|
||||
// argument is retryable; otherwise, it must return false.
|
||||
//
|
||||
// The function must return a non-zero time.Duration if the error contains
|
||||
// explicit throttle duration that should be honored, otherwise it must return
|
||||
// a zero valued time.Duration.
|
||||
// The function must return a nonzero time.Duration if the error contains an
|
||||
// explicit throttle duration that should be honored; otherwise, it must return
|
||||
// the zero value for time.Duration.
|
||||
type EvaluateFunc func(error) (bool, time.Duration)
|
||||
|
||||
// RequestFunc returns a RequestFunc using the evaluate function to determine
|
||||
// if requests can be retried and based on the exponential backoff
|
||||
// configuration of c.
|
||||
// RequestFunc returns a RequestFunc that uses evaluate to determine whether
|
||||
// requests can be retried and uses c to configure exponential backoff.
|
||||
func (c Config) RequestFunc(evaluate EvaluateFunc) RequestFunc {
|
||||
if !c.Enabled {
|
||||
return func(ctx context.Context, fn func(context.Context) error) error {
|
||||
@@ -96,7 +94,7 @@ func (c Config) RequestFunc(evaluate EvaluateFunc) RequestFunc {
|
||||
|
||||
// Check if context is canceled before attempting to wait and retry.
|
||||
if ctx.Err() != nil {
|
||||
return fmt.Errorf("%w: %w", ctx.Err(), err)
|
||||
return fmt.Errorf("%w: %w", context.Cause(ctx), err)
|
||||
}
|
||||
|
||||
if maxElapsedTime != 0 && time.Since(startTime) > maxElapsedTime {
|
||||
@@ -119,12 +117,12 @@ func (c Config) RequestFunc(evaluate EvaluateFunc) RequestFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// Allow override for testing.
|
||||
// waitFunc can be overridden for testing.
|
||||
var waitFunc = wait
|
||||
|
||||
// wait takes the caller's context, and the amount of time to wait. It will
|
||||
// return nil if the timer fires before or at the same time as the context's
|
||||
// deadline. This indicates that the call can be retried.
|
||||
// wait blocks until delay elapses or ctx is done. If both happen
|
||||
// simultaneously, wait favors the elapsed delay and returns nil to indicate
|
||||
// that the call can be retried.
|
||||
func wait(ctx context.Context, delay time.Duration) error {
|
||||
timer := time.NewTimer(delay)
|
||||
defer timer.Stop()
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -5,4 +5,4 @@ package internal
|
||||
|
||||
// Version is the current release version of the OpenTelemetry OTLP HTTP trace
|
||||
// exporter in use.
|
||||
const Version = "1.45.0"
|
||||
const Version = "1.46.0"
|
||||
Generated
Vendored
+2
-2
@@ -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
|
||||
//
|
||||
|
||||
Generated
Vendored
+19
@@ -17,6 +17,9 @@ import (
|
||||
// collector.
|
||||
type Compression otlpconfig.Compression
|
||||
|
||||
// Encoding describes the encoding used for payloads sent to the collector.
|
||||
type Encoding int
|
||||
|
||||
// HTTPTransportProxyFunc is a function that resolves which URL to use as proxy for a given request.
|
||||
// This type is compatible with http.Transport.Proxy and can be used to set a custom proxy function
|
||||
// to the OTLP HTTP client.
|
||||
@@ -31,6 +34,13 @@ const (
|
||||
GzipCompression = Compression(otlpconfig.GzipCompression)
|
||||
)
|
||||
|
||||
const (
|
||||
// EncodingProtobuf tells the driver to send protobuf-encoded payloads.
|
||||
EncodingProtobuf Encoding = iota
|
||||
// EncodingJSON tells the driver to send JSON-encoded payloads.
|
||||
EncodingJSON
|
||||
)
|
||||
|
||||
// Option applies an option to the HTTP client.
|
||||
type Option interface {
|
||||
applyHTTPOption(otlpconfig.Config) otlpconfig.Config
|
||||
@@ -111,6 +121,15 @@ func WithCompression(compression Compression) Option {
|
||||
return wrappedOption{otlpconfig.WithCompression(otlpconfig.Compression(compression))}
|
||||
}
|
||||
|
||||
// WithEncoding tells the driver to use a specific encoding for the request payload.
|
||||
func WithEncoding(encoding Encoding) Option {
|
||||
protocol := otlpconfig.ProtocolHTTPProtobuf
|
||||
if encoding == EncodingJSON {
|
||||
protocol = otlpconfig.ProtocolHTTPJSON
|
||||
}
|
||||
return wrappedOption{otlpconfig.WithProtocol(protocol)}
|
||||
}
|
||||
|
||||
// WithURLPath allows one to override the default URL path used
|
||||
// for sending traces. If unset, default ("/v1/traces") will be used.
|
||||
func WithURLPath(urlPath string) Option {
|
||||
|
||||
+1
-1
@@ -5,5 +5,5 @@ package otlptrace
|
||||
|
||||
// Version is the current release version of the OpenTelemetry OTLP trace exporter in use.
|
||||
func Version() string {
|
||||
return "1.45.0"
|
||||
return "1.46.0"
|
||||
}
|
||||
+7
@@ -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"
|
||||
|
||||
+11
-13
@@ -16,10 +16,10 @@ 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 {
|
||||
@@ -155,22 +155,20 @@ func needsTruncation(limit int, v attribute.Value) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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 shorter than the default limit (128).
|
||||
// - Strings with valid encodings that exceed the limit.
|
||||
// - No limit.
|
||||
// - Strings with invalid encodings that exceed the limit.
|
||||
|
||||
+2
-2
@@ -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
|
||||
//
|
||||
|
||||
+3
@@ -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
|
||||
|
||||
Generated
Vendored
+5
-35
@@ -6,7 +6,6 @@ package observ
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@@ -17,22 +16,10 @@ import (
|
||||
"go.opentelemetry.io/otel/semconv/v1.43.0/otelconv"
|
||||
)
|
||||
|
||||
var measureAttrsPool = sync.Pool{
|
||||
New: func() any {
|
||||
// "component.name" + "component.type" + "error.type"
|
||||
const n = 1 + 1 + 1
|
||||
s := make([]attribute.KeyValue, 0, n)
|
||||
// Return a pointer to a slice instead of a slice itself
|
||||
// to avoid allocations on every call.
|
||||
return &s
|
||||
},
|
||||
}
|
||||
|
||||
// SSP is the instrumentation for an OTel SDK SimpleSpanProcessor.
|
||||
type SSP struct {
|
||||
spansProcessedCounter metric.Int64Counter
|
||||
addOpts []metric.AddOption
|
||||
attrs []attribute.KeyValue
|
||||
}
|
||||
|
||||
// SSPComponentName returns the component name attribute for a
|
||||
@@ -70,29 +57,12 @@ func NewSSP(id int64) (*SSP, error) {
|
||||
return &SSP{
|
||||
spansProcessedCounter: spansProcessedCounter.Inst(),
|
||||
addOpts: addOpts,
|
||||
attrs: attrs,
|
||||
}, err
|
||||
}
|
||||
|
||||
// SpanProcessed records that a span has been processed by the SimpleSpanProcessor.
|
||||
// If err is non-nil, it records the processing error as an attribute.
|
||||
func (ssp *SSP) SpanProcessed(ctx context.Context, err error) {
|
||||
ssp.spansProcessedCounter.Add(ctx, 1, ssp.addOption(err)...)
|
||||
}
|
||||
|
||||
func (ssp *SSP) addOption(err error) []metric.AddOption {
|
||||
if err == nil {
|
||||
return ssp.addOpts
|
||||
}
|
||||
attrs := measureAttrsPool.Get().(*[]attribute.KeyValue)
|
||||
defer func() {
|
||||
clear(*attrs)
|
||||
*attrs = (*attrs)[:0] // reset the slice for reuse
|
||||
measureAttrsPool.Put(attrs)
|
||||
}()
|
||||
*attrs = append(*attrs, ssp.attrs...)
|
||||
*attrs = append(*attrs, semconv.ErrorType(err))
|
||||
// Do not inefficiently make a copy of attrs by using
|
||||
// WithAttributes instead of WithAttributeSet.
|
||||
return []metric.AddOption{metric.WithAttributeSet(attribute.NewSet(*attrs...))}
|
||||
// SpanProcessed records that a span has been submitted to the exporter by the
|
||||
// SimpleSpanProcessor. Per the semantic conventions, this count is recorded at
|
||||
// submission time and MUST NOT be affected by the export outcome.
|
||||
func (ssp *SSP) SpanProcessed(ctx context.Context) {
|
||||
ssp.spansProcessedCounter.Add(ctx, 1, ssp.addOpts...)
|
||||
}
|
||||
+10
-10
@@ -67,19 +67,19 @@ func (ssp *simpleSpanProcessor) OnEnd(s ReadOnlySpan) {
|
||||
ssp.exporterMu.Lock()
|
||||
defer ssp.exporterMu.Unlock()
|
||||
|
||||
var err error
|
||||
if ssp.exporter != nil && s.SpanContext().TraceFlags().IsSampled() {
|
||||
err = ssp.exporter.ExportSpans(context.Background(), []ReadOnlySpan{s})
|
||||
if err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
}
|
||||
|
||||
if ssp.inst != nil {
|
||||
// Add the span to the context to ensure the metric is recorded
|
||||
// with the correct span context.
|
||||
// with the correct span context. Record the span as processed before
|
||||
// invoking the exporter so the count is unaffected by the export
|
||||
// outcome.
|
||||
ctx := trace.ContextWithSpanContext(context.Background(), s.SpanContext())
|
||||
ssp.inst.SpanProcessed(ctx, err)
|
||||
ssp.inst.SpanProcessed(ctx)
|
||||
}
|
||||
|
||||
if ssp.exporter != nil && s.SpanContext().TraceFlags().IsSampled() {
|
||||
if err := ssp.exporter.ExportSpans(context.Background(), []ReadOnlySpan{s}); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+31
@@ -138,6 +138,11 @@ type recordingSpan struct {
|
||||
attributes []attribute.KeyValue
|
||||
droppedAttributes int
|
||||
logDropAttrsOnce sync.Once
|
||||
// attributesDirty indicates attributes may contain duplicate keys.
|
||||
attributesDirty bool
|
||||
// attributesShared indicates the attributes backing array has been exposed
|
||||
// to a reader and must not be modified.
|
||||
attributesShared bool
|
||||
|
||||
// events are stored in FIFO queue capped by configured limit.
|
||||
events evictedQueue[Event]
|
||||
@@ -251,6 +256,11 @@ func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) {
|
||||
s.addDroppedAttr(len(attributes))
|
||||
return
|
||||
}
|
||||
maxCap := len(s.attributes) + len(attributes)
|
||||
if limit > 0 {
|
||||
maxCap = min(maxCap, limit)
|
||||
}
|
||||
s.ensureAttrsWritable(maxCap)
|
||||
|
||||
// If adding these attributes could exceed the capacity of s perform a
|
||||
// de-duplication and truncation while adding to avoid over allocation.
|
||||
@@ -271,9 +281,23 @@ func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) {
|
||||
a = dedupAttr(a)
|
||||
a = attrnorm.Truncate(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a)
|
||||
s.attributes = append(s.attributes, a)
|
||||
s.attributesDirty = true
|
||||
}
|
||||
}
|
||||
|
||||
// ensureAttrsWritable copies shared attributes into a backing array with at
|
||||
// least capacity. This method assumes s.mu.Lock is held by the caller.
|
||||
func (s *recordingSpan) ensureAttrsWritable(capacity int) {
|
||||
if !s.attributesShared {
|
||||
return
|
||||
}
|
||||
capacity = max(capacity, len(s.attributes))
|
||||
attrs := make([]attribute.KeyValue, len(s.attributes), capacity)
|
||||
copy(attrs, s.attributes)
|
||||
s.attributes = attrs
|
||||
s.attributesShared = false
|
||||
}
|
||||
|
||||
// Declared as a var so tests can override.
|
||||
var logDropAttrs = func() {
|
||||
global.Warn("limit reached: dropping trace Span attributes")
|
||||
@@ -592,6 +616,7 @@ func (s *recordingSpan) Attributes() []attribute.KeyValue {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.dedupeAttrs()
|
||||
s.attributesShared = cap(s.attributes) > 0
|
||||
return s.attributes
|
||||
}
|
||||
|
||||
@@ -599,6 +624,10 @@ func (s *recordingSpan) Attributes() []attribute.KeyValue {
|
||||
//
|
||||
// This method assumes s.mu.Lock is held by the caller.
|
||||
func (s *recordingSpan) dedupeAttrs() {
|
||||
if !s.attributesDirty {
|
||||
return
|
||||
}
|
||||
s.ensureAttrsWritable(len(s.attributes))
|
||||
// Do not set a capacity when creating this map. Benchmark testing has
|
||||
// showed this to only add unused memory allocations in general use.
|
||||
exists := make(map[attribute.Key]int, len(s.attributes))
|
||||
@@ -622,6 +651,7 @@ func (s *recordingSpan) dedupeAttrsFromRecord(record map[attribute.Key]int) {
|
||||
}
|
||||
clear(s.attributes[len(unique):]) // Erase unneeded elements to let GC collect objects.
|
||||
s.attributes = unique
|
||||
s.attributesDirty = false
|
||||
}
|
||||
|
||||
// Links returns the links of this span.
|
||||
@@ -765,6 +795,7 @@ func (s *recordingSpan) snapshot() ReadOnlySpan {
|
||||
if len(s.attributes) > 0 {
|
||||
s.dedupeAttrs()
|
||||
sd.attributes = s.attributes
|
||||
s.attributesShared = true
|
||||
}
|
||||
sd.droppedAttributeCount = s.droppedAttributes
|
||||
if len(s.events.queue) > 0 {
|
||||
|
||||
+1
-1
@@ -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.46.0"
|
||||
}
|
||||
+1
-1
@@ -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.46.0"
|
||||
}
|
||||
+4
-4
@@ -3,7 +3,7 @@
|
||||
|
||||
module-sets:
|
||||
stable-v1:
|
||||
version: v1.45.0
|
||||
version: v1.46.0
|
||||
modules:
|
||||
- go.opentelemetry.io/otel
|
||||
- go.opentelemetry.io/otel/bridge/opencensus
|
||||
@@ -22,12 +22,12 @@ module-sets:
|
||||
- go.opentelemetry.io/otel/sdk/metric
|
||||
- go.opentelemetry.io/otel/trace
|
||||
experimental-metrics:
|
||||
version: v0.67.0
|
||||
version: v0.68.0
|
||||
modules:
|
||||
- go.opentelemetry.io/otel/exporters/prometheus
|
||||
- go.opentelemetry.io/otel/metric/x
|
||||
experimental-logs:
|
||||
version: v0.21.0
|
||||
version: v0.22.0
|
||||
modules:
|
||||
- go.opentelemetry.io/otel/log
|
||||
- go.opentelemetry.io/otel/log/logtest
|
||||
@@ -37,7 +37,7 @@ module-sets:
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp
|
||||
- go.opentelemetry.io/otel/exporters/stdout/stdoutlog
|
||||
experimental-schema:
|
||||
version: v0.0.18
|
||||
version: v0.0.19
|
||||
modules:
|
||||
- go.opentelemetry.io/otel/schema
|
||||
excluded-modules:
|
||||
|
||||
Vendored
+14
-13
@@ -397,7 +397,7 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus
|
||||
# github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
|
||||
## explicit; go 1.19
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors
|
||||
# github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0
|
||||
# github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0
|
||||
## explicit; go 1.25.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2/runtime
|
||||
@@ -609,19 +609,19 @@ go.etcd.io/bbolt/internal/freelist
|
||||
## explicit; go 1.24.0
|
||||
go.opentelemetry.io/auto/sdk
|
||||
go.opentelemetry.io/auto/sdk/internal/telemetry
|
||||
# go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0
|
||||
# go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/internal
|
||||
# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0
|
||||
# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv
|
||||
# go.opentelemetry.io/contrib/propagators/envcar v0.70.0
|
||||
# go.opentelemetry.io/contrib/propagators/envcar v0.71.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/contrib/propagators/envcar
|
||||
# go.opentelemetry.io/otel v1.45.0
|
||||
# go.opentelemetry.io/otel v1.46.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/otel
|
||||
go.opentelemetry.io/otel/attribute
|
||||
@@ -641,11 +641,11 @@ go.opentelemetry.io/otel/semconv/v1.43.0
|
||||
go.opentelemetry.io/otel/semconv/v1.43.0/httpconv
|
||||
go.opentelemetry.io/otel/semconv/v1.43.0/otelconv
|
||||
go.opentelemetry.io/otel/semconv/v1.43.0/rpcconv
|
||||
# go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0
|
||||
# go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform
|
||||
# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0
|
||||
# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal
|
||||
@@ -655,7 +655,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/observ
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/x
|
||||
# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0
|
||||
# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal
|
||||
@@ -663,14 +663,15 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/counter
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/envconfig
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/observ
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpjson
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/x
|
||||
# go.opentelemetry.io/otel/metric v1.45.0
|
||||
# go.opentelemetry.io/otel/metric v1.46.0
|
||||
## explicit; go 1.25.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
|
||||
# go.opentelemetry.io/otel/sdk v1.46.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/otel/sdk
|
||||
go.opentelemetry.io/otel/sdk/instrumentation
|
||||
@@ -681,7 +682,7 @@ go.opentelemetry.io/otel/sdk/trace
|
||||
go.opentelemetry.io/otel/sdk/trace/internal/env
|
||||
go.opentelemetry.io/otel/sdk/trace/internal/observ
|
||||
go.opentelemetry.io/otel/sdk/trace/tracetest
|
||||
# go.opentelemetry.io/otel/trace v1.45.0
|
||||
# go.opentelemetry.io/otel/trace v1.46.0
|
||||
## explicit; go 1.25.0
|
||||
go.opentelemetry.io/otel/trace
|
||||
go.opentelemetry.io/otel/trace/embedded
|
||||
@@ -755,10 +756,10 @@ golang.org/x/text/unicode/norm
|
||||
# golang.org/x/time v0.15.0
|
||||
## explicit; go 1.25.0
|
||||
golang.org/x/time/rate
|
||||
# google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d
|
||||
# google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5
|
||||
## explicit; go 1.25.0
|
||||
google.golang.org/genproto/googleapis/api/httpbody
|
||||
# google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d
|
||||
# google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5
|
||||
## explicit; go 1.25.0
|
||||
google.golang.org/genproto/googleapis/rpc/code
|
||||
google.golang.org/genproto/googleapis/rpc/errdetails
|
||||
|
||||
Reference in new issue
Block a user