Update lib

This commit is contained in:
xing-yang
2023-11-15 14:58:29 +00:00
parent be851d9b8c
commit ff4faefbd6
417 changed files with 2879 additions and 1450 deletions
+12 -12
View File
@@ -8,7 +8,7 @@ require (
github.com/fsnotify/fsnotify v1.7.0 github.com/fsnotify/fsnotify v1.7.0
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/google/gofuzz v1.2.0 github.com/google/gofuzz v1.2.0
github.com/kubernetes-csi/csi-lib-utils v0.15.0 github.com/kubernetes-csi/csi-lib-utils v0.16.0
github.com/kubernetes-csi/csi-test/v5 v5.1.0 github.com/kubernetes-csi/csi-test/v5 v5.1.0
github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0 github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0
github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_golang v1.17.0
@@ -31,7 +31,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.10.1 // indirect github.com/emicklei/go-restful/v3 v3.10.1 // indirect
github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect
@@ -40,7 +40,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.3.1 // indirect github.com/google/uuid v1.3.1 // indirect
github.com/imdario/mergo v0.3.13 // indirect github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -54,18 +54,18 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/procfs v0.11.1 // indirect github.com/prometheus/procfs v0.11.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 // indirect
go.opentelemetry.io/otel v1.15.0 // indirect go.opentelemetry.io/otel v1.20.0 // indirect
go.opentelemetry.io/otel/metric v0.38.0 // indirect go.opentelemetry.io/otel/metric v1.20.0 // indirect
go.opentelemetry.io/otel/trace v1.15.0 // indirect go.opentelemetry.io/otel/trace v1.20.0 // indirect
golang.org/x/net v0.17.0 // indirect golang.org/x/net v0.18.0 // indirect
golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect
golang.org/x/sys v0.13.0 // indirect golang.org/x/sys v0.14.0 // indirect
golang.org/x/term v0.13.0 // indirect golang.org/x/term v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
+25 -25
View File
@@ -23,8 +23,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
@@ -47,8 +47,8 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -71,8 +71,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubernetes-csi/csi-lib-utils v0.15.0 h1:YTMO6WilRUmjGh5/73kF4KjNcXev+V37O4bx8Uoxy5A= github.com/kubernetes-csi/csi-lib-utils v0.16.0 h1:LXCvkhXHtFOkl7LoDqFdho/MuebccZqWxLwhKiRGiBg=
github.com/kubernetes-csi/csi-lib-utils v0.15.0/go.mod h1:fsoR7g1fOfl1z0WDpA1WvWPtt4oVvgzChgSUgR3JWDw= github.com/kubernetes-csi/csi-lib-utils v0.16.0/go.mod h1:fp1Oik+45tP2o4X9SD/SBWXLTQYT9wtLxGasBE3+vBI=
github.com/kubernetes-csi/csi-test/v5 v5.1.0 h1:8UxFRH0W8C4RbppKYYJeOJ506C7ybngKZA5GabGgJec= github.com/kubernetes-csi/csi-test/v5 v5.1.0 h1:8UxFRH0W8C4RbppKYYJeOJ506C7ybngKZA5GabGgJec=
github.com/kubernetes-csi/csi-test/v5 v5.1.0/go.mod h1:LoAh2XHbXcKnCoM1WgEyviUXiLmTeCmFTsjzaNloL3k= github.com/kubernetes-csi/csi-test/v5 v5.1.0/go.mod h1:LoAh2XHbXcKnCoM1WgEyviUXiLmTeCmFTsjzaNloL3k=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -113,18 +113,18 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.0 h1:pWlIooxHVVdetyXFDsuzfqV42lXVIDmVGBCHeaXzDyI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.0/go.mod h1:YjmsSWM1VTcWXFSgyrmLADPMZZohioz9onjgkikk59w= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M=
go.opentelemetry.io/otel v1.15.0 h1:NIl24d4eiLJPM0vKn4HjLYM+UZf6gSfi9Z+NmCxkWbk= go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
go.opentelemetry.io/otel v1.15.0/go.mod h1:qfwLEbWhLPk5gyWrne4XnF0lC8wtywbuJbgfAE3zbek= go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs=
go.opentelemetry.io/otel/metric v0.38.0 h1:vv/Nv/44S3GzMMmeUhaesBKsAenE6xLkTVWL+zuv30w= go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA=
go.opentelemetry.io/otel/metric v0.38.0/go.mod h1:uAtxN5hl8aXh5irD8afBtSwQU5Zjg64WWSz6KheZxBg= go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM=
go.opentelemetry.io/otel/trace v1.15.0 h1:5Fwje4O2ooOxkfyqI/kJwxWotggDLix4BSAvpE1wlpo= go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ=
go.opentelemetry.io/otel/trace v1.15.0/go.mod h1:CUsmE2Ht1CRkvE8OsMESvraoZrrcgD1J2W8GV1ev0Y4= go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -137,8 +137,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -151,16 +151,16 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -175,8 +175,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+112 -1
View File
@@ -1,6 +1,7 @@
# A minimal logging API for Go # A minimal logging API for Go
[![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/logr.svg)](https://pkg.go.dev/github.com/go-logr/logr) [![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/logr.svg)](https://pkg.go.dev/github.com/go-logr/logr)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-logr/logr/badge)](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr)
logr offers an(other) opinion on how Go programs and libraries can do logging logr offers an(other) opinion on how Go programs and libraries can do logging
without becoming coupled to a particular logging implementation. This is not without becoming coupled to a particular logging implementation. This is not
@@ -73,6 +74,29 @@ received:
If the Go standard library had defined an interface for logging, this project If the Go standard library had defined an interface for logging, this project
probably would not be needed. Alas, here we are. probably would not be needed. Alas, here we are.
When the Go developers started developing such an interface with
[slog](https://github.com/golang/go/issues/56345), they adopted some of the
logr design but also left out some parts and changed others:
| Feature | logr | slog |
|---------|------|------|
| High-level API | `Logger` (passed by value) | `Logger` (passed by [pointer](https://github.com/golang/go/issues/59126)) |
| Low-level API | `LogSink` | `Handler` |
| Stack unwinding | done by `LogSink` | done by `Logger` |
| Skipping helper functions | `WithCallDepth`, `WithCallStackHelper` | [not supported by Logger](https://github.com/golang/go/issues/59145) |
| Generating a value for logging on demand | `Marshaler` | `LogValuer` |
| Log levels | >= 0, higher meaning "less important" | positive and negative, with 0 for "info" and higher meaning "more important" |
| Error log entries | always logged, don't have a verbosity level | normal log entries with level >= `LevelError` |
| Passing logger via context | `NewContext`, `FromContext` | no API |
| Adding a name to a logger | `WithName` | no API |
| Modify verbosity of log entries in a call chain | `V` | no API |
| Grouping of key/value pairs | not supported | `WithGroup`, `GroupValue` |
The high-level slog API is explicitly meant to be one of many different APIs
that can be layered on top of a shared `slog.Handler`. logr is one such
alternative API, with [interoperability](#slog-interoperability) provided by the [`slogr`](slogr)
package.
### Inspiration ### Inspiration
Before you consider this package, please read [this blog post by the Before you consider this package, please read [this blog post by the
@@ -118,6 +142,91 @@ There are implementations for the following logging libraries:
- **github.com/go-kit/log**: [gokitlogr](https://github.com/tonglil/gokitlogr) (also compatible with github.com/go-kit/kit/log since v0.12.0) - **github.com/go-kit/log**: [gokitlogr](https://github.com/tonglil/gokitlogr) (also compatible with github.com/go-kit/kit/log since v0.12.0)
- **bytes.Buffer** (writing to a buffer): [bufrlogr](https://github.com/tonglil/buflogr) (useful for ensuring values were logged, like during testing) - **bytes.Buffer** (writing to a buffer): [bufrlogr](https://github.com/tonglil/buflogr) (useful for ensuring values were logged, like during testing)
## slog interoperability
Interoperability goes both ways, using the `logr.Logger` API with a `slog.Handler`
and using the `slog.Logger` API with a `logr.LogSink`. [slogr](./slogr) provides `NewLogr` and
`NewSlogHandler` API calls to convert between a `logr.Logger` and a `slog.Handler`.
As usual, `slog.New` can be used to wrap such a `slog.Handler` in the high-level
slog API. `slogr` itself leaves that to the caller.
## Using a `logr.Sink` as backend for slog
Ideally, a logr sink implementation should support both logr and slog by
implementing both the normal logr interface(s) and `slogr.SlogSink`. Because
of a conflict in the parameters of the common `Enabled` method, it is [not
possible to implement both slog.Handler and logr.Sink in the same
type](https://github.com/golang/go/issues/59110).
If both are supported, log calls can go from the high-level APIs to the backend
without the need to convert parameters. `NewLogr` and `NewSlogHandler` can
convert back and forth without adding additional wrappers, with one exception:
when `Logger.V` was used to adjust the verbosity for a `slog.Handler`, then
`NewSlogHandler` has to use a wrapper which adjusts the verbosity for future
log calls.
Such an implementation should also support values that implement specific
interfaces from both packages for logging (`logr.Marshaler`, `slog.LogValuer`,
`slog.GroupValue`). logr does not convert those.
Not supporting slog has several drawbacks:
- Recording source code locations works correctly if the handler gets called
through `slog.Logger`, but may be wrong in other cases. That's because a
`logr.Sink` does its own stack unwinding instead of using the program counter
provided by the high-level API.
- slog levels <= 0 can be mapped to logr levels by negating the level without a
loss of information. But all slog levels > 0 (e.g. `slog.LevelWarning` as
used by `slog.Logger.Warn`) must be mapped to 0 before calling the sink
because logr does not support "more important than info" levels.
- The slog group concept is supported by prefixing each key in a key/value
pair with the group names, separated by a dot. For structured output like
JSON it would be better to group the key/value pairs inside an object.
- Special slog values and interfaces don't work as expected.
- The overhead is likely to be higher.
These drawbacks are severe enough that applications using a mixture of slog and
logr should switch to a different backend.
## Using a `slog.Handler` as backend for logr
Using a plain `slog.Handler` without support for logr works better than the
other direction:
- All logr verbosity levels can be mapped 1:1 to their corresponding slog level
by negating them.
- Stack unwinding is done by the `slogr.SlogSink` and the resulting program
counter is passed to the `slog.Handler`.
- Names added via `Logger.WithName` are gathered and recorded in an additional
attribute with `logger` as key and the names separated by slash as value.
- `Logger.Error` is turned into a log record with `slog.LevelError` as level
and an additional attribute with `err` as key, if an error was provided.
The main drawback is that `logr.Marshaler` will not be supported. Types should
ideally support both `logr.Marshaler` and `slog.Valuer`. If compatibility
with logr implementations without slog support is not important, then
`slog.Valuer` is sufficient.
## Context support for slog
Storing a logger in a `context.Context` is not supported by
slog. `logr.NewContext` and `logr.FromContext` can be used with slog like this
to fill this gap:
func HandlerFromContext(ctx context.Context) slog.Handler {
logger, err := logr.FromContext(ctx)
if err == nil {
return slogr.NewSlogHandler(logger)
}
return slog.Default().Handler()
}
func ContextWithHandler(ctx context.Context, handler slog.Handler) context.Context {
return logr.NewContext(ctx, slogr.NewLogr(handler))
}
The downside is that storing and retrieving a `slog.Handler` needs more
allocations compared to using a `logr.Logger`. Therefore the recommendation is
to use the `logr.Logger` API in code which uses contextual logging.
## FAQ ## FAQ
### Conceptual ### Conceptual
@@ -241,7 +350,9 @@ Otherwise, you can start out with `0` as "you always want to see this",
Then gradually choose levels in between as you need them, working your way Then gradually choose levels in between as you need them, working your way
down from 10 (for debug and trace style logs) and up from 1 (for chattier down from 10 (for debug and trace style logs) and up from 1 (for chattier
info-type logs.) info-type logs). For reference, slog pre-defines -4 for debug logs
(corresponds to 4 in logr), which matches what is
[recommended for Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md#what-method-to-use).
#### How do I choose my keys? #### How do I choose my keys?
+18
View File
@@ -0,0 +1,18 @@
# Security Policy
If you have discovered a security vulnerability in this project, please report it
privately. **Do not disclose it as a public issue.** This gives us time to work with you
to fix the issue before public exposure, reducing the chance that the exploit will be
used before a patch is released.
You may submit the report in the following ways:
- send an email to go-logr-security@googlegroups.com
- send us a [private vulnerability report](https://github.com/go-logr/logr/security/advisories/new)
Please provide the following information in your report:
- A description of the vulnerability and its impact
- How to reproduce the issue
We ask that you give us 90 days to work on a fix before public exposure.
+23 -23
View File
@@ -116,17 +116,17 @@ type Options struct {
// Equivalent hooks are offered for key-value pairs saved via // Equivalent hooks are offered for key-value pairs saved via
// logr.Logger.WithValues or Formatter.AddValues (see RenderValuesHook) and // logr.Logger.WithValues or Formatter.AddValues (see RenderValuesHook) and
// for user-provided pairs (see RenderArgsHook). // for user-provided pairs (see RenderArgsHook).
RenderBuiltinsHook func(kvList []interface{}) []interface{} RenderBuiltinsHook func(kvList []any) []any
// RenderValuesHook is the same as RenderBuiltinsHook, except that it is // RenderValuesHook is the same as RenderBuiltinsHook, except that it is
// only called for key-value pairs saved via logr.Logger.WithValues. See // only called for key-value pairs saved via logr.Logger.WithValues. See
// RenderBuiltinsHook for more details. // RenderBuiltinsHook for more details.
RenderValuesHook func(kvList []interface{}) []interface{} RenderValuesHook func(kvList []any) []any
// RenderArgsHook is the same as RenderBuiltinsHook, except that it is only // RenderArgsHook is the same as RenderBuiltinsHook, except that it is only
// called for key-value pairs passed directly to Info and Error. See // called for key-value pairs passed directly to Info and Error. See
// RenderBuiltinsHook for more details. // RenderBuiltinsHook for more details.
RenderArgsHook func(kvList []interface{}) []interface{} RenderArgsHook func(kvList []any) []any
// MaxLogDepth tells funcr how many levels of nested fields (e.g. a struct // MaxLogDepth tells funcr how many levels of nested fields (e.g. a struct
// that contains a struct, etc.) it may log. Every time it finds a struct, // that contains a struct, etc.) it may log. Every time it finds a struct,
@@ -163,7 +163,7 @@ func (l fnlogger) WithName(name string) logr.LogSink {
return &l return &l
} }
func (l fnlogger) WithValues(kvList ...interface{}) logr.LogSink { func (l fnlogger) WithValues(kvList ...any) logr.LogSink {
l.Formatter.AddValues(kvList) l.Formatter.AddValues(kvList)
return &l return &l
} }
@@ -173,12 +173,12 @@ func (l fnlogger) WithCallDepth(depth int) logr.LogSink {
return &l return &l
} }
func (l fnlogger) Info(level int, msg string, kvList ...interface{}) { func (l fnlogger) Info(level int, msg string, kvList ...any) {
prefix, args := l.FormatInfo(level, msg, kvList) prefix, args := l.FormatInfo(level, msg, kvList)
l.write(prefix, args) l.write(prefix, args)
} }
func (l fnlogger) Error(err error, msg string, kvList ...interface{}) { func (l fnlogger) Error(err error, msg string, kvList ...any) {
prefix, args := l.FormatError(err, msg, kvList) prefix, args := l.FormatError(err, msg, kvList)
l.write(prefix, args) l.write(prefix, args)
} }
@@ -229,7 +229,7 @@ func newFormatter(opts Options, outfmt outputFormat) Formatter {
type Formatter struct { type Formatter struct {
outputFormat outputFormat outputFormat outputFormat
prefix string prefix string
values []interface{} values []any
valuesStr string valuesStr string
depth int depth int
opts *Options opts *Options
@@ -246,10 +246,10 @@ const (
) )
// PseudoStruct is a list of key-value pairs that gets logged as a struct. // PseudoStruct is a list of key-value pairs that gets logged as a struct.
type PseudoStruct []interface{} type PseudoStruct []any
// render produces a log line, ready to use. // render produces a log line, ready to use.
func (f Formatter) render(builtins, args []interface{}) string { func (f Formatter) render(builtins, args []any) string {
// Empirically bytes.Buffer is faster than strings.Builder for this. // Empirically bytes.Buffer is faster than strings.Builder for this.
buf := bytes.NewBuffer(make([]byte, 0, 1024)) buf := bytes.NewBuffer(make([]byte, 0, 1024))
if f.outputFormat == outputJSON { if f.outputFormat == outputJSON {
@@ -292,7 +292,7 @@ func (f Formatter) render(builtins, args []interface{}) string {
// This function returns a potentially modified version of kvList, which // This function returns a potentially modified version of kvList, which
// ensures that there is a value for every key (adding a value if needed) and // ensures that there is a value for every key (adding a value if needed) and
// that each key is a string (substituting a key if needed). // that each key is a string (substituting a key if needed).
func (f Formatter) flatten(buf *bytes.Buffer, kvList []interface{}, continuing bool, escapeKeys bool) []interface{} { func (f Formatter) flatten(buf *bytes.Buffer, kvList []any, continuing bool, escapeKeys bool) []any {
// This logic overlaps with sanitize() but saves one type-cast per key, // This logic overlaps with sanitize() but saves one type-cast per key,
// which can be measurable. // which can be measurable.
if len(kvList)%2 != 0 { if len(kvList)%2 != 0 {
@@ -334,7 +334,7 @@ func (f Formatter) flatten(buf *bytes.Buffer, kvList []interface{}, continuing b
return kvList return kvList
} }
func (f Formatter) pretty(value interface{}) string { func (f Formatter) pretty(value any) string {
return f.prettyWithFlags(value, 0, 0) return f.prettyWithFlags(value, 0, 0)
} }
@@ -343,7 +343,7 @@ const (
) )
// TODO: This is not fast. Most of the overhead goes here. // TODO: This is not fast. Most of the overhead goes here.
func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) string { func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string {
if depth > f.opts.MaxLogDepth { if depth > f.opts.MaxLogDepth {
return `"<max-log-depth-exceeded>"` return `"<max-log-depth-exceeded>"`
} }
@@ -614,7 +614,7 @@ func isEmpty(v reflect.Value) bool {
return false return false
} }
func invokeMarshaler(m logr.Marshaler) (ret interface{}) { func invokeMarshaler(m logr.Marshaler) (ret any) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
ret = fmt.Sprintf("<panic: %s>", r) ret = fmt.Sprintf("<panic: %s>", r)
@@ -675,12 +675,12 @@ func (f Formatter) caller() Caller {
const noValue = "<no-value>" const noValue = "<no-value>"
func (f Formatter) nonStringKey(v interface{}) string { func (f Formatter) nonStringKey(v any) string {
return fmt.Sprintf("<non-string-key: %s>", f.snippet(v)) return fmt.Sprintf("<non-string-key: %s>", f.snippet(v))
} }
// snippet produces a short snippet string of an arbitrary value. // snippet produces a short snippet string of an arbitrary value.
func (f Formatter) snippet(v interface{}) string { func (f Formatter) snippet(v any) string {
const snipLen = 16 const snipLen = 16
snip := f.pretty(v) snip := f.pretty(v)
@@ -693,7 +693,7 @@ func (f Formatter) snippet(v interface{}) string {
// sanitize ensures that a list of key-value pairs has a value for every key // sanitize ensures that a list of key-value pairs has a value for every key
// (adding a value if needed) and that each key is a string (substituting a key // (adding a value if needed) and that each key is a string (substituting a key
// if needed). // if needed).
func (f Formatter) sanitize(kvList []interface{}) []interface{} { func (f Formatter) sanitize(kvList []any) []any {
if len(kvList)%2 != 0 { if len(kvList)%2 != 0 {
kvList = append(kvList, noValue) kvList = append(kvList, noValue)
} }
@@ -727,8 +727,8 @@ func (f Formatter) GetDepth() int {
// FormatInfo renders an Info log message into strings. The prefix will be // FormatInfo renders an Info log message into strings. The prefix will be
// empty when no names were set (via AddNames), or when the output is // empty when no names were set (via AddNames), or when the output is
// configured for JSON. // configured for JSON.
func (f Formatter) FormatInfo(level int, msg string, kvList []interface{}) (prefix, argsStr string) { func (f Formatter) FormatInfo(level int, msg string, kvList []any) (prefix, argsStr string) {
args := make([]interface{}, 0, 64) // using a constant here impacts perf args := make([]any, 0, 64) // using a constant here impacts perf
prefix = f.prefix prefix = f.prefix
if f.outputFormat == outputJSON { if f.outputFormat == outputJSON {
args = append(args, "logger", prefix) args = append(args, "logger", prefix)
@@ -747,8 +747,8 @@ func (f Formatter) FormatInfo(level int, msg string, kvList []interface{}) (pref
// FormatError renders an Error log message into strings. The prefix will be // FormatError renders an Error log message into strings. The prefix will be
// empty when no names were set (via AddNames), or when the output is // empty when no names were set (via AddNames), or when the output is
// configured for JSON. // configured for JSON.
func (f Formatter) FormatError(err error, msg string, kvList []interface{}) (prefix, argsStr string) { func (f Formatter) FormatError(err error, msg string, kvList []any) (prefix, argsStr string) {
args := make([]interface{}, 0, 64) // using a constant here impacts perf args := make([]any, 0, 64) // using a constant here impacts perf
prefix = f.prefix prefix = f.prefix
if f.outputFormat == outputJSON { if f.outputFormat == outputJSON {
args = append(args, "logger", prefix) args = append(args, "logger", prefix)
@@ -761,12 +761,12 @@ func (f Formatter) FormatError(err error, msg string, kvList []interface{}) (pre
args = append(args, "caller", f.caller()) args = append(args, "caller", f.caller())
} }
args = append(args, "msg", msg) args = append(args, "msg", msg)
var loggableErr interface{} var loggableErr any
if err != nil { if err != nil {
loggableErr = err.Error() loggableErr = err.Error()
} }
args = append(args, "error", loggableErr) args = append(args, "error", loggableErr)
return f.prefix, f.render(args, kvList) return prefix, f.render(args, kvList)
} }
// AddName appends the specified name. funcr uses '/' characters to separate // AddName appends the specified name. funcr uses '/' characters to separate
@@ -781,7 +781,7 @@ func (f *Formatter) AddName(name string) {
// AddValues adds key-value pairs to the set of saved values to be logged with // AddValues adds key-value pairs to the set of saved values to be logged with
// each log line. // each log line.
func (f *Formatter) AddValues(kvList []interface{}) { func (f *Formatter) AddValues(kvList []any) {
// Three slice args forces a copy. // Three slice args forces a copy.
n := len(f.values) n := len(f.values)
f.values = append(f.values[:n:n], kvList...) f.values = append(f.values[:n:n], kvList...)
+24 -11
View File
@@ -127,9 +127,9 @@ limitations under the License.
// such a value can call its methods without having to check whether the // such a value can call its methods without having to check whether the
// instance is ready for use. // instance is ready for use.
// //
// Calling methods with the null logger (Logger{}) as instance will crash // The zero logger (= Logger{}) is identical to Discard() and discards all log
// because it has no LogSink. Therefore this null logger should never be passed // entries. Code that receives a Logger by value can simply call it, the methods
// around. For cases where passing a logger is optional, a pointer to Logger // will never crash. For cases where passing a logger is optional, a pointer to Logger
// should be used. // should be used.
// //
// # Key Naming Conventions // # Key Naming Conventions
@@ -258,6 +258,12 @@ type Logger struct {
// Enabled tests whether this Logger is enabled. For example, commandline // Enabled tests whether this Logger is enabled. For example, commandline
// flags might be used to set the logging verbosity and disable some info logs. // flags might be used to set the logging verbosity and disable some info logs.
func (l Logger) Enabled() bool { func (l Logger) Enabled() bool {
// Some implementations of LogSink look at the caller in Enabled (e.g.
// different verbosity levels per package or file), but we only pass one
// CallDepth in (via Init). This means that all calls from Logger to the
// LogSink's Enabled, Info, and Error methods must have the same number of
// frames. In other words, Logger methods can't call other Logger methods
// which call these LogSink methods unless we do it the same in all paths.
return l.sink != nil && l.sink.Enabled(l.level) return l.sink != nil && l.sink.Enabled(l.level)
} }
@@ -267,11 +273,11 @@ func (l Logger) Enabled() bool {
// line. The key/value pairs can then be used to add additional variable // line. The key/value pairs can then be used to add additional variable
// information. The key/value pairs must alternate string keys and arbitrary // information. The key/value pairs must alternate string keys and arbitrary
// values. // values.
func (l Logger) Info(msg string, keysAndValues ...interface{}) { func (l Logger) Info(msg string, keysAndValues ...any) {
if l.sink == nil { if l.sink == nil {
return return
} }
if l.Enabled() { if l.sink.Enabled(l.level) { // see comment in Enabled
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok { if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
withHelper.GetCallStackHelper()() withHelper.GetCallStackHelper()()
} }
@@ -289,7 +295,7 @@ func (l Logger) Info(msg string, keysAndValues ...interface{}) {
// while the err argument should be used to attach the actual error that // while the err argument should be used to attach the actual error that
// triggered this log line, if present. The err parameter is optional // triggered this log line, if present. The err parameter is optional
// and nil may be passed instead of an error instance. // and nil may be passed instead of an error instance.
func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) { func (l Logger) Error(err error, msg string, keysAndValues ...any) {
if l.sink == nil { if l.sink == nil {
return return
} }
@@ -314,9 +320,16 @@ func (l Logger) V(level int) Logger {
return l return l
} }
// GetV returns the verbosity level of the logger. If the logger's LogSink is
// nil as in the Discard logger, this will always return 0.
func (l Logger) GetV() int {
// 0 if l.sink nil because of the if check in V above.
return l.level
}
// WithValues returns a new Logger instance with additional key/value pairs. // WithValues returns a new Logger instance with additional key/value pairs.
// See Info for documentation on how key/value pairs work. // See Info for documentation on how key/value pairs work.
func (l Logger) WithValues(keysAndValues ...interface{}) Logger { func (l Logger) WithValues(keysAndValues ...any) Logger {
if l.sink == nil { if l.sink == nil {
return l return l
} }
@@ -467,15 +480,15 @@ type LogSink interface {
// The level argument is provided for optional logging. This method will // The level argument is provided for optional logging. This method will
// only be called when Enabled(level) is true. See Logger.Info for more // only be called when Enabled(level) is true. See Logger.Info for more
// details. // details.
Info(level int, msg string, keysAndValues ...interface{}) Info(level int, msg string, keysAndValues ...any)
// Error logs an error, with the given message and key/value pairs as // Error logs an error, with the given message and key/value pairs as
// context. See Logger.Error for more details. // context. See Logger.Error for more details.
Error(err error, msg string, keysAndValues ...interface{}) Error(err error, msg string, keysAndValues ...any)
// WithValues returns a new LogSink with additional key/value pairs. See // WithValues returns a new LogSink with additional key/value pairs. See
// Logger.WithValues for more details. // Logger.WithValues for more details.
WithValues(keysAndValues ...interface{}) LogSink WithValues(keysAndValues ...any) LogSink
// WithName returns a new LogSink with the specified name appended. See // WithName returns a new LogSink with the specified name appended. See
// Logger.WithName for more details. // Logger.WithName for more details.
@@ -546,5 +559,5 @@ type Marshaler interface {
// with exported fields // with exported fields
// //
// It may return any value of any type. // It may return any value of any type.
MarshalLog() interface{} MarshalLog() any
} }
+20 -18
View File
@@ -5,7 +5,7 @@
// Package cmp determines equality of values. // Package cmp determines equality of values.
// //
// This package is intended to be a more powerful and safer alternative to // This package is intended to be a more powerful and safer alternative to
// reflect.DeepEqual for comparing whether two values are semantically equal. // [reflect.DeepEqual] for comparing whether two values are semantically equal.
// It is intended to only be used in tests, as performance is not a goal and // It is intended to only be used in tests, as performance is not a goal and
// it may panic if it cannot compare the values. Its propensity towards // it may panic if it cannot compare the values. Its propensity towards
// panicking means that its unsuitable for production environments where a // panicking means that its unsuitable for production environments where a
@@ -18,16 +18,17 @@
// For example, an equality function may report floats as equal so long as // For example, an equality function may report floats as equal so long as
// they are within some tolerance of each other. // they are within some tolerance of each other.
// //
// - Types with an Equal method may use that method to determine equality. // - Types with an Equal method (e.g., [time.Time.Equal]) may use that method
// This allows package authors to determine the equality operation // to determine equality. This allows package authors to determine
// for the types that they define. // the equality operation for the types that they define.
// //
// - If no custom equality functions are used and no Equal method is defined, // - If no custom equality functions are used and no Equal method is defined,
// equality is determined by recursively comparing the primitive kinds on // equality is determined by recursively comparing the primitive kinds on
// both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, // both values, much like [reflect.DeepEqual]. Unlike [reflect.DeepEqual],
// unexported fields are not compared by default; they result in panics // unexported fields are not compared by default; they result in panics
// unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported) // unless suppressed by using an [Ignore] option
// or explicitly compared using the Exporter option. // (see [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported])
// or explicitly compared using the [Exporter] option.
package cmp package cmp
import ( import (
@@ -45,14 +46,14 @@ import (
// Equal reports whether x and y are equal by recursively applying the // Equal reports whether x and y are equal by recursively applying the
// following rules in the given order to x and y and all of their sub-values: // following rules in the given order to x and y and all of their sub-values:
// //
// - Let S be the set of all Ignore, Transformer, and Comparer options that // - Let S be the set of all [Ignore], [Transformer], and [Comparer] options that
// remain after applying all path filters, value filters, and type filters. // remain after applying all path filters, value filters, and type filters.
// If at least one Ignore exists in S, then the comparison is ignored. // If at least one [Ignore] exists in S, then the comparison is ignored.
// If the number of Transformer and Comparer options in S is non-zero, // If the number of [Transformer] and [Comparer] options in S is non-zero,
// then Equal panics because it is ambiguous which option to use. // then Equal panics because it is ambiguous which option to use.
// If S contains a single Transformer, then use that to transform // If S contains a single [Transformer], then use that to transform
// the current values and recursively call Equal on the output values. // the current values and recursively call Equal on the output values.
// If S contains a single Comparer, then use that to compare the current values. // If S contains a single [Comparer], then use that to compare the current values.
// Otherwise, evaluation proceeds to the next rule. // Otherwise, evaluation proceeds to the next rule.
// //
// - If the values have an Equal method of the form "(T) Equal(T) bool" or // - If the values have an Equal method of the form "(T) Equal(T) bool" or
@@ -66,21 +67,22 @@ import (
// Functions are only equal if they are both nil, otherwise they are unequal. // Functions are only equal if they are both nil, otherwise they are unequal.
// //
// Structs are equal if recursively calling Equal on all fields report equal. // Structs are equal if recursively calling Equal on all fields report equal.
// If a struct contains unexported fields, Equal panics unless an Ignore option // If a struct contains unexported fields, Equal panics unless an [Ignore] option
// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option // (e.g., [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported]) ignores that field
// explicitly permits comparing the unexported field. // or the [Exporter] option explicitly permits comparing the unexported field.
// //
// Slices are equal if they are both nil or both non-nil, where recursively // Slices are equal if they are both nil or both non-nil, where recursively
// calling Equal on all non-ignored slice or array elements report equal. // calling Equal on all non-ignored slice or array elements report equal.
// Empty non-nil slices and nil slices are not equal; to equate empty slices, // Empty non-nil slices and nil slices are not equal; to equate empty slices,
// consider using cmpopts.EquateEmpty. // consider using [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty].
// //
// Maps are equal if they are both nil or both non-nil, where recursively // Maps are equal if they are both nil or both non-nil, where recursively
// calling Equal on all non-ignored map entries report equal. // calling Equal on all non-ignored map entries report equal.
// Map keys are equal according to the == operator. // Map keys are equal according to the == operator.
// To use custom comparisons for map keys, consider using cmpopts.SortMaps. // To use custom comparisons for map keys, consider using
// [github.com/google/go-cmp/cmp/cmpopts.SortMaps].
// Empty non-nil maps and nil maps are not equal; to equate empty maps, // Empty non-nil maps and nil maps are not equal; to equate empty maps,
// consider using cmpopts.EquateEmpty. // consider using [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty].
// //
// Pointers and interfaces are equal if they are both nil or both non-nil, // Pointers and interfaces are equal if they are both nil or both non-nil,
// where they have the same underlying concrete type and recursively // where they have the same underlying concrete type and recursively
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !purego
// +build !purego
package cmp package cmp
import ( import (
@@ -12,8 +9,6 @@ import (
"unsafe" "unsafe"
) )
const supportExporters = true
// retrieveUnexportedField uses unsafe to forcibly retrieve any field from // retrieveUnexportedField uses unsafe to forcibly retrieve any field from
// a struct such that the value has read-write permissions. // a struct such that the value has read-write permissions.
// //
-16
View File
@@ -1,16 +0,0 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build purego
// +build purego
package cmp
import "reflect"
const supportExporters = false
func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value {
panic("no support for forcibly accessing unexported fields")
}
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !purego
// +build !purego
package value package value
import ( import (
-34
View File
@@ -1,34 +0,0 @@
// Copyright 2018, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build purego
// +build purego
package value
import "reflect"
// Pointer is an opaque typed pointer and is guaranteed to be comparable.
type Pointer struct {
p uintptr
t reflect.Type
}
// PointerOf returns a Pointer from v, which must be a
// reflect.Ptr, reflect.Slice, or reflect.Map.
func PointerOf(v reflect.Value) Pointer {
// NOTE: Storing a pointer as an uintptr is technically incorrect as it
// assumes that the GC implementation does not use a moving collector.
return Pointer{v.Pointer(), v.Type()}
}
// IsNil reports whether the pointer is nil.
func (p Pointer) IsNil() bool {
return p.p == 0
}
// Uintptr returns the pointer as a uintptr.
func (p Pointer) Uintptr() uintptr {
return p.p
}
+42 -42
View File
@@ -13,15 +13,15 @@ import (
"github.com/google/go-cmp/cmp/internal/function" "github.com/google/go-cmp/cmp/internal/function"
) )
// Option configures for specific behavior of Equal and Diff. In particular, // Option configures for specific behavior of [Equal] and [Diff]. In particular,
// the fundamental Option functions (Ignore, Transformer, and Comparer), // the fundamental Option functions ([Ignore], [Transformer], and [Comparer]),
// configure how equality is determined. // configure how equality is determined.
// //
// The fundamental options may be composed with filters (FilterPath and // The fundamental options may be composed with filters ([FilterPath] and
// FilterValues) to control the scope over which they are applied. // [FilterValues]) to control the scope over which they are applied.
// //
// The cmp/cmpopts package provides helper functions for creating options that // The [github.com/google/go-cmp/cmp/cmpopts] package provides helper functions
// may be used with Equal and Diff. // for creating options that may be used with [Equal] and [Diff].
type Option interface { type Option interface {
// filter applies all filters and returns the option that remains. // filter applies all filters and returns the option that remains.
// Each option may only read s.curPath and call s.callTTBFunc. // Each option may only read s.curPath and call s.callTTBFunc.
@@ -56,9 +56,9 @@ type core struct{}
func (core) isCore() {} func (core) isCore() {}
// Options is a list of Option values that also satisfies the Option interface. // Options is a list of [Option] values that also satisfies the [Option] interface.
// Helper comparison packages may return an Options value when packing multiple // Helper comparison packages may return an Options value when packing multiple
// Option values into a single Option. When this package processes an Options, // [Option] values into a single [Option]. When this package processes an Options,
// it will be implicitly expanded into a flat list. // it will be implicitly expanded into a flat list.
// //
// Applying a filter on an Options is equivalent to applying that same filter // Applying a filter on an Options is equivalent to applying that same filter
@@ -105,16 +105,16 @@ func (opts Options) String() string {
return fmt.Sprintf("Options{%s}", strings.Join(ss, ", ")) return fmt.Sprintf("Options{%s}", strings.Join(ss, ", "))
} }
// FilterPath returns a new Option where opt is only evaluated if filter f // FilterPath returns a new [Option] where opt is only evaluated if filter f
// returns true for the current Path in the value tree. // returns true for the current [Path] in the value tree.
// //
// This filter is called even if a slice element or map entry is missing and // This filter is called even if a slice element or map entry is missing and
// provides an opportunity to ignore such cases. The filter function must be // provides an opportunity to ignore such cases. The filter function must be
// symmetric such that the filter result is identical regardless of whether the // symmetric such that the filter result is identical regardless of whether the
// missing value is from x or y. // missing value is from x or y.
// //
// The option passed in may be an Ignore, Transformer, Comparer, Options, or // The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or
// a previously filtered Option. // a previously filtered [Option].
func FilterPath(f func(Path) bool, opt Option) Option { func FilterPath(f func(Path) bool, opt Option) Option {
if f == nil { if f == nil {
panic("invalid path filter function") panic("invalid path filter function")
@@ -142,7 +142,7 @@ func (f pathFilter) String() string {
return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt) return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt)
} }
// FilterValues returns a new Option where opt is only evaluated if filter f, // FilterValues returns a new [Option] where opt is only evaluated if filter f,
// which is a function of the form "func(T, T) bool", returns true for the // which is a function of the form "func(T, T) bool", returns true for the
// current pair of values being compared. If either value is invalid or // current pair of values being compared. If either value is invalid or
// the type of the values is not assignable to T, then this filter implicitly // the type of the values is not assignable to T, then this filter implicitly
@@ -154,8 +154,8 @@ func (f pathFilter) String() string {
// If T is an interface, it is possible that f is called with two values with // If T is an interface, it is possible that f is called with two values with
// different concrete types that both implement T. // different concrete types that both implement T.
// //
// The option passed in may be an Ignore, Transformer, Comparer, Options, or // The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or
// a previously filtered Option. // a previously filtered [Option].
func FilterValues(f interface{}, opt Option) Option { func FilterValues(f interface{}, opt Option) Option {
v := reflect.ValueOf(f) v := reflect.ValueOf(f)
if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() { if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() {
@@ -192,9 +192,9 @@ func (f valuesFilter) String() string {
return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt) return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt)
} }
// Ignore is an Option that causes all comparisons to be ignored. // Ignore is an [Option] that causes all comparisons to be ignored.
// This value is intended to be combined with FilterPath or FilterValues. // This value is intended to be combined with [FilterPath] or [FilterValues].
// It is an error to pass an unfiltered Ignore option to Equal. // It is an error to pass an unfiltered Ignore option to [Equal].
func Ignore() Option { return ignore{} } func Ignore() Option { return ignore{} }
type ignore struct{ core } type ignore struct{ core }
@@ -234,6 +234,8 @@ func (validator) apply(s *state, vx, vy reflect.Value) {
name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType
if _, ok := reflect.New(t).Interface().(error); ok { if _, ok := reflect.New(t).Interface().(error); ok {
help = "consider using cmpopts.EquateErrors to compare error values" help = "consider using cmpopts.EquateErrors to compare error values"
} else if t.Comparable() {
help = "consider using cmpopts.EquateComparable to compare comparable Go types"
} }
} else { } else {
// Unnamed type with unexported fields. Derive PkgPath from field. // Unnamed type with unexported fields. Derive PkgPath from field.
@@ -254,7 +256,7 @@ const identRx = `[_\p{L}][_\p{L}\p{N}]*`
var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`)
// Transformer returns an Option that applies a transformation function that // Transformer returns an [Option] that applies a transformation function that
// converts values of a certain type into that of another. // converts values of a certain type into that of another.
// //
// The transformer f must be a function "func(T) R" that converts values of // The transformer f must be a function "func(T) R" that converts values of
@@ -265,13 +267,14 @@ var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`)
// same transform to the output of itself (e.g., in the case where the // same transform to the output of itself (e.g., in the case where the
// input and output types are the same), an implicit filter is added such that // input and output types are the same), an implicit filter is added such that
// a transformer is applicable only if that exact transformer is not already // a transformer is applicable only if that exact transformer is not already
// in the tail of the Path since the last non-Transform step. // in the tail of the [Path] since the last non-[Transform] step.
// For situations where the implicit filter is still insufficient, // For situations where the implicit filter is still insufficient,
// consider using cmpopts.AcyclicTransformer, which adds a filter // consider using [github.com/google/go-cmp/cmp/cmpopts.AcyclicTransformer],
// to prevent the transformer from being recursively applied upon itself. // which adds a filter to prevent the transformer from
// being recursively applied upon itself.
// //
// The name is a user provided label that is used as the Transform.Name in the // The name is a user provided label that is used as the [Transform.Name] in the
// transformation PathStep (and eventually shown in the Diff output). // transformation [PathStep] (and eventually shown in the [Diff] output).
// The name must be a valid identifier or qualified identifier in Go syntax. // The name must be a valid identifier or qualified identifier in Go syntax.
// If empty, an arbitrary name is used. // If empty, an arbitrary name is used.
func Transformer(name string, f interface{}) Option { func Transformer(name string, f interface{}) Option {
@@ -329,7 +332,7 @@ func (tr transformer) String() string {
return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc)) return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc))
} }
// Comparer returns an Option that determines whether two values are equal // Comparer returns an [Option] that determines whether two values are equal
// to each other. // to each other.
// //
// The comparer f must be a function "func(T, T) bool" and is implicitly // The comparer f must be a function "func(T, T) bool" and is implicitly
@@ -377,35 +380,32 @@ func (cm comparer) String() string {
return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc)) return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc))
} }
// Exporter returns an Option that specifies whether Equal is allowed to // Exporter returns an [Option] that specifies whether [Equal] is allowed to
// introspect into the unexported fields of certain struct types. // introspect into the unexported fields of certain struct types.
// //
// Users of this option must understand that comparing on unexported fields // Users of this option must understand that comparing on unexported fields
// from external packages is not safe since changes in the internal // from external packages is not safe since changes in the internal
// implementation of some external package may cause the result of Equal // implementation of some external package may cause the result of [Equal]
// to unexpectedly change. However, it may be valid to use this option on types // to unexpectedly change. However, it may be valid to use this option on types
// defined in an internal package where the semantic meaning of an unexported // defined in an internal package where the semantic meaning of an unexported
// field is in the control of the user. // field is in the control of the user.
// //
// In many cases, a custom Comparer should be used instead that defines // In many cases, a custom [Comparer] should be used instead that defines
// equality as a function of the public API of a type rather than the underlying // equality as a function of the public API of a type rather than the underlying
// unexported implementation. // unexported implementation.
// //
// For example, the reflect.Type documentation defines equality to be determined // For example, the [reflect.Type] documentation defines equality to be determined
// by the == operator on the interface (essentially performing a shallow pointer // by the == operator on the interface (essentially performing a shallow pointer
// comparison) and most attempts to compare *regexp.Regexp types are interested // comparison) and most attempts to compare *[regexp.Regexp] types are interested
// in only checking that the regular expression strings are equal. // in only checking that the regular expression strings are equal.
// Both of these are accomplished using Comparers: // Both of these are accomplished using [Comparer] options:
// //
// Comparer(func(x, y reflect.Type) bool { return x == y }) // Comparer(func(x, y reflect.Type) bool { return x == y })
// Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() }) // Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() })
// //
// In other cases, the cmpopts.IgnoreUnexported option can be used to ignore // In other cases, the [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported]
// all unexported fields on specified struct types. // option can be used to ignore all unexported fields on specified struct types.
func Exporter(f func(reflect.Type) bool) Option { func Exporter(f func(reflect.Type) bool) Option {
if !supportExporters {
panic("Exporter is not supported on purego builds")
}
return exporter(f) return exporter(f)
} }
@@ -415,10 +415,10 @@ func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableO
panic("not implemented") panic("not implemented")
} }
// AllowUnexported returns an Options that allows Equal to forcibly introspect // AllowUnexported returns an [Option] that allows [Equal] to forcibly introspect
// unexported fields of the specified struct types. // unexported fields of the specified struct types.
// //
// See Exporter for the proper use of this option. // See [Exporter] for the proper use of this option.
func AllowUnexported(types ...interface{}) Option { func AllowUnexported(types ...interface{}) Option {
m := make(map[reflect.Type]bool) m := make(map[reflect.Type]bool)
for _, typ := range types { for _, typ := range types {
@@ -432,7 +432,7 @@ func AllowUnexported(types ...interface{}) Option {
} }
// Result represents the comparison result for a single node and // Result represents the comparison result for a single node and
// is provided by cmp when calling Report (see Reporter). // is provided by cmp when calling Report (see [Reporter]).
type Result struct { type Result struct {
_ [0]func() // Make Result incomparable _ [0]func() // Make Result incomparable
flags resultFlags flags resultFlags
@@ -445,7 +445,7 @@ func (r Result) Equal() bool {
} }
// ByIgnore reports whether the node is equal because it was ignored. // ByIgnore reports whether the node is equal because it was ignored.
// This never reports true if Equal reports false. // This never reports true if [Result.Equal] reports false.
func (r Result) ByIgnore() bool { func (r Result) ByIgnore() bool {
return r.flags&reportByIgnore != 0 return r.flags&reportByIgnore != 0
} }
@@ -455,7 +455,7 @@ func (r Result) ByMethod() bool {
return r.flags&reportByMethod != 0 return r.flags&reportByMethod != 0
} }
// ByFunc reports whether a Comparer function determined equality. // ByFunc reports whether a [Comparer] function determined equality.
func (r Result) ByFunc() bool { func (r Result) ByFunc() bool {
return r.flags&reportByFunc != 0 return r.flags&reportByFunc != 0
} }
@@ -478,7 +478,7 @@ const (
reportByCycle reportByCycle
) )
// Reporter is an Option that can be passed to Equal. When Equal traverses // Reporter is an [Option] that can be passed to [Equal]. When [Equal] traverses
// the value trees, it calls PushStep as it descends into each node in the // the value trees, it calls PushStep as it descends into each node in the
// tree and PopStep as it ascend out of the node. The leaves of the tree are // tree and PopStep as it ascend out of the node. The leaves of the tree are
// either compared (determined to be equal or not equal) or ignored and reported // either compared (determined to be equal or not equal) or ignored and reported
+28 -18
View File
@@ -14,9 +14,9 @@ import (
"github.com/google/go-cmp/cmp/internal/value" "github.com/google/go-cmp/cmp/internal/value"
) )
// Path is a list of PathSteps describing the sequence of operations to get // Path is a list of [PathStep] describing the sequence of operations to get
// from some root type to the current position in the value tree. // from some root type to the current position in the value tree.
// The first Path element is always an operation-less PathStep that exists // The first Path element is always an operation-less [PathStep] that exists
// simply to identify the initial type. // simply to identify the initial type.
// //
// When traversing structs with embedded structs, the embedded struct will // When traversing structs with embedded structs, the embedded struct will
@@ -29,8 +29,13 @@ type Path []PathStep
// a value's tree structure. Users of this package never need to implement // a value's tree structure. Users of this package never need to implement
// these types as values of this type will be returned by this package. // these types as values of this type will be returned by this package.
// //
// Implementations of this interface are // Implementations of this interface:
// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. // - [StructField]
// - [SliceIndex]
// - [MapIndex]
// - [Indirect]
// - [TypeAssertion]
// - [Transform]
type PathStep interface { type PathStep interface {
String() string String() string
@@ -70,8 +75,9 @@ func (pa *Path) pop() {
*pa = (*pa)[:len(*pa)-1] *pa = (*pa)[:len(*pa)-1]
} }
// Last returns the last PathStep in the Path. // Last returns the last [PathStep] in the Path.
// If the path is empty, this returns a non-nil PathStep that reports a nil Type. // If the path is empty, this returns a non-nil [PathStep]
// that reports a nil [PathStep.Type].
func (pa Path) Last() PathStep { func (pa Path) Last() PathStep {
return pa.Index(-1) return pa.Index(-1)
} }
@@ -79,7 +85,8 @@ func (pa Path) Last() PathStep {
// Index returns the ith step in the Path and supports negative indexing. // Index returns the ith step in the Path and supports negative indexing.
// A negative index starts counting from the tail of the Path such that -1 // A negative index starts counting from the tail of the Path such that -1
// refers to the last step, -2 refers to the second-to-last step, and so on. // refers to the last step, -2 refers to the second-to-last step, and so on.
// If index is invalid, this returns a non-nil PathStep that reports a nil Type. // If index is invalid, this returns a non-nil [PathStep]
// that reports a nil [PathStep.Type].
func (pa Path) Index(i int) PathStep { func (pa Path) Index(i int) PathStep {
if i < 0 { if i < 0 {
i = len(pa) + i i = len(pa) + i
@@ -168,7 +175,8 @@ func (ps pathStep) String() string {
return fmt.Sprintf("{%s}", s) return fmt.Sprintf("{%s}", s)
} }
// StructField represents a struct field access on a field called Name. // StructField is a [PathStep] that represents a struct field access
// on a field called [StructField.Name].
type StructField struct{ *structField } type StructField struct{ *structField }
type structField struct { type structField struct {
pathStep pathStep
@@ -204,10 +212,11 @@ func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) }
func (sf StructField) Name() string { return sf.name } func (sf StructField) Name() string { return sf.name }
// Index is the index of the field in the parent struct type. // Index is the index of the field in the parent struct type.
// See reflect.Type.Field. // See [reflect.Type.Field].
func (sf StructField) Index() int { return sf.idx } func (sf StructField) Index() int { return sf.idx }
// SliceIndex is an index operation on a slice or array at some index Key. // SliceIndex is a [PathStep] that represents an index operation on
// a slice or array at some index [SliceIndex.Key].
type SliceIndex struct{ *sliceIndex } type SliceIndex struct{ *sliceIndex }
type sliceIndex struct { type sliceIndex struct {
pathStep pathStep
@@ -247,12 +256,12 @@ func (si SliceIndex) Key() int {
// all of the indexes to be shifted. If an index is -1, then that // all of the indexes to be shifted. If an index is -1, then that
// indicates that the element does not exist in the associated slice. // indicates that the element does not exist in the associated slice.
// //
// Key is guaranteed to return -1 if and only if the indexes returned // [SliceIndex.Key] is guaranteed to return -1 if and only if the indexes
// by SplitKeys are not the same. SplitKeys will never return -1 for // returned by SplitKeys are not the same. SplitKeys will never return -1 for
// both indexes. // both indexes.
func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey }
// MapIndex is an index operation on a map at some index Key. // MapIndex is a [PathStep] that represents an index operation on a map at some index Key.
type MapIndex struct{ *mapIndex } type MapIndex struct{ *mapIndex }
type mapIndex struct { type mapIndex struct {
pathStep pathStep
@@ -266,7 +275,7 @@ func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]",
// Key is the value of the map key. // Key is the value of the map key.
func (mi MapIndex) Key() reflect.Value { return mi.key } func (mi MapIndex) Key() reflect.Value { return mi.key }
// Indirect represents pointer indirection on the parent type. // Indirect is a [PathStep] that represents pointer indirection on the parent type.
type Indirect struct{ *indirect } type Indirect struct{ *indirect }
type indirect struct { type indirect struct {
pathStep pathStep
@@ -276,7 +285,7 @@ func (in Indirect) Type() reflect.Type { return in.typ }
func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy }
func (in Indirect) String() string { return "*" } func (in Indirect) String() string { return "*" }
// TypeAssertion represents a type assertion on an interface. // TypeAssertion is a [PathStep] that represents a type assertion on an interface.
type TypeAssertion struct{ *typeAssertion } type TypeAssertion struct{ *typeAssertion }
type typeAssertion struct { type typeAssertion struct {
pathStep pathStep
@@ -286,7 +295,8 @@ func (ta TypeAssertion) Type() reflect.Type { return ta.typ }
func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) } func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) }
// Transform is a transformation from the parent type to the current type. // Transform is a [PathStep] that represents a transformation
// from the parent type to the current type.
type Transform struct{ *transform } type Transform struct{ *transform }
type transform struct { type transform struct {
pathStep pathStep
@@ -297,13 +307,13 @@ func (tf Transform) Type() reflect.Type { return tf.typ }
func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy }
func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) } func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
// Name is the name of the Transformer. // Name is the name of the [Transformer].
func (tf Transform) Name() string { return tf.trans.name } func (tf Transform) Name() string { return tf.trans.name }
// Func is the function pointer to the transformer function. // Func is the function pointer to the transformer function.
func (tf Transform) Func() reflect.Value { return tf.trans.fnc } func (tf Transform) Func() reflect.Value { return tf.trans.fnc }
// Option returns the originally constructed Transformer option. // Option returns the originally constructed [Transformer] option.
// The == operator can be used to detect the exact option used. // The == operator can be used to detect the exact option used.
func (tf Transform) Option() Option { return tf.trans } func (tf Transform) Option() Option { return tf.trans }
+1 -1
View File
@@ -199,7 +199,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind,
break break
} }
sf := t.Field(i) sf := t.Field(i)
if supportExporters && !isExported(sf.Name) { if !isExported(sf.Name) {
vv = retrieveUnexportedField(v, sf, true) vv = retrieveUnexportedField(v, sf, true)
} }
s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs) s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs)
+4 -2
View File
@@ -20,8 +20,8 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os"
"strings" "strings"
"time" "time"
@@ -56,6 +56,7 @@ func SetMaxGRPCLogLength(characterCount int) {
// https://github.com/grpc/grpc/blob/master/doc/naming.md. // https://github.com/grpc/grpc/blob/master/doc/naming.md.
// //
// The function tries to connect for 30 seconds, and returns an error if no connection has been established at that point. // The function tries to connect for 30 seconds, and returns an error if no connection has been established at that point.
// The connection has zero idle timeout, i.e. it is never closed because of inactivity.
// The function automatically disables TLS and adds interceptor for logging of all gRPC messages at level 5. // The function automatically disables TLS and adds interceptor for logging of all gRPC messages at level 5.
// If the metricsManager is 'nil', no metrics will be recorded on the gRPC calls. // If the metricsManager is 'nil', no metrics will be recorded on the gRPC calls.
// The function behaviour can be tweaked with options. // The function behaviour can be tweaked with options.
@@ -107,7 +108,7 @@ func OnConnectionLoss(reconnect func() bool) Option {
func ExitOnConnectionLoss() func() bool { func ExitOnConnectionLoss() func() bool {
return func() bool { return func() bool {
terminationMsg := "Lost connection to CSI driver, exiting" terminationMsg := "Lost connection to CSI driver, exiting"
if err := ioutil.WriteFile(terminationLogPath, []byte(terminationMsg), 0644); err != nil { if err := os.WriteFile(terminationLogPath, []byte(terminationMsg), 0644); err != nil {
klog.Errorf("%s: %s", terminationLogPath, err) klog.Errorf("%s: %s", terminationLogPath, err)
} }
klog.Exit(terminationMsg) klog.Exit(terminationMsg)
@@ -157,6 +158,7 @@ func connect(
grpc.WithInsecure(), // Don't use TLS, it's usually local Unix domain socket in a container. grpc.WithInsecure(), // Don't use TLS, it's usually local Unix domain socket in a container.
grpc.WithBackoffMaxDelay(time.Second), // Retry every second after failure. grpc.WithBackoffMaxDelay(time.Second), // Retry every second after failure.
grpc.WithBlock(), // Block until connection succeeds. grpc.WithBlock(), // Block until connection succeeds.
grpc.WithIdleTimeout(time.Duration(0)), // Never close connection because of inactivity.
} }
if o.timeout > 0 { if o.timeout > 0 {
@@ -19,7 +19,6 @@ package leaderelection
import ( import (
"context" "context"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"os" "os"
"regexp" "regexp"
@@ -219,7 +218,7 @@ func inClusterNamespace() string {
return ns return ns
} }
if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { if data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil {
if ns := strings.TrimSpace(string(data)); len(ns) > 0 { if ns := strings.TrimSpace(string(data)); len(ns) > 0 {
return ns return ns
} }
@@ -18,15 +18,14 @@ import (
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/global"
"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"
) )
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")
) )
@@ -42,9 +41,19 @@ type config struct {
Propagators propagation.TextMapPropagator Propagators propagation.TextMapPropagator
TracerProvider trace.TracerProvider TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider MeterProvider metric.MeterProvider
SpanStartOptions []trace.SpanStartOption
ReceivedEvent bool
SentEvent bool
tracer trace.Tracer
meter metric.Meter meter metric.Meter
rpcServerDuration metric.Int64Histogram
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.
@@ -53,23 +62,60 @@ 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(),
MeterProvider: global.MeterProvider(), MeterProvider: otel.GetMeterProvider(),
} }
for _, o := range opts { for _, o := range opts {
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(SemVersion()), metric.WithInstrumentationVersion(Version()),
metric.WithSchemaURL(semconv.SchemaURL), metric.WithSchemaURL(semconv.SchemaURL),
) )
var err error var err error
if c.rpcServerDuration, err = c.meter.Int64Histogram("rpc.server.duration", metric.WithUnit("ms")); err != nil { c.rpcDuration, err = c.meter.Float64Histogram("rpc."+role+".duration",
metric.WithDescription("Measures the duration of inbound RPC."),
metric.WithUnit("ms"))
if err != nil {
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) otel.Handle(err)
} }
@@ -99,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}
} }
@@ -132,3 +180,50 @@ func (o meterProviderOption) apply(c *config) {
func WithMeterProvider(mp metric.MeterProvider) Option { func WithMeterProvider(mp metric.MeterProvider) Option {
return meterProviderOption{mp: mp} return meterProviderOption{mp: mp}
} }
// Event type that can be recorded, see WithMessageEvents.
type Event int
// Different types of events that can be recorded, see WithMessageEvents.
const (
ReceivedEvents Event = iota
SentEvents
)
type messageEventsProviderOption struct {
events []Event
}
func (m messageEventsProviderOption) apply(c *config) {
for _, e := range m.events {
switch e {
case ReceivedEvents:
c.ReceivedEvent = true
case SentEvents:
c.SentEvent = true
}
}
}
// WithMessageEvents configures the Handler to record the specified events
// (span.AddEvent) on spans. By default only summary attributes are added at the
// end of the request.
//
// Valid events are:
// - ReceivedEvents: Record the number of bytes read after every gRPC read operation.
// - SentEvents: Record the number of bytes written after every gRPC write operation.
func WithMessageEvents(events ...Event) Option {
return messageEventsProviderOption{events: events}
}
type spanStartOption struct{ opts []trace.SpanStartOption }
func (o spanStartOption) apply(c *config) {
c.SpanStartOptions = append(c.SpanStartOptions, o.opts...)
}
// WithSpanOptions configures an additional set of
// trace.SpanOptions, which are applied to each new span.
func WithSpanOptions(opts ...trace.SpanStartOption) Option {
return spanStartOption{opts}
}
@@ -0,0 +1,22 @@
// 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 otelgrpc is the instrumentation library for [google.golang.org/grpc].
Use [NewClientHandler] with [grpc.WithStatsHandler] to instrument a gRPC client.
Use [NewServerHandler] with [grpc.StatsHandler] to instrument a gRPC server.
*/
package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
@@ -60,11 +60,13 @@ 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(SemVersion()), trace.WithInstrumentationVersion(Version()),
) )
return func( return func(
@@ -83,23 +85,33 @@ 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())
var span trace.Span
ctx, span = tracer.Start( startOpts := append([]trace.SpanStartOption{
ctx,
name,
trace.WithSpanKind(trace.SpanKindClient), trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attr...), trace.WithAttributes(attr...),
},
cfg.SpanStartOptions...,
)
ctx, span := tracer.Start(
ctx,
name,
startOpts...,
) )
defer span.End() defer span.End()
ctx = inject(ctx, cfg.Propagators) ctx = inject(ctx, cfg.Propagators)
if cfg.SentEvent {
messageSent.Event(ctx, 1, req) messageSent.Event(ctx, 1, req)
}
err := invoker(ctx, method, req, reply, cc, callOpts...) err := invoker(ctx, method, req, reply, cc, callOpts...)
if cfg.ReceivedEvent {
messageReceived.Event(ctx, 1, reply) messageReceived.Event(ctx, 1, reply)
}
if err != nil { if err != nil {
s, _ := status.FromError(err) s, _ := status.FromError(err)
@@ -135,6 +147,9 @@ type clientStream struct {
eventsDone chan struct{} eventsDone chan struct{}
finished chan error finished chan error
receivedEvent bool
sentEvent bool
receivedMessageID int receivedMessageID int
sentMessageID int sentMessageID int
} }
@@ -152,8 +167,11 @@ func (w *clientStream) RecvMsg(m interface{}) error {
w.sendStreamEvent(errorEvent, err) w.sendStreamEvent(errorEvent, err)
} else { } else {
w.receivedMessageID++ w.receivedMessageID++
if w.receivedEvent {
messageReceived.Event(w.Context(), w.receivedMessageID, m) messageReceived.Event(w.Context(), w.receivedMessageID, m)
} }
}
return err return err
} }
@@ -162,7 +180,10 @@ func (w *clientStream) SendMsg(m interface{}) error {
err := w.ClientStream.SendMsg(m) err := w.ClientStream.SendMsg(m)
w.sentMessageID++ w.sentMessageID++
if w.sentEvent {
messageSent.Event(w.Context(), w.sentMessageID, m) messageSent.Event(w.Context(), w.sentMessageID, m)
}
if err != nil { if err != nil {
w.sendStreamEvent(errorEvent, err) w.sendStreamEvent(errorEvent, err)
@@ -173,7 +194,6 @@ 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.sendStreamEvent(errorEvent, err)
} }
@@ -183,7 +203,6 @@ 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.sendStreamEvent(errorEvent, err)
} }
@@ -191,7 +210,7 @@ func (w *clientStream) CloseSend() error {
return err return err
} }
func wrapClientStream(ctx context.Context, s grpc.ClientStream, desc *grpc.StreamDesc) *clientStream { func wrapClientStream(ctx context.Context, s grpc.ClientStream, desc *grpc.StreamDesc, cfg *config) *clientStream {
events := make(chan streamEvent) events := make(chan streamEvent)
eventsDone := make(chan struct{}) eventsDone := make(chan struct{})
finished := make(chan error) finished := make(chan error)
@@ -223,6 +242,8 @@ func wrapClientStream(ctx context.Context, s grpc.ClientStream, desc *grpc.Strea
events: events, events: events,
eventsDone: eventsDone, eventsDone: eventsDone,
finished: finished, finished: finished,
receivedEvent: cfg.ReceivedEvent,
sentEvent: cfg.SentEvent,
} }
} }
@@ -235,11 +256,13 @@ func (w *clientStream) sendStreamEvent(eventType streamEventType, err error) {
// 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(SemVersion()), trace.WithInstrumentationVersion(Version()),
) )
return func( return func(
@@ -258,13 +281,19 @@ 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())
var span trace.Span
ctx, span = tracer.Start( startOpts := append([]trace.SpanStartOption{
ctx,
name,
trace.WithSpanKind(trace.SpanKindClient), trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attr...), trace.WithAttributes(attr...),
},
cfg.SpanStartOptions...,
)
ctx, span := tracer.Start(
ctx,
name,
startOpts...,
) )
ctx = inject(ctx, cfg.Propagators) ctx = inject(ctx, cfg.Propagators)
@@ -277,7 +306,7 @@ func StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor {
span.End() span.End()
return s, err return s, err
} }
stream := wrapClientStream(ctx, s, desc) stream := wrapClientStream(ctx, s, desc, cfg)
go func() { go func() {
err := <-stream.finished err := <-stream.finished
@@ -299,11 +328,13 @@ func StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor {
// 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(SemVersion()), trace.WithInstrumentationVersion(Version()),
) )
return func( return func(
@@ -321,38 +352,48 @@ func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {
} }
ctx = extract(ctx, cfg.Propagators) ctx = extract(ctx, cfg.Propagators)
name, attr, metricAttrs := telemetryAttributes(info.FullMethod, peerFromCtx(ctx))
startOpts := append([]trace.SpanStartOption{
trace.WithSpanKind(trace.SpanKindServer),
trace.WithAttributes(attr...),
},
cfg.SpanStartOptions...,
)
name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx))
ctx, span := tracer.Start( ctx, span := tracer.Start(
trace.ContextWithRemoteSpanContext(ctx, trace.SpanContextFromContext(ctx)), trace.ContextWithRemoteSpanContext(ctx, trace.SpanContextFromContext(ctx)),
name, name,
trace.WithSpanKind(trace.SpanKindServer), startOpts...,
trace.WithAttributes(attr...),
) )
defer span.End() defer span.End()
if cfg.ReceivedEvent {
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)
if err != nil {
s, _ := status.FromError(err) s, _ := status.FromError(err)
if err != nil {
statusCode, msg := serverStatus(s) statusCode, msg := serverStatus(s)
span.SetStatus(statusCode, msg) span.SetStatus(statusCode, msg)
span.SetAttributes(statusCodeAttr(s.Code())) if cfg.SentEvent {
messageSent.Event(ctx, 1, s.Proto()) messageSent.Event(ctx, 1, s.Proto())
}
} else { } else {
statusCode = grpc_codes.OK if cfg.SentEvent {
span.SetAttributes(statusCodeAttr(grpc_codes.OK))
messageSent.Event(ctx, 1, resp) messageSent.Event(ctx, 1, resp)
} }
}
grpcStatusCodeAttr := statusCodeAttr(s.Code())
span.SetAttributes(grpcStatusCodeAttr)
elapsedTime := time.Since(before).Milliseconds()
metricAttrs = append(metricAttrs, grpcStatusCodeAttr)
cfg.rpcDuration.Record(ctx, float64(elapsedTime), metric.WithAttributes(metricAttrs...))
return resp, err return resp, err
} }
@@ -366,6 +407,9 @@ type serverStream struct {
receivedMessageID int receivedMessageID int
sentMessageID int sentMessageID int
receivedEvent bool
sentEvent bool
} }
func (w *serverStream) Context() context.Context { func (w *serverStream) Context() context.Context {
@@ -377,8 +421,10 @@ func (w *serverStream) RecvMsg(m interface{}) error {
if err == nil { if err == nil {
w.receivedMessageID++ w.receivedMessageID++
if w.receivedEvent {
messageReceived.Event(w.Context(), w.receivedMessageID, m) messageReceived.Event(w.Context(), w.receivedMessageID, m)
} }
}
return err return err
} }
@@ -387,25 +433,31 @@ func (w *serverStream) SendMsg(m interface{}) error {
err := w.ServerStream.SendMsg(m) err := w.ServerStream.SendMsg(m)
w.sentMessageID++ w.sentMessageID++
if w.sentEvent {
messageSent.Event(w.Context(), w.sentMessageID, m) messageSent.Event(w.Context(), w.sentMessageID, m)
}
return err return err
} }
func wrapServerStream(ctx context.Context, ss grpc.ServerStream) *serverStream { func wrapServerStream(ctx context.Context, ss grpc.ServerStream, cfg *config) *serverStream {
return &serverStream{ return &serverStream{
ServerStream: ss, ServerStream: ss,
ctx: ctx, ctx: ctx,
receivedEvent: cfg.ReceivedEvent,
sentEvent: cfg.SentEvent,
} }
} }
// 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(SemVersion()), trace.WithInstrumentationVersion(Version()),
) )
return func( return func(
@@ -420,21 +472,27 @@ func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
Type: StreamServer, Type: StreamServer,
} }
if cfg.Filter != nil && !cfg.Filter(i) { if cfg.Filter != nil && !cfg.Filter(i) {
return handler(srv, wrapServerStream(ctx, ss)) return handler(srv, wrapServerStream(ctx, ss, cfg))
} }
ctx = extract(ctx, cfg.Propagators) ctx = extract(ctx, cfg.Propagators)
name, attr, _ := telemetryAttributes(info.FullMethod, peerFromCtx(ctx))
startOpts := append([]trace.SpanStartOption{
trace.WithSpanKind(trace.SpanKindServer),
trace.WithAttributes(attr...),
},
cfg.SpanStartOptions...,
)
name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx))
ctx, span := tracer.Start( ctx, span := tracer.Start(
trace.ContextWithRemoteSpanContext(ctx, trace.SpanContextFromContext(ctx)), trace.ContextWithRemoteSpanContext(ctx, trace.SpanContextFromContext(ctx)),
name, name,
trace.WithSpanKind(trace.SpanKindServer), startOpts...,
trace.WithAttributes(attr...),
) )
defer span.End() defer span.End()
err := handler(srv, wrapServerStream(ctx, ss)) err := handler(srv, wrapServerStream(ctx, ss, cfg))
if err != nil { if err != nil {
s, _ := status.FromError(err) s, _ := status.FromError(err)
statusCode, msg := serverStatus(s) statusCode, msg := serverStatus(s)
@@ -448,21 +506,25 @@ 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) {
attrs := []attribute.KeyValue{RPCSystemGRPC} name, methodAttrs := internal.ParseFullMethod(fullMethod)
name, mAttrs := internal.ParseFullMethod(fullMethod) peerAttrs := peerAttr(peerAddress)
attrs = append(attrs, mAttrs...)
attrs = append(attrs, peerAttr(peerAddress)...) attrs := make([]attribute.KeyValue, 0, 1+len(methodAttrs)+len(peerAttrs))
return name, attrs attrs = append(attrs, RPCSystemGRPC)
attrs = append(attrs, methodAttrs...)
metricAttrs := attrs[:1+len(methodAttrs)]
attrs = append(attrs, peerAttrs...)
return name, attrs, metricAttrs
} }
// peerAttr returns attributes about the peer address. // peerAttr returns attributes about the peer address.
func peerAttr(addr string) []attribute.KeyValue { func peerAttr(addr string) []attribute.KeyValue {
host, p, err := net.SplitHostPort(addr) host, p, err := net.SplitHostPort(addr)
if err != nil { if err != nil {
return []attribute.KeyValue(nil) return nil
} }
if host == "" { if host == "" {
@@ -470,7 +532,7 @@ func peerAttr(addr string) []attribute.KeyValue {
} }
port, err := strconv.Atoi(p) port, err := strconv.Atoi(p)
if err != nil { if err != nil {
return []attribute.KeyValue(nil) return nil
} }
var attr []attribute.KeyValue var attr []attribute.KeyValue
@@ -24,19 +24,27 @@ import (
// ParseFullMethod returns a span name following the OpenTelemetry semantic // ParseFullMethod returns a span name following the OpenTelemetry semantic
// conventions as well as all applicable span attribute.KeyValue attributes based // conventions as well as all applicable span attribute.KeyValue attributes based
// on a gRPC's FullMethod. // on a gRPC's FullMethod.
//
// Parsing is consistent with grpc-go implementation:
// https://github.com/grpc/grpc-go/blob/v1.57.0/internal/grpcutil/method.go#L26-L39
func ParseFullMethod(fullMethod string) (string, []attribute.KeyValue) { func ParseFullMethod(fullMethod string) (string, []attribute.KeyValue) {
name := strings.TrimLeft(fullMethod, "/") if !strings.HasPrefix(fullMethod, "/") {
parts := strings.SplitN(name, "/", 2)
if len(parts) != 2 {
// Invalid format, does not follow `/package.service/method`. // Invalid format, does not follow `/package.service/method`.
return name, []attribute.KeyValue(nil) return fullMethod, nil
} }
name := fullMethod[1:]
pos := strings.LastIndex(name, "/")
if pos < 0 {
// Invalid format, does not follow `/package.service/method`.
return name, nil
}
service, method := name[:pos], name[pos+1:]
var attrs []attribute.KeyValue var attrs []attribute.KeyValue
if service := parts[0]; service != "" { if service != "" {
attrs = append(attrs, semconv.RPCService(service)) attrs = append(attrs, semconv.RPCService(service))
} }
if method := parts[1]; method != "" { if method != "" {
attrs = append(attrs, semconv.RPCMethod(method)) attrs = append(attrs, semconv.RPCMethod(method))
} }
return name, attrs return name, attrs
@@ -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,
}) })
@@ -0,0 +1,235 @@
// 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 otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
import (
"context"
"sync/atomic"
"time"
grpc_codes "google.golang.org/grpc/codes"
"google.golang.org/grpc/stats"
"google.golang.org/grpc/status"
"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/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
"go.opentelemetry.io/otel/trace"
)
type gRPCContextKey struct{}
type gRPCContext struct {
messagesReceived int64
messagesSent int64
metricAttrs []attribute.KeyValue
}
type serverHandler struct {
*config
}
// NewServerHandler creates a stats.Handler for gRPC server.
func NewServerHandler(opts ...Option) stats.Handler {
h := &serverHandler{
config: newConfig(opts, "server"),
}
return h
}
// TagConn can attach some information to the given context.
func (h *serverHandler) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
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.
func (h *serverHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
ctx = extract(ctx, h.config.Propagators)
name, attrs := internal.ParseFullMethod(info.FullMethodName)
attrs = append(attrs, RPCSystemGRPC)
ctx, _ = h.tracer.Start(
trace.ContextWithRemoteSpanContext(ctx, trace.SpanContextFromContext(ctx)),
name,
trace.WithSpanKind(trace.SpanKindServer),
trace.WithAttributes(attrs...),
)
gctx := gRPCContext{
metricAttrs: attrs,
}
return context.WithValue(ctx, gRPCContextKey{}, &gctx)
}
// HandleRPC processes the RPC stats.
func (h *serverHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
h.handleRPC(ctx, rs)
}
type clientHandler struct {
*config
}
// NewClientHandler creates a stats.Handler for gRPC client.
func NewClientHandler(opts ...Option) stats.Handler {
h := &clientHandler{
config: newConfig(opts, "client"),
}
return h
}
// TagRPC can attach some information to the given context.
func (h *clientHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
name, attrs := internal.ParseFullMethod(info.FullMethodName)
attrs = append(attrs, RPCSystemGRPC)
ctx, _ = h.tracer.Start(
ctx,
name,
trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attrs...),
)
gctx := gRPCContext{
metricAttrs: attrs,
}
return inject(context.WithValue(ctx, gRPCContextKey{}, &gctx), h.config.Propagators)
}
// HandleRPC processes the RPC stats.
func (h *clientHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
h.handleRPC(ctx, rs)
}
// TagConn can attach some information to the given context.
func (h *clientHandler) TagConn(ctx context.Context, cti *stats.ConnTagInfo) context.Context {
span := trace.SpanFromContext(ctx)
attrs := peerAttr(cti.RemoteAddr.String())
span.SetAttributes(attrs...)
return ctx
}
// HandleConn processes the Conn stats.
func (h *clientHandler) HandleConn(context.Context, stats.ConnStats) {
// no-op
}
func (c *config) handleRPC(ctx context.Context, rs stats.RPCStats) {
span := trace.SpanFromContext(ctx)
gctx, _ := ctx.Value(gRPCContextKey{}).(*gRPCContext)
var messageId int64
metricAttrs := make([]attribute.KeyValue, 0, len(gctx.metricAttrs)+1)
metricAttrs = append(metricAttrs, gctx.metricAttrs...)
wctx := withoutCancel(ctx)
switch rs := rs.(type) {
case *stats.Begin:
case *stats.InPayload:
if gctx != nil {
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),
),
)
}
case *stats.OutPayload:
if gctx != nil {
messageId = atomic.AddInt64(&gctx.messagesSent, 1)
c.rpcResponseSize.Record(wctx, int64(rs.Length), metric.WithAttributes(metricAttrs...))
}
if c.SentEvent {
span.AddEvent("message",
trace.WithAttributes(
semconv.MessageTypeSent,
semconv.MessageIDKey.Int64(messageId),
semconv.MessageCompressedSizeKey.Int(rs.CompressedLength),
semconv.MessageUncompressedSizeKey.Int(rs.Length),
),
)
}
case *stats.OutTrailer:
case *stats.End:
var rpcStatusAttr attribute.KeyValue
if rs.Error != nil {
s, _ := status.FromError(rs.Error)
span.SetStatus(codes.Error, s.Message())
rpcStatusAttr = semconv.RPCGRPCStatusCodeKey.Int(int(s.Code()))
} else {
rpcStatusAttr = semconv.RPCGRPCStatusCodeKey.Int(int(grpc_codes.OK))
}
span.SetAttributes(rpcStatusAttr)
span.End()
metricAttrs = append(metricAttrs, rpcStatusAttr)
c.rpcDuration.Record(wctx, float64(rs.EndTime.Sub(rs.BeginTime)), metric.WithAttributes(metricAttrs...))
c.rpcRequestsPerRPC.Record(wctx, gctx.messagesReceived, metric.WithAttributes(metricAttrs...))
c.rpcResponsesPerRPC.Record(wctx, gctx.messagesSent, metric.WithAttributes(metricAttrs...))
default:
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"
}
@@ -16,11 +16,13 @@ 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.41.0" return "0.46.0"
// This string is updated by the pre_release.sh script during release // This string is updated by the pre_release.sh script during release
} }
// SemVersion is the semantic version to be supplied to tracer/meter creation. // SemVersion is the semantic version to be supplied to tracer/meter creation.
//
// Deprecated: Use [Version] instead.
func SemVersion() string { func SemVersion() string {
return "semver:" + Version() return Version()
} }
+5
View File
@@ -0,0 +1,5 @@
ot
fo
te
collison
consequentially
+10
View File
@@ -0,0 +1,10 @@
# https://github.com/codespell-project/codespell
[codespell]
builtin = clear,rare,informal
check-filenames =
check-hidden =
ignore-words = .codespellignore
interactive = 1
skip = .git,go.mod,go.sum,semconv,venv,.tools
uri-ignore-words-list = *
write =
+4 -1
View File
@@ -2,6 +2,7 @@
Thumbs.db Thumbs.db
.tools/ .tools/
venv/
.idea/ .idea/
.vscode/ .vscode/
*.iml *.iml
@@ -12,12 +13,14 @@ go.work.sum
gen/ gen/
/example/dice/dice
/example/fib/fib /example/fib/fib
/example/fib/traces.txt /example/fib/traces.txt
/example/jaeger/jaeger /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/view/view
/example/zipkin/zipkin /example/zipkin/zipkin
/example/otel-collector/otel-collector
+74 -24
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
@@ -61,28 +76,63 @@ issues:
linters-settings: linters-settings:
depguard: depguard:
# Check the list against standard lib. rules:
# Default: false non-tests:
include-go-root: true files:
# A list of packages for the list type specified. - "!$test"
# Default: [] - "!**/*test/*.go"
packages: - "!**/internal/matchers/*.go"
- "crypto/md5" deny:
- "crypto/sha1" - pkg: "testing"
- "crypto/**/pkix" - pkg: "github.com/stretchr/testify"
ignore-file-rules: - pkg: "crypto/md5"
- "**/*_test.go" - pkg: "crypto/sha1"
additional-guards: - pkg: "crypto/**/pkix"
# Do not allow testing packages in non-test files. otlp-internal:
- list-type: denylist files:
include-go-root: true - "!**/exporters/otlp/internal/**/*.go"
packages: deny:
- testing - pkg: "go.opentelemetry.io/otel/exporters/otlp/internal"
- github.com/stretchr/testify desc: Do not use cross-module internal packages.
ignore-file-rules: otlptrace-internal:
- "**/*_test.go" files:
- "**/*test/*.go" - "!**/exporters/otlp/otlptrace/*.go"
- "**/internal/matchers/*.go" - "!**/exporters/otlp/otlptrace/internal/**.go"
deny:
- pkg: "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal"
desc: Do not use cross-module internal packages.
otlpmetric-internal:
files:
- "!**/exporters/otlp/otlpmetric/internal/*.go"
- "!**/exporters/otlp/otlpmetric/internal/**/*.go"
deny:
- pkg: "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal"
desc: Do not use cross-module internal packages.
otel-internal:
files:
- "**/sdk/*.go"
- "**/sdk/**/*.go"
- "**/exporters/*.go"
- "**/exporters/**/*.go"
- "**/schema/*.go"
- "**/schema/**/*.go"
- "**/metric/*.go"
- "**/metric/**/*.go"
- "**/bridge/*.go"
- "**/bridge/**/*.go"
- "**/example/*.go"
- "**/example/**/*.go"
- "**/trace/*.go"
- "**/trace/**/*.go"
deny:
- pkg: "go.opentelemetry.io/otel/internal$"
desc: Do not use cross-module internal packages.
- pkg: "go.opentelemetry.io/otel/internal/attribute"
desc: Do not use cross-module internal packages.
- pkg: "go.opentelemetry.io/otel/internal/internaltest"
desc: Do not use cross-module internal packages.
- pkg: "go.opentelemetry.io/otel/internal/matchers"
desc: Do not use cross-module internal packages.
godot: godot:
exclude: exclude:
# Exclude links. # Exclude links.
@@ -113,7 +163,7 @@ linters-settings:
- name: constant-logical-expr - name: constant-logical-expr
disabled: false disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-as-argument # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-as-argument
# TODO (#3372) reenable linter when it is compatible. https://github.com/golangci/golangci-lint/issues/3280 # TODO (#3372) re-enable linter when it is compatible. https://github.com/golangci/golangci-lint/issues/3280
- name: context-as-argument - name: context-as-argument
disabled: true disabled: true
arguments: arguments:
+297 -1
View File
@@ -8,6 +8,288 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [Unreleased] ## [Unreleased]
## [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
This release contains the first stable release of the OpenTelemetry Go [metric SDK].
Our project stability guarantees now apply to the `go.opentelemetry.io/otel/sdk/metric` package.
See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
### Added
- Add the "Roll the dice" getting started application example in `go.opentelemetry.io/otel/example/dice`. (#4539)
- The `WithWriter` and `WithPrettyPrint` options to `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` to set a custom `io.Writer`, and allow displaying the output in human-readable JSON. (#4507)
### Changed
- Allow '/' characters in metric instrument names. (#4501)
- The exporter in `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` does not prettify its output by default anymore. (#4507)
- Upgrade `gopkg.io/yaml` from `v2` to `v3` in `go.opentelemetry.io/otel/schema`. (#4535)
### Fixed
- In `go.opentelemetry.op/otel/exporters/prometheus`, don't try to create the Prometheus metric on every `Collect` if we know the scope is invalid. (#4499)
### Removed
- Remove `"go.opentelemetry.io/otel/bridge/opencensus".NewMetricExporter`, which is replaced by `NewMetricProducer`. (#4566)
## [1.19.0-rc.1/0.42.0-rc.1] 2023-09-14
This is a release candidate for the v1.19.0/v0.42.0 release.
That release is expected to include the `v1` release of the OpenTelemetry Go metric SDK and will provide stability guarantees of that SDK.
See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
### Changed
- Allow '/' characters in metric instrument names. (#4501)
### Fixed
- In `go.opentelemetry.op/otel/exporters/prometheus`, don't try to create the prometheus metric on every `Collect` if we know the scope is invalid. (#4499)
## [1.18.0/0.41.0/0.0.6] 2023-09-12
This release drops the compatibility guarantee of [Go 1.19].
### Added
- Add `WithProducer` option in `go.opentelemetry.op/otel/exporters/prometheus` to restore the ability to register producers on the prometheus exporter's manual reader. (#4473)
- Add `IgnoreValue` option in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest` to allow ignoring values when comparing metrics. (#4447)
### Changed
- Use a `TestingT` interface instead of `*testing.T` struct in `go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#4483)
### Deprecated
- The `NewMetricExporter` in `go.opentelemetry.io/otel/bridge/opencensus` was deprecated in `v0.35.0` (#3541).
The deprecation notice format for the function has been corrected to trigger Go documentation and build tooling. (#4470)
### Removed
- Removed the deprecated `go.opentelemetry.io/otel/exporters/jaeger` package. (#4467)
- Removed the deprecated `go.opentelemetry.io/otel/example/jaeger` package. (#4467)
- Removed the deprecated `go.opentelemetry.io/otel/sdk/metric/aggregation` package. (#4468)
- Removed the deprecated internal packages in `go.opentelemetry.io/otel/exporters/otlp` and its sub-packages. (#4469)
- Dropped guaranteed support for versions of Go less than 1.20. (#4481)
## [1.17.0/0.40.0/0.0.5] 2023-08-28
### Added
- Export the `ManualReader` struct in `go.opentelemetry.io/otel/sdk/metric`. (#4244)
- Export the `PeriodicReader` struct in `go.opentelemetry.io/otel/sdk/metric`. (#4244)
- Add support for exponential histogram aggregations.
A histogram can be configured as an exponential histogram using a view with `"go.opentelemetry.io/otel/sdk/metric".ExponentialHistogram` as the aggregation. (#4245)
- Export the `Exporter` struct in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#4272)
- Export the `Exporter` struct in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4272)
- The exporters in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` now support the `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE` environment variable. (#4287)
- Add `WithoutCounterSuffixes` option in `go.opentelemetry.io/otel/exporters/prometheus` to disable addition of `_total` suffixes. (#4306)
- Add info and debug logging to the metric SDK in `go.opentelemetry.io/otel/sdk/metric`. (#4315)
- The `go.opentelemetry.io/otel/semconv/v1.21.0` package.
The package contains semantic conventions from the `v1.21.0` version of the OpenTelemetry Semantic Conventions. (#4362)
- Accept 201 to 299 HTTP status as success in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` and `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#4365)
- Document the `Temporality` and `Aggregation` methods of the `"go.opentelemetry.io/otel/sdk/metric".Exporter"` need to be concurrent safe. (#4381)
- Expand the set of units supported by the Prometheus exporter, and don't add unit suffixes if they are already present in `go.opentelemetry.op/otel/exporters/prometheus` (#4374)
- Move the `Aggregation` interface and its implementations from `go.opentelemetry.io/otel/sdk/metric/aggregation` to `go.opentelemetry.io/otel/sdk/metric`. (#4435)
- The exporters in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` now support the `OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION` environment variable. (#4437)
- Add the `NewAllowKeysFilter` and `NewDenyKeysFilter` functions to `go.opentelemetry.io/otel/attribute` to allow convenient creation of allow-keys and deny-keys filters. (#4444)
- Support Go 1.21. (#4463)
### Changed
- Starting from `v1.21.0` of semantic conventions, `go.opentelemetry.io/otel/semconv/{version}/httpconv` and `go.opentelemetry.io/otel/semconv/{version}/netconv` packages will no longer be published. (#4145)
- Log duplicate instrument conflict at a warning level instead of info in `go.opentelemetry.io/otel/sdk/metric`. (#4202)
- Return an error on the creation of new instruments in `go.opentelemetry.io/otel/sdk/metric` if their name doesn't pass regexp validation. (#4210)
- `NewManualReader` in `go.opentelemetry.io/otel/sdk/metric` returns `*ManualReader` instead of `Reader`. (#4244)
- `NewPeriodicReader` in `go.opentelemetry.io/otel/sdk/metric` returns `*PeriodicReader` instead of `Reader`. (#4244)
- Count the Collect time in the `PeriodicReader` timeout in `go.opentelemetry.io/otel/sdk/metric`. (#4221)
- The function `New` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` returns `*Exporter` instead of `"go.opentelemetry.io/otel/sdk/metric".Exporter`. (#4272)
- The function `New` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` returns `*Exporter` instead of `"go.opentelemetry.io/otel/sdk/metric".Exporter`. (#4272)
- If an attribute set is omitted from an async callback, the previous value will no longer be exported in `go.opentelemetry.io/otel/sdk/metric`. (#4290)
- If an attribute set is observed multiple times in an async callback in `go.opentelemetry.io/otel/sdk/metric`, the values will be summed instead of the last observation winning. (#4289)
- Allow the explicit bucket histogram aggregation to be used for the up-down counter, observable counter, observable up-down counter, and observable gauge in the `go.opentelemetry.io/otel/sdk/metric` package. (#4332)
- Restrict `Meter`s in `go.opentelemetry.io/otel/sdk/metric` to only register and collect instruments it created. (#4333)
- `PeriodicReader.Shutdown` and `PeriodicReader.ForceFlush` in `go.opentelemetry.io/otel/sdk/metric` now apply the periodic reader's timeout to the operation if the user provided context does not contain a deadline. (#4356, #4377)
- Upgrade all use of `go.opentelemetry.io/otel/semconv` to use `v1.21.0`. (#4408)
- Increase instrument name maximum length from 63 to 255 characters in `go.opentelemetry.io/otel/sdk/metric`. (#4434)
- Add `go.opentelemetry.op/otel/sdk/metric.WithProducer` as an `Option` for `"go.opentelemetry.io/otel/sdk/metric".NewManualReader` and `"go.opentelemetry.io/otel/sdk/metric".NewPeriodicReader`. (#4346)
### Removed
- Remove `Reader.RegisterProducer` in `go.opentelemetry.io/otel/metric`.
Use the added `WithProducer` option instead. (#4346)
- Remove `Reader.ForceFlush` in `go.opentelemetry.io/otel/metric`.
Notice that `PeriodicReader.ForceFlush` is still available. (#4375)
### Fixed
- Correctly format log messages from the `go.opentelemetry.io/otel/exporters/zipkin` exporter. (#4143)
- Log an error for calls to `NewView` in `go.opentelemetry.io/otel/sdk/metric` that have empty criteria. (#4307)
- Fix `"go.opentelemetry.io/otel/sdk/resource".WithHostID()` to not set an empty `host.id`. (#4317)
- Use the instrument identifying fields to cache aggregators and determine duplicate instrument registrations in `go.opentelemetry.io/otel/sdk/metric`. (#4337)
- Detect duplicate instruments for case-insensitive names in `go.opentelemetry.io/otel/sdk/metric`. (#4338)
- The `ManualReader` will not panic if `AggregationSelector` returns `nil` in `go.opentelemetry.io/otel/sdk/metric`. (#4350)
- If a `Reader`'s `AggregationSelector` returns `nil` or `DefaultAggregation` the pipeline will use the default aggregation. (#4350)
- Log a suggested view that fixes instrument conflicts in `go.opentelemetry.io/otel/sdk/metric`. (#4349)
- Fix possible panic, deadlock and race condition in batch span processor in `go.opentelemetry.io/otel/sdk/trace`. (#4353)
- Improve context cancellation handling in batch span processor's `ForceFlush` in `go.opentelemetry.io/otel/sdk/trace`. (#4369)
- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` using gotmpl. (#4397, #3846)
- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal` using gotmpl. (#4404, #3846)
- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal` using gotmpl. (#4407, #3846)
- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` and `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal` using gotmpl. (#4400, #3846)
- Decouple `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal` from `go.opentelemetry.io/otel/exporters/otlp/internal` and `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal` using gotmpl. (#4401, #3846)
- Do not block the metric SDK when OTLP metric exports are blocked in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#3925, #4395)
- Do not append `_total` if the counter already has that suffix for the Prometheus exproter in `go.opentelemetry.io/otel/exporter/prometheus`. (#4373)
- Fix resource detection data race in `go.opentelemetry.io/otel/sdk/resource`. (#4409)
- Use the first-seen instrument name during instrument name conflicts in `go.opentelemetry.io/otel/sdk/metric`. (#4428)
### Deprecated
- The `go.opentelemetry.io/otel/exporters/jaeger` package is deprecated.
OpenTelemetry dropped support for Jaeger exporter in July 2023.
Use `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`
or `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` instead. (#4423)
- The `go.opentelemetry.io/otel/example/jaeger` package is deprecated. (#4423)
- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal` package is deprecated. (#4420)
- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal/oconf` package is deprecated. (#4420)
- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal/otest` package is deprecated. (#4420)
- The `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/internal/transform` package is deprecated. (#4420)
- The `go.opentelemetry.io/otel/exporters/otlp/internal` package is deprecated. (#4421)
- The `go.opentelemetry.io/otel/exporters/otlp/internal/envconfig` package is deprecated. (#4421)
- The `go.opentelemetry.io/otel/exporters/otlp/internal/retry` package is deprecated. (#4421)
- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal` package is deprecated. (#4425)
- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/envconfig` package is deprecated. (#4425)
- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlpconfig` package is deprecated. (#4425)
- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlptracetest` package is deprecated. (#4425)
- The `go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/retry` package is deprecated. (#4425)
- The `go.opentelemetry.io/otel/sdk/metric/aggregation` package is deprecated.
Use the aggregation types added to `go.opentelemetry.io/otel/sdk/metric` instead. (#4435)
## [1.16.0/0.39.0] 2023-05-18
This release contains the first stable release of the OpenTelemetry Go [metric API].
Our project stability guarantees now apply to the `go.opentelemetry.io/otel/metric` package.
See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
### Added
- The `go.opentelemetry.io/otel/semconv/v1.19.0` package.
The package contains semantic conventions from the `v1.19.0` version of the OpenTelemetry specification. (#3848)
- The `go.opentelemetry.io/otel/semconv/v1.20.0` package.
The package contains semantic conventions from the `v1.20.0` version of the OpenTelemetry specification. (#4078)
- The Exponential Histogram data types in `go.opentelemetry.io/otel/sdk/metric/metricdata`. (#4165)
- OTLP metrics exporter now supports the Exponential Histogram Data Type. (#4222)
- Fix serialization of `time.Time` zero values in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` packages. (#4271)
### Changed
- Use `strings.Cut()` instead of `string.SplitN()` for better readability and memory use. (#4049)
- `MeterProvider` returns noop meters once it has been shutdown. (#4154)
### Removed
- The deprecated `go.opentelemetry.io/otel/metric/instrument` package is removed.
Use `go.opentelemetry.io/otel/metric` instead. (#4055)
### Fixed
- Fix build for BSD based systems in `go.opentelemetry.io/otel/sdk/resource`. (#4077)
## [1.16.0-rc.1/0.39.0-rc.1] 2023-05-03
This is a release candidate for the v1.16.0/v0.39.0 release.
That release is expected to include the `v1` release of the OpenTelemetry Go metric API and will provide stability guarantees of that API.
See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
### Added
- Support global `MeterProvider` in `go.opentelemetry.io/otel`. (#4039)
- Use `Meter` for a `metric.Meter` from the global `metric.MeterProvider`.
- Use `GetMeterProivder` for a global `metric.MeterProvider`.
- Use `SetMeterProivder` to set the global `metric.MeterProvider`.
### Changed
- Move the `go.opentelemetry.io/otel/metric` module to the `stable-v1` module set.
This stages the metric API to be released as a stable module. (#4038)
### Removed
- The `go.opentelemetry.io/otel/metric/global` package is removed.
Use `go.opentelemetry.io/otel` instead. (#4039)
## [1.15.1/0.38.1] 2023-05-02
### Fixed
- Remove unused imports from `sdk/resource/host_id_bsd.go` which caused build failures. (#4040, #4041)
## [1.15.0/0.38.0] 2023-04-27 ## [1.15.0/0.38.0] 2023-04-27
### Added ### Added
@@ -133,6 +415,8 @@ This release drops the compatibility guarantee of [Go 1.18].
- Handle empty environment variable as it they were not set. (#3764) - Handle empty environment variable as it they were not set. (#3764)
- Clarify the `httpconv` and `netconv` packages in `go.opentelemetry.io/otel/semconv/*` provide tracing semantic conventions. (#3823) - Clarify the `httpconv` and `netconv` packages in `go.opentelemetry.io/otel/semconv/*` provide tracing semantic conventions. (#3823)
- Fix race conditions in `go.opentelemetry.io/otel/exporters/metric/prometheus` that could cause a panic. (#3899)
- Fix sending nil `scopeInfo` to metrics channel in `go.opentelemetry.io/otel/exporters/metric/prometheus` that could cause a panic in `github.com/prometheus/client_golang/prometheus`. (#3899)
### Deprecated ### Deprecated
@@ -2437,7 +2721,15 @@ 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.15.0...HEAD [Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.20.0...HEAD
[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-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.17.0/0.40.0/0.0.5]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.17.0
[1.16.0/0.39.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.16.0
[1.16.0-rc.1/0.39.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.16.0-rc.1
[1.15.1/0.38.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.1
[1.15.0/0.38.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0 [1.15.0/0.38.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0
[1.15.0-rc.2/0.38.0-rc.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0-rc.2 [1.15.0-rc.2/0.38.0-rc.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0-rc.2
[1.15.0-rc.1/0.38.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0-rc.1 [1.15.0-rc.1/0.38.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.0-rc.1
@@ -2505,3 +2797,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
[metric API]:https://pkg.go.dev/go.opentelemetry.io/otel/metric
[metric SDK]:https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric
[trace API]:https://pkg.go.dev/go.opentelemetry.io/otel/trace
+1 -1
View File
@@ -14,4 +14,4 @@
* @MrAlias @Aneurysm9 @evantorrie @XSAM @dashpole @MadVikingGod @pellared @hanyuancheung @dmathieu * @MrAlias @Aneurysm9 @evantorrie @XSAM @dashpole @MadVikingGod @pellared @hanyuancheung @dmathieu
CODEOWNERS @MrAlias @Aneurysm9 @MadVikingGod CODEOWNERS @MrAlias @MadVikingGod @pellared
+81 -18
View File
@@ -28,6 +28,11 @@ precommit` - the `precommit` target is the default).
The `precommit` target also fixes the formatting of the code and The `precommit` target also fixes the formatting of the code and
checks the status of the go module files. checks the status of the go module files.
Additionally, there is a `codespell` target that checks for common
typos in the code. It is not run by default, but you can run it
manually with `make codespell`. It will set up a virtual environment
in `venv` and install `codespell` there.
If after running `make precommit` the output of `git status` contains If after running `make precommit` the output of `git status` contains
`nothing to commit, working tree clean` then it means that everything `nothing to commit, working tree clean` then it means that everything
is up-to-date and properly formatted. is up-to-date and properly formatted.
@@ -150,10 +155,10 @@ Any [Maintainer] can merge the PR once the above criteria have been met.
## Design Choices ## Design Choices
As with other OpenTelemetry clients, opentelemetry-go follows the As with other OpenTelemetry clients, opentelemetry-go follows the
[opentelemetry-specification](https://github.com/open-telemetry/opentelemetry-specification). [OpenTelemetry Specification](https://opentelemetry.io/docs/specs/otel).
It's especially valuable to read through the [library It's especially valuable to read through the [library
guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/library-guidelines.md). guidelines](https://opentelemetry.io/docs/specs/otel/library-guidelines).
### Focus on Capabilities, Not Structure Compliance ### Focus on Capabilities, Not Structure Compliance
@@ -174,23 +179,23 @@ For a deeper discussion, see
## Documentation ## Documentation
Each non-example Go Module should have its own `README.md` containing: Each (non-internal, non-test) package must be documented using
[Go Doc Comments](https://go.dev/doc/comment),
preferably in a `doc.go` file.
- A pkg.go.dev badge which can be generated [here](https://pkg.go.dev/badge/). Prefer using [Examples](https://pkg.go.dev/testing#hdr-Examples)
- Brief description. instead of putting code snippets in Go doc comments.
- Installation instructions (and requirements if applicable). In some cases, you can even create [Testable Examples](https://go.dev/blog/examples).
- Hyperlink to an example. Depending on the component the example can be:
- An `example_test.go` like [here](exporters/stdout/stdouttrace/example_test.go).
- A sample Go application with its own `README.md`, like [here](example/zipkin).
- Additional documentation sections such us:
- Configuration,
- Contributing,
- References.
[Here](exporters/jaeger/README.md) is an example of a concise `README.md`. You can install and run a "local Go Doc site" in the following way:
Moreover, it should be possible to navigate to any `README.md` from the ```sh
root `README.md`. go install golang.org/x/pkgsite/cmd/pkgsite@latest
pkgsite
```
[`go.opentelemetry.io/otel/metric`](https://pkg.go.dev/go.opentelemetry.io/otel/metric)
is an example of a very well-documented package.
## Style Guide ## Style Guide
@@ -470,8 +475,33 @@ documentation are allowed to be extended with additional methods.
> Warning: methods may be added to this interface in minor releases. > Warning: methods may be added to this interface in minor releases.
These interfaces are defined by the OpenTelemetry specification and will be
updated as the specification evolves.
Otherwise, stable interfaces MUST NOT be modified. Otherwise, stable interfaces MUST NOT be modified.
#### How to Change Specification Interfaces
When an API change must be made, we will update the SDK with the new method one
release before the API change. This will allow the SDK one version before the
API change to work seamlessly with the new API.
If an incompatible version of the SDK is used with the new API the application
will fail to compile.
#### How Not to Change Specification Interfaces
We have explored using a v2 of the API to change interfaces and found that there
was no way to introduce a v2 and have it work seamlessly with the v1 of the API.
Problems happened with libraries that upgraded to v2 when an application did not,
and would not produce any telemetry.
More detail of the approaches considered and their limitations can be found in
the [Use a V2 API to evolve interfaces](https://github.com/open-telemetry/opentelemetry-go/issues/3920)
issue.
#### How to Change Other Interfaces
If new functionality is needed for an interface that cannot be changed it MUST If new functionality is needed for an interface that cannot be changed it MUST
be added by including an additional interface. That added interface can be a be added by including an additional interface. That added interface can be a
simple interface for the specific functionality that you want to add or it can simple interface for the specific functionality that you want to add or it can
@@ -526,6 +556,37 @@ functionality should be added, each one will need their own super-set
interfaces and will duplicate the pattern. For this reason, the simple targeted interfaces and will duplicate the pattern. For this reason, the simple targeted
interface that defines the specific functionality should be preferred. interface that defines the specific functionality should be preferred.
### Testing
The tests should never leak goroutines.
Use the term `ConcurrentSafe` in the test name when it aims to verify the
absence of race conditions.
### Internal packages
The use of internal packages should be scoped to a single module. A sub-module
should never import from a parent internal package. This creates a coupling
between the two modules where a user can upgrade the parent without the child
and if the internal package API has changed it will fail to upgrade[^3].
There are two known exceptions to this rule:
- `go.opentelemetry.io/otel/internal/global`
- This package manages global state for all of opentelemetry-go. It needs to
be a single package in order to ensure the uniqueness of the global state.
- `go.opentelemetry.io/otel/internal/baggage`
- This package provides values in a `context.Context` that need to be
recognized by `go.opentelemetry.io/otel/baggage` and
`go.opentelemetry.io/otel/bridge/opentracing` but remain private.
If you have duplicate code in multiple modules, make that code into a Go
template stored in `go.opentelemetry.io/otel/internal/shared` and use [gotmpl]
to render the templates in the desired locations. See [#4404] for an example of
this.
[^3]: https://github.com/open-telemetry/opentelemetry-go/issues/3548
## Approvers and Maintainers ## Approvers and Maintainers
### Approvers ### Approvers
@@ -533,14 +594,14 @@ interface that defines the specific functionality should be preferred.
- [Evan Torrie](https://github.com/evantorrie), Verizon Media - [Evan Torrie](https://github.com/evantorrie), Verizon Media
- [Sam Xie](https://github.com/XSAM), Cisco/AppDynamics - [Sam Xie](https://github.com/XSAM), Cisco/AppDynamics
- [David Ashpole](https://github.com/dashpole), Google - [David Ashpole](https://github.com/dashpole), Google
- [Robert Pająk](https://github.com/pellared), Splunk
- [Chester Cheung](https://github.com/hanyuancheung), Tencent - [Chester Cheung](https://github.com/hanyuancheung), Tencent
- [Damien Mathieu](https://github.com/dmathieu), Elastic - [Damien Mathieu](https://github.com/dmathieu), Elastic
- [Anthony Mirabella](https://github.com/Aneurysm9), AWS
### Maintainers ### Maintainers
- [Aaron Clawson](https://github.com/MadVikingGod), LightStep - [Aaron Clawson](https://github.com/MadVikingGod), LightStep
- [Anthony Mirabella](https://github.com/Aneurysm9), AWS - [Robert Pająk](https://github.com/pellared), Splunk
- [Tyler Yahn](https://github.com/MrAlias), Splunk - [Tyler Yahn](https://github.com/MrAlias), Splunk
### Emeritus ### Emeritus
@@ -555,3 +616,5 @@ repo](https://github.com/open-telemetry/community/blob/main/community-membership
[Approver]: #approvers [Approver]: #approvers
[Maintainer]: #maintainers [Maintainer]: #maintainers
[gotmpl]: https://pkg.go.dev/go.opentelemetry.io/build-tools/gotmpl
[#4404]: https://github.com/open-telemetry/opentelemetry-go/pull/4404
+117 -26
View File
@@ -25,8 +25,8 @@ TIMEOUT = 60
.DEFAULT_GOAL := precommit .DEFAULT_GOAL := precommit
.PHONY: precommit ci .PHONY: precommit ci
precommit: dependabot-generate license-check vanity-import-fix misspell go-mod-tidy golangci-lint-fix test-default precommit: generate dependabot-generate license-check misspell go-mod-tidy golangci-lint-fix test-default
ci: dependabot-check license-check lint vanity-import-check build test-default check-clean-work-tree test-coverage ci: generate dependabot-check license-check lint vanity-import-check build test-default check-clean-work-tree test-coverage
# Tools # Tools
@@ -71,21 +71,78 @@ $(TOOLS)/porto: PACKAGE=github.com/jcchavezs/porto/cmd/porto
GOJQ = $(TOOLS)/gojq GOJQ = $(TOOLS)/gojq
$(TOOLS)/gojq: PACKAGE=github.com/itchyny/gojq/cmd/gojq $(TOOLS)/gojq: PACKAGE=github.com/itchyny/gojq/cmd/gojq
GOTMPL = $(TOOLS)/gotmpl
$(GOTMPL): PACKAGE=go.opentelemetry.io/build-tools/gotmpl
GORELEASE = $(TOOLS)/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) tools: $(CROSSLINK) $(DBOTCONF) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(GOJQ) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
# Virtualized python tools via docker
# The directory where the virtual environment is created.
VENVDIR := venv
# The directory where the python tools are installed.
PYTOOLS := $(VENVDIR)/bin
# The pip executable in the virtual environment.
PIP := $(PYTOOLS)/pip
# The directory in the docker image where the current directory is mounted.
WORKDIR := /workdir
# The python image to use for the virtual environment.
PYTHONIMAGE := python:3.11.3-slim-bullseye
# Run the python image with the current directory mounted.
DOCKERPY := docker run --rm -v "$(CURDIR):$(WORKDIR)" -w $(WORKDIR) $(PYTHONIMAGE)
# Create a virtual environment for Python tools.
$(PYTOOLS):
# The `--upgrade` flag is needed to ensure that the virtual environment is
# created with the latest pip version.
@$(DOCKERPY) bash -c "python3 -m venv $(VENVDIR) && $(PIP) install --upgrade pip"
# Install python packages into the virtual environment.
$(PYTOOLS)/%: | $(PYTOOLS)
@$(DOCKERPY) $(PIP) install -r requirements.txt
CODESPELL = $(PYTOOLS)/codespell
$(CODESPELL): PACKAGE=codespell
# Generate
.PHONY: generate
generate: go-generate vanity-import-fix
.PHONY: go-generate
go-generate: $(OTEL_GO_MOD_DIRS:%=go-generate/%)
go-generate/%: DIR=$*
go-generate/%: | $(STRINGER) $(GOTMPL)
@echo "$(GO) generate $(DIR)/..." \
&& cd $(DIR) \
&& PATH="$(TOOLS):$${PATH}" $(GO) generate ./...
.PHONY: vanity-import-fix
vanity-import-fix: | $(PORTO)
@$(PORTO) --include-internal -w .
# Generate go.work file for local development.
.PHONY: go-work
go-work: | $(CROSSLINK)
$(CROSSLINK) work --root=$(shell pwd)
# Build # Build
.PHONY: generate build .PHONY: build
generate: $(OTEL_GO_MOD_DIRS:%=generate/%) build: $(OTEL_GO_MOD_DIRS:%=build/%) $(OTEL_GO_MOD_DIRS:%=build-tests/%)
generate/%: DIR=$*
generate/%: | $(STRINGER) $(PORTO)
@echo "$(GO) generate $(DIR)/..." \
&& cd $(DIR) \
&& PATH="$(TOOLS):$${PATH}" $(GO) generate ./... && $(PORTO) -w .
build: generate $(OTEL_GO_MOD_DIRS:%=build/%) $(OTEL_GO_MOD_DIRS:%=build-tests/%)
build/%: DIR=$* build/%: DIR=$*
build/%: build/%:
@echo "$(GO) build $(DIR)/..." \ @echo "$(GO) build $(DIR)/..." \
@@ -135,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
@@ -156,30 +225,38 @@ go-mod-tidy/%: DIR=$*
go-mod-tidy/%: | crosslink go-mod-tidy/%: | crosslink
@echo "$(GO) mod tidy in $(DIR)" \ @echo "$(GO) mod tidy in $(DIR)" \
&& cd $(DIR) \ && cd $(DIR) \
&& $(GO) mod tidy -compat=1.19 && $(GO) mod tidy -compat=1.20
.PHONY: lint-modules .PHONY: lint-modules
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)
@$(PORTO) --include-internal -l . || echo "(run: make vanity-import-fix)" @$(PORTO) --include-internal -l . || ( echo "(run: make vanity-import-fix)"; exit 1 )
.PHONY: vanity-import-fix
vanity-import-fix: | $(PORTO)
@$(PORTO) --include-internal -w .
.PHONY: misspell .PHONY: misspell
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
codespell: | $(CODESPELL)
@$(DOCKERPY) $(CODESPELL)
.PHONY: license-check .PHONY: license-check
license-check: license-check:
@licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*' ! -path './.git/*' ) ; do \ @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*' ! -path './.git/*' ) ; do \
awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=3 { found=1; next } END { if (!found) print FILENAME }' $$f; \ awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \
done); \ done); \
if [ -n "$${licRes}" ]; then \ if [ -n "$${licRes}" ]; then \
echo "license header checking failed:"; echo "$${licRes}"; \ echo "license header checking failed:"; echo "$${licRes}"; \
@@ -189,7 +266,7 @@ license-check:
DEPENDABOT_CONFIG = .github/dependabot.yml DEPENDABOT_CONFIG = .github/dependabot.yml
.PHONY: dependabot-check .PHONY: dependabot-check
dependabot-check: | $(DBOTCONF) dependabot-check: | $(DBOTCONF)
@$(DBOTCONF) verify $(DEPENDABOT_CONFIG) || echo "(run: make dependabot-generate)" @$(DBOTCONF) verify $(DEPENDABOT_CONFIG) || ( echo "(run: make dependabot-generate)"; exit 1 )
.PHONY: dependabot-generate .PHONY: dependabot-generate
dependabot-generate: | $(DBOTCONF) dependabot-generate: | $(DBOTCONF)
@@ -208,13 +285,23 @@ check-clean-work-tree:
SEMCONVPKG ?= "semconv/" SEMCONVPKG ?= "semconv/"
.PHONY: semconv-generate .PHONY: semconv-generate
semconv-generate: | $(SEMCONVGEN) $(SEMCONVKIT) semconv-generate: | $(SEMCONVGEN) $(SEMCONVKIT)
[ "$(TAG)" ] || ( echo "TAG unset: missing opentelemetry specification tag"; exit 1 ) [ "$(TAG)" ] || ( echo "TAG unset: missing opentelemetry semantic-conventions tag"; exit 1 )
[ "$(OTEL_SPEC_REPO)" ] || ( echo "OTEL_SPEC_REPO unset: missing path to opentelemetry specification repo"; exit 1 ) [ "$(OTEL_SEMCONV_REPO)" ] || ( echo "OTEL_SEMCONV_REPO unset: missing path to opentelemetry semantic-conventions repo"; exit 1 )
$(SEMCONVGEN) -i "$(OTEL_SPEC_REPO)/semantic_conventions/." --only=span -p conventionType=trace -f trace.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)" $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=span -p conventionType=trace -f trace.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
$(SEMCONVGEN) -i "$(OTEL_SPEC_REPO)/semantic_conventions/." --only=event -p conventionType=event -f event.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)" $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=attribute_group -p conventionType=trace -f attribute_group.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
$(SEMCONVGEN) -i "$(OTEL_SPEC_REPO)/semantic_conventions/." --only=resource -p conventionType=resource -f resource.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)" $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=event -p conventionType=event -f event.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
$(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=resource -p conventionType=resource -f resource.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)"
$(SEMCONVKIT) -output "$(SEMCONVPKG)/$(TAG)" -tag "$(TAG)" $(SEMCONVKIT) -output "$(SEMCONVPKG)/$(TAG)" -tag "$(TAG)"
.PHONY: gorelease
gorelease: $(OTEL_GO_MOD_DIRS:%=gorelease/%)
gorelease/%: DIR=$*
gorelease/%:| $(GORELEASE)
@echo "gorelease in $(DIR):" \
&& cd $(DIR) \
&& $(GORELEASE) \
|| echo ""
.PHONY: prerelease .PHONY: prerelease
prerelease: | $(MULTIMOD) prerelease: | $(MULTIMOD)
@[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 ) @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 )
@@ -225,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
+15 -16
View File
@@ -11,22 +11,22 @@ 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 | Beta | N/A | | Metrics | Stable |
| Logs | Frozen [1] | N/A | | Logs | Design [1] |
- [1]: The Logs signal development is halted for this project while we develop both Traces and Metrics. - [1]: Currently the logs signal development is in a design phase ([#4696](https://github.com/open-telemetry/opentelemetry-go/issues/4696)).
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 local Progress and status specific to this repository is tracked in our
[project boards](https://github.com/open-telemetry/opentelemetry-go/projects) [project boards](https://github.com/open-telemetry/opentelemetry-go/projects)
and and
[milestones](https://github.com/open-telemetry/opentelemetry-go/milestones). [milestones](https://github.com/open-telemetry/opentelemetry-go/milestones).
Project versioning information and stability guarantees can be found in the Project versioning information and stability guarantees can be found in the
[versioning documentation](./VERSIONING.md). [versioning documentation](VERSIONING.md).
### Compatibility ### Compatibility
@@ -49,17 +49,17 @@ stop ensuring compatibility with these versions in the following manner:
Currently, this project supports the following environments. Currently, this project supports the following environments.
| OS | Go Version | Architecture | | OS | Go Version | Architecture |
| ------- | ---------- | ------------ | |---------|------------|--------------|
| Ubuntu | 1.21 | amd64 |
| Ubuntu | 1.20 | amd64 | | Ubuntu | 1.20 | amd64 |
| Ubuntu | 1.19 | amd64 | | Ubuntu | 1.21 | 386 |
| Ubuntu | 1.20 | 386 | | Ubuntu | 1.20 | 386 |
| Ubuntu | 1.19 | 386 | | MacOS | 1.21 | amd64 |
| MacOS | 1.20 | amd64 | | MacOS | 1.20 | amd64 |
| MacOS | 1.19 | amd64 | | Windows | 1.21 | amd64 |
| Windows | 1.20 | amd64 | | Windows | 1.20 | amd64 |
| Windows | 1.19 | amd64 | | Windows | 1.21 | 386 |
| Windows | 1.20 | 386 | | Windows | 1.20 | 386 |
| Windows | 1.19 | 386 |
While this project should work for other systems, no compatibility guarantees While this project should work for other systems, no compatibility guarantees
are made for those systems currently. are made for those systems currently.
@@ -97,8 +97,7 @@ export pipeline to send that telemetry to an observability platform.
All officially supported exporters for the OpenTelemetry project are contained in the [exporters directory](./exporters). All officially supported exporters for the OpenTelemetry project are contained in the [exporters directory](./exporters).
| Exporter | Metrics | Traces | | Exporter | Metrics | Traces |
| :-----------------------------------: | :-----: | :----: | |---------------------------------------|:-------:|:------:|
| [Jaeger](./exporters/jaeger/) | | ✓ |
| [OTLP](./exporters/otlp/) | ✓ | ✓ | | [OTLP](./exporters/otlp/) | ✓ | ✓ |
| [Prometheus](./exporters/prometheus/) | ✓ | | | [Prometheus](./exporters/prometheus/) | ✓ | |
| [stdout](./exporters/stdout/) | ✓ | ✓ | | [stdout](./exporters/stdout/) | ✓ | ✓ |
+22 -10
View File
@@ -2,28 +2,30 @@
## Semantic Convention Generation ## Semantic Convention Generation
New versions of the [OpenTelemetry specification] mean new versions of the `semconv` package need to be generated. New versions of the [OpenTelemetry Semantic Conventions] mean new versions of the `semconv` package need to be generated.
The `semconv-generate` make target is used for this. The `semconv-generate` make target is used for this.
1. Checkout a local copy of the [OpenTelemetry specification] to the desired release tag. 1. Checkout a local copy of the [OpenTelemetry Semantic Conventions] to the desired release tag.
2. Pull the latest `otel/semconvgen` image: `docker pull otel/semconvgen:latest` 2. Pull the latest `otel/semconvgen` image: `docker pull otel/semconvgen:latest`
3. Run the `make semconv-generate ...` target from this repository. 3. Run the `make semconv-generate ...` target from this repository.
For example, For example,
```sh ```sh
export TAG="v1.13.0" # Change to the release version you are generating. export TAG="v1.21.0" # Change to the release version you are generating.
export OTEL_SPEC_REPO="/absolute/path/to/opentelemetry-specification" export OTEL_SEMCONV_REPO="/absolute/path/to/opentelemetry/semantic-conventions"
git -C "$OTEL_SPEC_REPO" checkout "tags/$TAG" -b "$TAG"
docker pull otel/semconvgen:latest docker pull otel/semconvgen:latest
make semconv-generate # Uses the exported TAG and OTEL_SPEC_REPO. make semconv-generate # Uses the exported TAG and OTEL_SEMCONV_REPO.
``` ```
This should create a new sub-package of [`semconv`](./semconv). This should create a new sub-package of [`semconv`](./semconv).
Ensure things look correct before submitting a pull request to include the addition. Ensure things look correct before submitting a pull request to include the addition.
**Note**, the generation code was changed to generate versions >= 1.13. ## Breaking changes validation
To generate versions prior to this, checkout the old release of this repository (i.e. [2fe8861](https://github.com/open-telemetry/opentelemetry-go/commit/2fe8861a24e20088c065b116089862caf9e3cd8b)).
You can run `make gorelease` that runs [gorelease](https://pkg.go.dev/golang.org/x/exp/cmd/gorelease) to ensure that there are no unwanted changes done in the public API.
You can check/report problems with `gorelease` [here](https://golang.org/issues/26420).
## Pre-Release ## Pre-Release
@@ -121,7 +123,17 @@ Once verified be sure to [make a release for the `contrib` repository](https://g
### Website Documentation ### Website Documentation
Update [the documentation](./website_docs) for [the OpenTelemetry website](https://opentelemetry.io/docs/go/). Update the [Go instrumentation documentation] in the OpenTelemetry website under [content/en/docs/instrumentation/go].
Importantly, bump any package versions referenced to be the latest one you just released and ensure all code examples still compile and are accurate. Importantly, bump any package versions referenced to be the latest one you just released and ensure all code examples still compile and are accurate.
[OpenTelemetry specification]: https://github.com/open-telemetry/opentelemetry-specification [OpenTelemetry Semantic Conventions]: https://github.com/open-telemetry/semantic-conventions
[Go instrumentation documentation]: https://opentelemetry.io/docs/instrumentation/go/
[content/en/docs/instrumentation/go]: https://github.com/open-telemetry/opentelemetry.io/tree/main/content/en/docs/instrumentation/go
### Demo Repository
Bump the dependencies in the following Go services:
- [`accountingservice`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/accountingservice)
- [`checkoutservice`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/checkoutservice)
- [`productcatalogservice`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/productcatalogservice)
+60
View File
@@ -0,0 +1,60 @@
// 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 attribute // import "go.opentelemetry.io/otel/attribute"
// Filter supports removing certain attributes from attribute sets. When
// the filter returns true, the attribute will be kept in the filtered
// attribute set. When the filter returns false, the attribute is excluded
// from the filtered attribute set, and the attribute instead appears in
// the removed list of excluded attributes.
type Filter func(KeyValue) bool
// NewAllowKeysFilter returns a Filter that only allows attributes with one of
// the provided keys.
//
// If keys is empty a deny-all filter is returned.
func NewAllowKeysFilter(keys ...Key) Filter {
if len(keys) <= 0 {
return func(kv KeyValue) bool { return false }
}
allowed := make(map[Key]struct{})
for _, k := range keys {
allowed[k] = struct{}{}
}
return func(kv KeyValue) bool {
_, ok := allowed[kv.Key]
return ok
}
}
// NewDenyKeysFilter returns a Filter that only allows attributes
// that do not have one of the provided keys.
//
// If keys is empty an allow-all filter is returned.
func NewDenyKeysFilter(keys ...Key) Filter {
if len(keys) <= 0 {
return func(kv KeyValue) bool { return true }
}
forbid := make(map[Key]struct{})
for _, k := range keys {
forbid[k] = struct{}{}
}
return func(kv KeyValue) bool {
_, ok := forbid[kv.Key]
return !ok
}
}
-7
View File
@@ -39,13 +39,6 @@ type (
iface interface{} iface interface{}
} }
// Filter supports removing certain attributes from attribute sets. When
// the filter returns true, the attribute will be kept in the filtered
// attribute set. When the filter returns false, the attribute is excluded
// from the filtered attribute set, and the attribute instead appears in
// the removed list of excluded attributes.
Filter func(KeyValue) bool
// Sortable implements sort.Interface, used for sorting KeyValue. This is // Sortable implements sort.Interface, used for sorting KeyValue. This is
// an exported type to support a memory optimization. A pointer to one of // an exported type to support a memory optimization. A pointer to one of
// these is needed for the call to sort.Stable(), which the caller may // these is needed for the call to sort.Stable(), which the caller may
+11 -29
View File
@@ -61,11 +61,6 @@ type Property struct {
// hasValue indicates if a zero-value value means the property does not // hasValue indicates if a zero-value value means the property does not
// have a value or if it was the zero-value. // have a value or if it was the zero-value.
hasValue bool hasValue bool
// hasData indicates whether the created property contains data or not.
// Properties that do not contain data are invalid with no other check
// required.
hasData bool
} }
// NewKeyProperty returns a new Property for key. // NewKeyProperty returns a new Property for key.
@@ -76,7 +71,7 @@ func NewKeyProperty(key string) (Property, error) {
return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key) return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key)
} }
p := Property{key: key, hasData: true} p := Property{key: key}
return p, nil return p, nil
} }
@@ -95,7 +90,6 @@ func NewKeyValueProperty(key, value string) (Property, error) {
key: key, key: key,
value: value, value: value,
hasValue: true, hasValue: true,
hasData: true,
} }
return p, nil return p, nil
} }
@@ -117,7 +111,7 @@ func parseProperty(property string) (Property, error) {
return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidProperty, property) return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidProperty, property)
} }
p := Property{hasData: true} var p Property
if match[1] != "" { if match[1] != "" {
p.key = match[1] p.key = match[1]
} else { } else {
@@ -136,10 +130,6 @@ func (p Property) validate() error {
return fmt.Errorf("invalid property: %w", err) return fmt.Errorf("invalid property: %w", err)
} }
if !p.hasData {
return errFunc(fmt.Errorf("%w: %q", errInvalidProperty, p))
}
if !keyRe.MatchString(p.key) { if !keyRe.MatchString(p.key) {
return errFunc(fmt.Errorf("%w: %q", errInvalidKey, p.key)) return errFunc(fmt.Errorf("%w: %q", errInvalidKey, p.key))
} }
@@ -264,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)
} }
@@ -289,31 +279,29 @@ func parseMember(member string) (Member, error) {
props properties props properties
) )
parts := strings.SplitN(member, propertyDelimiter, 2) keyValue, properties, found := strings.Cut(member, propertyDelimiter)
switch len(parts) { if found {
case 2:
// Parse the member properties. // Parse the member properties.
for _, pStr := range strings.Split(parts[1], propertyDelimiter) { for _, pStr := range strings.Split(properties, propertyDelimiter) {
p, err := parseProperty(pStr) p, err := parseProperty(pStr)
if err != nil { if err != nil {
return newInvalidMember(), err return newInvalidMember(), err
} }
props = append(props, p) props = append(props, p)
} }
fallthrough }
case 1:
// Parse the member key/value pair. // Parse the member key/value pair.
// Take into account a value can contain equal signs (=). // Take into account a value can contain equal signs (=).
kv := strings.SplitN(parts[0], keyValueDelimiter, 2) k, v, found := strings.Cut(keyValue, keyValueDelimiter)
if len(kv) != 2 { if !found {
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidMember, member) return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidMember, member)
} }
// "Leading and trailing whitespaces are allowed but MUST be trimmed // "Leading and trailing whitespaces are allowed but MUST be trimmed
// when converting the header into a data structure." // when converting the header into a data structure."
key = strings.TrimSpace(kv[0]) key = strings.TrimSpace(k)
var err error var err error
value, err = url.QueryUnescape(strings.TrimSpace(kv[1])) 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)
} }
@@ -323,12 +311,6 @@ func parseMember(member string) (Member, error) {
if !valueRe.MatchString(value) { if !valueRe.MatchString(value) {
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
} }
default:
// This should never happen unless a developer has changed the string
// splitting somehow. Panic instead of failing silently and allowing
// the bug to slip past the CI checks.
panic("failed to parse baggage member")
}
return Member{key: key, value: value, properties: props, hasData: true}, nil return Member{key: key, value: value, properties: props, hasData: true}, nil
} }
+1 -1
View File
@@ -16,6 +16,6 @@
Package codes defines the canonical error codes used by OpenTelemetry. Package codes defines the canonical error codes used by OpenTelemetry.
It conforms to [the OpenTelemetry It conforms to [the OpenTelemetry
specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#statuscanonicalcode). specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/trace/api.md#set-status).
*/ */
package codes // import "go.opentelemetry.io/otel/codes" package codes // import "go.opentelemetry.io/otel/codes"
+29
View File
@@ -0,0 +1,29 @@
// 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 internal // import "go.opentelemetry.io/otel/internal"
//go:generate gotmpl --body=./shared/matchers/expectation.go.tmpl "--data={}" --out=matchers/expectation.go
//go:generate gotmpl --body=./shared/matchers/expecter.go.tmpl "--data={}" --out=matchers/expecter.go
//go:generate gotmpl --body=./shared/matchers/temporal_matcher.go.tmpl "--data={}" --out=matchers/temporal_matcher.go
//go:generate gotmpl --body=./shared/internaltest/alignment.go.tmpl "--data={}" --out=internaltest/alignment.go
//go:generate gotmpl --body=./shared/internaltest/env.go.tmpl "--data={}" --out=internaltest/env.go
//go:generate gotmpl --body=./shared/internaltest/env_test.go.tmpl "--data={}" --out=internaltest/env_test.go
//go:generate gotmpl --body=./shared/internaltest/errors.go.tmpl "--data={}" --out=internaltest/errors.go
//go:generate gotmpl --body=./shared/internaltest/harness.go.tmpl "--data={\"matchersImportPath\": \"go.opentelemetry.io/otel/internal/matchers\"}" --out=internaltest/harness.go
//go:generate gotmpl --body=./shared/internaltest/text_map_carrier.go.tmpl "--data={}" --out=internaltest/text_map_carrier.go
//go:generate gotmpl --body=./shared/internaltest/text_map_carrier_test.go.tmpl "--data={}" --out=internaltest/text_map_carrier_test.go
//go:generate gotmpl --body=./shared/internaltest/text_map_propagator.go.tmpl "--data={}" --out=internaltest/text_map_propagator.go
//go:generate gotmpl --body=./shared/internaltest/text_map_propagator_test.go.tmpl "--data={}" --out=internaltest/text_map_propagator_test.go
+3 -4
View File
@@ -18,7 +18,6 @@ import (
"log" "log"
"os" "os"
"sync/atomic" "sync/atomic"
"unsafe"
) )
var ( var (
@@ -42,7 +41,7 @@ type ErrorHandler interface {
} }
type ErrDelegator struct { type ErrDelegator struct {
delegate unsafe.Pointer delegate atomic.Pointer[ErrorHandler]
} }
func (d *ErrDelegator) Handle(err error) { func (d *ErrDelegator) Handle(err error) {
@@ -50,12 +49,12 @@ func (d *ErrDelegator) Handle(err error) {
} }
func (d *ErrDelegator) getDelegate() ErrorHandler { func (d *ErrDelegator) getDelegate() ErrorHandler {
return *(*ErrorHandler)(atomic.LoadPointer(&d.delegate)) return *d.delegate.Load()
} }
// setDelegate sets the ErrorHandler delegate. // setDelegate sets the ErrorHandler delegate.
func (d *ErrDelegator) setDelegate(eh ErrorHandler) { func (d *ErrDelegator) setDelegate(eh ErrorHandler) {
atomic.StorePointer(&d.delegate, unsafe.Pointer(&eh)) d.delegate.Store(&eh)
} }
func defaultErrorHandler() *ErrDelegator { func defaultErrorHandler() *ErrDelegator {
@@ -12,13 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package global // import "go.opentelemetry.io/otel/metric/internal/global" package global // import "go.opentelemetry.io/otel/internal/global"
import ( import (
"context" "context"
"sync/atomic" "sync/atomic"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded" "go.opentelemetry.io/otel/metric/embedded"
) )
@@ -38,13 +37,15 @@ type afCounter struct {
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...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -67,13 +68,15 @@ type afUpDownCounter struct {
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...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -96,13 +99,15 @@ type afGauge struct {
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...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -125,13 +130,15 @@ type aiCounter struct {
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...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -154,13 +161,15 @@ type aiUpDownCounter struct {
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...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -183,13 +192,15 @@ type aiGauge struct {
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...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -217,7 +228,7 @@ var _ metric.Float64Counter = (*sfCounter)(nil)
func (i *sfCounter) setDelegate(m metric.Meter) { func (i *sfCounter) setDelegate(m metric.Meter) {
ctr, err := m.Float64Counter(i.name, i.opts...) ctr, err := m.Float64Counter(i.name, i.opts...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -243,7 +254,7 @@ var _ metric.Float64UpDownCounter = (*sfUpDownCounter)(nil)
func (i *sfUpDownCounter) setDelegate(m metric.Meter) { func (i *sfUpDownCounter) setDelegate(m metric.Meter) {
ctr, err := m.Float64UpDownCounter(i.name, i.opts...) ctr, err := m.Float64UpDownCounter(i.name, i.opts...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -269,7 +280,7 @@ var _ metric.Float64Histogram = (*sfHistogram)(nil)
func (i *sfHistogram) setDelegate(m metric.Meter) { func (i *sfHistogram) setDelegate(m metric.Meter) {
ctr, err := m.Float64Histogram(i.name, i.opts...) ctr, err := m.Float64Histogram(i.name, i.opts...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -295,7 +306,7 @@ var _ metric.Int64Counter = (*siCounter)(nil)
func (i *siCounter) setDelegate(m metric.Meter) { func (i *siCounter) setDelegate(m metric.Meter) {
ctr, err := m.Int64Counter(i.name, i.opts...) ctr, err := m.Int64Counter(i.name, i.opts...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -321,7 +332,7 @@ var _ metric.Int64UpDownCounter = (*siUpDownCounter)(nil)
func (i *siUpDownCounter) setDelegate(m metric.Meter) { func (i *siUpDownCounter) setDelegate(m metric.Meter) {
ctr, err := m.Int64UpDownCounter(i.name, i.opts...) ctr, err := m.Int64UpDownCounter(i.name, i.opts...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
@@ -347,7 +358,7 @@ var _ metric.Int64Histogram = (*siHistogram)(nil)
func (i *siHistogram) setDelegate(m metric.Meter) { func (i *siHistogram) setDelegate(m metric.Meter) {
ctr, err := m.Int64Histogram(i.name, i.opts...) ctr, err := m.Int64Histogram(i.name, i.opts...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
return return
} }
i.delegate.Store(ctr) i.delegate.Store(ctr)
+3 -4
View File
@@ -18,7 +18,6 @@ import (
"log" "log"
"os" "os"
"sync/atomic" "sync/atomic"
"unsafe"
"github.com/go-logr/logr" "github.com/go-logr/logr"
"github.com/go-logr/stdr" "github.com/go-logr/stdr"
@@ -28,7 +27,7 @@ import (
// //
// The default logger uses stdr which is backed by the standard `log.Logger` // The default logger uses stdr which is backed by the standard `log.Logger`
// interface. This logger will only show messages at the Error Level. // interface. This logger will only show messages at the Error Level.
var globalLogger unsafe.Pointer var globalLogger atomic.Pointer[logr.Logger]
func init() { func init() {
SetLogger(stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile))) SetLogger(stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile)))
@@ -40,11 +39,11 @@ func init() {
// To see Info messages use a logger with `l.V(4).Enabled() == true` // To see Info messages use a logger with `l.V(4).Enabled() == true`
// To see Debug messages use a logger with `l.V(8).Enabled() == true`. // To see Debug messages use a logger with `l.V(8).Enabled() == true`.
func SetLogger(l logr.Logger) { func SetLogger(l logr.Logger) {
atomic.StorePointer(&globalLogger, unsafe.Pointer(&l)) globalLogger.Store(&l)
} }
func getLogger() logr.Logger { func getLogger() logr.Logger {
return *(*logr.Logger)(atomic.LoadPointer(&globalLogger)) return *globalLogger.Load()
} }
// Info prints messages about the general state of the API or SDK. // Info prints messages about the general state of the API or SDK.
@@ -12,14 +12,13 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package global // import "go.opentelemetry.io/otel/metric/internal/global" package global // import "go.opentelemetry.io/otel/internal/global"
import ( import (
"container/list" "container/list"
"sync" "sync"
"sync/atomic" "sync/atomic"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/embedded" "go.opentelemetry.io/otel/metric/embedded"
) )
@@ -37,11 +36,6 @@ type meterProvider struct {
delegate metric.MeterProvider delegate metric.MeterProvider
} }
type il struct {
name string
version string
}
// setDelegate configures p to delegate all MeterProvider functionality to // setDelegate configures p to delegate all MeterProvider functionality to
// provider. // provider.
// //
@@ -340,7 +334,7 @@ func (c *registration) setDelegate(m metric.Meter) {
reg, err := m.RegisterCallback(c.function, insts...) reg, err := m.RegisterCallback(c.function, insts...)
if err != nil { if err != nil {
otel.Handle(err) GetErrorHandler().Handle(err)
} }
c.unreg = reg.Unregister c.unreg = reg.Unregister
+41
View File
@@ -19,6 +19,7 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@@ -31,14 +32,20 @@ type (
propagatorsHolder struct { propagatorsHolder struct {
tm propagation.TextMapPropagator tm propagation.TextMapPropagator
} }
meterProviderHolder struct {
mp metric.MeterProvider
}
) )
var ( var (
globalTracer = defaultTracerValue() globalTracer = defaultTracerValue()
globalPropagators = defaultPropagatorsValue() globalPropagators = defaultPropagatorsValue()
globalMeterProvider = defaultMeterProvider()
delegateTraceOnce sync.Once delegateTraceOnce sync.Once
delegateTextMapPropagatorOnce sync.Once delegateTextMapPropagatorOnce sync.Once
delegateMeterOnce sync.Once
) )
// TracerProvider is the internal implementation for global.TracerProvider. // TracerProvider is the internal implementation for global.TracerProvider.
@@ -102,6 +109,34 @@ func SetTextMapPropagator(p propagation.TextMapPropagator) {
globalPropagators.Store(propagatorsHolder{tm: p}) globalPropagators.Store(propagatorsHolder{tm: p})
} }
// MeterProvider is the internal implementation for global.MeterProvider.
func MeterProvider() metric.MeterProvider {
return globalMeterProvider.Load().(meterProviderHolder).mp
}
// SetMeterProvider is the internal implementation for global.SetMeterProvider.
func SetMeterProvider(mp metric.MeterProvider) {
current := MeterProvider()
if _, cOk := current.(*meterProvider); cOk {
if _, mpOk := mp.(*meterProvider); mpOk && current == mp {
// Do not assign the default delegating MeterProvider to delegate
// to itself.
Error(
errors.New("no delegate configured in meter provider"),
"Setting meter provider to it's current value. No delegate will be configured",
)
return
}
}
delegateMeterOnce.Do(func() {
if def, ok := current.(*meterProvider); ok {
def.setDelegate(mp)
}
})
globalMeterProvider.Store(meterProviderHolder{mp: mp})
}
func defaultTracerValue() *atomic.Value { func defaultTracerValue() *atomic.Value {
v := &atomic.Value{} v := &atomic.Value{}
v.Store(tracerProviderHolder{tp: &tracerProvider{}}) v.Store(tracerProviderHolder{tp: &tracerProvider{}})
@@ -113,3 +148,9 @@ func defaultPropagatorsValue() *atomic.Value {
v.Store(propagatorsHolder{tm: newTextMapPropagator()}) v.Store(propagatorsHolder{tm: newTextMapPropagator()})
return v return v
} }
func defaultMeterProvider() *atomic.Value {
v := &atomic.Value{}
v.Store(meterProviderHolder{mp: &meterProvider{}})
return v
}
+7
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
} }
@@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package global // import "go.opentelemetry.io/otel/metric/global" package otel // import "go.opentelemetry.io/otel"
import ( import (
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/internal/global"
) )
// Meter returns a Meter from the global MeterProvider. The name must be the // Meter returns a Meter from the global MeterProvider. The name must be the
@@ -32,14 +32,18 @@ import (
// the new MeterProvider. // the new MeterProvider.
// //
// This is short for GetMeterProvider().Meter(name). // This is short for GetMeterProvider().Meter(name).
func Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { func Meter(name string, opts ...metric.MeterOption) metric.Meter {
return MeterProvider().Meter(instrumentationName, opts...) return GetMeterProvider().Meter(name, opts...)
} }
// MeterProvider returns the registered global meter provider. // GetMeterProvider returns the registered global meter provider.
// //
// If no global MeterProvider has been registered, a No-op MeterProvider implementation is returned. When a global MeterProvider is registered for the first time, the returned MeterProvider, and all the Meters it has created or will create, are recreated automatically from the new MeterProvider. // If no global GetMeterProvider has been registered, a No-op GetMeterProvider
func MeterProvider() metric.MeterProvider { // implementation is returned. When a global GetMeterProvider is registered for
// the first time, the returned GetMeterProvider, and all the Meters it has
// created or will create, are recreated automatically from the new
// GetMeterProvider.
func GetMeterProvider() metric.MeterProvider {
return global.MeterProvider() return global.MeterProvider()
} }
+29 -16
View File
@@ -37,10 +37,13 @@ type Float64Observable interface {
// assumed the to be the cumulative sum of the count. // assumed the to be the cumulative sum of the count.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for
// unimplemented methods. // unimplemented methods.
type Float64ObservableCounter interface { type Float64ObservableCounter 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.Float64ObservableCounter embedded.Float64ObservableCounter
Float64Observable Float64Observable
@@ -80,8 +83,9 @@ func (c Float64ObservableCounterConfig) Callbacks() []Float64Callback {
} }
// Float64ObservableCounterOption applies options to a // Float64ObservableCounterOption applies options to a
// [Float64ObservableCounterConfig]. See [Float64ObservableOption] and [Option] // [Float64ObservableCounterConfig]. See [Float64ObservableOption] and
// for other options that can be used as a Float64ObservableCounterOption. // [InstrumentOption] for other options that can be used as a
// Float64ObservableCounterOption.
type Float64ObservableCounterOption interface { type Float64ObservableCounterOption interface {
applyFloat64ObservableCounter(Float64ObservableCounterConfig) Float64ObservableCounterConfig applyFloat64ObservableCounter(Float64ObservableCounterConfig) Float64ObservableCounterConfig
} }
@@ -92,10 +96,12 @@ type Float64ObservableCounterOption interface {
// the to be the cumulative sum of the count. // the to be the cumulative sum of the count.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Float64ObservableUpDownCounter interface { type Float64ObservableUpDownCounter 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.Float64ObservableUpDownCounter embedded.Float64ObservableUpDownCounter
Float64Observable Float64Observable
@@ -136,7 +142,7 @@ func (c Float64ObservableUpDownCounterConfig) Callbacks() []Float64Callback {
// Float64ObservableUpDownCounterOption applies options to a // Float64ObservableUpDownCounterOption applies options to a
// [Float64ObservableUpDownCounterConfig]. See [Float64ObservableOption] and // [Float64ObservableUpDownCounterConfig]. See [Float64ObservableOption] and
// [Option] for other options that can be used as a // [InstrumentOption] for other options that can be used as a
// Float64ObservableUpDownCounterOption. // Float64ObservableUpDownCounterOption.
type Float64ObservableUpDownCounterOption interface { type Float64ObservableUpDownCounterOption interface {
applyFloat64ObservableUpDownCounter(Float64ObservableUpDownCounterConfig) Float64ObservableUpDownCounterConfig applyFloat64ObservableUpDownCounter(Float64ObservableUpDownCounterConfig) Float64ObservableUpDownCounterConfig
@@ -147,10 +153,12 @@ type Float64ObservableUpDownCounterOption interface {
// are only made within a callback for this instrument. // are only made within a callback for this instrument.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Float64ObservableGauge interface { type Float64ObservableGauge 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.Float64ObservableGauge embedded.Float64ObservableGauge
Float64Observable Float64Observable
@@ -191,7 +199,7 @@ func (c Float64ObservableGaugeConfig) Callbacks() []Float64Callback {
// Float64ObservableGaugeOption applies options to a // Float64ObservableGaugeOption applies options to a
// [Float64ObservableGaugeConfig]. See [Float64ObservableOption] and // [Float64ObservableGaugeConfig]. See [Float64ObservableOption] and
// [Option] for other options that can be used as a // [InstrumentOption] for other options that can be used as a
// Float64ObservableGaugeOption. // Float64ObservableGaugeOption.
type Float64ObservableGaugeOption interface { type Float64ObservableGaugeOption interface {
applyFloat64ObservableGauge(Float64ObservableGaugeConfig) Float64ObservableGaugeConfig applyFloat64ObservableGauge(Float64ObservableGaugeConfig) Float64ObservableGaugeConfig
@@ -200,14 +208,19 @@ type Float64ObservableGaugeOption interface {
// Float64Observer is a recorder of float64 measurements. // Float64Observer is a recorder of float64 measurements.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Float64Observer interface { type Float64Observer 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.Float64Observer embedded.Float64Observer
// Observe records the float64 value. // Observe records the float64 value.
Observe(value float64, opts ...ObserveOption) //
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Observe(value float64, options ...ObserveOption)
} }
// Float64Callback is a function registered with a Meter that makes // Float64Callback is a function registered with a Meter that makes
+31 -18
View File
@@ -37,10 +37,12 @@ type Int64Observable interface {
// assumed the to be the cumulative sum of the count. // assumed the to be the cumulative sum of the count.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Int64ObservableCounter interface { type Int64ObservableCounter 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.Int64ObservableCounter embedded.Int64ObservableCounter
Int64Observable Int64Observable
@@ -80,8 +82,9 @@ func (c Int64ObservableCounterConfig) Callbacks() []Int64Callback {
} }
// Int64ObservableCounterOption applies options to a // Int64ObservableCounterOption applies options to a
// [Int64ObservableCounterConfig]. See [Int64ObservableOption] and [Option] for // [Int64ObservableCounterConfig]. See [Int64ObservableOption] and
// other options that can be used as an Int64ObservableCounterOption. // [InstrumentOption] for other options that can be used as an
// Int64ObservableCounterOption.
type Int64ObservableCounterOption interface { type Int64ObservableCounterOption interface {
applyInt64ObservableCounter(Int64ObservableCounterConfig) Int64ObservableCounterConfig applyInt64ObservableCounter(Int64ObservableCounterConfig) Int64ObservableCounterConfig
} }
@@ -92,10 +95,12 @@ type Int64ObservableCounterOption interface {
// be the cumulative sum of the count. // be the cumulative sum of the count.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Int64ObservableUpDownCounter interface { type Int64ObservableUpDownCounter 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.Int64ObservableUpDownCounter embedded.Int64ObservableUpDownCounter
Int64Observable Int64Observable
@@ -136,7 +141,7 @@ func (c Int64ObservableUpDownCounterConfig) Callbacks() []Int64Callback {
// Int64ObservableUpDownCounterOption applies options to a // Int64ObservableUpDownCounterOption applies options to a
// [Int64ObservableUpDownCounterConfig]. See [Int64ObservableOption] and // [Int64ObservableUpDownCounterConfig]. See [Int64ObservableOption] and
// [Option] for other options that can be used as an // [InstrumentOption] for other options that can be used as an
// Int64ObservableUpDownCounterOption. // Int64ObservableUpDownCounterOption.
type Int64ObservableUpDownCounterOption interface { type Int64ObservableUpDownCounterOption interface {
applyInt64ObservableUpDownCounter(Int64ObservableUpDownCounterConfig) Int64ObservableUpDownCounterConfig applyInt64ObservableUpDownCounter(Int64ObservableUpDownCounterConfig) Int64ObservableUpDownCounterConfig
@@ -147,10 +152,12 @@ type Int64ObservableUpDownCounterOption interface {
// only made within a callback for this instrument. // only made within a callback for this instrument.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Int64ObservableGauge interface { type Int64ObservableGauge 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.Int64ObservableGauge embedded.Int64ObservableGauge
Int64Observable Int64Observable
@@ -190,8 +197,9 @@ func (c Int64ObservableGaugeConfig) Callbacks() []Int64Callback {
} }
// Int64ObservableGaugeOption applies options to a // Int64ObservableGaugeOption applies options to a
// [Int64ObservableGaugeConfig]. See [Int64ObservableOption] and [Option] for // [Int64ObservableGaugeConfig]. See [Int64ObservableOption] and
// other options that can be used as an Int64ObservableGaugeOption. // [InstrumentOption] for other options that can be used as an
// Int64ObservableGaugeOption.
type Int64ObservableGaugeOption interface { type Int64ObservableGaugeOption interface {
applyInt64ObservableGauge(Int64ObservableGaugeConfig) Int64ObservableGaugeConfig applyInt64ObservableGauge(Int64ObservableGaugeConfig) Int64ObservableGaugeConfig
} }
@@ -199,14 +207,19 @@ type Int64ObservableGaugeOption interface {
// Int64Observer is a recorder of int64 measurements. // Int64Observer is a recorder of int64 measurements.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Int64Observer interface { type Int64Observer 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.Int64Observer embedded.Int64Observer
// Observe records the int64 value. // Observe records the int64 value.
Observe(value int64, opts ...ObserveOption) //
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Observe(value int64, options ...ObserveOption)
} }
// Int64Callback is a function registered with a Meter that makes observations // Int64Callback is a function registered with a Meter that makes observations
+46 -13
View File
@@ -35,14 +35,14 @@ all instruments fall into two overlapping logical categories: asynchronous or
synchronous, and int64 or float64. synchronous, and int64 or float64.
All synchronous instruments ([Int64Counter], [Int64UpDownCounter], All synchronous instruments ([Int64Counter], [Int64UpDownCounter],
[Int64Histogram], [Float64Counter], [Float64UpDownCounter], [Float64Histogram]) [Int64Histogram], [Float64Counter], [Float64UpDownCounter], and
are used to measure the operation and performance of source code during the [Float64Histogram]) are used to measure the operation and performance of source
source code execution. These instruments only make measurements when the source code during the source code execution. These instruments only make measurements
code they instrument is run. when the source code they instrument is run.
All asynchronous instruments ([Int64ObservableCounter], All asynchronous instruments ([Int64ObservableCounter],
[Int64ObservableUpDownCounter], [Int64ObservableGauge], [Int64ObservableUpDownCounter], [Int64ObservableGauge],
[Float64ObservableCounter], [Float64ObservableUpDownCounter], [Float64ObservableCounter], [Float64ObservableUpDownCounter], and
[Float64ObservableGauge]) are used to measure metrics outside of the execution [Float64ObservableGauge]) are used to measure metrics outside of the execution
of source code. They are said to make "observations" via a callback function of source code. They are said to make "observations" via a callback function
called once every measurement collection cycle. called once every measurement collection cycle.
@@ -53,21 +53,54 @@ categories to use.
Outside of these two broad categories, instruments are described by the Outside of these two broad categories, instruments are described by the
function they are designed to serve. All Counters ([Int64Counter], function they are designed to serve. All Counters ([Int64Counter],
[Float64Counter], [Int64ObservableCounter], [Float64ObservableCounter]) are [Float64Counter], [Int64ObservableCounter], and [Float64ObservableCounter]) are
designed to measure values that never decrease in value, but instead only designed to measure values that never decrease in value, but instead only
incrementally increase in value. UpDownCounters ([Int64UpDownCounter], incrementally increase in value. UpDownCounters ([Int64UpDownCounter],
[Float64UpDownCounter], [Int64ObservableUpDownCounter], [Float64UpDownCounter], [Int64ObservableUpDownCounter], and
[Float64ObservableUpDownCounter]) on the other hand, are designed to measure [Float64ObservableUpDownCounter]) on the other hand, are designed to measure
values that can increase and decrease. When more information values that can increase and decrease. When more information needs to be
needs to be conveyed about all the synchronous measurements made during a conveyed about all the synchronous measurements made during a collection cycle,
collection cycle, a Histogram ([Int64Histogram], [Float64Histogram]) should be a Histogram ([Int64Histogram] and [Float64Histogram]) should be used. Finally,
used. Finally, when just the most recent measurement needs to be conveyed about an when just the most recent measurement needs to be conveyed about an
asynchronous measurement, a Gauge ([Int64ObservableGauge], asynchronous measurement, a Gauge ([Int64ObservableGauge] and
[Float64ObservableGauge]) should be used. [Float64ObservableGauge]) should be used.
See the [OpenTelemetry documentation] for more information about instruments See the [OpenTelemetry documentation] for more information about instruments
and their intended use. and their intended use.
# Measurements
Measurements are made by recording values and information about the values with
an instrument. How these measurements are recorded depends on the instrument.
Measurements for synchronous instruments ([Int64Counter], [Int64UpDownCounter],
[Int64Histogram], [Float64Counter], [Float64UpDownCounter], and
[Float64Histogram]) are recorded using the instrument methods directly. All
counter instruments have an Add method that is used to measure an increment
value, and all histogram instruments have a Record method to measure a data
point.
Asynchronous instruments ([Int64ObservableCounter],
[Int64ObservableUpDownCounter], [Int64ObservableGauge],
[Float64ObservableCounter], [Float64ObservableUpDownCounter], and
[Float64ObservableGauge]) record measurements within a callback function. The
callback is registered with the Meter which ensures the callback is called once
per collection cycle. A callback can be registered two ways: during the
instrument's creation using an option, or later using the RegisterCallback
method of the [Meter] that created the instrument.
If the following criteria are met, an option ([WithInt64Callback] or
[WithFloat64Callback]) can be used during the asynchronous instrument's
creation to register a callback ([Int64Callback] or [Float64Callback],
respectively):
- The measurement process is known when the instrument is created
- Only that instrument will make a measurement within the callback
- The callback never needs to be unregistered
If the criteria are not met, use the RegisterCallback method of the [Meter] that
created the instrument to register a [Callback].
# API Implementations # API Implementations
This package does not conform to the standard Go versioning policy, all of its This package does not conform to the standard Go versioning policy, all of its
@@ -116,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"
+26 -1
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 {
@@ -167,10 +173,29 @@ func (o unitOpt) applyInt64ObservableGauge(c Int64ObservableGaugeConfig) Int64Ob
} }
// WithUnit sets the instrument unit. // WithUnit sets the instrument unit.
//
// 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 a AddOption. // [MeasurementOption] for other options that can be used as an AddOption.
type AddOption interface { type AddOption interface {
applyAdd(AddConfig) AddConfig applyAdd(AddConfig) AddConfig
} }
-68
View File
@@ -1,68 +0,0 @@
// 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
//
// htmp://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 global // import "go.opentelemetry.io/otel/metric/internal/global"
import (
"errors"
"sync"
"sync/atomic"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/metric"
)
var (
globalMeterProvider = defaultMeterProvider()
delegateMeterOnce sync.Once
)
type meterProviderHolder struct {
mp metric.MeterProvider
}
// MeterProvider is the internal implementation for global.MeterProvider.
func MeterProvider() metric.MeterProvider {
return globalMeterProvider.Load().(meterProviderHolder).mp
}
// SetMeterProvider is the internal implementation for global.SetMeterProvider.
func SetMeterProvider(mp metric.MeterProvider) {
current := MeterProvider()
if _, cOk := current.(*meterProvider); cOk {
if _, mpOk := mp.(*meterProvider); mpOk && current == mp {
// Do not assign the default delegating MeterProvider to delegate
// to itself.
global.Error(
errors.New("no delegate configured in meter provider"),
"Setting meter provider to it's current value. No delegate will be configured",
)
return
}
}
delegateMeterOnce.Do(func() {
if def, ok := current.(*meterProvider); ok {
def.setDelegate(mp)
}
})
globalMeterProvider.Store(meterProviderHolder{mp: mp})
}
func defaultMeterProvider() *atomic.Value {
v := &atomic.Value{}
v.Store(meterProviderHolder{mp: &meterProvider{}})
return v
}
+94 -43
View File
@@ -27,6 +27,9 @@ import (
// package documentation on API implementation for information on how to set // package documentation on API implementation for information on how to set
// default behavior for unimplemented methods. // default behavior for unimplemented methods.
type MeterProvider interface { type MeterProvider 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.MeterProvider embedded.MeterProvider
// Meter returns a new Meter with the provided name and configuration. // Meter returns a new Meter with the provided name and configuration.
@@ -47,60 +50,100 @@ type MeterProvider interface {
// package documentation on API implementation for information on how to set // package documentation on API implementation for information on how to set
// default behavior for unimplemented methods. // default behavior for unimplemented methods.
type Meter interface { type Meter 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.Meter embedded.Meter
// Int64Counter returns a new instrument identified by name and configured // Int64Counter returns a new Int64Counter instrument identified by name
// with options. The instrument is used to synchronously record increasing // and configured with options. The instrument is used to synchronously
// int64 measurements during a computational operation. // record increasing int64 measurements during a computational operation.
Int64Counter(name string, options ...Int64CounterOption) (Int64Counter, error) Int64Counter(name string, options ...Int64CounterOption) (Int64Counter, error)
// Int64UpDownCounter returns a new instrument identified by name and // Int64UpDownCounter returns a new Int64UpDownCounter instrument
// configured with options. The instrument is used to synchronously record // identified by name and configured with options. The instrument is used
// int64 measurements during a computational operation. // to synchronously record int64 measurements during a computational
// operation.
Int64UpDownCounter(name string, options ...Int64UpDownCounterOption) (Int64UpDownCounter, error) Int64UpDownCounter(name string, options ...Int64UpDownCounterOption) (Int64UpDownCounter, error)
// Int64Histogram returns a new instrument identified by name and // Int64Histogram returns a new Int64Histogram instrument identified by
// configured with options. The instrument is used to synchronously record // name and configured with options. The instrument is used to
// the distribution of int64 measurements during a computational operation. // synchronously record the distribution of int64 measurements during a
// computational operation.
Int64Histogram(name string, options ...Int64HistogramOption) (Int64Histogram, error) Int64Histogram(name string, options ...Int64HistogramOption) (Int64Histogram, error)
// Int64ObservableCounter returns a new instrument identified by name and // Int64ObservableCounter returns a new Int64ObservableCounter identified
// configured with options. The instrument is used to asynchronously record // by name and configured with options. The instrument is used to
// increasing int64 measurements once per a measurement collection cycle. // asynchronously record increasing int64 measurements once per a
// measurement collection cycle.
//
// Measurements for the returned instrument are made via a callback. Use
// the WithInt64Callback option to register the callback here, or use the
// RegisterCallback method of this Meter to register one later. See the
// Measurements section of the package documentation for more information.
Int64ObservableCounter(name string, options ...Int64ObservableCounterOption) (Int64ObservableCounter, error) Int64ObservableCounter(name string, options ...Int64ObservableCounterOption) (Int64ObservableCounter, error)
// Int64ObservableUpDownCounter returns a new instrument identified by name // Int64ObservableUpDownCounter returns a new Int64ObservableUpDownCounter
// and configured with options. The instrument is used to asynchronously // instrument identified by name and configured with options. The
// record int64 measurements once per a measurement collection cycle. // instrument is used to asynchronously record int64 measurements once per
// a measurement collection cycle.
//
// Measurements for the returned instrument are made via a callback. Use
// the WithInt64Callback option to register the callback here, or use the
// RegisterCallback method of this Meter to register one later. See the
// Measurements section of the package documentation for more information.
Int64ObservableUpDownCounter(name string, options ...Int64ObservableUpDownCounterOption) (Int64ObservableUpDownCounter, error) Int64ObservableUpDownCounter(name string, options ...Int64ObservableUpDownCounterOption) (Int64ObservableUpDownCounter, error)
// Int64ObservableGauge returns a new instrument identified by name and // Int64ObservableGauge returns a new Int64ObservableGauge instrument
// configured with options. The instrument is used to asynchronously record // identified by name and configured with options. The instrument is used
// instantaneous int64 measurements once per a measurement collection // to asynchronously record instantaneous int64 measurements once per a
// cycle. // measurement collection cycle.
//
// Measurements for the returned instrument are made via a callback. Use
// the WithInt64Callback option to register the callback here, or use the
// RegisterCallback method of this Meter to register one later. See the
// Measurements section of the package documentation for more information.
Int64ObservableGauge(name string, options ...Int64ObservableGaugeOption) (Int64ObservableGauge, error) Int64ObservableGauge(name string, options ...Int64ObservableGaugeOption) (Int64ObservableGauge, error)
// Float64Counter returns a new instrument identified by name and // Float64Counter returns a new Float64Counter instrument identified by
// configured with options. The instrument is used to synchronously record
// increasing float64 measurements during a computational operation.
Float64Counter(name string, options ...Float64CounterOption) (Float64Counter, error)
// Float64UpDownCounter returns a new instrument identified by name and
// configured with options. The instrument is used to synchronously record
// float64 measurements during a computational operation.
Float64UpDownCounter(name string, options ...Float64UpDownCounterOption) (Float64UpDownCounter, error)
// Float64Histogram returns a new instrument identified by name and
// configured with options. The instrument is used to synchronously record
// the distribution of float64 measurements during a computational
// operation.
Float64Histogram(name string, options ...Float64HistogramOption) (Float64Histogram, error)
// Float64ObservableCounter returns a new instrument identified by name and
// configured with options. The instrument is used to asynchronously record
// increasing float64 measurements once per a measurement collection cycle.
Float64ObservableCounter(name string, options ...Float64ObservableCounterOption) (Float64ObservableCounter, error)
// Float64ObservableUpDownCounter returns a new instrument identified by
// name and configured with options. The instrument is used to // name and configured with options. The instrument is used to
// asynchronously record float64 measurements once per a measurement // synchronously record increasing float64 measurements during a
// collection cycle. // computational operation.
Float64ObservableUpDownCounter(name string, options ...Float64ObservableUpDownCounterOption) (Float64ObservableUpDownCounter, error) Float64Counter(name string, options ...Float64CounterOption) (Float64Counter, error)
// Float64ObservableGauge returns a new instrument identified by name and // Float64UpDownCounter returns a new Float64UpDownCounter instrument
// identified by name and configured with options. The instrument is used
// to synchronously record float64 measurements during a computational
// operation.
Float64UpDownCounter(name string, options ...Float64UpDownCounterOption) (Float64UpDownCounter, error)
// Float64Histogram returns a new Float64Histogram instrument identified by
// name and configured with options. The instrument is used to
// synchronously record the distribution of float64 measurements during a
// computational operation.
Float64Histogram(name string, options ...Float64HistogramOption) (Float64Histogram, error)
// Float64ObservableCounter returns a new Float64ObservableCounter
// instrument identified by name and configured with options. The
// instrument is used to asynchronously record increasing float64
// measurements once per a measurement collection cycle.
//
// Measurements for the returned instrument are made via a callback. Use
// the WithFloat64Callback option to register the callback here, or use the
// RegisterCallback method of this Meter to register one later. See the
// Measurements section of the package documentation for more information.
Float64ObservableCounter(name string, options ...Float64ObservableCounterOption) (Float64ObservableCounter, error)
// Float64ObservableUpDownCounter returns a new
// Float64ObservableUpDownCounter instrument identified by name and
// configured with options. The instrument is used to asynchronously record // configured with options. The instrument is used to asynchronously record
// instantaneous float64 measurements once per a measurement collection // float64 measurements once per a measurement collection cycle.
// cycle. //
// Measurements for the returned instrument are made via a callback. Use
// the WithFloat64Callback option to register the callback here, or use the
// RegisterCallback method of this Meter to register one later. See the
// Measurements section of the package documentation for more information.
Float64ObservableUpDownCounter(name string, options ...Float64ObservableUpDownCounterOption) (Float64ObservableUpDownCounter, error)
// Float64ObservableGauge returns a new Float64ObservableGauge instrument
// identified by name and configured with options. The instrument is used
// to asynchronously record instantaneous float64 measurements once per a
// measurement collection cycle.
//
// Measurements for the returned instrument are made via a callback. Use
// the WithFloat64Callback option to register the callback here, or use the
// RegisterCallback method of this Meter to register one later. See the
// Measurements section of the package documentation for more information.
Float64ObservableGauge(name string, options ...Float64ObservableGaugeOption) (Float64ObservableGauge, error) Float64ObservableGauge(name string, options ...Float64ObservableGaugeOption) (Float64ObservableGauge, error)
// RegisterCallback registers f to be called during the collection of a // RegisterCallback registers f to be called during the collection of a
@@ -114,6 +157,8 @@ type Meter interface {
// //
// If no instruments are passed, f should not be registered nor called // If no instruments are passed, f should not be registered nor called
// during collection. // during collection.
//
// The function f needs to be concurrent safe.
RegisterCallback(f Callback, instruments ...Observable) (Registration, error) RegisterCallback(f Callback, instruments ...Observable) (Registration, error)
} }
@@ -137,6 +182,9 @@ type Callback func(context.Context, Observer) error
// package documentation on API implementation for information on how to set // package documentation on API implementation for information on how to set
// default behavior for unimplemented methods. // default behavior for unimplemented methods.
type Observer interface { type Observer 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.Observer embedded.Observer
// ObserveFloat64 records the float64 value for obsrv. // ObserveFloat64 records the float64 value for obsrv.
@@ -152,6 +200,9 @@ type Observer interface {
// package documentation on API implementation for information on how to set // package documentation on API implementation for information on how to set
// default behavior for unimplemented methods. // default behavior for unimplemented methods.
type Registration interface { type Registration 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.Registration embedded.Registration
// Unregister removes the callback registration from a Meter. // Unregister removes the callback registration from a Meter.
+39 -16
View File
@@ -23,14 +23,19 @@ import (
// Float64Counter is an instrument that records increasing float64 values. // Float64Counter is an instrument that records increasing float64 values.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Float64Counter interface { type Float64Counter 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.Float64Counter embedded.Float64Counter
// Add records a change to the counter. // Add records a change to the counter.
Add(ctx context.Context, incr float64, opts ...AddOption) //
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Add(ctx context.Context, incr float64, options ...AddOption)
} }
// Float64CounterConfig contains options for synchronous counter instruments that // Float64CounterConfig contains options for synchronous counter instruments that
@@ -61,7 +66,8 @@ func (c Float64CounterConfig) Unit() string {
} }
// Float64CounterOption applies options to a [Float64CounterConfig]. See // Float64CounterOption applies options to a [Float64CounterConfig]. See
// [Option] for other options that can be used as a Float64CounterOption. // [InstrumentOption] for other options that can be used as a
// Float64CounterOption.
type Float64CounterOption interface { type Float64CounterOption interface {
applyFloat64Counter(Float64CounterConfig) Float64CounterConfig applyFloat64Counter(Float64CounterConfig) Float64CounterConfig
} }
@@ -70,14 +76,19 @@ type Float64CounterOption interface {
// float64 values. // float64 values.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Float64UpDownCounter interface { type Float64UpDownCounter 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.Float64UpDownCounter embedded.Float64UpDownCounter
// Add records a change to the counter. // Add records a change to the counter.
Add(ctx context.Context, incr float64, opts ...AddOption) //
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Add(ctx context.Context, incr float64, options ...AddOption)
} }
// Float64UpDownCounterConfig contains options for synchronous counter // Float64UpDownCounterConfig contains options for synchronous counter
@@ -108,8 +119,8 @@ func (c Float64UpDownCounterConfig) Unit() string {
} }
// Float64UpDownCounterOption applies options to a // Float64UpDownCounterOption applies options to a
// [Float64UpDownCounterConfig]. See [Option] for other options that can be // [Float64UpDownCounterConfig]. See [InstrumentOption] for other options that
// used as a Float64UpDownCounterOption. // can be used as a Float64UpDownCounterOption.
type Float64UpDownCounterOption interface { type Float64UpDownCounterOption interface {
applyFloat64UpDownCounter(Float64UpDownCounterConfig) Float64UpDownCounterConfig applyFloat64UpDownCounter(Float64UpDownCounterConfig) Float64UpDownCounterConfig
} }
@@ -118,14 +129,19 @@ type Float64UpDownCounterOption interface {
// values. // values.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Float64Histogram interface { type Float64Histogram 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.Float64Histogram embedded.Float64Histogram
// Record adds an additional value to the distribution. // Record adds an additional value to the distribution.
Record(ctx context.Context, incr float64, opts ...RecordOption) //
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Record(ctx context.Context, incr float64, options ...RecordOption)
} }
// Float64HistogramConfig contains options for synchronous counter instruments // Float64HistogramConfig contains options for synchronous counter instruments
@@ -133,6 +149,7 @@ type Float64Histogram interface {
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
@@ -155,8 +172,14 @@ 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
// [Option] for other options that can be used as a Float64HistogramOption. // [InstrumentOption] for other options that can be used as a
// Float64HistogramOption.
type Float64HistogramOption interface { type Float64HistogramOption interface {
applyFloat64Histogram(Float64HistogramConfig) Float64HistogramConfig applyFloat64Histogram(Float64HistogramConfig) Float64HistogramConfig
} }
+39 -16
View File
@@ -23,14 +23,19 @@ import (
// Int64Counter is an instrument that records increasing int64 values. // Int64Counter is an instrument that records increasing int64 values.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Int64Counter interface { type Int64Counter 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.Int64Counter embedded.Int64Counter
// Add records a change to the counter. // Add records a change to the counter.
Add(ctx context.Context, incr int64, opts ...AddOption) //
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Add(ctx context.Context, incr int64, options ...AddOption)
} }
// Int64CounterConfig contains options for synchronous counter instruments that // Int64CounterConfig contains options for synchronous counter instruments that
@@ -60,8 +65,9 @@ func (c Int64CounterConfig) Unit() string {
return c.unit return c.unit
} }
// Int64CounterOption applies options to a [Int64CounterConfig]. See [Option] // Int64CounterOption applies options to a [Int64CounterConfig]. See
// for other options that can be used as an Int64CounterOption. // [InstrumentOption] for other options that can be used as an
// Int64CounterOption.
type Int64CounterOption interface { type Int64CounterOption interface {
applyInt64Counter(Int64CounterConfig) Int64CounterConfig applyInt64Counter(Int64CounterConfig) Int64CounterConfig
} }
@@ -70,14 +76,19 @@ type Int64CounterOption interface {
// int64 values. // int64 values.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Int64UpDownCounter interface { type Int64UpDownCounter 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.Int64UpDownCounter embedded.Int64UpDownCounter
// Add records a change to the counter. // Add records a change to the counter.
Add(ctx context.Context, incr int64, opts ...AddOption) //
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Add(ctx context.Context, incr int64, options ...AddOption)
} }
// Int64UpDownCounterConfig contains options for synchronous counter // Int64UpDownCounterConfig contains options for synchronous counter
@@ -108,7 +119,7 @@ func (c Int64UpDownCounterConfig) Unit() string {
} }
// Int64UpDownCounterOption applies options to a [Int64UpDownCounterConfig]. // Int64UpDownCounterOption applies options to a [Int64UpDownCounterConfig].
// See [Option] for other options that can be used as an // See [InstrumentOption] for other options that can be used as an
// Int64UpDownCounterOption. // Int64UpDownCounterOption.
type Int64UpDownCounterOption interface { type Int64UpDownCounterOption interface {
applyInt64UpDownCounter(Int64UpDownCounterConfig) Int64UpDownCounterConfig applyInt64UpDownCounter(Int64UpDownCounterConfig) Int64UpDownCounterConfig
@@ -118,14 +129,19 @@ type Int64UpDownCounterOption interface {
// values. // values.
// //
// Warning: Methods may be added to this interface in minor releases. See // Warning: Methods may be added to this interface in minor releases. See
// [go.opentelemetry.io/otel/metric] package documentation on API // package documentation on API implementation for information on how to set
// implementation for information on how to set default behavior for // default behavior for unimplemented methods.
// unimplemented methods.
type Int64Histogram interface { type Int64Histogram 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.Int64Histogram embedded.Int64Histogram
// Record adds an additional value to the distribution. // Record adds an additional value to the distribution.
Record(ctx context.Context, incr int64, opts ...RecordOption) //
// Use the WithAttributeSet (or, if performance is not a concern,
// the WithAttributes) option to include measurement attributes.
Record(ctx context.Context, incr int64, options ...RecordOption)
} }
// Int64HistogramConfig contains options for synchronous counter instruments // Int64HistogramConfig contains options for synchronous counter instruments
@@ -133,6 +149,7 @@ type Int64Histogram interface {
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
@@ -155,8 +172,14 @@ 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
// [Option] for other options that can be used as an Int64HistogramOption. // [InstrumentOption] for other options that can be used as an
// Int64HistogramOption.
type Int64HistogramOption interface { type Int64HistogramOption interface {
applyInt64Histogram(Int64HistogramConfig) Int64HistogramConfig applyInt64Histogram(Int64HistogramConfig) Int64HistogramConfig
} }
+4 -2
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) {
+1
View File
@@ -0,0 +1 @@
codespell==2.2.6
+1
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
+64
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"
+56
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() }
+7 -3
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{}
+33 -7
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.
+24 -14
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
+1 -1
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.15.0" return "1.20.0"
} }
+9 -11
View File
@@ -14,43 +14,41 @@
module-sets: module-sets:
stable-v1: stable-v1:
version: v1.15.0 version: v1.20.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/fib - go.opentelemetry.io/otel/example/fib
- go.opentelemetry.io/otel/example/jaeger
- 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
- go.opentelemetry.io/otel/example/zipkin - go.opentelemetry.io/otel/example/zipkin
- go.opentelemetry.io/otel/exporters/jaeger
- go.opentelemetry.io/otel/exporters/otlp/internal/retry
- go.opentelemetry.io/otel/exporters/otlp/otlptrace - go.opentelemetry.io/otel/exporters/otlp/otlptrace
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
- go.opentelemetry.io/otel/exporters/stdout/stdouttrace - go.opentelemetry.io/otel/exporters/stdout/stdouttrace
- go.opentelemetry.io/otel/exporters/zipkin - go.opentelemetry.io/otel/exporters/zipkin
- go.opentelemetry.io/otel/metric
- go.opentelemetry.io/otel/sdk - go.opentelemetry.io/otel/sdk
- go.opentelemetry.io/otel/sdk/metric
- go.opentelemetry.io/otel/trace - go.opentelemetry.io/otel/trace
experimental-metrics: experimental-metrics:
version: v0.38.0 version: v0.43.0
modules: modules:
- go.opentelemetry.io/otel/bridge/opencensus
- 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
- 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
- go.opentelemetry.io/otel/exporters/stdout/stdoutmetric - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric
- go.opentelemetry.io/otel/metric
- go.opentelemetry.io/otel/sdk/metric
- go.opentelemetry.io/otel/bridge/opencensus
- go.opentelemetry.io/otel/bridge/opencensus/test
- go.opentelemetry.io/otel/example/view
experimental-schema: experimental-schema:
version: v0.0.4 version: v0.0.7
modules: modules:
- go.opentelemetry.io/otel/schema - go.opentelemetry.io/otel/schema
excluded-modules: excluded-modules:
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.7 //go:build go1.7
// +build go1.7
package context package context
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.9 //go:build go1.9
// +build go1.9
package context package context
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.7 //go:build !go1.7
// +build !go1.7
package context package context
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.9 //go:build !go1.9
// +build !go1.9
package context package context
+30 -27
View File
@@ -20,42 +20,45 @@ import (
// TODO: Benchmark to determine if the pools are necessary. The GC may have // TODO: Benchmark to determine if the pools are necessary. The GC may have
// improved enough that we can instead allocate chunks like this: // improved enough that we can instead allocate chunks like this:
// make([]byte, max(16<<10, expectedBytesRemaining)) // make([]byte, max(16<<10, expectedBytesRemaining))
var ( var dataChunkPools = [...]sync.Pool{
dataChunkSizeClasses = []int{ {New: func() interface{} { return new([1 << 10]byte) }},
1 << 10, {New: func() interface{} { return new([2 << 10]byte) }},
2 << 10, {New: func() interface{} { return new([4 << 10]byte) }},
4 << 10, {New: func() interface{} { return new([8 << 10]byte) }},
8 << 10, {New: func() interface{} { return new([16 << 10]byte) }},
16 << 10,
} }
dataChunkPools = [...]sync.Pool{
{New: func() interface{} { return make([]byte, 1<<10) }},
{New: func() interface{} { return make([]byte, 2<<10) }},
{New: func() interface{} { return make([]byte, 4<<10) }},
{New: func() interface{} { return make([]byte, 8<<10) }},
{New: func() interface{} { return make([]byte, 16<<10) }},
}
)
func getDataBufferChunk(size int64) []byte { func getDataBufferChunk(size int64) []byte {
i := 0 switch {
for ; i < len(dataChunkSizeClasses)-1; i++ { case size <= 1<<10:
if size <= int64(dataChunkSizeClasses[i]) { return dataChunkPools[0].Get().(*[1 << 10]byte)[:]
break case size <= 2<<10:
return dataChunkPools[1].Get().(*[2 << 10]byte)[:]
case size <= 4<<10:
return dataChunkPools[2].Get().(*[4 << 10]byte)[:]
case size <= 8<<10:
return dataChunkPools[3].Get().(*[8 << 10]byte)[:]
default:
return dataChunkPools[4].Get().(*[16 << 10]byte)[:]
} }
} }
return dataChunkPools[i].Get().([]byte)
}
func putDataBufferChunk(p []byte) { func putDataBufferChunk(p []byte) {
for i, n := range dataChunkSizeClasses { switch len(p) {
if len(p) == n { case 1 << 10:
dataChunkPools[i].Put(p) dataChunkPools[0].Put((*[1 << 10]byte)(p))
return case 2 << 10:
} dataChunkPools[1].Put((*[2 << 10]byte)(p))
} case 4 << 10:
dataChunkPools[2].Put((*[4 << 10]byte)(p))
case 8 << 10:
dataChunkPools[3].Put((*[8 << 10]byte)(p))
case 16 << 10:
dataChunkPools[4].Put((*[16 << 10]byte)(p))
default:
panic(fmt.Sprintf("unexpected buffer len=%v", len(p))) panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
} }
}
// dataBuffer is an io.ReadWriter backed by a list of data chunks. // dataBuffer is an io.ReadWriter backed by a list of data chunks.
// Each dataBuffer is used to read DATA frames on a single stream. // Each dataBuffer is used to read DATA frames on a single stream.
-30
View File
@@ -1,30 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.11
// +build go1.11
package http2
import (
"net/http/httptrace"
"net/textproto"
)
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
return trace != nil && trace.WroteHeaderField != nil
}
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
if trace != nil && trace.WroteHeaderField != nil {
trace.WroteHeaderField(k, []string{v})
}
}
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
if trace != nil {
return trace.Got1xxResponse
}
return nil
}
-27
View File
@@ -1,27 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.15
// +build go1.15
package http2
import (
"context"
"crypto/tls"
)
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
// connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
dialer := &tls.Dialer{
Config: cfg,
}
cn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
return tlsCn, nil
}
-17
View File
@@ -1,17 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.18
// +build go1.18
package http2
import (
"crypto/tls"
"net"
)
func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
return tc.NetConn()
}
-21
View File
@@ -1,21 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.11
// +build !go1.11
package http2
import (
"net/http/httptrace"
"net/textproto"
)
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { return false }
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {}
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
return nil
}
-31
View File
@@ -1,31 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.15
// +build !go1.15
package http2
import (
"context"
"crypto/tls"
)
// dialTLSWithContext opens a TLS connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
cn, err := tls.Dial(network, addr, cfg)
if err != nil {
return nil, err
}
if err := cn.Handshake(); err != nil {
return nil, err
}
if cfg.InsecureSkipVerify {
return cn, nil
}
if err := cn.VerifyHostname(cfg.ServerName); err != nil {
return nil, err
}
return cn, nil
}
-17
View File
@@ -1,17 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.18
// +build !go1.18
package http2
import (
"crypto/tls"
"net"
)
func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
return nil
}
+3 -19
View File
@@ -2549,7 +2549,6 @@ type responseWriterState struct {
wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet. wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet.
sentHeader bool // have we sent the header frame? sentHeader bool // have we sent the header frame?
handlerDone bool // handler has finished handlerDone bool // handler has finished
dirty bool // a Write failed; don't reuse this responseWriterState
sentContentLen int64 // non-zero if handler set a Content-Length header sentContentLen int64 // non-zero if handler set a Content-Length header
wroteBytes int64 wroteBytes int64
@@ -2669,7 +2668,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
date: date, date: date,
}) })
if err != nil { if err != nil {
rws.dirty = true
return 0, err return 0, err
} }
if endStream { if endStream {
@@ -2690,7 +2688,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
if len(p) > 0 || endStream { if len(p) > 0 || endStream {
// only send a 0 byte DATA frame if we're ending the stream. // only send a 0 byte DATA frame if we're ending the stream.
if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil { if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
rws.dirty = true
return 0, err return 0, err
} }
} }
@@ -2702,9 +2699,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
trailers: rws.trailers, trailers: rws.trailers,
endStream: true, endStream: true,
}) })
if err != nil {
rws.dirty = true
}
return len(p), err return len(p), err
} }
return len(p), nil return len(p), nil
@@ -2920,14 +2914,12 @@ func (rws *responseWriterState) writeHeader(code int) {
h.Del("Transfer-Encoding") h.Del("Transfer-Encoding")
} }
if rws.conn.writeHeaders(rws.stream, &writeResHeaders{ rws.conn.writeHeaders(rws.stream, &writeResHeaders{
streamID: rws.stream.id, streamID: rws.stream.id,
httpResCode: code, httpResCode: code,
h: h, h: h,
endStream: rws.handlerDone && !rws.hasTrailers(), endStream: rws.handlerDone && !rws.hasTrailers(),
}) != nil { })
rws.dirty = true
}
return return
} }
@@ -2992,20 +2984,11 @@ func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int,
func (w *responseWriter) handlerDone() { func (w *responseWriter) handlerDone() {
rws := w.rws rws := w.rws
dirty := rws.dirty
rws.handlerDone = true rws.handlerDone = true
w.Flush() w.Flush()
w.rws = nil w.rws = nil
if !dirty {
// Only recycle the pool if all prior Write calls to
// the serverConn goroutine completed successfully. If
// they returned earlier due to resets from the peer
// there might still be write goroutines outstanding
// from the serverConn referencing the rws memory. See
// issue 20704.
responseWriterStatePool.Put(rws) responseWriterStatePool.Put(rws)
} }
}
// Push errors. // Push errors.
var ( var (
@@ -3187,6 +3170,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err)) panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
} }
sc.curHandlers++
go sc.runHandler(rw, req, sc.handler.ServeHTTP) go sc.runHandler(rw, req, sc.handler.ServeHTTP)
return promisedID, nil return promisedID, nil
} }
+32 -1
View File
@@ -1018,7 +1018,7 @@ func (cc *ClientConn) forceCloseConn() {
if !ok { if !ok {
return return
} }
if nc := tlsUnderlyingConn(tc); nc != nil { if nc := tc.NetConn(); nc != nil {
nc.Close() nc.Close()
} }
} }
@@ -3201,3 +3201,34 @@ func traceFirstResponseByte(trace *httptrace.ClientTrace) {
trace.GotFirstResponseByte() trace.GotFirstResponseByte()
} }
} }
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
return trace != nil && trace.WroteHeaderField != nil
}
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
if trace != nil && trace.WroteHeaderField != nil {
trace.WroteHeaderField(k, []string{v})
}
}
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
if trace != nil {
return trace.Got1xxResponse
}
return nil
}
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
// connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
dialer := &tls.Dialer{
Config: cfg,
}
cn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
return tlsCn, nil
}
-1
View File
@@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.18 //go:build go1.18
// +build go1.18
package idna package idna
-1
View File
@@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.10 //go:build go1.10
// +build go1.10
// Package idna implements IDNA2008 using the compatibility processing // Package idna implements IDNA2008 using the compatibility processing
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to // defined by UTS (Unicode Technical Standard) #46, which defines a standard to
-1
View File
@@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.10 //go:build !go1.10
// +build !go1.10
// Package idna implements IDNA2008 using the compatibility processing // Package idna implements IDNA2008 using the compatibility processing
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to // defined by UTS (Unicode Technical Standard) #46, which defines a standard to
-1
View File
@@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.18 //go:build !go1.18
// +build !go1.18
package idna package idna
-1
View File
@@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.10 && !go1.13 //go:build go1.10 && !go1.13
// +build go1.10,!go1.13
package idna package idna
-1
View File
@@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.13 && !go1.14 //go:build go1.13 && !go1.14
// +build go1.13,!go1.14
package idna package idna
-1
View File
@@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.14 && !go1.16 //go:build go1.14 && !go1.16
// +build go1.14,!go1.16
package idna package idna
-1
View File
@@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.16 && !go1.21 //go:build go1.16 && !go1.21
// +build go1.16,!go1.21
package idna package idna
-1
View File
@@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21 //go:build go1.21
// +build go1.21
package idna package idna
-1
View File
@@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build !go1.10 //go:build !go1.10
// +build !go1.10
package idna package idna
-1
View File
@@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.16 //go:build !go1.16
// +build !go1.16
package idna package idna
-1
View File
@@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.16 //go:build go1.16
// +build go1.16
package idna package idna
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.5 //go:build go1.5
// +build go1.5
package plan9 package plan9
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.5 //go:build !go1.5
// +build !go1.5
package plan9 package plan9
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build plan9 && race //go:build plan9 && race
// +build plan9,race
package plan9 package plan9
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build plan9 && !race //go:build plan9 && !race
// +build plan9,!race
package plan9 package plan9
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build plan9 //go:build plan9
// +build plan9
package plan9 package plan9
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build plan9 //go:build plan9
// +build plan9
// Package plan9 contains an interface to the low-level operating system // Package plan9 contains an interface to the low-level operating system
// primitives. OS details vary depending on the underlying system, and // primitives. OS details vary depending on the underlying system, and
-1
View File
@@ -2,7 +2,6 @@
// Code generated by the command above; see README.md. DO NOT EDIT. // Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && 386 //go:build plan9 && 386
// +build plan9,386
package plan9 package plan9
-1
View File
@@ -2,7 +2,6 @@
// Code generated by the command above; see README.md. DO NOT EDIT. // Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && amd64 //go:build plan9 && amd64
// +build plan9,amd64
package plan9 package plan9
-1
View File
@@ -2,7 +2,6 @@
// Code generated by the command above; see README.md. DO NOT EDIT. // Code generated by the command above; see README.md. DO NOT EDIT.
//go:build plan9 && arm //go:build plan9 && arm
// +build plan9,arm
package plan9 package plan9
-2
View File
@@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9 //go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
// +build go1.9
package unix package unix
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
#include "textflag.h" #include "textflag.h"
-2
View File
@@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (freebsd || netbsd || openbsd) && gc //go:build (freebsd || netbsd || openbsd) && gc
// +build freebsd netbsd openbsd
// +build gc
#include "textflag.h" #include "textflag.h"

Some files were not shown because too many files have changed in this diff Show More