vendor: OTEL v0.46.1 / v1.21.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2024-01-29 19:01:37 +01:00
parent 445d500aeb
commit c516804d6f
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
65 changed files with 1087 additions and 467 deletions

View file

@ -21,7 +21,7 @@ type grpcRouter struct {
// NewRouter initializes a new grpc http router // NewRouter initializes a new grpc http router
func NewRouter(backends ...Backend) router.Router { func NewRouter(backends ...Backend) router.Router {
unary := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptor(), grpcerrors.UnaryServerInterceptor)) unary := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptor(), grpcerrors.UnaryServerInterceptor))
stream := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(otelgrpc.StreamServerInterceptor(), grpcerrors.StreamServerInterceptor)) stream := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(otelgrpc.StreamServerInterceptor(), grpcerrors.StreamServerInterceptor)) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
r := &grpcRouter{ r := &grpcRouter{
h2Server: &http2.Server{}, h2Server: &http2.Server{},
@ -46,7 +46,7 @@ func (gr *grpcRouter) initRoutes() {
} }
func unaryInterceptor() grpc.UnaryServerInterceptor { func unaryInterceptor() grpc.UnaryServerInterceptor {
withTrace := otelgrpc.UnaryServerInterceptor() withTrace := otelgrpc.UnaryServerInterceptor() //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
// This method is used by the clients to send their traces to buildkit so they can be included // This method is used by the clients to send their traces to buildkit so they can be included

View file

@ -962,8 +962,8 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
// TODO(stevvooe): We may need to allow configuration of this on the client. // TODO(stevvooe): We may need to allow configuration of this on the client.
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)),
grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)),
grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
} }
if cfgStore.ContainerdAddr != "" { if cfgStore.ContainerdAddr != "" {

View file

@ -302,8 +302,8 @@ func (r *remote) monitorDaemon(ctx context.Context) {
r.GRPC.Address, r.GRPC.Address,
containerd.WithTimeout(60*time.Second), containerd.WithTimeout(60*time.Second),
containerd.WithDialOpts([]grpc.DialOption{ containerd.WithDialOpts([]grpc.DialOption{
grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)),
grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)),

View file

@ -92,12 +92,12 @@ require (
github.com/vishvananda/netlink v1.2.1-beta.2 github.com/vishvananda/netlink v1.2.1-beta.2
github.com/vishvananda/netns v0.0.4 github.com/vishvananda/netns v0.0.4
go.etcd.io/bbolt v1.3.7 go.etcd.io/bbolt v1.3.7
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1
go.opentelemetry.io/otel v1.19.0 go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
go.opentelemetry.io/otel/sdk v1.19.0 go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/trace v1.19.0 go.opentelemetry.io/otel/trace v1.21.0
golang.org/x/mod v0.13.0 golang.org/x/mod v0.13.0
golang.org/x/net v0.18.0 golang.org/x/net v0.18.0
golang.org/x/sync v0.5.0 golang.org/x/sync v0.5.0
@ -197,10 +197,10 @@ require (
go.etcd.io/etcd/raft/v3 v3.5.6 // indirect go.etcd.io/etcd/raft/v3 v3.5.6 // indirect
go.etcd.io/etcd/server/v3 v3.5.6 // indirect go.etcd.io/etcd/server/v3 v3.5.6 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect
go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect go.uber.org/multierr v1.8.0 // indirect

View file

@ -1325,31 +1325,31 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 h1:2ea0IkZBsWH+HA2GkD+7+hRw2u97jzdFyRtXuO14a1s= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 h1:gbhw/u49SS3gkPWiYweQNJGm/uJN5GkI/FrosxSHT7A=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0/go.mod h1:4m3RnBBb+7dB9d21y510oO1pdB1V4J6smNf14WXcBFQ= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1/go.mod h1:GnOaBaFQ2we3b9AGWJpsBa7v1S5RlQzlC3O7dRMxZhM=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI=
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
@ -1360,7 +1360,7 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=

View file

@ -24,8 +24,8 @@ import (
) )
const ( const (
// instrumentationName is the name of this instrumentation package. // ScopeName is the instrumentation scope name.
instrumentationName = "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" ScopeName = "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
// GRPCStatusCodeKey is convention for numeric status code of a gRPC request. // GRPCStatusCodeKey is convention for numeric status code of a gRPC request.
GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code") GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code")
) )
@ -46,8 +46,14 @@ type config struct {
ReceivedEvent bool ReceivedEvent bool
SentEvent bool SentEvent bool
meter metric.Meter tracer trace.Tracer
rpcServerDuration metric.Int64Histogram meter metric.Meter
rpcDuration metric.Float64Histogram
rpcRequestSize metric.Int64Histogram
rpcResponseSize metric.Int64Histogram
rpcRequestsPerRPC metric.Int64Histogram
rpcResponsesPerRPC metric.Int64Histogram
} }
// Option applies an option value for a config. // Option applies an option value for a config.
@ -56,7 +62,7 @@ type Option interface {
} }
// newConfig returns a config configured with all the passed Options. // newConfig returns a config configured with all the passed Options.
func newConfig(opts []Option) *config { func newConfig(opts []Option, role string) *config {
c := &config{ c := &config{
Propagators: otel.GetTextMapPropagator(), Propagators: otel.GetTextMapPropagator(),
TracerProvider: otel.GetTracerProvider(), TracerProvider: otel.GetTracerProvider(),
@ -66,19 +72,53 @@ func newConfig(opts []Option) *config {
o.apply(c) o.apply(c)
} }
c.tracer = c.TracerProvider.Tracer(
ScopeName,
trace.WithInstrumentationVersion(SemVersion()),
)
c.meter = c.MeterProvider.Meter( c.meter = c.MeterProvider.Meter(
instrumentationName, ScopeName,
metric.WithInstrumentationVersion(Version()), metric.WithInstrumentationVersion(Version()),
metric.WithSchemaURL(semconv.SchemaURL), metric.WithSchemaURL(semconv.SchemaURL),
) )
var err error var err error
c.rpcServerDuration, err = c.meter.Int64Histogram("rpc.server.duration", c.rpcDuration, err = c.meter.Float64Histogram("rpc."+role+".duration",
metric.WithDescription("Measures the duration of inbound RPC."), metric.WithDescription("Measures the duration of inbound RPC."),
metric.WithUnit("ms")) metric.WithUnit("ms"))
if err != nil { if err != nil {
otel.Handle(err) otel.Handle(err)
} }
c.rpcRequestSize, err = c.meter.Int64Histogram("rpc."+role+".request.size",
metric.WithDescription("Measures size of RPC request messages (uncompressed)."),
metric.WithUnit("By"))
if err != nil {
otel.Handle(err)
}
c.rpcResponseSize, err = c.meter.Int64Histogram("rpc."+role+".response.size",
metric.WithDescription("Measures size of RPC response messages (uncompressed)."),
metric.WithUnit("By"))
if err != nil {
otel.Handle(err)
}
c.rpcRequestsPerRPC, err = c.meter.Int64Histogram("rpc."+role+".requests_per_rpc",
metric.WithDescription("Measures the number of messages received per RPC. Should be 1 for all non-streaming RPCs."),
metric.WithUnit("{count}"))
if err != nil {
otel.Handle(err)
}
c.rpcResponsesPerRPC, err = c.meter.Int64Histogram("rpc."+role+".responses_per_rpc",
metric.WithDescription("Measures the number of messages received per RPC. Should be 1 for all non-streaming RPCs."),
metric.WithUnit("{count}"))
if err != nil {
otel.Handle(err)
}
return c return c
} }
@ -105,6 +145,8 @@ func (o tracerProviderOption) apply(c *config) {
} }
// WithInterceptorFilter returns an Option to use the request filter. // WithInterceptorFilter returns an Option to use the request filter.
//
// Deprecated: Use stats handlers instead.
func WithInterceptorFilter(f Filter) Option { func WithInterceptorFilter(f Filter) Option {
return interceptorFilterOption{f: f} return interceptorFilterOption{f: f}
} }

View file

@ -13,33 +13,10 @@
// limitations under the License. // limitations under the License.
/* /*
Package otelgrpc is the instrumentation library for [google.golang.org/grpc] Package otelgrpc is the instrumentation library for [google.golang.org/grpc].
For now you can instrument your program which use [google.golang.org/grpc] in two ways: Use [NewClientHandler] with [grpc.WithStatsHandler] to instrument a gRPC client.
- by [grpc.UnaryClientInterceptor], [grpc.UnaryServerInterceptor], [grpc.StreamClientInterceptor], [grpc.StreamServerInterceptor] Use [NewServerHandler] with [grpc.StatsHandler] to instrument a gRPC server.
- by [stats.Handler]
Notice: Do not use both interceptors and [stats.Handler] at the same time! If so, you will get duplicated spans and the parent/child relationships between spans will also be broken.
We strongly still recommand you to use [stats.Handler], mainly for two reasons:
Functional advantages: [stats.Handler] has more information for user to build more flexible and granular metric, for example
- multiple different types of represent "data length": In [stats.InPayload], there exists "Length", "CompressedLength", "WireLength" to denote the size of uncompressed, compressed payload data, with or without framing data. But in interceptors, we can only got uncompressed data, and this feature is also removed due to performance problem.
- more accurate timestamp: [stats.InPayload]'s "RecvTime" and [stats.OutPayload]'s "SentTime" records more accurate timestamp that server got and sent the message, the timestamp recorded by interceptors depends on the location of this interceptors in the total interceptor chain.
- some other use cases: for example, catch failure of decoding message.
Performance advantages: If too many interceptors are registered in a service, the interceptor chain can become too long, which increases the latency and processing time of the entire RPC call.
[stats.Handler]: https://pkg.go.dev/google.golang.org/grpc/stats#Handler
[grpc.UnaryClientInterceptor]: https://pkg.go.dev/google.golang.org/grpc#UnaryClientInterceptor
[grpc.UnaryServerInterceptor]: https://pkg.go.dev/google.golang.org/grpc#UnaryServerInterceptor
[grpc.StreamClientInterceptor]: https://pkg.go.dev/google.golang.org/grpc#StreamClientInterceptor
[grpc.StreamServerInterceptor]: https://pkg.go.dev/google.golang.org/grpc#StreamServerInterceptor
[stats.OutPayload]: https://pkg.go.dev/google.golang.org/grpc/stats#OutPayload
[stats.InPayload]: https://pkg.go.dev/google.golang.org/grpc/stats#InPayload
*/ */
package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"

View file

@ -60,10 +60,12 @@ var (
// UnaryClientInterceptor returns a grpc.UnaryClientInterceptor suitable // UnaryClientInterceptor returns a grpc.UnaryClientInterceptor suitable
// for use in a grpc.Dial call. // for use in a grpc.Dial call.
//
// Deprecated: Use [NewClientHandler] instead.
func UnaryClientInterceptor(opts ...Option) grpc.UnaryClientInterceptor { func UnaryClientInterceptor(opts ...Option) grpc.UnaryClientInterceptor {
cfg := newConfig(opts) cfg := newConfig(opts, "client")
tracer := cfg.TracerProvider.Tracer( tracer := cfg.TracerProvider.Tracer(
instrumentationName, ScopeName,
trace.WithInstrumentationVersion(Version()), trace.WithInstrumentationVersion(Version()),
) )
@ -83,11 +85,12 @@ func UnaryClientInterceptor(opts ...Option) grpc.UnaryClientInterceptor {
return invoker(ctx, method, req, reply, cc, callOpts...) return invoker(ctx, method, req, reply, cc, callOpts...)
} }
name, attr := spanInfo(method, cc.Target()) name, attr, _ := telemetryAttributes(method, cc.Target())
startOpts := append([]trace.SpanStartOption{ startOpts := append([]trace.SpanStartOption{
trace.WithSpanKind(trace.SpanKindClient), trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attr...)}, trace.WithAttributes(attr...),
},
cfg.SpanStartOptions..., cfg.SpanStartOptions...,
) )
@ -122,27 +125,13 @@ func UnaryClientInterceptor(opts ...Option) grpc.UnaryClientInterceptor {
} }
} }
type streamEventType int
type streamEvent struct {
Type streamEventType
Err error
}
const (
receiveEndEvent streamEventType = iota
errorEvent
)
// clientStream wraps around the embedded grpc.ClientStream, and intercepts the RecvMsg and // clientStream wraps around the embedded grpc.ClientStream, and intercepts the RecvMsg and
// SendMsg method call. // SendMsg method call.
type clientStream struct { type clientStream struct {
grpc.ClientStream grpc.ClientStream
desc *grpc.StreamDesc
desc *grpc.StreamDesc span trace.Span
events chan streamEvent
eventsDone chan struct{}
finished chan error
receivedEvent bool receivedEvent bool
sentEvent bool sentEvent bool
@ -157,11 +146,11 @@ func (w *clientStream) RecvMsg(m interface{}) error {
err := w.ClientStream.RecvMsg(m) err := w.ClientStream.RecvMsg(m)
if err == nil && !w.desc.ServerStreams { if err == nil && !w.desc.ServerStreams {
w.sendStreamEvent(receiveEndEvent, nil) w.endSpan(nil)
} else if err == io.EOF { } else if err == io.EOF {
w.sendStreamEvent(receiveEndEvent, nil) w.endSpan(nil)
} else if err != nil { } else if err != nil {
w.sendStreamEvent(errorEvent, err) w.endSpan(err)
} else { } else {
w.receivedMessageID++ w.receivedMessageID++
@ -183,7 +172,7 @@ func (w *clientStream) SendMsg(m interface{}) error {
} }
if err != nil { if err != nil {
w.sendStreamEvent(errorEvent, err) w.endSpan(err)
} }
return err return err
@ -191,9 +180,8 @@ func (w *clientStream) SendMsg(m interface{}) error {
func (w *clientStream) Header() (metadata.MD, error) { func (w *clientStream) Header() (metadata.MD, error) {
md, err := w.ClientStream.Header() md, err := w.ClientStream.Header()
if err != nil { if err != nil {
w.sendStreamEvent(errorEvent, err) w.endSpan(err)
} }
return md, err return md, err
@ -201,64 +189,43 @@ func (w *clientStream) Header() (metadata.MD, error) {
func (w *clientStream) CloseSend() error { func (w *clientStream) CloseSend() error {
err := w.ClientStream.CloseSend() err := w.ClientStream.CloseSend()
if err != nil { if err != nil {
w.sendStreamEvent(errorEvent, err) w.endSpan(err)
} }
return err return err
} }
func wrapClientStream(ctx context.Context, s grpc.ClientStream, desc *grpc.StreamDesc, cfg *config) *clientStream { func wrapClientStream(ctx context.Context, s grpc.ClientStream, desc *grpc.StreamDesc, span trace.Span, cfg *config) *clientStream {
events := make(chan streamEvent)
eventsDone := make(chan struct{})
finished := make(chan error)
go func() {
defer close(eventsDone)
for {
select {
case event := <-events:
switch event.Type {
case receiveEndEvent:
finished <- nil
return
case errorEvent:
finished <- event.Err
return
}
case <-ctx.Done():
finished <- ctx.Err()
return
}
}
}()
return &clientStream{ return &clientStream{
ClientStream: s, ClientStream: s,
span: span,
desc: desc, desc: desc,
events: events,
eventsDone: eventsDone,
finished: finished,
receivedEvent: cfg.ReceivedEvent, receivedEvent: cfg.ReceivedEvent,
sentEvent: cfg.SentEvent, sentEvent: cfg.SentEvent,
} }
} }
func (w *clientStream) sendStreamEvent(eventType streamEventType, err error) { func (w *clientStream) endSpan(err error) {
select { if err != nil {
case <-w.eventsDone: s, _ := status.FromError(err)
case w.events <- streamEvent{Type: eventType, Err: err}: w.span.SetStatus(codes.Error, s.Message())
w.span.SetAttributes(statusCodeAttr(s.Code()))
} else {
w.span.SetAttributes(statusCodeAttr(grpc_codes.OK))
} }
w.span.End()
} }
// StreamClientInterceptor returns a grpc.StreamClientInterceptor suitable // StreamClientInterceptor returns a grpc.StreamClientInterceptor suitable
// for use in a grpc.Dial call. // for use in a grpc.Dial call.
//
// Deprecated: Use [NewClientHandler] instead.
func StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor { func StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor {
cfg := newConfig(opts) cfg := newConfig(opts, "client")
tracer := cfg.TracerProvider.Tracer( tracer := cfg.TracerProvider.Tracer(
instrumentationName, ScopeName,
trace.WithInstrumentationVersion(Version()), trace.WithInstrumentationVersion(Version()),
) )
@ -278,11 +245,12 @@ func StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor {
return streamer(ctx, desc, cc, method, callOpts...) return streamer(ctx, desc, cc, method, callOpts...)
} }
name, attr := spanInfo(method, cc.Target()) name, attr, _ := telemetryAttributes(method, cc.Target())
startOpts := append([]trace.SpanStartOption{ startOpts := append([]trace.SpanStartOption{
trace.WithSpanKind(trace.SpanKindClient), trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attr...)}, trace.WithAttributes(attr...),
},
cfg.SpanStartOptions..., cfg.SpanStartOptions...,
) )
@ -302,32 +270,19 @@ func StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor {
span.End() span.End()
return s, err return s, err
} }
stream := wrapClientStream(ctx, s, desc, cfg) stream := wrapClientStream(ctx, s, desc, span, cfg)
go func() {
err := <-stream.finished
if err != nil {
s, _ := status.FromError(err)
span.SetStatus(codes.Error, s.Message())
span.SetAttributes(statusCodeAttr(s.Code()))
} else {
span.SetAttributes(statusCodeAttr(grpc_codes.OK))
}
span.End()
}()
return stream, nil return stream, nil
} }
} }
// UnaryServerInterceptor returns a grpc.UnaryServerInterceptor suitable // UnaryServerInterceptor returns a grpc.UnaryServerInterceptor suitable
// for use in a grpc.NewServer call. // for use in a grpc.NewServer call.
//
// Deprecated: Use [NewServerHandler] instead.
func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor { func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {
cfg := newConfig(opts) cfg := newConfig(opts, "server")
tracer := cfg.TracerProvider.Tracer( tracer := cfg.TracerProvider.Tracer(
instrumentationName, ScopeName,
trace.WithInstrumentationVersion(Version()), trace.WithInstrumentationVersion(Version()),
) )
@ -346,11 +301,12 @@ func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {
} }
ctx = extract(ctx, cfg.Propagators) ctx = extract(ctx, cfg.Propagators)
name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx)) name, attr, metricAttrs := telemetryAttributes(info.FullMethod, peerFromCtx(ctx))
startOpts := append([]trace.SpanStartOption{ startOpts := append([]trace.SpanStartOption{
trace.WithSpanKind(trace.SpanKindServer), trace.WithSpanKind(trace.SpanKindServer),
trace.WithAttributes(attr...)}, trace.WithAttributes(attr...),
},
cfg.SpanStartOptions..., cfg.SpanStartOptions...,
) )
@ -365,30 +321,30 @@ func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {
messageReceived.Event(ctx, 1, req) messageReceived.Event(ctx, 1, req)
} }
var statusCode grpc_codes.Code before := time.Now()
defer func(t time.Time) {
elapsedTime := time.Since(t) / time.Millisecond
attr = append(attr, semconv.RPCGRPCStatusCodeKey.Int64(int64(statusCode)))
o := metric.WithAttributes(attr...)
cfg.rpcServerDuration.Record(ctx, int64(elapsedTime), o)
}(time.Now())
resp, err := handler(ctx, req) resp, err := handler(ctx, req)
s, _ := status.FromError(err)
if err != nil { if err != nil {
s, _ := status.FromError(err)
statusCode, msg := serverStatus(s) statusCode, msg := serverStatus(s)
span.SetStatus(statusCode, msg) span.SetStatus(statusCode, msg)
span.SetAttributes(statusCodeAttr(s.Code()))
if cfg.SentEvent { if cfg.SentEvent {
messageSent.Event(ctx, 1, s.Proto()) messageSent.Event(ctx, 1, s.Proto())
} }
} else { } else {
statusCode = grpc_codes.OK
span.SetAttributes(statusCodeAttr(grpc_codes.OK))
if cfg.SentEvent { if cfg.SentEvent {
messageSent.Event(ctx, 1, resp) messageSent.Event(ctx, 1, resp)
} }
} }
grpcStatusCodeAttr := statusCodeAttr(s.Code())
span.SetAttributes(grpcStatusCodeAttr)
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedTime := float64(time.Since(before)) / float64(time.Millisecond)
metricAttrs = append(metricAttrs, grpcStatusCodeAttr)
cfg.rpcDuration.Record(ctx, elapsedTime, metric.WithAttributes(metricAttrs...))
return resp, err return resp, err
} }
@ -446,10 +402,12 @@ func wrapServerStream(ctx context.Context, ss grpc.ServerStream, cfg *config) *s
// StreamServerInterceptor returns a grpc.StreamServerInterceptor suitable // StreamServerInterceptor returns a grpc.StreamServerInterceptor suitable
// for use in a grpc.NewServer call. // for use in a grpc.NewServer call.
//
// Deprecated: Use [NewServerHandler] instead.
func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor { func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
cfg := newConfig(opts) cfg := newConfig(opts, "server")
tracer := cfg.TracerProvider.Tracer( tracer := cfg.TracerProvider.Tracer(
instrumentationName, ScopeName,
trace.WithInstrumentationVersion(Version()), trace.WithInstrumentationVersion(Version()),
) )
@ -469,11 +427,12 @@ func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
} }
ctx = extract(ctx, cfg.Propagators) ctx = extract(ctx, cfg.Propagators)
name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx)) name, attr, _ := telemetryAttributes(info.FullMethod, peerFromCtx(ctx))
startOpts := append([]trace.SpanStartOption{ startOpts := append([]trace.SpanStartOption{
trace.WithSpanKind(trace.SpanKindServer), trace.WithSpanKind(trace.SpanKindServer),
trace.WithAttributes(attr...)}, trace.WithAttributes(attr...),
},
cfg.SpanStartOptions..., cfg.SpanStartOptions...,
) )
@ -498,17 +457,18 @@ func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
} }
} }
// spanInfo returns a span name and all appropriate attributes from the gRPC // telemetryAttributes returns a span name and span and metric attributes from
// method and peer address. // the gRPC method and peer address.
func spanInfo(fullMethod, peerAddress string) (string, []attribute.KeyValue) { func telemetryAttributes(fullMethod, peerAddress string) (string, []attribute.KeyValue, []attribute.KeyValue) {
name, mAttrs := internal.ParseFullMethod(fullMethod) name, methodAttrs := internal.ParseFullMethod(fullMethod)
peerAttrs := peerAttr(peerAddress) peerAttrs := peerAttr(peerAddress)
attrs := make([]attribute.KeyValue, 0, 1+len(mAttrs)+len(peerAttrs)) attrs := make([]attribute.KeyValue, 0, 1+len(methodAttrs)+len(peerAttrs))
attrs = append(attrs, RPCSystemGRPC) attrs = append(attrs, RPCSystemGRPC)
attrs = append(attrs, mAttrs...) attrs = append(attrs, methodAttrs...)
metricAttrs := attrs[:1+len(methodAttrs)]
attrs = append(attrs, peerAttrs...) attrs = append(attrs, peerAttrs...)
return name, attrs return name, attrs, metricAttrs
} }
// peerAttr returns attributes about the peer address. // peerAttr returns attributes about the peer address.

