Merge pull request #2281 from crazy-max/update-buildkit

vendor: github.com/moby/buildkit v0.13.0-rc2
This commit is contained in:
Tõnis Tiigi 2024-02-25 22:19:45 -08:00 committed by GitHub
commit 5723ceefb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
89 changed files with 1427 additions and 575 deletions

26
go.mod
View File

@ -24,7 +24,7 @@ require (
github.com/google/uuid v1.5.0 github.com/google/uuid v1.5.0
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992 github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992
github.com/hashicorp/hcl/v2 v2.19.1 github.com/hashicorp/hcl/v2 v2.19.1
github.com/moby/buildkit v0.13.0-rc1.0.20240222164755-8e3fe35738c2 // master (v0.13.0-dev) github.com/moby/buildkit v0.13.0-rc2
github.com/moby/sys/mountinfo v0.7.1 github.com/moby/sys/mountinfo v0.7.1
github.com/moby/sys/signal v0.7.0 github.com/moby/sys/signal v0.7.0
github.com/morikuni/aec v1.0.0 github.com/morikuni/aec v1.0.0
@ -38,13 +38,13 @@ require (
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/zclconf/go-cty v1.14.1 github.com/zclconf/go-cty v1.14.1
go.opentelemetry.io/otel v1.19.0 go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0
go.opentelemetry.io/otel/metric v1.19.0 go.opentelemetry.io/otel/metric v1.21.0
go.opentelemetry.io/otel/sdk v1.19.0 go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/sdk/metric v1.19.0 go.opentelemetry.io/otel/sdk/metric v1.21.0
go.opentelemetry.io/otel/trace v1.19.0 go.opentelemetry.io/otel/trace v1.21.0
golang.org/x/mod v0.14.0 golang.org/x/mod v0.14.0
golang.org/x/sync v0.5.0 golang.org/x/sync v0.5.0
golang.org/x/sys v0.16.0 golang.org/x/sys v0.16.0
@ -140,19 +140,19 @@ require (
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/theupdateframework/notary v0.7.0 // indirect github.com/theupdateframework/notary v0.7.0 // indirect
github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302 // indirect github.com/tonistiigi/fsutil v0.0.0-20240223190444-7a889f53dbf6 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // 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/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // 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/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.42.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.42.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/crypto v0.17.0 // indirect golang.org/x/crypto v0.17.0 // indirect

56
go.sum
View File

@ -311,8 +311,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/buildkit v0.13.0-rc1.0.20240222164755-8e3fe35738c2 h1:e3FYb+yyx1SM1w4Mjn8L9WP5h/6u23P/xCAPZXx4m2Y= github.com/moby/buildkit v0.13.0-rc2 h1:LWAIkaBIoRTne57NJCnFMdFV30auPia3j9UUZeUc24A=
github.com/moby/buildkit v0.13.0-rc1.0.20240222164755-8e3fe35738c2/go.mod h1:XaLDo1L55QqXS/04FE91+mAbwjkr0vZu9g6zZlzvXL8= github.com/moby/buildkit v0.13.0-rc2/go.mod h1:RWPZ1bRcehlF1bjPzj7+wOPZ5cLViAEtx5ZNQWma5/s=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
@ -450,8 +450,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c= github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw= github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302 h1:ZT8ibgassurSISJ1Pj26NsM3vY2jxFZn63Nd/TpHmRw= github.com/tonistiigi/fsutil v0.0.0-20240223190444-7a889f53dbf6 h1:v9u6pmdUkarXL/1S/6LGcG9wsiBLd9N/WyJq/Y9WPcg=
github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302/go.mod h1:9kMVqMyQ/Sx2df5LtnGG+nbrmiZzCS7V6gjW3oGHsvI= github.com/tonistiigi/fsutil v0.0.0-20240223190444-7a889f53dbf6/go.mod h1:vbbYqJlnswsbJqWUcJN8fKtBhnEgldDrcagTgnBVKKM=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk=
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 h1:Y/M5lygoNPKwVNLMPXgVfsRT40CSFKXCxuU8LoHySjs= github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 h1:Y/M5lygoNPKwVNLMPXgVfsRT40CSFKXCxuU8LoHySjs=
@ -473,41 +473,41 @@ github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA
github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
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.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.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/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU= go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU= go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0=
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.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/exporters/prometheus v0.42.0 h1:jwV9iQdvp38fxXi8ZC+lNpxjK16MRcZlpDYvbuO1FiA= go.opentelemetry.io/otel/exporters/prometheus v0.42.0 h1:jwV9iQdvp38fxXi8ZC+lNpxjK16MRcZlpDYvbuO1FiA=
go.opentelemetry.io/otel/exporters/prometheus v0.42.0/go.mod h1:f3bYiqNqhoPxkvI2LrXqQVC546K7BuRDL/kKuxkujhA= go.opentelemetry.io/otel/exporters/prometheus v0.42.0/go.mod h1:f3bYiqNqhoPxkvI2LrXqQVC546K7BuRDL/kKuxkujhA=
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.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/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k= go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0=
go.opentelemetry.io/otel/sdk/metric v1.19.0/go.mod h1:XjG0jQyFJrv2PbMvwND7LwCEhsJzCzV5210euduKcKY= go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q=
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 v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
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/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

View File

@ -102,8 +102,8 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error
if tracerProvider != nil { if tracerProvider != nil {
var propagators = propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}) var propagators = propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
unary = append(unary, filterInterceptor(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider), otelgrpc.WithPropagators(propagators)))) unary = append(unary, filterInterceptor(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider), otelgrpc.WithPropagators(propagators)))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681
stream = append(stream, otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider), otelgrpc.WithPropagators(propagators))) stream = append(stream, otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider), otelgrpc.WithPropagators(propagators))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681
} }
if needDialer { if needDialer {

View File

@ -398,6 +398,18 @@ func WithAllowWildcard(b bool) RmOption {
}) })
} }
type excludeOnCopyAction struct {
patterns []string
}
func (e *excludeOnCopyAction) SetCopyOption(i *CopyInfo) {
i.ExcludePatterns = append(i.ExcludePatterns, e.patterns...)
}
func WithExcludePatterns(patterns []string) CopyOption {
return &excludeOnCopyAction{patterns}
}
type fileActionRm struct { type fileActionRm struct {
file string file string
info RmInfo info RmInfo

View File

@ -13,6 +13,7 @@ const (
ExporterImageConfigKey = "containerimage.config" ExporterImageConfigKey = "containerimage.config"
ExporterImageConfigDigestKey = "containerimage.config.digest" ExporterImageConfigDigestKey = "containerimage.config.digest"
ExporterImageDescriptorKey = "containerimage.descriptor" ExporterImageDescriptorKey = "containerimage.descriptor"
ExporterImageBaseConfigKey = "containerimage.base.config"
ExporterPlatformsKey = "refs.platforms" ExporterPlatformsKey = "refs.platforms"
) )
@ -20,6 +21,7 @@ const (
// a platform to become platform specific // a platform to become platform specific
var KnownRefMetadataKeys = []string{ var KnownRefMetadataKeys = []string{
ExporterImageConfigKey, ExporterImageConfigKey,
ExporterImageBaseConfigKey,
} }
type Platforms struct { type Platforms struct {

View File

@ -14,7 +14,7 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
type BuildFunc func(ctx context.Context, platform *ocispecs.Platform, idx int) (client.Reference, *dockerspec.DockerOCIImage, error) type BuildFunc func(ctx context.Context, platform *ocispecs.Platform, idx int) (r client.Reference, img, baseImg *dockerspec.DockerOCIImage, err error)
func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, error) { func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, error) {
res := client.NewResult() res := client.NewResult()
@ -36,7 +36,7 @@ func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, erro
for i, tp := range targets { for i, tp := range targets {
i, tp := i, tp i, tp := i, tp
eg.Go(func() error { eg.Go(func() error {
ref, img, err := fn(ctx, tp, i) ref, img, baseImg, err := fn(ctx, tp, i)
if err != nil { if err != nil {
return err return err
} }
@ -46,6 +46,14 @@ func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, erro
return errors.Wrapf(err, "failed to marshal image config") return errors.Wrapf(err, "failed to marshal image config")
} }
var baseConfig []byte
if baseImg != nil {
baseConfig, err = json.Marshal(baseImg)
if err != nil {
return errors.Wrapf(err, "failed to marshal source image config")
}
}
p := platforms.DefaultSpec() p := platforms.DefaultSpec()
if tp != nil { if tp != nil {
p = *tp p = *tp
@ -67,9 +75,15 @@ func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, erro
if bc.MultiPlatformRequested { if bc.MultiPlatformRequested {
res.AddRef(k, ref) res.AddRef(k, ref)
res.AddMeta(fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, k), config) res.AddMeta(fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, k), config)
if len(baseConfig) > 0 {
res.AddMeta(fmt.Sprintf("%s/%s", exptypes.ExporterImageBaseConfigKey, k), baseConfig)
}
} else { } else {
res.SetRef(ref) res.SetRef(ref)
res.AddMeta(exptypes.ExporterImageConfigKey, config) res.AddMeta(exptypes.ExporterImageConfigKey, config)
if len(baseConfig) > 0 {
res.AddMeta(exptypes.ExporterImageBaseConfigKey, baseConfig)
}
} }
expPlatforms.Platforms[i] = exptypes.Platform{ expPlatforms.Platforms[i] = exptypes.Platform{
ID: k, ID: k,

View File

@ -50,8 +50,8 @@ func grpcClientConn(ctx context.Context, conn net.Conn) (context.Context, *grpc.
} }
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() { if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
unary = append(unary, filterClient(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators)))) unary = append(unary, filterClient(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators)))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681
stream = append(stream, otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators))) stream = append(stream, otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681
} }
unary = append(unary, grpcerrors.UnaryClientInterceptor) unary = append(unary, grpcerrors.UnaryClientInterceptor)

View File

@ -59,8 +59,8 @@ func NewSession(ctx context.Context, name, sharedKey string) (*Session, error) {
serverOpts := []grpc.ServerOption{} serverOpts := []grpc.ServerOption{}
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() { if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
unary = append(unary, filterServer(otelgrpc.UnaryServerInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators)))) unary = append(unary, filterServer(otelgrpc.UnaryServerInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators)))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681
stream = append(stream, otelgrpc.StreamServerInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators))) stream = append(stream, otelgrpc.StreamServerInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681
} }
unary = append(unary, grpcerrors.UnaryServerInterceptor) unary = append(unary, grpcerrors.UnaryServerInterceptor)