View file

@ -56,7 +56,7 @@ func (s *metadataSupplier) Keys() []string {
// requests. // requests.
// Deprecated: Unnecessary public func. // Deprecated: Unnecessary public func.
func Inject(ctx context.Context, md *metadata.MD, opts ...Option) { func Inject(ctx context.Context, md *metadata.MD, opts ...Option) {
c := newConfig(opts) c := newConfig(opts, "")
c.Propagators.Inject(ctx, &metadataSupplier{ c.Propagators.Inject(ctx, &metadataSupplier{
metadata: md, metadata: md,
}) })
@ -78,7 +78,7 @@ func inject(ctx context.Context, propagators propagation.TextMapPropagator) cont
// This function is meant to be used on incoming requests. // This function is meant to be used on incoming requests.
// Deprecated: Unnecessary public func. // Deprecated: Unnecessary public func.
func Extract(ctx context.Context, md *metadata.MD, opts ...Option) (baggage.Baggage, trace.SpanContext) { func Extract(ctx context.Context, md *metadata.MD, opts ...Option) (baggage.Baggage, trace.SpanContext) {
c := newConfig(opts) c := newConfig(opts, "")
ctx = c.Propagators.Extract(ctx, &metadataSupplier{ ctx = c.Propagators.Extract(ctx, &metadataSupplier{
metadata: md, metadata: md,
}) })

View file

@ -17,13 +17,16 @@ package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.g
import ( import (
"context" "context"
"sync/atomic" "sync/atomic"
"time"
grpc_codes "google.golang.org/grpc/codes" grpc_codes "google.golang.org/grpc/codes"
"google.golang.org/grpc/stats" "google.golang.org/grpc/stats"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/internal" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/internal"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0" semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@ -33,24 +36,32 @@ type gRPCContextKey struct{}
type gRPCContext struct { type gRPCContext struct {
messagesReceived int64 messagesReceived int64
messagesSent int64 messagesSent int64
metricAttrs []attribute.KeyValue
}
type serverHandler struct {
*config
} }
// NewServerHandler creates a stats.Handler for gRPC server. // NewServerHandler creates a stats.Handler for gRPC server.
func NewServerHandler(opts ...Option) stats.Handler { func NewServerHandler(opts ...Option) stats.Handler {
h := &serverHandler{ h := &serverHandler{
config: newConfig(opts), config: newConfig(opts, "server"),
} }
h.tracer = h.config.TracerProvider.Tracer(
instrumentationName,
trace.WithInstrumentationVersion(SemVersion()),
)
return h return h
} }
type serverHandler struct { // TagConn can attach some information to the given context.
*config func (h *serverHandler) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
tracer trace.Tracer span := trace.SpanFromContext(ctx)
attrs := peerAttr(peerFromCtx(ctx))
span.SetAttributes(attrs...)
return ctx
}
// HandleConn processes the Conn stats.
func (h *serverHandler) HandleConn(ctx context.Context, info stats.ConnStats) {
} }
// TagRPC can attach some information to the given context. // TagRPC can attach some information to the given context.
@ -66,46 +77,30 @@ func (h *serverHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) cont
trace.WithAttributes(attrs...), trace.WithAttributes(attrs...),
) )
gctx := gRPCContext{} gctx := gRPCContext{
metricAttrs: attrs,
}
return context.WithValue(ctx, gRPCContextKey{}, &gctx) return context.WithValue(ctx, gRPCContextKey{}, &gctx)
} }
// HandleRPC processes the RPC stats. // HandleRPC processes the RPC stats.
func (h *serverHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) { func (h *serverHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
handleRPC(ctx, rs) h.handleRPC(ctx, rs)
} }
// TagConn can attach some information to the given context. type clientHandler struct {
func (h *serverHandler) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context { *config
span := trace.SpanFromContext(ctx)
attrs := peerAttr(peerFromCtx(ctx))
span.SetAttributes(attrs...)
return ctx
}
// HandleConn processes the Conn stats.
func (h *serverHandler) HandleConn(ctx context.Context, info stats.ConnStats) {
} }
// NewClientHandler creates a stats.Handler for gRPC client. // NewClientHandler creates a stats.Handler for gRPC client.
func NewClientHandler(opts ...Option) stats.Handler { func NewClientHandler(opts ...Option) stats.Handler {
h := &clientHandler{ h := &clientHandler{
config: newConfig(opts), config: newConfig(opts, "client"),
} }
h.tracer = h.config.TracerProvider.Tracer(
instrumentationName,
trace.WithInstrumentationVersion(SemVersion()),
)
return h return h
} }
type clientHandler struct {
*config
tracer trace.Tracer
}
// TagRPC can attach some information to the given context. // TagRPC can attach some information to the given context.
func (h *clientHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context { func (h *clientHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
name, attrs := internal.ParseFullMethod(info.FullMethodName) name, attrs := internal.ParseFullMethod(info.FullMethodName)
@ -117,14 +112,16 @@ func (h *clientHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) cont
trace.WithAttributes(attrs...), trace.WithAttributes(attrs...),
) )
gctx := gRPCContext{} gctx := gRPCContext{
metricAttrs: attrs,
}
return inject(context.WithValue(ctx, gRPCContextKey{}, &gctx), h.config.Propagators) return inject(context.WithValue(ctx, gRPCContextKey{}, &gctx), h.config.Propagators)
} }
// HandleRPC processes the RPC stats. // HandleRPC processes the RPC stats.
func (h *clientHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) { func (h *clientHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
handleRPC(ctx, rs) h.handleRPC(ctx, rs)
} }
// TagConn can attach some information to the given context. // TagConn can attach some information to the given context.
@ -140,48 +137,102 @@ func (h *clientHandler) HandleConn(context.Context, stats.ConnStats) {
// no-op // no-op
} }
func handleRPC(ctx context.Context, rs stats.RPCStats) { func (c *config) handleRPC(ctx context.Context, rs stats.RPCStats) {
span := trace.SpanFromContext(ctx) span := trace.SpanFromContext(ctx)
gctx, _ := ctx.Value(gRPCContextKey{}).(*gRPCContext) gctx, _ := ctx.Value(gRPCContextKey{}).(*gRPCContext)
var messageId int64 var messageId int64
metricAttrs := make([]attribute.KeyValue, 0, len(gctx.metricAttrs)+1)
metricAttrs = append(metricAttrs, gctx.metricAttrs...)
wctx := withoutCancel(ctx)
switch rs := rs.(type) { switch rs := rs.(type) {
case *stats.Begin: case *stats.Begin:
case *stats.InPayload: case *stats.InPayload:
if gctx != nil { if gctx != nil {
messageId = atomic.AddInt64(&gctx.messagesReceived, 1) messageId = atomic.AddInt64(&gctx.messagesReceived, 1)
c.rpcRequestSize.Record(wctx, int64(rs.Length), metric.WithAttributes(metricAttrs...))
}
if c.ReceivedEvent {
span.AddEvent("message",
trace.WithAttributes(
semconv.MessageTypeReceived,
semconv.MessageIDKey.Int64(messageId),
semconv.MessageCompressedSizeKey.Int(rs.CompressedLength),
semconv.MessageUncompressedSizeKey.Int(rs.Length),
),
)
} }
span.AddEvent("message",
trace.WithAttributes(
semconv.MessageTypeReceived,
semconv.MessageIDKey.Int64(messageId),
semconv.MessageCompressedSizeKey.Int(rs.CompressedLength),
semconv.MessageUncompressedSizeKey.Int(rs.Length),
),
)
case *stats.OutPayload: case *stats.OutPayload:
if gctx != nil { if gctx != nil {
messageId = atomic.AddInt64(&gctx.messagesSent, 1) messageId = atomic.AddInt64(&gctx.messagesSent, 1)
c.rpcResponseSize.Record(wctx, int64(rs.Length), metric.WithAttributes(metricAttrs...))
} }
span.AddEvent("message", if c.SentEvent {
trace.WithAttributes( span.AddEvent("message",
semconv.MessageTypeSent, trace.WithAttributes(
semconv.MessageIDKey.Int64(messageId), semconv.MessageTypeSent,
semconv.MessageCompressedSizeKey.Int(rs.CompressedLength), semconv.MessageIDKey.Int64(messageId),
semconv.MessageUncompressedSizeKey.Int(rs.Length), semconv.MessageCompressedSizeKey.Int(rs.CompressedLength),
), semconv.MessageUncompressedSizeKey.Int(rs.Length),
) ),
)
}
case *stats.OutTrailer:
case *stats.End: case *stats.End:
var rpcStatusAttr attribute.KeyValue
if rs.Error != nil { if rs.Error != nil {
s, _ := status.FromError(rs.Error) s, _ := status.FromError(rs.Error)
span.SetStatus(codes.Error, s.Message()) span.SetStatus(codes.Error, s.Message())
span.SetAttributes(statusCodeAttr(s.Code())) rpcStatusAttr = semconv.RPCGRPCStatusCodeKey.Int(int(s.Code()))
} else { } else {
span.SetAttributes(statusCodeAttr(grpc_codes.OK)) rpcStatusAttr = semconv.RPCGRPCStatusCodeKey.Int(int(grpc_codes.OK))
} }
span.SetAttributes(rpcStatusAttr)
span.End() span.End()
metricAttrs = append(metricAttrs, rpcStatusAttr)
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedTime := float64(rs.EndTime.Sub(rs.BeginTime)) / float64(time.Millisecond)
c.rpcDuration.Record(wctx, elapsedTime, metric.WithAttributes(metricAttrs...))
c.rpcRequestsPerRPC.Record(wctx, atomic.LoadInt64(&gctx.messagesReceived), metric.WithAttributes(metricAttrs...))
c.rpcResponsesPerRPC.Record(wctx, atomic.LoadInt64(&gctx.messagesSent), metric.WithAttributes(metricAttrs...))
default: default:
return return
} }
} }
func withoutCancel(parent context.Context) context.Context {
if parent == nil {
panic("cannot create context from nil parent")
}
return withoutCancelCtx{parent}
}
type withoutCancelCtx struct {
c context.Context
}
func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (withoutCancelCtx) Done() <-chan struct{} {
return nil
}
func (withoutCancelCtx) Err() error {
return nil
}
func (w withoutCancelCtx) Value(key any) any {
return w.c.Value(key)
}
func (w withoutCancelCtx) String() string {
return "withoutCancel"
}