View File

@ -18,6 +18,7 @@ import (
sdktrace "go.opentelemetry.io/otel/sdk/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace"
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/noop"
) )
type ExporterDetector func() (sdktrace.SpanExporter, sdkmetric.Exporter, error) type ExporterDetector func() (sdktrace.SpanExporter, sdkmetric.Exporter, error)
@ -105,7 +106,7 @@ func getExporters() (sdktrace.SpanExporter, sdkmetric.Exporter, error) {
} }
func detect() error { func detect() error {
tp = trace.NewNoopTracerProvider() tp = noop.NewTracerProvider()
mp = sdkmetric.NewMeterProvider() mp = sdkmetric.NewMeterProvider()
texp, mexp, err := getExporters() texp, mexp, err := getExporters()

View File

@ -14,13 +14,14 @@ import (
"go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/propagation"
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"
"go.opentelemetry.io/otel/trace/noop"
) )
// StartSpan starts a new span as a child of the span in context. // StartSpan starts a new span as a child of the span in context.
// If there is no span in context then this is a no-op. // If there is no span in context then this is a no-op.
func StartSpan(ctx context.Context, operationName string, opts ...trace.SpanStartOption) (trace.Span, context.Context) { func StartSpan(ctx context.Context, operationName string, opts ...trace.SpanStartOption) (trace.Span, context.Context) {
parent := trace.SpanFromContext(ctx) parent := trace.SpanFromContext(ctx)
tracer := trace.NewNoopTracerProvider().Tracer("") tracer := noop.NewTracerProvider().Tracer("")
if parent != nil && parent.SpanContext().IsValid() { if parent != nil && parent.SpanContext().IsValid() {
tracer = parent.TracerProvider().Tracer("") tracer = parent.TracerProvider().Tracer("")
} }

View File

@ -1,9 +1,5 @@
# if you want to ignore files created by your editor/tools, consider using a # if you want to ignore files created by your editor/tools, consider using a
# global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files # global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files
.* bin/
!.github
!.gitignore
!.travis.yml
*.prof
# support running go modules in vendor mode for local development # support running go modules in vendor mode for local development
vendor/ vendor/

30
vendor/github.com/tonistiigi/fsutil/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,30 @@
run:
timeout: 10m
skip-files:
- ".*\\.pb\\.go$"
linters:
enable:
- gofmt
- govet
- goimports
- ineffassign
- misspell
- unused
- staticcheck
- typecheck
disable-all: true
linters-settings:
depguard:
rules:
main:
deny:
# The io/ioutil package has been deprecated.
# https://go.dev/doc/go1.16#ioutil
- pkg: "io/ioutil"
desc: The io/ioutil package has been deprecated.
# show all
max-issues-per-linter: 0
max-same-issues: 0

View File

@ -1,7 +1,9 @@
#syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
ARG GO_VERSION=1.20
FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.1.0 AS xx ARG GO_VERSION=1.21
ARG XX_VERSION=1.4.0
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS base FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS base
RUN apk add --no-cache git RUN apk add --no-cache git
@ -18,13 +20,19 @@ FROM base AS test
ARG TESTFLAGS ARG TESTFLAGS
RUN --mount=target=. --mount=target=/go/pkg/mod,type=cache \ RUN --mount=target=. --mount=target=/go/pkg/mod,type=cache \
--mount=target=/root/.cache,type=cache \ --mount=target=/root/.cache,type=cache \
CGO_ENABLED=0 xx-go test -test.v ${TESTFLAGS} ./... CGO_ENABLED=0 xx-go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic ${TESTFLAGS} ./...
FROM base AS test-noroot FROM base AS test-noroot
RUN mkdir /go/pkg && chmod 0777 /go/pkg RUN mkdir /go/pkg && chmod 0777 /go/pkg
USER 1000:1000 USER 1000:1000
RUN --mount=target=. \ RUN --mount=target=. \
--mount=target=/tmp/.cache,type=cache \ --mount=target=/tmp/.cache,type=cache \
CGO_ENABLED=0 GOCACHE=/tmp/gocache xx-go test -test.v ./... CGO_ENABLED=0 GOCACHE=/tmp/gocache xx-go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic ./...
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage.txt /coverage-root.txt
FROM scratch AS test-noroot-coverage
COPY --from=test-noroot /tmp/coverage.txt /coverage-noroot.txt
FROM build FROM build

12
vendor/github.com/tonistiigi/fsutil/codecov.yml generated vendored Normal file
View File

@ -0,0 +1,12 @@
comment: false
coverage:
status:
project: # settings affecting project coverage
default:
target: auto # auto % coverage target
threshold: 1% # allow for 1% reduction of coverage without failing
patch: off
github_checks:
annotations: false

View File

@ -5,6 +5,7 @@ import (
"context" "context"
"io" "io"
"os" "os"
"path/filepath"
"strings" "strings"
"github.com/tonistiigi/fsutil/types" "github.com/tonistiigi/fsutil/types"
@ -110,7 +111,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil
if filter != nil { if filter != nil {
filter(f2.path, &statCopy) filter(f2.path, &statCopy)
} }
f2copy = &currentPath{path: f2.path, stat: &statCopy} f2copy = &currentPath{path: filepath.FromSlash(f2.path), stat: &statCopy}
} }
k, p := pathChange(f1, f2copy) k, p := pathChange(f1, f2copy)
switch k { switch k {
@ -127,7 +128,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil
f1 = nil f1 = nil
continue continue
} else if rmdir == "" && f1.stat.IsDir() { } else if rmdir == "" && f1.stat.IsDir() {
rmdir = f1.path + string(os.PathSeparator) rmdir = f1.path + string(filepath.Separator)
} else if rmdir != "" { } else if rmdir != "" {
rmdir = "" rmdir = ""
} }
@ -138,7 +139,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil
return err return err
} }
if f1.stat.IsDir() && !f2copy.stat.IsDir() { if f1.stat.IsDir() && !f2copy.stat.IsDir() {
rmdir = f1.path + string(os.PathSeparator) rmdir = f1.path + string(filepath.Separator)
} else if rmdir != "" { } else if rmdir != "" {
rmdir = "" rmdir = ""
} }

View File

@ -1,5 +1,9 @@
variable "GO_VERSION" { variable "GO_VERSION" {
default = "1.20" default = null
}
variable "DESTDIR" {
default = "./bin"
} }
group "default" { group "default" {
@ -18,12 +22,14 @@ group "test" {
target "test-root" { target "test-root" {
inherits = ["build"] inherits = ["build"]
target = "test" target = "test-coverage"
output = ["${DESTDIR}/coverage"]
} }
target "test-noroot" { target "test-noroot" {
inherits = ["build"] inherits = ["build"]
target = "test-noroot" target = "test-noroot-coverage"
output = ["${DESTDIR}/coverage"]
} }
target "lint" { target "lint" {

View File

@ -66,9 +66,9 @@ type filterFS struct {
// NewFilterFS creates a new FS that filters the given FS using the given // NewFilterFS creates a new FS that filters the given FS using the given
// FilterOpt. // FilterOpt.
//
// The returned FS will not contain any paths that do not match the provided // The returned FS will not contain any paths that do not match the provided
// include and exclude patterns, or that are are exlcluded using the mapping // include and exclude patterns, or that are are excluded using the mapping
// function. // function.
// //
// The FS is assumed to be a snapshot of the filesystem at the time of the // The FS is assumed to be a snapshot of the filesystem at the time of the
@ -96,7 +96,7 @@ func NewFilterFS(fs FS, opt *FilterOpt) (FS, error) {
} }
patternChars := "*[]?^" patternChars := "*[]?^"
if os.PathSeparator != '\\' { if filepath.Separator != '\\' {
patternChars += `\` patternChars += `\`
} }
@ -176,6 +176,7 @@ func (fs *filterFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc
includeMatchInfo patternmatcher.MatchInfo includeMatchInfo patternmatcher.MatchInfo
excludeMatchInfo patternmatcher.MatchInfo excludeMatchInfo patternmatcher.MatchInfo
calledFn bool calledFn bool
skipFn bool
} }
// used only for include/exclude handling // used only for include/exclude handling
@ -333,6 +334,9 @@ func (fs *filterFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc
} }
} }
for i, parentDir := range parentDirs { for i, parentDir := range parentDirs {
if parentDir.skipFn {
return filepath.SkipDir
}
if parentDir.calledFn { if parentDir.calledFn {
continue continue
} }
@ -352,15 +356,21 @@ func (fs *filterFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc
} }
if fs.mapFn != nil { if fs.mapFn != nil {
result := fs.mapFn(parentStat.Path, parentStat) result := fs.mapFn(parentStat.Path, parentStat)
if result == MapResultSkipDir || result == MapResultExclude { if result == MapResultExclude {
continue continue
} else if result == MapResultSkipDir {
parentDirs[i].skipFn = true
return filepath.SkipDir
} }
} }
if err := fn(parentStat.Path, &DirEntryInfo{Stat: parentStat}, nil); err != nil { parentDirs[i].calledFn = true
if err := fn(parentStat.Path, &DirEntryInfo{Stat: parentStat}, nil); err == filepath.SkipDir {
parentDirs[i].skipFn = true
return filepath.SkipDir
} else if err != nil {
return err return err
} }
parentDirs[i].calledFn = true
} }
if err := fn(stat.Path, &DirEntryInfo{Stat: stat}, nil); err != nil { if err := fn(stat.Path, &DirEntryInfo{Stat: stat}, nil); err != nil {
return err return err

View File

@ -137,8 +137,8 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e
func statFile(fs FS, root string) (os.DirEntry, error) { func statFile(fs FS, root string) (os.DirEntry, error) {
var out os.DirEntry var out os.DirEntry
root = filepath.Clean(root) root = filepath.FromSlash(filepath.Clean(root))
if root == "/" || root == "." { if root == string(filepath.Separator) || root == "." {
return nil, nil return nil, nil
} }
@ -168,8 +168,8 @@ func statFile(fs FS, root string) (os.DirEntry, error) {
func readDir(fs FS, root string) ([]os.DirEntry, error) { func readDir(fs FS, root string) ([]os.DirEntry, error) {
var out []os.DirEntry var out []os.DirEntry
root = filepath.Clean(root) root = filepath.FromSlash(filepath.Clean(root))
if root == "/" || root == "." { if root == string(filepath.Separator) || root == "." {
root = "." root = "."
out = make([]gofs.DirEntry, 0) out = make([]gofs.DirEntry, 0)
} }

View File

@ -1,3 +1,8 @@
[![PkgGoDev](https://img.shields.io/badge/go.dev-docs-007d9c?style=flat-square&logo=go&logoColor=white)](https://pkg.go.dev/github.com/tonistiigi/fsutil)
[![CI Status](https://img.shields.io/github/actions/workflow/status/tonistiigi/fsutil/ci.yml?label=ci&logo=github&style=flat-square)](https://github.com/tonistiigi/fsutil/actions?query=workflow%3Aci)
[![Go Report Card](https://goreportcard.com/badge/github.com/tonistiigi/fsutil?style=flat-square)](https://goreportcard.com/report/github.com/tonistiigi/fsutil)
[![Codecov](https://img.shields.io/codecov/c/github/tonistiigi/fsutil?logo=codecov&style=flat-square)](https://codecov.io/gh/tonistiigi/fsutil)
Incremental file directory sync tools in golang. Incremental file directory sync tools in golang.
``` ```

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"io" "io"
"os" "os"
"path/filepath"
"sync" "sync"
"syscall" "syscall"
@ -156,7 +157,7 @@ func (s *sender) walk(ctx context.Context) error {
if !ok { if !ok {
return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"})
} }
stat.Path = filepath.ToSlash(stat.Path)
p := &types.Packet{ p := &types.Packet{
Type: types.PACKET_STAT, Type: types.PACKET_STAT,
Stat: stat, Stat: stat,

View File

@ -19,7 +19,7 @@ func mkstat(path, relpath string, fi os.FileInfo, inodemap map[uint64]string) (*
relpath = filepath.ToSlash(relpath) relpath = filepath.ToSlash(relpath)
stat := &types.Stat{ stat := &types.Stat{
Path: relpath, Path: filepath.FromSlash(relpath),
Mode: uint32(fi.Mode()), Mode: uint32(fi.Mode()),
ModTime: fi.ModTime().UnixNano(), ModTime: fi.ModTime().UnixNano(),
} }

View File

@ -2,8 +2,7 @@ package fsutil
import ( import (
"os" "os"
"path" "path/filepath"
"runtime"
"sort" "sort"
"strings" "strings"
"syscall" "syscall"
@ -28,21 +27,18 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err
if v.parentDirs == nil { if v.parentDirs == nil {
v.parentDirs = make([]parent, 1, 10) v.parentDirs = make([]parent, 1, 10)
} }
if runtime.GOOS == "windows" { if p != filepath.Clean(p) {
p = strings.Replace(p, "\\", "", -1)
}
if p != path.Clean(p) {
return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "unclean path"}) return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "unclean path"})
} }
if path.IsAbs(p) { if filepath.IsAbs(p) {
return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "absolute path"}) return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "absolute path"})
} }
dir := path.Dir(p) dir := filepath.Dir(p)
base := path.Base(p) base := filepath.Base(p)
if dir == "." { if dir == "." {
dir = "" dir = ""
} }
if dir == ".." || strings.HasPrefix(p, "../") { if dir == ".." || strings.HasPrefix(p, filepath.FromSlash("../")) {
return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "escape check"}) return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "escape check"})
} }
@ -56,12 +52,12 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err
} }
if dir != v.parentDirs[len(v.parentDirs)-1].dir || v.parentDirs[i].last >= base { if dir != v.parentDirs[len(v.parentDirs)-1].dir || v.parentDirs[i].last >= base {
return errors.Errorf("changes out of order: %q %q", p, path.Join(v.parentDirs[i].dir, v.parentDirs[i].last)) return errors.Errorf("changes out of order: %q %q", p, filepath.Join(v.parentDirs[i].dir, v.parentDirs[i].last))
} }
v.parentDirs[i].last = base v.parentDirs[i].last = base
if kind != ChangeKindDelete && fi.IsDir() { if kind != ChangeKindDelete && fi.IsDir() {
v.parentDirs = append(v.parentDirs, parent{ v.parentDirs = append(v.parentDirs, parent{
dir: path.Join(dir, base), dir: filepath.Join(dir, base),
last: "", last: "",
}) })
} }
@ -76,7 +72,7 @@ func ComparePath(p1, p2 string) int {
switch { switch {
case p1[i] == p2[i]: case p1[i] == p2[i]:
continue continue
case p2[i] != '/' && p1[i] < p2[i] || p1[i] == '/': case p2[i] != filepath.Separator && p1[i] < p2[i] || p1[i] == filepath.Separator:
return -1 return -1
default: default:
return 1 return 1

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

@ -188,9 +188,11 @@ type int64Inst struct {
embedded.Int64Histogram embedded.Int64Histogram
} }
var _ metric.Int64Counter = (*int64Inst)(nil) var (
var _ metric.Int64UpDownCounter = (*int64Inst)(nil) _ metric.Int64Counter = (*int64Inst)(nil)
var _ metric.Int64Histogram = (*int64Inst)(nil) _ metric.Int64UpDownCounter = (*int64Inst)(nil)
_ metric.Int64Histogram = (*int64Inst)(nil)
)
func (i *int64Inst) Add(ctx context.Context, val int64, opts ...metric.AddOption) { func (i *int64Inst) Add(ctx context.Context, val int64, opts ...metric.AddOption) {
c := metric.NewAddConfig(opts) c := metric.NewAddConfig(opts)
@ -219,9 +221,11 @@ type float64Inst struct {
embedded.Float64Histogram embedded.Float64Histogram
} }
var _ metric.Float64Counter = (*float64Inst)(nil) var (
var _ metric.Float64UpDownCounter = (*float64Inst)(nil) _ metric.Float64Counter = (*float64Inst)(nil)
var _ metric.Float64Histogram = (*float64Inst)(nil) _ metric.Float64UpDownCounter = (*float64Inst)(nil)
_ metric.Float64Histogram = (*float64Inst)(nil)
)
func (i *float64Inst) Add(ctx context.Context, val float64, opts ...metric.AddOption) { func (i *float64Inst) Add(ctx context.Context, val float64, opts ...metric.AddOption) {
c := metric.NewAddConfig(opts) c := metric.NewAddConfig(opts)
@ -260,9 +264,11 @@ type float64Observable struct {
embedded.Float64ObservableGauge embedded.Float64ObservableGauge
} }
var _ metric.Float64ObservableCounter = float64Observable{} var (
var _ metric.Float64ObservableUpDownCounter = float64Observable{} _ metric.Float64ObservableCounter = float64Observable{}
var _ metric.Float64ObservableGauge = float64Observable{} _ metric.Float64ObservableUpDownCounter = float64Observable{}
_ metric.Float64ObservableGauge = float64Observable{}
)
func newFloat64Observable(m *meter, kind InstrumentKind, name, desc, u string, meas []aggregate.Measure[float64]) float64Observable { func newFloat64Observable(m *meter, kind InstrumentKind, name, desc, u string, meas []aggregate.Measure[float64]) float64Observable {
return float64Observable{ return float64Observable{
@ -279,9 +285,11 @@ type int64Observable struct {
embedded.Int64ObservableGauge embedded.Int64ObservableGauge
} }
var _ metric.Int64ObservableCounter = int64Observable{} var (
var _ metric.Int64ObservableUpDownCounter = int64Observable{} _ metric.Int64ObservableCounter = int64Observable{}
var _ metric.Int64ObservableGauge = int64Observable{} _ metric.Int64ObservableUpDownCounter = int64Observable{}
_ metric.Int64ObservableGauge = int64Observable{}
)
func newInt64Observable(m *meter, kind InstrumentKind, name, desc, u string, meas []aggregate.Measure[int64]) int64Observable { func newInt64Observable(m *meter, kind InstrumentKind, name, desc, u string, meas []aggregate.Measure[int64]) int64Observable {
return int64Observable{ return int64Observable{

View File

@ -113,7 +113,7 @@ func (p *expoHistogramDataPoint[N]) record(v N) {
otel.Handle(errors.New("exponential histogram scale underflow")) otel.Handle(errors.New("exponential histogram scale underflow"))
return return
} }
//Downscale // Downscale
p.scale -= scaleDelta p.scale -= scaleDelta
p.posBuckets.downscale(scaleDelta) p.posBuckets.downscale(scaleDelta)
p.negBuckets.downscale(scaleDelta) p.negBuckets.downscale(scaleDelta)

View File

@ -26,11 +26,9 @@ import (
"go.opentelemetry.io/otel/sdk/metric/internal/aggregate" "go.opentelemetry.io/otel/sdk/metric/internal/aggregate"
) )
var ( // ErrInstrumentName indicates the created instrument has an invalid name.
// ErrInstrumentName indicates the created instrument has an invalid name. // Valid names must consist of 255 or fewer characters including alphanumeric, _, ., -, / and start with a letter.
// Valid names must consist of 255 or fewer characters including alphanumeric, _, ., -, / and start with a letter. var ErrInstrumentName = errors.New("invalid instrument name")
ErrInstrumentName = errors.New("invalid instrument name")
)
// meter handles the creation and coordination of all metric instruments. A // meter handles the creation and coordination of all metric instruments. A
// meter represents a single instrumentation scope; all metric telemetry // meter represents a single instrumentation scope; all metric telemetry
@ -97,9 +95,8 @@ func (m *meter) Int64UpDownCounter(name string, options ...metric.Int64UpDownCou
// distribution of int64 measurements during a computational operation. // distribution of int64 measurements during a computational operation.
func (m *meter) Int64Histogram(name string, options ...metric.Int64HistogramOption) (metric.Int64Histogram, error) { func (m *meter) Int64Histogram(name string, options ...metric.Int64HistogramOption) (metric.Int64Histogram, error) {
cfg := metric.NewInt64HistogramConfig(options...) cfg := metric.NewInt64HistogramConfig(options...)
const kind = InstrumentKindHistogram
p := int64InstProvider{m} p := int64InstProvider{m}
i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) i, err := p.lookupHistogram(name, cfg)
if err != nil { if err != nil {
return i, err return i, err
} }
@ -190,9 +187,8 @@ func (m *meter) Float64UpDownCounter(name string, options ...metric.Float64UpDow
// distribution of float64 measurements during a computational operation. // distribution of float64 measurements during a computational operation.
func (m *meter) Float64Histogram(name string, options ...metric.Float64HistogramOption) (metric.Float64Histogram, error) { func (m *meter) Float64Histogram(name string, options ...metric.Float64HistogramOption) (metric.Float64Histogram, error) {
cfg := metric.NewFloat64HistogramConfig(options...) cfg := metric.NewFloat64HistogramConfig(options...)
const kind = InstrumentKindHistogram
p := float64InstProvider{m} p := float64InstProvider{m}
i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) i, err := p.lookupHistogram(name, cfg)
if err != nil { if err != nil {
return i, err return i, err
} }
@ -268,9 +264,11 @@ func validateInstrumentName(name string) error {
} }
return nil return nil
} }
func isAlpha(c rune) bool { func isAlpha(c rune) bool {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
} }
func isAlphanumeric(c rune) bool { func isAlphanumeric(c rune) bool {
return isAlpha(c) || ('0' <= c && c <= '9') return isAlpha(c) || ('0' <= c && c <= '9')
} }
@ -456,12 +454,36 @@ func (p int64InstProvider) aggs(kind InstrumentKind, name, desc, u string) ([]ag
return p.int64Resolver.Aggregators(inst) return p.int64Resolver.Aggregators(inst)
} }
func (p int64InstProvider) histogramAggs(name string, cfg metric.Int64HistogramConfig) ([]aggregate.Measure[int64], error) {
boundaries := cfg.ExplicitBucketBoundaries()
aggError := AggregationExplicitBucketHistogram{Boundaries: boundaries}.err()
if aggError != nil {
// If boundaries are invalid, ignore them.
boundaries = nil
}
inst := Instrument{
Name: name,
Description: cfg.Description(),
Unit: cfg.Unit(),
Kind: InstrumentKindHistogram,
Scope: p.scope,
}
measures, err := p.int64Resolver.HistogramAggregators(inst, boundaries)
return measures, errors.Join(aggError, err)
}
// lookup returns the resolved instrumentImpl. // lookup returns the resolved instrumentImpl.
func (p int64InstProvider) lookup(kind InstrumentKind, name, desc, u string) (*int64Inst, error) { func (p int64InstProvider) lookup(kind InstrumentKind, name, desc, u string) (*int64Inst, error) {
aggs, err := p.aggs(kind, name, desc, u) aggs, err := p.aggs(kind, name, desc, u)
return &int64Inst{measures: aggs}, err return &int64Inst{measures: aggs}, err
} }
// lookupHistogram returns the resolved instrumentImpl.
func (p int64InstProvider) lookupHistogram(name string, cfg metric.Int64HistogramConfig) (*int64Inst, error) {
aggs, err := p.histogramAggs(name, cfg)
return &int64Inst{measures: aggs}, err
}
// float64InstProvider provides float64 OpenTelemetry instruments. // float64InstProvider provides float64 OpenTelemetry instruments.
type float64InstProvider struct{ *meter } type float64InstProvider struct{ *meter }
@ -476,12 +498,36 @@ func (p float64InstProvider) aggs(kind InstrumentKind, name, desc, u string) ([]
return p.float64Resolver.Aggregators(inst) return p.float64Resolver.Aggregators(inst)
} }
func (p float64InstProvider) histogramAggs(name string, cfg metric.Float64HistogramConfig) ([]aggregate.Measure[float64], error) {
boundaries := cfg.ExplicitBucketBoundaries()
aggError := AggregationExplicitBucketHistogram{Boundaries: boundaries}.err()
if aggError != nil {
// If boundaries are invalid, ignore them.
boundaries = nil
}
inst := Instrument{
Name: name,
Description: cfg.Description(),
Unit: cfg.Unit(),
Kind: InstrumentKindHistogram,
Scope: p.scope,
}
measures, err := p.float64Resolver.HistogramAggregators(inst, boundaries)
return measures, errors.Join(aggError, err)
}
// lookup returns the resolved instrumentImpl. // lookup returns the resolved instrumentImpl.
func (p float64InstProvider) lookup(kind InstrumentKind, name, desc, u string) (*float64Inst, error) { func (p float64InstProvider) lookup(kind InstrumentKind, name, desc, u string) (*float64Inst, error) {
aggs, err := p.aggs(kind, name, desc, u) aggs, err := p.aggs(kind, name, desc, u)
return &float64Inst{measures: aggs}, err return &float64Inst{measures: aggs}, err
} }
// lookupHistogram returns the resolved instrumentImpl.
func (p float64InstProvider) lookupHistogram(name string, cfg metric.Float64HistogramConfig) (*float64Inst, error) {
aggs, err := p.histogramAggs(name, cfg)
return &float64Inst{measures: aggs}, err
}
type int64ObservProvider struct{ *meter } type int64ObservProvider struct{ *meter }
func (p int64ObservProvider) lookup(kind InstrumentKind, name, desc, u string) (int64Observable, error) { func (p int64ObservProvider) lookup(kind InstrumentKind, name, desc, u string) (int64Observable, error) {

View File

@ -240,3 +240,54 @@ type Exemplar[N int64 | float64] struct {
// be empty. // be empty.
TraceID []byte `json:",omitempty"` TraceID []byte `json:",omitempty"`
} }
// Summary metric data are used to convey quantile summaries,
// a Prometheus (see: https://prometheus.io/docs/concepts/metric_types/#summary)
// data type.
//
// These data points cannot always be merged in a meaningful way. The Summary
// type is only used by bridges from other metrics libraries, and cannot be
// produced using OpenTelemetry instrumentation.
type Summary struct {
// DataPoints are the individual aggregated measurements with unique
// attributes.
DataPoints []SummaryDataPoint
}
func (Summary) privateAggregation() {}
// SummaryDataPoint is a single data point in a timeseries that describes the
// time-varying values of a Summary metric.
type SummaryDataPoint struct {
// Attributes is the set of key value pairs that uniquely identify the
// timeseries.
Attributes attribute.Set
// StartTime is when the timeseries was started.
StartTime time.Time
// Time is the time when the timeseries was recorded.
Time time.Time
// Count is the number of updates this summary has been calculated with.
Count uint64
// Sum is the sum of the values recorded.
Sum float64
// (Optional) list of values at different quantiles of the distribution calculated
// from the current snapshot. The quantiles must be strictly increasing.
QuantileValues []QuantileValue
}
// QuantileValue is the value at a given quantile of a summary.
type QuantileValue struct {
// Quantile is the quantile of this value.
//
// Must be in the interval [0.0, 1.0].
Quantile float64
// Value is the value at the given quantile of a summary.
//
// Quantile values must NOT be negative.
Value float64
}

View File

@ -127,7 +127,8 @@ func NewPeriodicReader(exporter Exporter, options ...PeriodicReaderOption) *Peri
rmPool: sync.Pool{ rmPool: sync.Pool{
New: func() interface{} { New: func() interface{} {
return &metricdata.ResourceMetrics{} return &metricdata.ResourceMetrics{}
}}, },
},
} }
r.externalProducers.Store(conf.producers) r.externalProducers.Store(conf.producers)

View File

@ -231,7 +231,7 @@ func newInserter[N int64 | float64](p *pipeline, vc *cache[string, instID]) *ins
// //
// If an instrument is determined to use a Drop aggregation, that instrument is // If an instrument is determined to use a Drop aggregation, that instrument is
// not inserted nor returned. // not inserted nor returned.
func (i *inserter[N]) Instrument(inst Instrument) ([]aggregate.Measure[N], error) { func (i *inserter[N]) Instrument(inst Instrument, readerAggregation Aggregation) ([]aggregate.Measure[N], error) {
var ( var (
matched bool matched bool
measures []aggregate.Measure[N] measures []aggregate.Measure[N]
@ -245,8 +245,7 @@ func (i *inserter[N]) Instrument(inst Instrument) ([]aggregate.Measure[N], error
continue continue
} }
matched = true matched = true
in, id, err := i.cachedAggregator(inst.Scope, inst.Kind, stream, readerAggregation)
in, id, err := i.cachedAggregator(inst.Scope, inst.Kind, stream)
if err != nil { if err != nil {
errs.append(err) errs.append(err)
} }
@ -271,7 +270,7 @@ func (i *inserter[N]) Instrument(inst Instrument) ([]aggregate.Measure[N], error
Description: inst.Description, Description: inst.Description,
Unit: inst.Unit, Unit: inst.Unit,
} }
in, _, err := i.cachedAggregator(inst.Scope, inst.Kind, stream) in, _, err := i.cachedAggregator(inst.Scope, inst.Kind, stream, readerAggregation)
if err != nil { if err != nil {
errs.append(err) errs.append(err)
} }
@ -291,6 +290,31 @@ type aggVal[N int64 | float64] struct {
Err error Err error
} }
// readerDefaultAggregation returns the default aggregation for the instrument
// kind based on the reader's aggregation preferences. This is used unless the
// aggregation is overridden with a view.
func (i *inserter[N]) readerDefaultAggregation(kind InstrumentKind) Aggregation {
aggregation := i.pipeline.reader.aggregation(kind)
switch aggregation.(type) {
case nil, AggregationDefault:
// If the reader returns default or nil use the default selector.
aggregation = DefaultAggregationSelector(kind)
default:
// Deep copy and validate before using.
aggregation = aggregation.copy()
if err := aggregation.err(); err != nil {
orig := aggregation
aggregation = DefaultAggregationSelector(kind)
global.Error(
err, "using default aggregation instead",
"aggregation", orig,
"replacement", aggregation,
)
}
}
return aggregation
}
// cachedAggregator returns the appropriate aggregate input and output // cachedAggregator returns the appropriate aggregate input and output
// functions for an instrument configuration. If the exact instrument has been // functions for an instrument configuration. If the exact instrument has been
// created within the inst.Scope, those aggregate function instances will be // created within the inst.Scope, those aggregate function instances will be
@ -305,29 +329,14 @@ type aggVal[N int64 | float64] struct {
// //
// If the instrument defines an unknown or incompatible aggregation, an error // If the instrument defines an unknown or incompatible aggregation, an error
// is returned. // is returned.
func (i *inserter[N]) cachedAggregator(scope instrumentation.Scope, kind InstrumentKind, stream Stream) (meas aggregate.Measure[N], aggID uint64, err error) { func (i *inserter[N]) cachedAggregator(scope instrumentation.Scope, kind InstrumentKind, stream Stream, readerAggregation Aggregation) (meas aggregate.Measure[N], aggID uint64, err error) {
switch stream.Aggregation.(type) { switch stream.Aggregation.(type) {
case nil: case nil:
// Undefined, nil, means to use the default from the reader. // The aggregation was not overridden with a view. Use the aggregation
stream.Aggregation = i.pipeline.reader.aggregation(kind) // provided by the reader.
switch stream.Aggregation.(type) { stream.Aggregation = readerAggregation
case nil, AggregationDefault:
// If the reader returns default or nil use the default selector.
stream.Aggregation = DefaultAggregationSelector(kind)
default:
// Deep copy and validate before using.
stream.Aggregation = stream.Aggregation.copy()
if err := stream.Aggregation.err(); err != nil {
orig := stream.Aggregation
stream.Aggregation = DefaultAggregationSelector(kind)
global.Error(
err, "using default aggregation instead",
"aggregation", orig,
"replacement", stream.Aggregation,
)
}
}
case AggregationDefault: case AggregationDefault:
// The view explicitly requested the default aggregation.
stream.Aggregation = DefaultAggregationSelector(kind) stream.Aggregation = DefaultAggregationSelector(kind)
} }
@ -596,7 +605,29 @@ func (r resolver[N]) Aggregators(id Instrument) ([]aggregate.Measure[N], error)
errs := &multierror{} errs := &multierror{}
for _, i := range r.inserters { for _, i := range r.inserters {
in, err := i.Instrument(id) in, err := i.Instrument(id, i.readerDefaultAggregation(id.Kind))
if err != nil {
errs.append(err)
}
measures = append(measures, in...)
}
return measures, errs.errorOrNil()
}
// HistogramAggregators returns the histogram Aggregators that must be updated by the instrument
// defined by key. If boundaries were provided on instrument instantiation, those take precedence
// over boundaries provided by the reader.
func (r resolver[N]) HistogramAggregators(id Instrument, boundaries []float64) ([]aggregate.Measure[N], error) {
var measures []aggregate.Measure[N]
errs := &multierror{}
for _, i := range r.inserters {
agg := i.readerDefaultAggregation(id.Kind)
if histAgg, ok := agg.(AggregationExplicitBucketHistogram); ok && len(boundaries) > 0 {
histAgg.Boundaries = boundaries
agg = histAgg
}
in, err := i.Instrument(id, agg)
if err != nil { if err != nil {
errs.append(err) errs.append(err)
} }

View File

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

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

36
vendor/modules.txt vendored
View File

@ -513,7 +513,7 @@ github.com/mitchellh/mapstructure
# github.com/mitchellh/reflectwalk v1.0.2 # github.com/mitchellh/reflectwalk v1.0.2
## explicit ## explicit
github.com/mitchellh/reflectwalk github.com/mitchellh/reflectwalk
# github.com/moby/buildkit v0.13.0-rc1.0.20240222164755-8e3fe35738c2 # github.com/moby/buildkit v0.13.0-rc2
## explicit; go 1.21 ## explicit; go 1.21
github.com/moby/buildkit/api/services/control github.com/moby/buildkit/api/services/control
github.com/moby/buildkit/api/types github.com/moby/buildkit/api/types
@ -707,8 +707,8 @@ github.com/theupdateframework/notary/tuf/data
github.com/theupdateframework/notary/tuf/signed github.com/theupdateframework/notary/tuf/signed
github.com/theupdateframework/notary/tuf/utils github.com/theupdateframework/notary/tuf/utils
github.com/theupdateframework/notary/tuf/validation github.com/theupdateframework/notary/tuf/validation
# github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302 # github.com/tonistiigi/fsutil v0.0.0-20240223190444-7a889f53dbf6
## explicit; go 1.19 ## explicit; go 1.20
github.com/tonistiigi/fsutil github.com/tonistiigi/fsutil
github.com/tonistiigi/fsutil/types github.com/tonistiigi/fsutil/types
# github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea # github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea
@ -736,19 +736,19 @@ github.com/zclconf/go-cty/cty/function/stdlib
github.com/zclconf/go-cty/cty/gocty github.com/zclconf/go-cty/cty/gocty
github.com/zclconf/go-cty/cty/json github.com/zclconf/go-cty/cty/json
github.com/zclconf/go-cty/cty/set github.com/zclconf/go-cty/cty/set
# 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
@ -780,18 +780,18 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envco
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform
# 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
@ -801,12 +801,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry
# go.opentelemetry.io/otel/exporters/prometheus v0.42.0 # go.opentelemetry.io/otel/exporters/prometheus v0.42.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel/exporters/prometheus go.opentelemetry.io/otel/exporters/prometheus
# 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/metric/noop go.opentelemetry.io/otel/metric/noop
# 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
@ -815,15 +815,17 @@ 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/sdk/metric v1.19.0 # go.opentelemetry.io/otel/sdk/metric v1.21.0
## explicit; go 1.20 ## explicit; go 1.20
go.opentelemetry.io/otel/sdk/metric go.opentelemetry.io/otel/sdk/metric
go.opentelemetry.io/otel/sdk/metric/internal go.opentelemetry.io/otel/sdk/metric/internal
go.opentelemetry.io/otel/sdk/metric/internal/aggregate go.opentelemetry.io/otel/sdk/metric/internal/aggregate
go.opentelemetry.io/otel/sdk/metric/metricdata go.opentelemetry.io/otel/sdk/metric/metricdata
# 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/metrics/v1 go.opentelemetry.io/proto/otlp/collector/metrics/v1