View file

@ -16,7 +16,7 @@ package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.g
// Version is the current release version of the gRPC instrumentation. // Version is the current release version of the gRPC instrumentation.
func Version() string { func Version() string {
return "0.45.0" return "0.46.1"
// This string is updated by the pre_release.sh script during release // This string is updated by the pre_release.sh script during release
} }

View file

@ -29,6 +29,9 @@ import (
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
// ScopeName is the instrumentation scope name.
const ScopeName = "go.opentelemetry.io/otel/instrumentation/httptrace"
// HTTP attributes. // HTTP attributes.
var ( var (
HTTPStatus = attribute.Key("http.status") HTTPStatus = attribute.Key("http.status")
@ -44,13 +47,11 @@ var (
HTTPDNSAddrs = attribute.Key("http.dns.addrs") HTTPDNSAddrs = attribute.Key("http.dns.addrs")
) )
var ( var hookMap = map[string]string{
hookMap = map[string]string{ "http.dns": "http.getconn",
"http.dns": "http.getconn", "http.connect": "http.getconn",
"http.connect": "http.getconn", "http.tls": "http.getconn",
"http.tls": "http.getconn", }
}
)
func parentHook(hook string) string { func parentHook(hook string) string {
if strings.HasPrefix(hook, "http.connect") { if strings.HasPrefix(hook, "http.connect") {
@ -171,7 +172,7 @@ func NewClientTrace(ctx context.Context, opts ...ClientTraceOption) *httptrace.C
} }
ct.tr = ct.tracerProvider.Tracer( ct.tr = ct.tracerProvider.Tracer(
"go.opentelemetry.io/otel/instrumentation/httptrace", ScopeName,
trace.WithInstrumentationVersion(Version()), trace.WithInstrumentationVersion(Version()),
) )

View file

@ -16,7 +16,7 @@ package otelhttptrace // import "go.opentelemetry.io/contrib/instrumentation/net
// Version is the current release version of the httptrace instrumentation. // Version is the current release version of the httptrace instrumentation.
func Version() string { func Version() string {
return "0.45.0" return "0.46.1"
// This string is updated by the pre_release.sh script during release // This string is updated by the pre_release.sh script during release
} }

View file

@ -34,7 +34,7 @@ const (
RequestCount = "http.server.request_count" // Incoming request count total RequestCount = "http.server.request_count" // Incoming request count total
RequestContentLength = "http.server.request_content_length" // Incoming request bytes total RequestContentLength = "http.server.request_content_length" // Incoming request bytes total
ResponseContentLength = "http.server.response_content_length" // Incoming response bytes total ResponseContentLength = "http.server.response_content_length" // Incoming response bytes total
ServerLatency = "http.server.duration" // Incoming end to end duration, microseconds ServerLatency = "http.server.duration" // Incoming end to end duration, milliseconds
) )
// Filter is a predicate used to determine whether a given http.request should // Filter is a predicate used to determine whether a given http.request should
@ -42,5 +42,5 @@ const (
type Filter func(*http.Request) bool type Filter func(*http.Request) bool
func newTracer(tp trace.TracerProvider) trace.Tracer { func newTracer(tp trace.TracerProvider) trace.Tracer {
return tp.Tracer(instrumentationName, trace.WithInstrumentationVersion(Version())) return tp.Tracer(ScopeName, trace.WithInstrumentationVersion(Version()))
} }

View file

@ -25,9 +25,8 @@ import (
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
const ( // ScopeName is the instrumentation scope name.
instrumentationName = "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" const ScopeName = "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
// config represents the configuration options available for the http.Handler // config represents the configuration options available for the http.Handler
// and http.Transport types. // and http.Transport types.
@ -76,7 +75,7 @@ func newConfig(opts ...Option) *config {
} }
c.Meter = c.MeterProvider.Meter( c.Meter = c.MeterProvider.Meter(
instrumentationName, ScopeName,
metric.WithInstrumentationVersion(Version()), metric.WithInstrumentationVersion(Version()),
) )

View file

@ -107,13 +107,25 @@ func (h *middleware) createMeasures() {
h.counters = make(map[string]metric.Int64Counter) h.counters = make(map[string]metric.Int64Counter)
h.valueRecorders = make(map[string]metric.Float64Histogram) h.valueRecorders = make(map[string]metric.Float64Histogram)
requestBytesCounter, err := h.meter.Int64Counter(RequestContentLength) requestBytesCounter, err := h.meter.Int64Counter(
RequestContentLength,
metric.WithUnit("By"),
metric.WithDescription("Measures the size of HTTP request content length (uncompressed)"),
)
handleErr(err) handleErr(err)
responseBytesCounter, err := h.meter.Int64Counter(ResponseContentLength) responseBytesCounter, err := h.meter.Int64Counter(
ResponseContentLength,
metric.WithUnit("By"),
metric.WithDescription("Measures the size of HTTP response content length (uncompressed)"),
)
handleErr(err) handleErr(err)
serverLatencyMeasure, err := h.meter.Float64Histogram(ServerLatency) serverLatencyMeasure, err := h.meter.Float64Histogram(
ServerLatency,
metric.WithUnit("ms"),
metric.WithDescription("Measures the duration of HTTP request handling"),
)
handleErr(err) handleErr(err)
h.counters[RequestContentLength] = requestBytesCounter h.counters[RequestContentLength] = requestBytesCounter

View file

@ -16,7 +16,7 @@ package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http
// Version is the current release version of the otelhttp instrumentation. // Version is the current release version of the otelhttp instrumentation.
func Version() string { func Version() string {
return "0.45.0" return "0.46.1"
// This string is updated by the pre_release.sh script during release // This string is updated by the pre_release.sh script during release
} }

View file

@ -14,12 +14,9 @@ go.work.sum
gen/ gen/
/example/dice/dice /example/dice/dice
/example/fib/fib
/example/fib/traces.txt
/example/jaeger/jaeger
/example/namedtracer/namedtracer /example/namedtracer/namedtracer
/example/otel-collector/otel-collector
/example/opencensus/opencensus /example/opencensus/opencensus
/example/passthrough/passthrough /example/passthrough/passthrough
/example/prometheus/prometheus /example/prometheus/prometheus
/example/zipkin/zipkin /example/zipkin/zipkin
/example/otel-collector/otel-collector

View file

@ -12,8 +12,9 @@ linters:
- depguard - depguard
- errcheck - errcheck
- godot - godot
- gofmt - gofumpt
- goimports - goimports
- gosec
- gosimple - gosimple
- govet - govet
- ineffassign - ineffassign
@ -53,6 +54,20 @@ issues:
text: "calls to (.+) only in main[(][)] or init[(][)] functions" text: "calls to (.+) only in main[(][)] or init[(][)] functions"
linters: linters:
- revive - revive
# It's okay to not run gosec in a test.
- path: _test\.go
linters:
- gosec
# Igonoring gosec G404: Use of weak random number generator (math/rand instead of crypto/rand)
# as we commonly use it in tests and examples.
- text: "G404:"
linters:
- gosec
# Igonoring gosec G402: TLS MinVersion too low
# as the https://pkg.go.dev/crypto/tls#Config handles MinVersion default well.
- text: "G402: TLS MinVersion too low."
linters:
- gosec
include: include:
# revive exported should have comment or be unexported. # revive exported should have comment or be unexported.
- EXC0012 - EXC0012

View file

@ -8,6 +8,85 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [Unreleased] ## [Unreleased]
## [1.21.0/0.44.0] 2023-11-16
### Removed
- Remove the deprecated `go.opentelemetry.io/otel/bridge/opencensus.NewTracer`. (#4706)
- Remove the deprecated `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` module. (#4707)
- Remove the deprecated `go.opentelemetry.io/otel/example/view` module. (#4708)
- Remove the deprecated `go.opentelemetry.io/otel/example/fib` module. (#4723)
### Fixed
- Do not parse non-protobuf responses in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4719)
- Do not parse non-protobuf responses in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#4719)
## [1.20.0/0.43.0] 2023-11-10
This release brings a breaking change for custom trace API implementations. Some interfaces (`TracerProvider`, `Tracer`, `Span`) now embed the `go.opentelemetry.io/otel/trace/embedded` types. Implementors need to update their implementations based on what they want the default behavior to be. See the "API Implementations" section of the [trace API] package documentation for more information about how to accomplish this.
### Added
- Add `go.opentelemetry.io/otel/bridge/opencensus.InstallTraceBridge`, which installs the OpenCensus trace bridge, and replaces `opencensus.NewTracer`. (#4567)
- Add scope version to trace and metric bridges in `go.opentelemetry.io/otel/bridge/opencensus`. (#4584)
- Add the `go.opentelemetry.io/otel/trace/embedded` package to be embedded in the exported trace API interfaces. (#4620)
- Add the `go.opentelemetry.io/otel/trace/noop` package as a default no-op implementation of the trace API. (#4620)
- Add context propagation in `go.opentelemetry.io/otel/example/dice`. (#4644)
- Add view configuration to `go.opentelemetry.io/otel/example/prometheus`. (#4649)
- Add `go.opentelemetry.io/otel/metric.WithExplicitBucketBoundaries`, which allows defining default explicit bucket boundaries when creating histogram instruments. (#4603)
- Add `Version` function in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#4660)
- Add `Version` function in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4660)
- Add Summary, SummaryDataPoint, and QuantileValue to `go.opentelemetry.io/sdk/metric/metricdata`. (#4622)
- `go.opentelemetry.io/otel/bridge/opencensus.NewMetricProducer` now supports exemplars from OpenCensus. (#4585)
- Add support for `WithExplicitBucketBoundaries` in `go.opentelemetry.io/otel/sdk/metric`. (#4605)
- Add support for Summary metrics in `go.opentelemetry.io/otel/bridge/opencensus`. (#4668)
### Deprecated
- Deprecate `go.opentelemetry.io/otel/bridge/opencensus.NewTracer` in favor of `opencensus.InstallTraceBridge`. (#4567)
- Deprecate `go.opentelemetry.io/otel/example/fib` package is in favor of `go.opentelemetry.io/otel/example/dice`. (#4618)
- Deprecate `go.opentelemetry.io/otel/trace.NewNoopTracerProvider`.
Use the added `NewTracerProvider` function in `go.opentelemetry.io/otel/trace/noop` instead. (#4620)
- Deprecate `go.opentelemetry.io/otel/example/view` package in favor of `go.opentelemetry.io/otel/example/prometheus`. (#4649)
- Deprecate `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#4693)
### Changed
- `go.opentelemetry.io/otel/bridge/opencensus.NewMetricProducer` returns a `*MetricProducer` struct instead of the metric.Producer interface. (#4583)
- The `TracerProvider` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.TracerProvider` type.
This extends the `TracerProvider` interface and is is a breaking change for any existing implementation.
Implementors need to update their implementations based on what they want the default behavior of the interface to be.
See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more information about how to accomplish this. (#4620)
- The `Tracer` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.Tracer` type.
This extends the `Tracer` interface and is is a breaking change for any existing implementation.
Implementors need to update their implementations based on what they want the default behavior of the interface to be.
See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more information about how to accomplish this. (#4620)
- The `Span` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.Span` type.
This extends the `Span` interface and is is a breaking change for any existing implementation.
Implementors need to update their implementations based on what they want the default behavior of the interface to be.
See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more information about how to accomplish this. (#4620)
- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` does no longer depend on `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#4660)
- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` does no longer depend on `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#4660)
- Retry for `502 Bad Gateway` and `504 Gateway Timeout` HTTP statuses in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4670)
- Retry for `502 Bad Gateway` and `504 Gateway Timeout` HTTP statuses in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#4670)
- Retry for `RESOURCE_EXHAUSTED` only if RetryInfo is returned in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#4669)
- Retry for `RESOURCE_EXHAUSTED` only if RetryInfo is returned in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#4669)
- Retry temporary HTTP request failures in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4679)
- Retry temporary HTTP request failures in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#4679)
### Fixed
- Fix improper parsing of characters such us `+`, `/` by `Parse` in `go.opentelemetry.io/otel/baggage` as they were rendered as a whitespace. (#4667)
- Fix improper parsing of characters such us `+`, `/` passed via `OTEL_RESOURCE_ATTRIBUTES` in `go.opentelemetry.io/otel/sdk/resource` as they were rendered as a whitespace. (#4699)
- Fix improper parsing of characters such us `+`, `/` passed via `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_EXPORTER_OTLP_METRICS_HEADERS` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` as they were rendered as a whitespace. (#4699)
- Fix improper parsing of characters such us `+`, `/` passed via `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_EXPORTER_OTLP_METRICS_HEADERS` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` as they were rendered as a whitespace. (#4699)
- Fix improper parsing of characters such us `+`, `/` passed via `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_EXPORTER_OTLP_TRACES_HEADERS` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlptracegrpc` as they were rendered as a whitespace. (#4699)
- Fix improper parsing of characters such us `+`, `/` passed via `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_EXPORTER_OTLP_TRACES_HEADERS` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlptracehttp` as they were rendered as a whitespace. (#4699)
- In `go.opentelemetry.op/otel/exporters/prometheus`, the exporter no longer `Collect`s metrics after `Shutdown` is invoked. (#4648)
- Fix documentation for `WithCompressor` in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#4695)
- Fix documentation for `WithCompressor` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#4695)
## [1.19.0/0.42.0/0.0.7] 2023-09-28 ## [1.19.0/0.42.0/0.0.7] 2023-09-28
This release contains the first stable release of the OpenTelemetry Go [metric SDK]. This release contains the first stable release of the OpenTelemetry Go [metric SDK].
@ -2656,7 +2735,9 @@ It contains api and sdk for trace and meter.
- CircleCI build CI manifest files. - CircleCI build CI manifest files.
- CODEOWNERS file to track owners of this project. - CODEOWNERS file to track owners of this project.
[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.19.0...HEAD [Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.21.0...HEAD
[1.21.0/0.44.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.21.0
[1.20.0/0.43.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.20.0
[1.19.0/0.42.0/0.0.7]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0 [1.19.0/0.42.0/0.0.7]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0
[1.19.0-rc.1/0.42.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0-rc.1 [1.19.0-rc.1/0.42.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0-rc.1
[1.18.0/0.41.0/0.0.6]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.18.0 [1.18.0/0.41.0/0.0.6]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.18.0
@ -2731,7 +2812,7 @@ It contains api and sdk for trace and meter.
[Go 1.20]: https://go.dev/doc/go1.20 [Go 1.20]: https://go.dev/doc/go1.20
[Go 1.19]: https://go.dev/doc/go1.19 [Go 1.19]: https://go.dev/doc/go1.19
[Go 1.18]: https://go.dev/doc/go1.18 [Go 1.18]: https://go.dev/doc/go1.18
[Go 1.19]: https://go.dev/doc/go1.19
[metric API]:https://pkg.go.dev/go.opentelemetry.io/otel/metric [metric API]:https://pkg.go.dev/go.opentelemetry.io/otel/metric
[metric SDK]:https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric [metric SDK]:https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric
[trace API]:https://pkg.go.dev/go.opentelemetry.io/otel/trace

View file

@ -90,6 +90,10 @@ git push <YOUR_FORK> <YOUR_BRANCH_NAME>
Open a pull request against the main `opentelemetry-go` repo. Be sure to add the pull Open a pull request against the main `opentelemetry-go` repo. Be sure to add the pull
request ID to the entry you added to `CHANGELOG.md`. request ID to the entry you added to `CHANGELOG.md`.
Avoid rebasing and force-pushing to your branch to facilitate reviewing the pull request.
Rewriting Git history makes it difficult to keep track of iterations during code review.
All pull requests are squashed to a single commit upon merge to `main`.
### How to Receive Comments ### How to Receive Comments
* If the PR is not ready for review, please put `[WIP]` in the title, * If the PR is not ready for review, please put `[WIP]` in the title,

View file

@ -77,6 +77,9 @@ $(GOTMPL): PACKAGE=go.opentelemetry.io/build-tools/gotmpl
GORELEASE = $(TOOLS)/gorelease GORELEASE = $(TOOLS)/gorelease
$(GORELEASE): PACKAGE=golang.org/x/exp/cmd/gorelease $(GORELEASE): PACKAGE=golang.org/x/exp/cmd/gorelease
GOVULNCHECK = $(TOOLS)/govulncheck
$(TOOLS)/govulncheck: PACKAGE=golang.org/x/vuln/cmd/govulncheck
.PHONY: tools .PHONY: tools
tools: $(CROSSLINK) $(DBOTCONF) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(GOJQ) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE) tools: $(CROSSLINK) $(DBOTCONF) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(GOJQ) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
@ -189,6 +192,18 @@ test-coverage: | $(GOCOVMERGE)
done; \ done; \
$(GOCOVMERGE) $$(find . -name coverage.out) > coverage.txt $(GOCOVMERGE) $$(find . -name coverage.out) > coverage.txt
# Adding a directory will include all benchmarks in that direcotry if a filter is not specified.
BENCHMARK_TARGETS := sdk/trace
.PHONY: benchmark
benchmark: $(BENCHMARK_TARGETS:%=benchmark/%)
BENCHMARK_FILTER = .
# You can override the filter for a particular directory by adding a rule here.
benchmark/sdk/trace: BENCHMARK_FILTER = SpanWithAttributes_8/AlwaysSample
benchmark/%:
@echo "$(GO) test -timeout $(TIMEOUT)s -run=xxxxxMatchNothingxxxxx -bench=$(BENCHMARK_FILTER) $*..." \
&& cd $* \
$(foreach filter, $(BENCHMARK_FILTER), && $(GO) test -timeout $(TIMEOUT)s -run=xxxxxMatchNothingxxxxx -bench=$(filter))
.PHONY: golangci-lint golangci-lint-fix .PHONY: golangci-lint golangci-lint-fix
golangci-lint-fix: ARGS=--fix golangci-lint-fix: ARGS=--fix
golangci-lint-fix: golangci-lint golangci-lint-fix: golangci-lint
@ -216,7 +231,7 @@ go-mod-tidy/%: | crosslink
lint-modules: go-mod-tidy lint-modules: go-mod-tidy
.PHONY: lint .PHONY: lint
lint: misspell lint-modules golangci-lint lint: misspell lint-modules golangci-lint govulncheck
.PHONY: vanity-import-check .PHONY: vanity-import-check
vanity-import-check: | $(PORTO) vanity-import-check: | $(PORTO)
@ -226,6 +241,14 @@ vanity-import-check: | $(PORTO)
misspell: | $(MISSPELL) misspell: | $(MISSPELL)
@$(MISSPELL) -w $(ALL_DOCS) @$(MISSPELL) -w $(ALL_DOCS)
.PHONY: govulncheck
govulncheck: $(OTEL_GO_MOD_DIRS:%=govulncheck/%)
govulncheck/%: DIR=$*
govulncheck/%: | $(GOVULNCHECK)
@echo "govulncheck ./... in $(DIR)" \
&& cd $(DIR) \
&& $(GOVULNCHECK) ./...
.PHONY: codespell .PHONY: codespell
codespell: | $(CODESPELL) codespell: | $(CODESPELL)
@$(DOCKERPY) $(CODESPELL) @$(DOCKERPY) $(CODESPELL)
@ -289,3 +312,7 @@ COMMIT ?= "HEAD"
add-tags: | $(MULTIMOD) add-tags: | $(MULTIMOD)
@[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 ) @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 )
$(MULTIMOD) verify && $(MULTIMOD) tag -m ${MODSET} -c ${COMMIT} $(MULTIMOD) verify && $(MULTIMOD) tag -m ${MODSET} -c ${COMMIT}
.PHONY: lint-markdown
lint-markdown:
docker run -v "$(CURDIR):$(WORKDIR)" docker://avtodev/markdown-lint:v1 -c $(WORKDIR)/.markdownlint.yaml $(WORKDIR)/**/*.md

View file

@ -11,16 +11,13 @@ It provides a set of APIs to directly measure performance and behavior of your s
## Project Status ## Project Status
| Signal | Status | Project | | Signal | Status |
|---------|------------|-----------------------| |---------|------------|
| Traces | Stable | N/A | | Traces | Stable |
| Metrics | Mixed [1] | [Go: Metric SDK (GA)] | | Metrics | Stable |
| Logs | Frozen [2] | N/A | | Logs | Design [1] |
[Go: Metric SDK (GA)]: https://github.com/orgs/open-telemetry/projects/34 - [1]: Currently the logs signal development is in a design phase ([#4696](https://github.com/open-telemetry/opentelemetry-go/issues/4696)).
- [1]: [Metrics API](https://pkg.go.dev/go.opentelemetry.io/otel/metric) is Stable. [Metrics SDK](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric) is Beta.
- [2]: The Logs signal development is halted for this project while we stabilize the Metrics SDK.
No Logs Pull Requests are currently being accepted. No Logs Pull Requests are currently being accepted.
Progress and status specific to this repository is tracked in our Progress and status specific to this repository is tracked in our

View file

@ -254,7 +254,7 @@ func NewMember(key, value string, props ...Property) (Member, error) {
if err := m.validate(); err != nil { if err := m.validate(); err != nil {
return newInvalidMember(), err return newInvalidMember(), err
} }
decodedValue, err := url.QueryUnescape(value) decodedValue, err := url.PathUnescape(value)
if err != nil { if err != nil {
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
} }
@ -301,7 +301,7 @@ func parseMember(member string) (Member, error) {
// when converting the header into a data structure." // when converting the header into a data structure."
key = strings.TrimSpace(k) key = strings.TrimSpace(k)
var err error var err error
value, err = url.QueryUnescape(strings.TrimSpace(v)) value, err = url.PathUnescape(strings.TrimSpace(v))
if err != nil { if err != nil {
return newInvalidMember(), fmt.Errorf("%w: %q", err, value) return newInvalidMember(), fmt.Errorf("%w: %q", err, value)
} }

View file

@ -1,51 +0,0 @@
# OpenTelemetry-Go OTLP Span Exporter
[![Go Reference](https://pkg.go.dev/badge/go.opentelemetry.io/otel/exporters/otlp/otlptrace.svg)](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace)
[OpenTelemetry Protocol Exporter](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/protocol/exporter.md) implementation.
## Installation
```
go get -u go.opentelemetry.io/otel/exporters/otlp/otlptrace
```
## Examples
- [HTTP Exporter setup and examples](./otlptracehttp/example_test.go)
- [Full example of gRPC Exporter sending telemetry to a local collector](../../../example/otel-collector)
## [`otlptrace`](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace)
The `otlptrace` package provides an exporter implementing the OTel span exporter interface.
This exporter is configured using a client satisfying the `otlptrace.Client` interface.
This client handles the transformation of data into wire format and the transmission of that data to the collector.
## [`otlptracegrpc`](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc)
The `otlptracegrpc` package implements a client for the span exporter that sends trace telemetry data to the collector using gRPC with protobuf-encoded payloads.
## [`otlptracehttp`](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp)
The `otlptracehttp` package implements a client for the span exporter that sends trace telemetry data to the collector using HTTP with protobuf-encoded payloads.
## Configuration
### Environment Variables
The following environment variables can be used (instead of options objects) to
override the default configuration. For more information about how each of
these environment variables is interpreted, see [the OpenTelemetry
specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/protocol/exporter.md).
| Environment variable | Option | Default value |
| ------------------------------------------------------------------------ |------------------------------ | -------------------------------------------------------- |
| `OTEL_EXPORTER_OTLP_ENDPOINT` `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | `WithEndpoint` `WithInsecure` | `https://localhost:4317` or `https://localhost:4318`[^1] |
| `OTEL_EXPORTER_OTLP_CERTIFICATE` `OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE` | `WithTLSClientConfig` | |
| `OTEL_EXPORTER_OTLP_HEADERS` `OTEL_EXPORTER_OTLP_TRACES_HEADERS` | `WithHeaders` | |
| `OTEL_EXPORTER_OTLP_COMPRESSION` `OTEL_EXPORTER_OTLP_TRACES_COMPRESSION` | `WithCompression` | |
| `OTEL_EXPORTER_OTLP_TIMEOUT` `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` | `WithTimeout` | `10s` |
[^1]: The gRPC client defaults to `https://localhost:4317` and the HTTP client `https://localhost:4318`.
Configuration using options have precedence over the environment variables.

View file

@ -0,0 +1,21 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package otlptrace contains abstractions for OTLP span exporters.
See the official OTLP span exporter implementations:
- [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc],
- [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp].
*/
package otlptrace // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace"

View file

@ -24,9 +24,7 @@ import (
tracesdk "go.opentelemetry.io/otel/sdk/trace" tracesdk "go.opentelemetry.io/otel/sdk/trace"
) )
var ( var errAlreadyStarted = errors.New("already started")
errAlreadyStarted = errors.New("already started")
)
// Exporter exports trace data in the OTLP wire format. // Exporter exports trace data in the OTLP wire format.
type Exporter struct { type Exporter struct {
@ -55,7 +53,7 @@ func (e *Exporter) ExportSpans(ctx context.Context, ss []tracesdk.ReadOnlySpan)
// Start establishes a connection to the receiving endpoint. // Start establishes a connection to the receiving endpoint.
func (e *Exporter) Start(ctx context.Context) error { func (e *Exporter) Start(ctx context.Context) error {
var err = errAlreadyStarted err := errAlreadyStarted
e.startOnce.Do(func() { e.startOnce.Do(func() {
e.mu.Lock() e.mu.Lock()
e.started = true e.started = true

View file

@ -260,30 +260,38 @@ func (c *client) exportContext(parent context.Context) (context.Context, context
// duration to wait for if an explicit throttle time is included in err. // duration to wait for if an explicit throttle time is included in err.
func retryable(err error) (bool, time.Duration) { func retryable(err error) (bool, time.Duration) {
s := status.Convert(err) s := status.Convert(err)
return retryableGRPCStatus(s)
}
func retryableGRPCStatus(s *status.Status) (bool, time.Duration) {
switch s.Code() { switch s.Code() {
case codes.Canceled, case codes.Canceled,
codes.DeadlineExceeded, codes.DeadlineExceeded,
codes.ResourceExhausted,
codes.Aborted, codes.Aborted,
codes.OutOfRange, codes.OutOfRange,
codes.Unavailable, codes.Unavailable,
codes.DataLoss: codes.DataLoss:
return true, throttleDelay(s) // Additionally handle RetryInfo.
_, d := throttleDelay(s)
return true, d
case codes.ResourceExhausted:
// Retry only if the server signals that the recovery from resource exhaustion is possible.
return throttleDelay(s)
} }
// Not a retry-able error. // Not a retry-able error.
return false, 0 return false, 0
} }
// throttleDelay returns a duration to wait for if an explicit throttle time // throttleDelay returns of the status is RetryInfo
// is included in the response status. // and the its duration to wait for if an explicit throttle time.
func throttleDelay(s *status.Status) time.Duration { func throttleDelay(s *status.Status) (bool, time.Duration) {
for _, detail := range s.Details() { for _, detail := range s.Details() {
if t, ok := detail.(*errdetails.RetryInfo); ok { if t, ok := detail.(*errdetails.RetryInfo); ok {
return t.RetryDelay.AsDuration() return true, t.RetryDelay.AsDuration()
} }
} }
return 0 return false, 0
} }
// MarshalLog is the marshaling function used by the logging system to represent this Client. // MarshalLog is the marshaling function used by the logging system to represent this Client.

View file

@ -0,0 +1,77 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package otlptracegrpc provides an OTLP span exporter using gRPC.
By default the telemetry is sent to https://localhost:4317.
Exporter should be created using [New].
The environment variables described below can be used for configuration.
OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT (default: "https://localhost:4317") -
target to which the exporter sends telemetry.
The target syntax is defined in https://github.com/grpc/grpc/blob/master/doc/naming.md.
The value must contain a host.
The value may additionally a port, a scheme, and a path.
The value accepts "http" and "https" scheme.
The value should not contain a query string or fragment.
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT takes precedence over OTEL_EXPORTER_OTLP_ENDPOINT.
The configuration can be overridden by [WithEndpoint], [WithInsecure], [WithGRPCConn] options.
OTEL_EXPORTER_OTLP_INSECURE, OTEL_EXPORTER_OTLP_TRACES_INSECURE (default: "false") -
setting "true" disables client transport security for the exporter's gRPC connection.
You can use this only when an endpoint is provided without the http or https scheme.
OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT setting overrides
the scheme defined via OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT.
OTEL_EXPORTER_OTLP_TRACES_INSECURE takes precedence over OTEL_EXPORTER_OTLP_INSECURE.
The configuration can be overridden by [WithInsecure], [WithGRPCConn] options.
OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_HEADERS (default: none) -
key-value pairs used as gRPC metadata associated with gRPC requests.
The value is expected to be represented in a format matching to the [W3C Baggage HTTP Header Content Format],
except that additional semi-colon delimited metadata is not supported.
Example value: "key1=value1,key2=value2".
OTEL_EXPORTER_OTLP_TRACES_HEADERS takes precedence over OTEL_EXPORTER_OTLP_HEADERS.
The configuration can be overridden by [WithHeaders] option.
OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_TRACES_TIMEOUT (default: "10000") -
maximum time in milliseconds the OTLP exporter waits for each batch export.
OTEL_EXPORTER_OTLP_TRACES_TIMEOUT takes precedence over OTEL_EXPORTER_OTLP_TIMEOUT.
The configuration can be overridden by [WithTimeout] option.
OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_TRACES_COMPRESSION (default: none) -
the gRPC compressor the exporter uses.
Supported value: "gzip".
OTEL_EXPORTER_OTLP_TRACES_COMPRESSION takes precedence over OTEL_EXPORTER_OTLP_COMPRESSION.
The configuration can be overridden by [WithCompressor], [WithGRPCConn] options.
OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE (default: none) -
the filepath to the trusted certificate to use when verifying a server's TLS credentials.
OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CERTIFICATE.
The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] options.
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE (default: none) -
the filepath to the client certificate/chain trust for clients private key to use in mTLS communication in PEM format.
OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE.
The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] options.
OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY (default: none) -
the filepath to the clients private key to use in mTLS communication in PEM format.
OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY takes precedence over OTEL_EXPORTER_OTLP_CLIENT_KEY.
The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] option.
[W3C Baggage HTTP Header Content Format]: https://www.w3.org/TR/baggage/#header-content
*/
package otlptracegrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"

View file

@ -174,13 +174,13 @@ func stringToHeader(value string) map[string]string {
global.Error(errors.New("missing '="), "parse headers", "input", header) global.Error(errors.New("missing '="), "parse headers", "input", header)
continue continue
} }
name, err := url.QueryUnescape(n) name, err := url.PathUnescape(n)
if err != nil { if err != nil {
global.Error(err, "escape header key", "key", n) global.Error(err, "escape header key", "key", n)
continue continue
} }
trimmedName := strings.TrimSpace(name) trimmedName := strings.TrimSpace(name)
value, err := url.QueryUnescape(v) value, err := url.PathUnescape(v)
if err != nil { if err != nil {
global.Error(err, "escape header value", "value", v) global.Error(err, "escape header value", "value", v)
continue continue

View file

@ -141,9 +141,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
if cfg.Traces.Compression == GzipCompression { if cfg.Traces.Compression == GzipCompression {
cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
} }
if len(cfg.DialOptions) != 0 {
cfg.DialOptions = append(cfg.DialOptions, cfg.DialOptions...)
}
if cfg.ReconnectionPeriod != 0 { if cfg.ReconnectionPeriod != 0 {
p := grpc.ConnectParams{ p := grpc.ConnectParams{
Backoff: backoff.DefaultConfig, Backoff: backoff.DefaultConfig,

View file

@ -93,13 +93,7 @@ func compressorToCompression(compressor string) otlpconfig.Compression {
} }
// WithCompressor sets the compressor for the gRPC client to use when sending // WithCompressor sets the compressor for the gRPC client to use when sending
// requests. It is the responsibility of the caller to ensure that the // requests. Supported compressor values: "gzip".
// compressor set has been registered with google.golang.org/grpc/encoding.
// This can be done by encoding.RegisterCompressor. Some compressors
// auto-register on import, such as gzip, which can be registered by calling
// `import _ "google.golang.org/grpc/encoding/gzip"`.
//
// This option has no effect if WithGRPCConn is used.
func WithCompressor(compressor string) Option { func WithCompressor(compressor string) Option {
return wrappedOption{otlpconfig.WithCompression(compressorToCompression(compressor))} return wrappedOption{otlpconfig.WithCompression(compressorToCompression(compressor))}
} }

View file

@ -18,6 +18,7 @@ import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"net" "net"
@ -152,6 +153,10 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
request.reset(ctx) request.reset(ctx)
resp, err := d.client.Do(request.Request) resp, err := d.client.Do(request.Request)
var urlErr *url.Error
if errors.As(err, &urlErr) && urlErr.Temporary() {
return newResponseError(http.Header{})
}
if err != nil { if err != nil {
return err return err
} }
@ -172,8 +177,11 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
if _, err := io.Copy(&respData, resp.Body); err != nil { if _, err := io.Copy(&respData, resp.Body); err != nil {
return err return err
} }
if respData.Len() == 0 {
return nil
}
if respData.Len() != 0 { if resp.Header.Get("Content-Type") == "application/x-protobuf" {
var respProto coltracepb.ExportTraceServiceResponse var respProto coltracepb.ExportTraceServiceResponse
if err := proto.Unmarshal(respData.Bytes(), &respProto); err != nil { if err := proto.Unmarshal(respData.Bytes(), &respProto); err != nil {
return err return err
@ -190,7 +198,10 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
} }
return nil return nil
case sc == http.StatusTooManyRequests, sc == http.StatusServiceUnavailable: case sc == http.StatusTooManyRequests,
sc == http.StatusBadGateway,
sc == http.StatusServiceUnavailable,
sc == http.StatusGatewayTimeout:
// Retry-able failures. Drain the body to reuse the connection. // Retry-able failures. Drain the body to reuse the connection.
if _, err := io.Copy(io.Discard, resp.Body); err != nil { if _, err := io.Copy(io.Discard, resp.Body); err != nil {
otel.Handle(err) otel.Handle(err)

View file

@ -13,7 +13,62 @@
// limitations under the License. // limitations under the License.
/* /*
Package otlptracehttp a client that sends traces to the collector using HTTP Package otlptracehttp provides an OTLP span exporter using HTTP with protobuf payloads.
with binary protobuf payloads. By default the telemetry is sent to https://localhost:4318/v1/traces.
Exporter should be created using [New].
The environment variables described below can be used for configuration.
OTEL_EXPORTER_OTLP_ENDPOINT (default: "https://localhost:4318") -
target base URL ("/v1/traces" is appended) to which the exporter sends telemetry.
The value must contain a scheme ("http" or "https") and host.
The value may additionally contain a port and a path.
The value should not contain a query string or fragment.
The configuration can be overridden by OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
environment variable and by [WithEndpoint], [WithInsecure] options.
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT (default: "https://localhost:4318/v1/traces") -
target URL to which the exporter sends telemetry.
The value must contain a scheme ("http" or "https") and host.
The value may additionally contain a port and a path.
The value should not contain a query string or fragment.
The configuration can be overridden by [WithEndpoint], [WitnInsecure], [WithURLPath] options.
OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_HEADERS (default: none) -
key-value pairs used as headers associated with HTTP requests.
The value is expected to be represented in a format matching to the [W3C Baggage HTTP Header Content Format],
except that additional semi-colon delimited metadata is not supported.
Example value: "key1=value1,key2=value2".
OTEL_EXPORTER_OTLP_TRACES_HEADERS takes precedence over OTEL_EXPORTER_OTLP_HEADERS.
The configuration can be overridden by [WithHeaders] option.
OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_TRACES_TIMEOUT (default: "10000") -
maximum time in milliseconds the OTLP exporter waits for each batch export.
OTEL_EXPORTER_OTLP_TRACES_TIMEOUT takes precedence over OTEL_EXPORTER_OTLP_TIMEOUT.
The configuration can be overridden by [WithTimeout] option.
OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_TRACES_COMPRESSION (default: none) -
the compression strategy the exporter uses to compress the HTTP body.
Supported value: "gzip".
OTEL_EXPORTER_OTLP_TRACES_COMPRESSION takes precedence over OTEL_EXPORTER_OTLP_COMPRESSION.
The configuration can be overridden by [WithCompression] option.
OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE (default: none) -
the filepath to the trusted certificate to use when verifying a server's TLS credentials.
OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CERTIFICATE.
The configuration can be overridden by [WithTLSClientConfig] option.
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE (default: none) -
the filepath to the client certificate/chain trust for clients private key to use in mTLS communication in PEM format.
OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE.
The configuration can be overridden by [WithTLSClientConfig] option.
OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY (default: none) -
the filepath to the clients private key to use in mTLS communication in PEM format.
OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY takes precedence over OTEL_EXPORTER_OTLP_CLIENT_KEY.
The configuration can be overridden by [WithTLSClientConfig] option.
[W3C Baggage HTTP Header Content Format]: https://www.w3.org/TR/baggage/#header-content
*/ */
package otlptracehttp // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" package otlptracehttp // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"

View file

@ -174,13 +174,13 @@ func stringToHeader(value string) map[string]string {
global.Error(errors.New("missing '="), "parse headers", "input", header) global.Error(errors.New("missing '="), "parse headers", "input", header)
continue continue
} }
name, err := url.QueryUnescape(n) name, err := url.PathUnescape(n)
if err != nil { if err != nil {
global.Error(err, "escape header key", "key", n) global.Error(err, "escape header key", "key", n)
continue continue
} }
trimmedName := strings.TrimSpace(name) trimmedName := strings.TrimSpace(name)
value, err := url.QueryUnescape(v) value, err := url.PathUnescape(v)
if err != nil { if err != nil {
global.Error(err, "escape header value", "value", v) global.Error(err, "escape header value", "value", v)
continue continue

View file

@ -141,9 +141,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
if cfg.Traces.Compression == GzipCompression { if cfg.Traces.Compression == GzipCompression {
cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
} }
if len(cfg.DialOptions) != 0 {
cfg.DialOptions = append(cfg.DialOptions, cfg.DialOptions...)
}
if cfg.ReconnectionPeriod != 0 { if cfg.ReconnectionPeriod != 0 {
p := grpc.ConnectParams{ p := grpc.ConnectParams{
Backoff: backoff.DefaultConfig, Backoff: backoff.DefaultConfig,

View file

@ -16,5 +16,5 @@ package otlptrace // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace"
// Version is the current release version of the OpenTelemetry OTLP trace exporter in use. // Version is the current release version of the OpenTelemetry OTLP trace exporter in use.
func Version() string { func Version() string {
return "1.19.0" return "1.21.0"
} }

View file

@ -34,11 +34,13 @@ type afCounter struct {
name string name string
opts []metric.Float64ObservableCounterOption opts []metric.Float64ObservableCounterOption
delegate atomic.Value //metric.Float64ObservableCounter delegate atomic.Value // metric.Float64ObservableCounter
} }
var _ unwrapper = (*afCounter)(nil) var (
var _ metric.Float64ObservableCounter = (*afCounter)(nil) _ unwrapper = (*afCounter)(nil)
_ metric.Float64ObservableCounter = (*afCounter)(nil)
)
func (i *afCounter) setDelegate(m metric.Meter) { func (i *afCounter) setDelegate(m metric.Meter) {
ctr, err := m.Float64ObservableCounter(i.name, i.opts...) ctr, err := m.Float64ObservableCounter(i.name, i.opts...)
@ -63,11 +65,13 @@ type afUpDownCounter struct {
name string name string
opts []metric.Float64ObservableUpDownCounterOption opts []metric.Float64ObservableUpDownCounterOption
delegate atomic.Value //metric.Float64ObservableUpDownCounter delegate atomic.Value // metric.Float64ObservableUpDownCounter
} }
var _ unwrapper = (*afUpDownCounter)(nil) var (
var _ metric.Float64ObservableUpDownCounter = (*afUpDownCounter)(nil) _ unwrapper = (*afUpDownCounter)(nil)
_ metric.Float64ObservableUpDownCounter = (*afUpDownCounter)(nil)
)
func (i *afUpDownCounter) setDelegate(m metric.Meter) { func (i *afUpDownCounter) setDelegate(m metric.Meter) {
ctr, err := m.Float64ObservableUpDownCounter(i.name, i.opts...) ctr, err := m.Float64ObservableUpDownCounter(i.name, i.opts...)
@ -92,11 +96,13 @@ type afGauge struct {
name string name string
opts []metric.Float64ObservableGaugeOption opts []metric.Float64ObservableGaugeOption
delegate atomic.Value //metric.Float64ObservableGauge delegate atomic.Value // metric.Float64ObservableGauge
} }
var _ unwrapper = (*afGauge)(nil) var (
var _ metric.Float64ObservableGauge = (*afGauge)(nil) _ unwrapper = (*afGauge)(nil)
_ metric.Float64ObservableGauge = (*afGauge)(nil)
)
func (i *afGauge) setDelegate(m metric.Meter) { func (i *afGauge) setDelegate(m metric.Meter) {
ctr, err := m.Float64ObservableGauge(i.name, i.opts...) ctr, err := m.Float64ObservableGauge(i.name, i.opts...)
@ -121,11 +127,13 @@ type aiCounter struct {
name string name string
opts []metric.Int64ObservableCounterOption opts []metric.Int64ObservableCounterOption
delegate atomic.Value //metric.Int64ObservableCounter delegate atomic.Value // metric.Int64ObservableCounter
} }
var _ unwrapper = (*aiCounter)(nil) var (
var _ metric.Int64ObservableCounter = (*aiCounter)(nil) _ unwrapper = (*aiCounter)(nil)
_ metric.Int64ObservableCounter = (*aiCounter)(nil)
)
func (i *aiCounter) setDelegate(m metric.Meter) { func (i *aiCounter) setDelegate(m metric.Meter) {
ctr, err := m.Int64ObservableCounter(i.name, i.opts...) ctr, err := m.Int64ObservableCounter(i.name, i.opts...)
@ -150,11 +158,13 @@ type aiUpDownCounter struct {
name string name string
opts []metric.Int64ObservableUpDownCounterOption opts []metric.Int64ObservableUpDownCounterOption
delegate atomic.Value //metric.Int64ObservableUpDownCounter delegate atomic.Value // metric.Int64ObservableUpDownCounter
} }
var _ unwrapper = (*aiUpDownCounter)(nil) var (
var _ metric.Int64ObservableUpDownCounter = (*aiUpDownCounter)(nil) _ unwrapper = (*aiUpDownCounter)(nil)
_ metric.Int64ObservableUpDownCounter = (*aiUpDownCounter)(nil)
)
func (i *aiUpDownCounter) setDelegate(m metric.Meter) { func (i *aiUpDownCounter) setDelegate(m metric.Meter) {
ctr, err := m.Int64ObservableUpDownCounter(i.name, i.opts...) ctr, err := m.Int64ObservableUpDownCounter(i.name, i.opts...)
@ -179,11 +189,13 @@ type aiGauge struct {
name string name string
opts []metric.Int64ObservableGaugeOption opts []metric.Int64ObservableGaugeOption
delegate atomic.Value //metric.Int64ObservableGauge delegate atomic.Value // metric.Int64ObservableGauge
} }
var _ unwrapper = (*aiGauge)(nil) var (
var _ metric.Int64ObservableGauge = (*aiGauge)(nil) _ unwrapper = (*aiGauge)(nil)
_ metric.Int64ObservableGauge = (*aiGauge)(nil)
)
func (i *aiGauge) setDelegate(m metric.Meter) { func (i *aiGauge) setDelegate(m metric.Meter) {
ctr, err := m.Int64ObservableGauge(i.name, i.opts...) ctr, err := m.Int64ObservableGauge(i.name, i.opts...)
@ -208,7 +220,7 @@ type sfCounter struct {
name string name string
opts []metric.Float64CounterOption opts []metric.Float64CounterOption
delegate atomic.Value //metric.Float64Counter delegate atomic.Value // metric.Float64Counter
} }
var _ metric.Float64Counter = (*sfCounter)(nil) var _ metric.Float64Counter = (*sfCounter)(nil)
@ -234,7 +246,7 @@ type sfUpDownCounter struct {
name string name string
opts []metric.Float64UpDownCounterOption opts []metric.Float64UpDownCounterOption
delegate atomic.Value //metric.Float64UpDownCounter delegate atomic.Value // metric.Float64UpDownCounter
} }
var _ metric.Float64UpDownCounter = (*sfUpDownCounter)(nil) var _ metric.Float64UpDownCounter = (*sfUpDownCounter)(nil)
@ -260,7 +272,7 @@ type sfHistogram struct {
name string name string
opts []metric.Float64HistogramOption opts []metric.Float64HistogramOption
delegate atomic.Value //metric.Float64Histogram delegate atomic.Value // metric.Float64Histogram
} }
var _ metric.Float64Histogram = (*sfHistogram)(nil) var _ metric.Float64Histogram = (*sfHistogram)(nil)
@ -286,7 +298,7 @@ type siCounter struct {
name string name string
opts []metric.Int64CounterOption opts []metric.Int64CounterOption
delegate atomic.Value //metric.Int64Counter delegate atomic.Value // metric.Int64Counter
} }
var _ metric.Int64Counter = (*siCounter)(nil) var _ metric.Int64Counter = (*siCounter)(nil)
@ -312,7 +324,7 @@ type siUpDownCounter struct {
name string name string
opts []metric.Int64UpDownCounterOption opts []metric.Int64UpDownCounterOption
delegate atomic.Value //metric.Int64UpDownCounter delegate atomic.Value // metric.Int64UpDownCounter
} }
var _ metric.Int64UpDownCounter = (*siUpDownCounter)(nil) var _ metric.Int64UpDownCounter = (*siUpDownCounter)(nil)
@ -338,7 +350,7 @@ type siHistogram struct {
name string name string
opts []metric.Int64HistogramOption opts []metric.Int64HistogramOption
delegate atomic.Value //metric.Int64Histogram delegate atomic.Value // metric.Int64Histogram
} }
var _ metric.Int64Histogram = (*siHistogram)(nil) var _ metric.Int64Histogram = (*siHistogram)(nil)

View file

@ -39,6 +39,7 @@ import (
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
) )
// tracerProvider is a placeholder for a configured SDK TracerProvider. // tracerProvider is a placeholder for a configured SDK TracerProvider.
@ -46,6 +47,8 @@ import (
// All TracerProvider functionality is forwarded to a delegate once // All TracerProvider functionality is forwarded to a delegate once
// configured. // configured.
type tracerProvider struct { type tracerProvider struct {
embedded.TracerProvider
mtx sync.Mutex mtx sync.Mutex
tracers map[il]*tracer tracers map[il]*tracer
delegate trace.TracerProvider delegate trace.TracerProvider
@ -119,6 +122,8 @@ type il struct {
// All Tracer functionality is forwarded to a delegate once configured. // All Tracer functionality is forwarded to a delegate once configured.
// Otherwise, all functionality is forwarded to a NoopTracer. // Otherwise, all functionality is forwarded to a NoopTracer.
type tracer struct { type tracer struct {
embedded.Tracer
name string name string
opts []trace.TracerOption opts []trace.TracerOption
provider *tracerProvider provider *tracerProvider
@ -156,6 +161,8 @@ func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStart
// SpanContext. It performs no operations other than to return the wrapped // SpanContext. It performs no operations other than to return the wrapped
// SpanContext. // SpanContext.
type nonRecordingSpan struct { type nonRecordingSpan struct {
embedded.Span
sc trace.SpanContext sc trace.SpanContext
tracer *tracer tracer *tracer
} }

View file

@ -149,7 +149,7 @@ of [go.opentelemetry.io/otel/metric].
Finally, an author can embed another implementation in theirs. The embedded Finally, an author can embed another implementation in theirs. The embedded
implementation will be used for methods not defined by the author. For example, implementation will be used for methods not defined by the author. For example,
an author who want to default to silently dropping the call can use an author who wants to default to silently dropping the call can use
[go.opentelemetry.io/otel/metric/noop]: [go.opentelemetry.io/otel/metric/noop]:
import "go.opentelemetry.io/otel/metric/noop" import "go.opentelemetry.io/otel/metric/noop"

View file

@ -39,6 +39,12 @@ type InstrumentOption interface {
Float64ObservableGaugeOption Float64ObservableGaugeOption
} }
// HistogramOption applies options to histogram instruments.
type HistogramOption interface {
Int64HistogramOption
Float64HistogramOption
}
type descOpt string type descOpt string
func (o descOpt) applyFloat64Counter(c Float64CounterConfig) Float64CounterConfig { func (o descOpt) applyFloat64Counter(c Float64CounterConfig) Float64CounterConfig {
@ -171,6 +177,23 @@ func (o unitOpt) applyInt64ObservableGauge(c Int64ObservableGaugeConfig) Int64Ob
// The unit u should be defined using the appropriate [UCUM](https://ucum.org) case-sensitive code. // The unit u should be defined using the appropriate [UCUM](https://ucum.org) case-sensitive code.
func WithUnit(u string) InstrumentOption { return unitOpt(u) } func WithUnit(u string) InstrumentOption { return unitOpt(u) }
// WithExplicitBucketBoundaries sets the instrument explicit bucket boundaries.
//
// This option is considered "advisory", and may be ignored by API implementations.
func WithExplicitBucketBoundaries(bounds ...float64) HistogramOption { return bucketOpt(bounds) }
type bucketOpt []float64
func (o bucketOpt) applyFloat64Histogram(c Float64HistogramConfig) Float64HistogramConfig {
c.explicitBucketBoundaries = o
return c
}
func (o bucketOpt) applyInt64Histogram(c Int64HistogramConfig) Int64HistogramConfig {
c.explicitBucketBoundaries = o
return c
}
// AddOption applies options to an addition measurement. See // AddOption applies options to an addition measurement. See
// [MeasurementOption] for other options that can be used as an AddOption. // [MeasurementOption] for other options that can be used as an AddOption.
type AddOption interface { type AddOption interface {

View file

@ -147,8 +147,9 @@ type Float64Histogram interface {
// Float64HistogramConfig contains options for synchronous counter instruments // Float64HistogramConfig contains options for synchronous counter instruments
// that record int64 values. // that record int64 values.
type Float64HistogramConfig struct { type Float64HistogramConfig struct {
description string description string
unit string unit string
explicitBucketBoundaries []float64
} }
// NewFloat64HistogramConfig returns a new [Float64HistogramConfig] with all // NewFloat64HistogramConfig returns a new [Float64HistogramConfig] with all
@ -171,6 +172,11 @@ func (c Float64HistogramConfig) Unit() string {
return c.unit return c.unit
} }
// ExplicitBucketBoundaries returns the configured explicit bucket boundaries.
func (c Float64HistogramConfig) ExplicitBucketBoundaries() []float64 {
return c.explicitBucketBoundaries
}
// Float64HistogramOption applies options to a [Float64HistogramConfig]. See // Float64HistogramOption applies options to a [Float64HistogramConfig]. See
// [InstrumentOption] for other options that can be used as a // [InstrumentOption] for other options that can be used as a
// Float64HistogramOption. // Float64HistogramOption.

View file

@ -147,8 +147,9 @@ type Int64Histogram interface {
// Int64HistogramConfig contains options for synchronous counter instruments // Int64HistogramConfig contains options for synchronous counter instruments
// that record int64 values. // that record int64 values.
type Int64HistogramConfig struct { type Int64HistogramConfig struct {
description string description string
unit string unit string
explicitBucketBoundaries []float64
} }
// NewInt64HistogramConfig returns a new [Int64HistogramConfig] with all opts // NewInt64HistogramConfig returns a new [Int64HistogramConfig] with all opts
@ -171,6 +172,11 @@ func (c Int64HistogramConfig) Unit() string {
return c.unit return c.unit
} }
// ExplicitBucketBoundaries returns the configured explicit bucket boundaries.
func (c Int64HistogramConfig) ExplicitBucketBoundaries() []float64 {
return c.explicitBucketBoundaries
}
// Int64HistogramOption applies options to a [Int64HistogramConfig]. See // Int64HistogramOption applies options to a [Int64HistogramConfig]. See
// [InstrumentOption] for other options that can be used as an // [InstrumentOption] for other options that can be used as an
// Int64HistogramOption. // Int64HistogramOption.

View file

@ -40,8 +40,10 @@ const (
// their proprietary information. // their proprietary information.
type TraceContext struct{} type TraceContext struct{}
var _ TextMapPropagator = TraceContext{} var (
var traceCtxRegExp = regexp.MustCompile("^(?P<version>[0-9a-f]{2})-(?P<traceID>[a-f0-9]{32})-(?P<spanID>[a-f0-9]{16})-(?P<traceFlags>[a-f0-9]{2})(?:-.*)?$") _ TextMapPropagator = TraceContext{}
traceCtxRegExp = regexp.MustCompile("^(?P<version>[0-9a-f]{2})-(?P<traceID>[a-f0-9]{32})-(?P<spanID>[a-f0-9]{16})-(?P<traceFlags>[a-f0-9]{2})(?:-.*)?$")
)
// Inject set tracecontext from the Context into the carrier. // Inject set tracecontext from the Context into the carrier.
func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) { func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) {

View file

@ -1 +1 @@
codespell==2.2.5 codespell==2.2.6

View file

@ -21,12 +21,10 @@ import (
"strings" "strings"
) )
var ( // ErrPartialResource is returned by a detector when complete source
// ErrPartialResource is returned by a detector when complete source // information for a Resource is unavailable or the source information
// information for a Resource is unavailable or the source information // contains invalid values that are omitted from the returned Resource.
// contains invalid values that are omitted from the returned Resource. var ErrPartialResource = errors.New("partial resource")
ErrPartialResource = errors.New("partial resource")
)
// Detector detects OpenTelemetry resource information. // Detector detects OpenTelemetry resource information.
type Detector interface { type Detector interface {

View file

@ -28,16 +28,14 @@ import (
const ( const (
// resourceAttrKey is the environment variable name OpenTelemetry Resource information will be read from. // resourceAttrKey is the environment variable name OpenTelemetry Resource information will be read from.
resourceAttrKey = "OTEL_RESOURCE_ATTRIBUTES" resourceAttrKey = "OTEL_RESOURCE_ATTRIBUTES" //nolint:gosec // False positive G101: Potential hardcoded credentials
// svcNameKey is the environment variable name that Service Name information will be read from. // svcNameKey is the environment variable name that Service Name information will be read from.
svcNameKey = "OTEL_SERVICE_NAME" svcNameKey = "OTEL_SERVICE_NAME"
) )
var ( // errMissingValue is returned when a resource value is missing.
// errMissingValue is returned when a resource value is missing. var errMissingValue = fmt.Errorf("%w: missing value", ErrPartialResource)
errMissingValue = fmt.Errorf("%w: missing value", ErrPartialResource)
)
// fromEnv is a Detector that implements the Detector and collects // fromEnv is a Detector that implements the Detector and collects
// resources from environment. This Detector is included as a // resources from environment. This Detector is included as a
@ -91,7 +89,7 @@ func constructOTResources(s string) (*Resource, error) {
continue continue
} }
key := strings.TrimSpace(k) key := strings.TrimSpace(k)
val, err := url.QueryUnescape(strings.TrimSpace(v)) val, err := url.PathUnescape(strings.TrimSpace(v))
if err != nil { if err != nil {
// Retain original value if decoding fails, otherwise it will be // Retain original value if decoding fails, otherwise it will be
// an empty string. // an empty string.

View file

@ -36,8 +36,10 @@ func setOSDescriptionProvider(osDescriptionProvider osDescriptionProvider) {
osDescription = osDescriptionProvider osDescription = osDescriptionProvider
} }
type osTypeDetector struct{} type (
type osDescriptionDetector struct{} osTypeDetector struct{}
osDescriptionDetector struct{}
)
// Detect returns a *Resource that describes the operating system type the // Detect returns a *Resource that describes the operating system type the
// service is running on. // service is running on.
@ -56,7 +58,6 @@ func (osTypeDetector) Detect(ctx context.Context) (*Resource, error) {
// service is running on. // service is running on.
func (osDescriptionDetector) Detect(ctx context.Context) (*Resource, error) { func (osDescriptionDetector) Detect(ctx context.Context) (*Resource, error) {
description, err := osDescription() description, err := osDescription()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -25,14 +25,16 @@ import (
semconv "go.opentelemetry.io/otel/semconv/v1.21.0" semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
) )
type pidProvider func() int type (
type executablePathProvider func() (string, error) pidProvider func() int
type commandArgsProvider func() []string executablePathProvider func() (string, error)
type ownerProvider func() (*user.User, error) commandArgsProvider func() []string
type runtimeNameProvider func() string ownerProvider func() (*user.User, error)
type runtimeVersionProvider func() string runtimeNameProvider func() string
type runtimeOSProvider func() string runtimeVersionProvider func() string
type runtimeArchProvider func() string runtimeOSProvider func() string
runtimeArchProvider func() string
)
var ( var (
defaultPidProvider pidProvider = os.Getpid defaultPidProvider pidProvider = os.Getpid
@ -108,14 +110,16 @@ func setUserProviders(ownerProvider ownerProvider) {
owner = ownerProvider owner = ownerProvider
} }
type processPIDDetector struct{} type (
type processExecutableNameDetector struct{} processPIDDetector struct{}
type processExecutablePathDetector struct{} processExecutableNameDetector struct{}
type processCommandArgsDetector struct{} processExecutablePathDetector struct{}
type processOwnerDetector struct{} processCommandArgsDetector struct{}
type processRuntimeNameDetector struct{} processOwnerDetector struct{}
type processRuntimeVersionDetector struct{} processRuntimeNameDetector struct{}
type processRuntimeDescriptionDetector struct{} processRuntimeVersionDetector struct{}
processRuntimeDescriptionDetector struct{}
)
// Detect returns a *Resource that describes the process identifier (PID) of the // Detect returns a *Resource that describes the process identifier (PID) of the
// executing process. // executing process.

View file

@ -25,6 +25,8 @@ import (
"go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
"go.opentelemetry.io/otel/trace/noop"
) )
const ( const (
@ -73,6 +75,8 @@ func (cfg tracerProviderConfig) MarshalLog() interface{} {
// TracerProvider is an OpenTelemetry TracerProvider. It provides Tracers to // TracerProvider is an OpenTelemetry TracerProvider. It provides Tracers to
// instrumentation so it can trace operational flow through a system. // instrumentation so it can trace operational flow through a system.
type TracerProvider struct { type TracerProvider struct {
embedded.TracerProvider
mu sync.Mutex mu sync.Mutex
namedTracer map[instrumentation.Scope]*tracer namedTracer map[instrumentation.Scope]*tracer
spanProcessors atomic.Pointer[spanProcessorStates] spanProcessors atomic.Pointer[spanProcessorStates]
@ -139,7 +143,7 @@ func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider {
func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
// This check happens before the mutex is acquired to avoid deadlocking if Tracer() is called from within Shutdown(). // This check happens before the mutex is acquired to avoid deadlocking if Tracer() is called from within Shutdown().
if p.isShutdown.Load() { if p.isShutdown.Load() {
return trace.NewNoopTracerProvider().Tracer(name, opts...) return noop.NewTracerProvider().Tracer(name, opts...)
} }
c := trace.NewTracerConfig(opts...) c := trace.NewTracerConfig(opts...)
if name == "" { if name == "" {
@ -157,7 +161,7 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T
// Must check the flag after acquiring the mutex to avoid returning a valid tracer if Shutdown() ran // Must check the flag after acquiring the mutex to avoid returning a valid tracer if Shutdown() ran
// after the first check above but before we acquired the mutex. // after the first check above but before we acquired the mutex.
if p.isShutdown.Load() { if p.isShutdown.Load() {
return trace.NewNoopTracerProvider().Tracer(name, opts...), true return noop.NewTracerProvider().Tracer(name, opts...), true
} }
t, ok := p.namedTracer[is] t, ok := p.namedTracer[is]
if !ok { if !ok {

View file

@ -158,9 +158,9 @@ func NeverSample() Sampler {
return alwaysOffSampler{} return alwaysOffSampler{}
} }
// ParentBased returns a composite sampler which behaves differently, // ParentBased returns a sampler decorator which behaves differently,
// based on the parent of the span. If the span has no parent, // based on the parent of the span. If the span has no parent,
// the root(Sampler) is used to make sampling decision. If the span has // the decorated sampler is used to make sampling decision. If the span has
// a parent, depending on whether the parent is remote and whether it // a parent, depending on whether the parent is remote and whether it
// is sampled, one of the following samplers will apply: // is sampled, one of the following samplers will apply:
// - remoteParentSampled(Sampler) (default: AlwaysOn) // - remoteParentSampled(Sampler) (default: AlwaysOn)

View file

@ -32,6 +32,7 @@ import (
"go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0" semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
) )
// ReadOnlySpan allows reading information from the data structure underlying a // ReadOnlySpan allows reading information from the data structure underlying a
@ -108,6 +109,8 @@ type ReadWriteSpan interface {
// recordingSpan is an implementation of the OpenTelemetry Span API // recordingSpan is an implementation of the OpenTelemetry Span API
// representing the individual component of a trace that is sampled. // representing the individual component of a trace that is sampled.
type recordingSpan struct { type recordingSpan struct {
embedded.Span
// mu protects the contents of this span. // mu protects the contents of this span.
mu sync.Mutex mu sync.Mutex
@ -158,8 +161,10 @@ type recordingSpan struct {
tracer *tracer tracer *tracer
} }
var _ ReadWriteSpan = (*recordingSpan)(nil) var (
var _ runtimeTracer = (*recordingSpan)(nil) _ ReadWriteSpan = (*recordingSpan)(nil)
_ runtimeTracer = (*recordingSpan)(nil)
)
// SpanContext returns the SpanContext of this span. // SpanContext returns the SpanContext of this span.
func (s *recordingSpan) SpanContext() trace.SpanContext { func (s *recordingSpan) SpanContext() trace.SpanContext {
@ -772,6 +777,8 @@ func (s *recordingSpan) runtimeTrace(ctx context.Context) context.Context {
// that wraps a SpanContext. It performs no operations other than to return // that wraps a SpanContext. It performs no operations other than to return
// the wrapped SpanContext or TracerProvider that created it. // the wrapped SpanContext or TracerProvider that created it.
type nonRecordingSpan struct { type nonRecordingSpan struct {
embedded.Span
// tracer is the SDK tracer that created this span. // tracer is the SDK tracer that created this span.
tracer *tracer tracer *tracer
sc trace.SpanContext sc trace.SpanContext

View file

@ -20,9 +20,12 @@ import (
"go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
) )
type tracer struct { type tracer struct {
embedded.Tracer
provider *TracerProvider provider *TracerProvider
instrumentationScope instrumentation.Scope instrumentationScope instrumentation.Scope
} }

View file

@ -162,6 +162,7 @@ func (s spanSnapshot) Resource() *resource.Resource { return s.resource }
func (s spanSnapshot) InstrumentationScope() instrumentation.Scope { func (s spanSnapshot) InstrumentationScope() instrumentation.Scope {
return s.instrumentationScope return s.instrumentationScope
} }
func (s spanSnapshot) InstrumentationLibrary() instrumentation.Library { func (s spanSnapshot) InstrumentationLibrary() instrumentation.Library {
return s.instrumentationScope return s.instrumentationScope
} }

View file

@ -16,5 +16,5 @@ package sdk // import "go.opentelemetry.io/otel/sdk"
// Version is the current release version of the OpenTelemetry SDK in use. // Version is the current release version of the OpenTelemetry SDK in use.
func Version() string { func Version() string {
return "1.19.0" return "1.21.0"
} }

View file

@ -268,6 +268,7 @@ func (o stackTraceOption) applyEvent(c EventConfig) EventConfig {
c.stackTrace = bool(o) c.stackTrace = bool(o)
return c return c
} }
func (o stackTraceOption) applySpan(c SpanConfig) SpanConfig { func (o stackTraceOption) applySpan(c SpanConfig) SpanConfig {
c.stackTrace = bool(o) c.stackTrace = bool(o)
return c return c

View file

@ -62,5 +62,69 @@ a default.
defer span.End() defer span.End()
// ... // ...
} }
# API Implementations
This package does not conform to the standard Go versioning policy; all of its
interfaces may have methods added to them without a package major version bump.
This non-standard API evolution could surprise an uninformed implementation
author. They could unknowingly build their implementation in a way that would
result in a runtime panic for their users that update to the new API.
The API is designed to help inform an instrumentation author about this
non-standard API evolution. It requires them to choose a default behavior for
unimplemented interface methods. There are three behavior choices they can
make:
- Compilation failure
- Panic
- Default to another implementation
All interfaces in this API embed a corresponding interface from
[go.opentelemetry.io/otel/trace/embedded]. If an author wants the default
behavior of their implementations to be a compilation failure, signaling to
their users they need to update to the latest version of that implementation,
they need to embed the corresponding interface from
[go.opentelemetry.io/otel/trace/embedded] in their implementation. For
example,
import "go.opentelemetry.io/otel/trace/embedded"
type TracerProvider struct {
embedded.TracerProvider
// ...
}
If an author wants the default behavior of their implementations to panic, they
can embed the API interface directly.
import "go.opentelemetry.io/otel/trace"
type TracerProvider struct {
trace.TracerProvider
// ...
}
This option is not recommended. It will lead to publishing packages that
contain runtime panics when users update to newer versions of
[go.opentelemetry.io/otel/trace], which may be done with a trasitive
dependency.
Finally, an author can embed another implementation in theirs. The embedded
implementation will be used for methods not defined by the author. For example,
an author who wants to default to silently dropping the call can use
[go.opentelemetry.io/otel/trace/noop]:
import "go.opentelemetry.io/otel/trace/noop"
type TracerProvider struct {
noop.TracerProvider
// ...
}
It is strongly recommended that authors only embed
[go.opentelemetry.io/otel/trace/noop] if they choose this default behavior.
That implementation is the only one OpenTelemetry authors can guarantee will
fully implement all the API interfaces when a user updates their API.
*/ */
package trace // import "go.opentelemetry.io/otel/trace" package trace // import "go.opentelemetry.io/otel/trace"

View file

@ -0,0 +1,56 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package embedded provides interfaces embedded within the [OpenTelemetry
// trace API].
//
// Implementers of the [OpenTelemetry trace API] can embed the relevant type
// from this package into their implementation directly. Doing so will result
// in a compilation error for users when the [OpenTelemetry trace API] is
// extended (which is something that can happen without a major version bump of
// the API package).
//
// [OpenTelemetry trace API]: https://pkg.go.dev/go.opentelemetry.io/otel/trace
package embedded // import "go.opentelemetry.io/otel/trace/embedded"
// TracerProvider is embedded in
// [go.opentelemetry.io/otel/trace.TracerProvider].
//
// Embed this interface in your implementation of the
// [go.opentelemetry.io/otel/trace.TracerProvider] if you want users to
// experience a compilation error, signaling they need to update to your latest
// implementation, when the [go.opentelemetry.io/otel/trace.TracerProvider]
// interface is extended (which is something that can happen without a major
// version bump of the API package).
type TracerProvider interface{ tracerProvider() }
// Tracer is embedded in [go.opentelemetry.io/otel/trace.Tracer].
//
// Embed this interface in your implementation of the
// [go.opentelemetry.io/otel/trace.Tracer] if you want users to experience a
// compilation error, signaling they need to update to your latest
// implementation, when the [go.opentelemetry.io/otel/trace.Tracer] interface
// is extended (which is something that can happen without a major version bump
// of the API package).
type Tracer interface{ tracer() }
// Span is embedded in [go.opentelemetry.io/otel/trace.Span].
//
// Embed this interface in your implementation of the
// [go.opentelemetry.io/otel/trace.Span] if you want users to experience a
// compilation error, signaling they need to update to your latest
// implementation, when the [go.opentelemetry.io/otel/trace.Span] interface is
// extended (which is something that can happen without a major version bump of
// the API package).
type Span interface{ span() }

View file

@ -19,16 +19,20 @@ import (
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace/embedded"
) )
// NewNoopTracerProvider returns an implementation of TracerProvider that // NewNoopTracerProvider returns an implementation of TracerProvider that
// performs no operations. The Tracer and Spans created from the returned // performs no operations. The Tracer and Spans created from the returned
// TracerProvider also perform no operations. // TracerProvider also perform no operations.
//
// Deprecated: Use [go.opentelemetry.io/otel/trace/noop.NewTracerProvider]
// instead.
func NewNoopTracerProvider() TracerProvider { func NewNoopTracerProvider() TracerProvider {
return noopTracerProvider{} return noopTracerProvider{}
} }
type noopTracerProvider struct{} type noopTracerProvider struct{ embedded.TracerProvider }
var _ TracerProvider = noopTracerProvider{} var _ TracerProvider = noopTracerProvider{}
@ -38,7 +42,7 @@ func (p noopTracerProvider) Tracer(string, ...TracerOption) Tracer {
} }
// noopTracer is an implementation of Tracer that performs no operations. // noopTracer is an implementation of Tracer that performs no operations.
type noopTracer struct{} type noopTracer struct{ embedded.Tracer }
var _ Tracer = noopTracer{} var _ Tracer = noopTracer{}
@ -54,7 +58,7 @@ func (t noopTracer) Start(ctx context.Context, name string, _ ...SpanStartOption
} }
// noopSpan is an implementation of Span that performs no operations. // noopSpan is an implementation of Span that performs no operations.
type noopSpan struct{} type noopSpan struct{ embedded.Span }
var _ Span = noopSpan{} var _ Span = noopSpan{}

118
vendor/go.opentelemetry.io/otel/trace/noop/noop.go generated vendored Normal file
View file

@ -0,0 +1,118 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package noop provides an implementation of the OpenTelemetry trace API that
// produces no telemetry and minimizes used computation resources.
//
// Using this package to implement the OpenTelemetry trace API will effectively
// disable OpenTelemetry.
//
// This implementation can be embedded in other implementations of the
// OpenTelemetry trace API. Doing so will mean the implementation defaults to
// no operation for methods it does not implement.
package noop // import "go.opentelemetry.io/otel/trace/noop"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
)
var (
// Compile-time check this implements the OpenTelemetry API.
_ trace.TracerProvider = TracerProvider{}
_ trace.Tracer = Tracer{}
_ trace.Span = Span{}
)
// TracerProvider is an OpenTelemetry No-Op TracerProvider.
type TracerProvider struct{ embedded.TracerProvider }
// NewTracerProvider returns a TracerProvider that does not record any telemetry.
func NewTracerProvider() TracerProvider {
return TracerProvider{}
}
// Tracer returns an OpenTelemetry Tracer that does not record any telemetry.
func (TracerProvider) Tracer(string, ...trace.TracerOption) trace.Tracer {
return Tracer{}
}
// Tracer is an OpenTelemetry No-Op Tracer.
type Tracer struct{ embedded.Tracer }
// Start creates a span. The created span will be set in a child context of ctx
// and returned with the span.
//
// If ctx contains a span context, the returned span will also contain that
// span context. If the span context in ctx is for a non-recording span, that
// span instance will be returned directly.
func (t Tracer) Start(ctx context.Context, _ string, _ ...trace.SpanStartOption) (context.Context, trace.Span) {
span := trace.SpanFromContext(ctx)
// If the parent context contains a non-zero span context, that span
// context needs to be returned as a non-recording span
// (https://github.com/open-telemetry/opentelemetry-specification/blob/3a1dde966a4ce87cce5adf464359fe369741bbea/specification/trace/api.md#behavior-of-the-api-in-the-absence-of-an-installed-sdk).
var zeroSC trace.SpanContext
if sc := span.SpanContext(); !sc.Equal(zeroSC) {
if !span.IsRecording() {
// If the span is not recording return it directly.
return ctx, span
}
// Otherwise, return the span context needs in a non-recording span.
span = Span{sc: sc}
} else {
// No parent, return a No-Op span with an empty span context.
span = Span{}
}
return trace.ContextWithSpan(ctx, span), span
}
// Span is an OpenTelemetry No-Op Span.
type Span struct {
embedded.Span
sc trace.SpanContext
}
// SpanContext returns an empty span context.
func (s Span) SpanContext() trace.SpanContext { return s.sc }
// IsRecording always returns false.
func (Span) IsRecording() bool { return false }
// SetStatus does nothing.
func (Span) SetStatus(codes.Code, string) {}
// SetAttributes does nothing.
func (Span) SetAttributes(...attribute.KeyValue) {}
// End does nothing.
func (Span) End(...trace.SpanEndOption) {}
// RecordError does nothing.
func (Span) RecordError(error, ...trace.EventOption) {}
// AddEvent does nothing.
func (Span) AddEvent(string, ...trace.EventOption) {}
// SetName does nothing.
func (Span) SetName(string) {}
// TracerProvider returns a No-Op TracerProvider.
func (Span) TracerProvider() trace.TracerProvider { return TracerProvider{} }

View file

@ -22,6 +22,7 @@ import (
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace/embedded"
) )
const ( const (
@ -48,8 +49,10 @@ func (e errorConst) Error() string {
// nolint:revive // revive complains about stutter of `trace.TraceID`. // nolint:revive // revive complains about stutter of `trace.TraceID`.
type TraceID [16]byte type TraceID [16]byte
var nilTraceID TraceID var (
var _ json.Marshaler = nilTraceID nilTraceID TraceID
_ json.Marshaler = nilTraceID
)
// IsValid checks whether the trace TraceID is valid. A valid trace ID does // IsValid checks whether the trace TraceID is valid. A valid trace ID does
// not consist of zeros only. // not consist of zeros only.
@ -71,8 +74,10 @@ func (t TraceID) String() string {
// SpanID is a unique identity of a span in a trace. // SpanID is a unique identity of a span in a trace.
type SpanID [8]byte type SpanID [8]byte
var nilSpanID SpanID var (
var _ json.Marshaler = nilSpanID nilSpanID SpanID
_ json.Marshaler = nilSpanID
)
// IsValid checks whether the SpanID is valid. A valid SpanID does not consist // IsValid checks whether the SpanID is valid. A valid SpanID does not consist
// of zeros only. // of zeros only.
@ -338,8 +343,15 @@ func (sc SpanContext) MarshalJSON() ([]byte, error) {
// create a Span and it is then up to the operation the Span represents to // create a Span and it is then up to the operation the Span represents to
// properly end the Span when the operation itself ends. // properly end the Span when the operation itself ends.
// //
// Warning: methods may be added to this interface in minor releases. // Warning: Methods may be added to this interface in minor releases. See
// package documentation on API implementation for information on how to set
// default behavior for unimplemented methods.
type Span interface { type Span interface {
// Users of the interface can ignore this. This embedded type is only used
// by implementations of this interface. See the "API Implementations"
// section of the package documentation for more information.
embedded.Span
// End completes the Span. The Span is considered complete and ready to be // End completes the Span. The Span is considered complete and ready to be
// delivered through the rest of the telemetry pipeline after this method // delivered through the rest of the telemetry pipeline after this method
// is called. Therefore, updates to the Span are not allowed after this // is called. Therefore, updates to the Span are not allowed after this
@ -486,8 +498,15 @@ func (sk SpanKind) String() string {
// Tracer is the creator of Spans. // Tracer is the creator of Spans.
// //
// Warning: methods may be added to this interface in minor releases. // Warning: Methods may be added to this interface in minor releases. See
// package documentation on API implementation for information on how to set
// default behavior for unimplemented methods.
type Tracer interface { type Tracer interface {
// Users of the interface can ignore this. This embedded type is only used
// by implementations of this interface. See the "API Implementations"
// section of the package documentation for more information.
embedded.Tracer
// Start creates a span and a context.Context containing the newly-created span. // Start creates a span and a context.Context containing the newly-created span.
// //
// If the context.Context provided in `ctx` contains a Span then the newly-created // If the context.Context provided in `ctx` contains a Span then the newly-created
@ -518,8 +537,15 @@ type Tracer interface {
// at runtime from its users or it can simply use the globally registered one // at runtime from its users or it can simply use the globally registered one
// (see https://pkg.go.dev/go.opentelemetry.io/otel#GetTracerProvider). // (see https://pkg.go.dev/go.opentelemetry.io/otel#GetTracerProvider).
// //
// Warning: methods may be added to this interface in minor releases. // Warning: Methods may be added to this interface in minor releases. See
// package documentation on API implementation for information on how to set
// default behavior for unimplemented methods.
type TracerProvider interface { type TracerProvider interface {
// Users of the interface can ignore this. This embedded type is only used
// by implementations of this interface. See the "API Implementations"
// section of the package documentation for more information.
embedded.TracerProvider
// Tracer returns a unique Tracer scoped to be used by instrumentation code // Tracer returns a unique Tracer scoped to be used by instrumentation code
// to trace computational workflows. The scope and identity of that // to trace computational workflows. The scope and identity of that
// instrumentation code is uniquely defined by the name and options passed. // instrumentation code is uniquely defined by the name and options passed.

View file

@ -28,9 +28,9 @@ const (
// based on the W3C Trace Context specification, see // based on the W3C Trace Context specification, see
// https://www.w3.org/TR/trace-context-1/#tracestate-header // https://www.w3.org/TR/trace-context-1/#tracestate-header
noTenantKeyFormat = `[a-z][_0-9a-z\-\*\/]{0,255}` noTenantKeyFormat = `[a-z][_0-9a-z\-\*\/]*`
withTenantKeyFormat = `[a-z0-9][_0-9a-z\-\*\/]{0,240}@[a-z][_0-9a-z\-\*\/]{0,13}` withTenantKeyFormat = `[a-z0-9][_0-9a-z\-\*\/]*@[a-z][_0-9a-z\-\*\/]*`
valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]{0,255}[\x21-\x2b\x2d-\x3c\x3e-\x7e]` valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]*[\x21-\x2b\x2d-\x3c\x3e-\x7e]`
errInvalidKey errorConst = "invalid tracestate key" errInvalidKey errorConst = "invalid tracestate key"
errInvalidValue errorConst = "invalid tracestate value" errInvalidValue errorConst = "invalid tracestate value"
@ -40,9 +40,10 @@ const (
) )
var ( var (
keyRe = regexp.MustCompile(`^((` + noTenantKeyFormat + `)|(` + withTenantKeyFormat + `))$`) noTenantKeyRe = regexp.MustCompile(`^` + noTenantKeyFormat + `$`)
valueRe = regexp.MustCompile(`^(` + valueFormat + `)$`) withTenantKeyRe = regexp.MustCompile(`^` + withTenantKeyFormat + `$`)
memberRe = regexp.MustCompile(`^\s*((` + noTenantKeyFormat + `)|(` + withTenantKeyFormat + `))=(` + valueFormat + `)\s*$`) valueRe = regexp.MustCompile(`^` + valueFormat + `$`)
memberRe = regexp.MustCompile(`^\s*((?:` + noTenantKeyFormat + `)|(?:` + withTenantKeyFormat + `))=(` + valueFormat + `)\s*$`)
) )
type member struct { type member struct {
@ -51,10 +52,19 @@ type member struct {
} }
func newMember(key, value string) (member, error) { func newMember(key, value string) (member, error) {
if !keyRe.MatchString(key) { if len(key) > 256 {
return member{}, fmt.Errorf("%w: %s", errInvalidKey, key) return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
} }
if !valueRe.MatchString(value) { if !noTenantKeyRe.MatchString(key) {
if !withTenantKeyRe.MatchString(key) {
return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
}
atIndex := strings.LastIndex(key, "@")
if atIndex > 241 || len(key)-1-atIndex > 14 {
return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
}
}
if len(value) > 256 || !valueRe.MatchString(value) {
return member{}, fmt.Errorf("%w: %s", errInvalidValue, value) return member{}, fmt.Errorf("%w: %s", errInvalidValue, value)
} }
return member{Key: key, Value: value}, nil return member{Key: key, Value: value}, nil
@ -62,14 +72,14 @@ func newMember(key, value string) (member, error) {
func parseMember(m string) (member, error) { func parseMember(m string) (member, error) {
matches := memberRe.FindStringSubmatch(m) matches := memberRe.FindStringSubmatch(m)
if len(matches) != 5 { if len(matches) != 3 {
return member{}, fmt.Errorf("%w: %s", errInvalidMember, m) return member{}, fmt.Errorf("%w: %s", errInvalidMember, m)
} }
result, e := newMember(matches[1], matches[2])
return member{ if e != nil {
Key: matches[1], return member{}, fmt.Errorf("%w: %s", errInvalidMember, m)
Value: matches[4], }
}, nil return result, nil
} }
// String encodes member into a string compliant with the W3C Trace Context // String encodes member into a string compliant with the W3C Trace Context

View file

@ -16,5 +16,5 @@ package otel // import "go.opentelemetry.io/otel"
// Version is the current release version of OpenTelemetry in use. // Version is the current release version of OpenTelemetry in use.
func Version() string { func Version() string {
return "1.19.0" return "1.21.0"
} }

View file

@ -14,13 +14,12 @@
module-sets: module-sets:
stable-v1: stable-v1:
version: v1.19.0 version: v1.21.0
modules: modules:
- go.opentelemetry.io/otel - go.opentelemetry.io/otel
- go.opentelemetry.io/otel/bridge/opentracing - go.opentelemetry.io/otel/bridge/opentracing
- go.opentelemetry.io/otel/bridge/opentracing/test - go.opentelemetry.io/otel/bridge/opentracing/test
- go.opentelemetry.io/otel/example/dice - go.opentelemetry.io/otel/example/dice
- go.opentelemetry.io/otel/example/fib
- go.opentelemetry.io/otel/example/namedtracer - go.opentelemetry.io/otel/example/namedtracer
- go.opentelemetry.io/otel/example/otel-collector - go.opentelemetry.io/otel/example/otel-collector
- go.opentelemetry.io/otel/example/passthrough - go.opentelemetry.io/otel/example/passthrough
@ -35,14 +34,12 @@ module-sets:
- go.opentelemetry.io/otel/sdk/metric - go.opentelemetry.io/otel/sdk/metric
- go.opentelemetry.io/otel/trace - go.opentelemetry.io/otel/trace
experimental-metrics: experimental-metrics:
version: v0.42.0 version: v0.44.0
modules: modules:
- go.opentelemetry.io/otel/bridge/opencensus - go.opentelemetry.io/otel/bridge/opencensus
- go.opentelemetry.io/otel/bridge/opencensus/test - go.opentelemetry.io/otel/bridge/opencensus/test
- go.opentelemetry.io/otel/example/opencensus - go.opentelemetry.io/otel/example/opencensus
- go.opentelemetry.io/otel/example/prometheus - go.opentelemetry.io/otel/example/prometheus
- go.opentelemetry.io/otel/example/view
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
- go.opentelemetry.io/otel/exporters/prometheus - go.opentelemetry.io/otel/exporters/prometheus

28
vendor/modules.txt vendored
View file

@ -1160,19 +1160,19 @@ go.opencensus.io/trace
go.opencensus.io/trace/internal go.opencensus.io/trace/internal
go.opencensus.io/trace/propagation go.opencensus.io/trace/propagation
go.opencensus.io/trace/tracestate go.opencensus.io/trace/tracestate
# go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 # go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1
## explicit; go 1.19 ## explicit; go 1.20
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc 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/google.golang.org/grpc/otelgrpc/internal
# go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 # go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1
## explicit; go 1.19 ## explicit; go 1.20
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/internal/semconvutil go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/internal/semconvutil
# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 # go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1
## explicit; go 1.19 ## explicit; go 1.20
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil
# go.opentelemetry.io/otel v1.19.0 # go.opentelemetry.io/otel v1.21.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel go.opentelemetry.io/otel
go.opentelemetry.io/otel/attribute go.opentelemetry.io/otel/attribute
@ -1185,29 +1185,29 @@ go.opentelemetry.io/otel/internal/global
go.opentelemetry.io/otel/propagation go.opentelemetry.io/otel/propagation
go.opentelemetry.io/otel/semconv/v1.17.0 go.opentelemetry.io/otel/semconv/v1.17.0
go.opentelemetry.io/otel/semconv/v1.21.0 go.opentelemetry.io/otel/semconv/v1.21.0
# go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 # go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel/exporters/otlp/otlptrace go.opentelemetry.io/otel/exporters/otlp/otlptrace
go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform
# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 # go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/envconfig go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/envconfig
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig 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/retry
# go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 # go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/envconfig go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/envconfig
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry
# go.opentelemetry.io/otel/metric v1.19.0 # go.opentelemetry.io/otel/metric v1.21.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel/metric go.opentelemetry.io/otel/metric
go.opentelemetry.io/otel/metric/embedded go.opentelemetry.io/otel/metric/embedded
# go.opentelemetry.io/otel/sdk v1.19.0 # go.opentelemetry.io/otel/sdk v1.21.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel/sdk go.opentelemetry.io/otel/sdk
go.opentelemetry.io/otel/sdk/instrumentation go.opentelemetry.io/otel/sdk/instrumentation
@ -1216,9 +1216,11 @@ go.opentelemetry.io/otel/sdk/internal/env
go.opentelemetry.io/otel/sdk/resource go.opentelemetry.io/otel/sdk/resource
go.opentelemetry.io/otel/sdk/trace go.opentelemetry.io/otel/sdk/trace
go.opentelemetry.io/otel/sdk/trace/tracetest go.opentelemetry.io/otel/sdk/trace/tracetest
# go.opentelemetry.io/otel/trace v1.19.0 # go.opentelemetry.io/otel/trace v1.21.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel/trace go.opentelemetry.io/otel/trace
go.opentelemetry.io/otel/trace/embedded
go.opentelemetry.io/otel/trace/noop
# go.opentelemetry.io/proto/otlp v1.0.0 # go.opentelemetry.io/proto/otlp v1.0.0
## explicit; go 1.17 ## explicit; go 1.17
go.opentelemetry.io/proto/otlp/collector/trace/v1 go.opentelemetry.io/proto/otlp/collector/trace/v1