Support OTEL_PROPAGATORS to configure tracing propagation
Co-authored-by: Romain <rtribotte@users.noreply.github.com>
This commit is contained in:
parent
5a2e233a15
commit
baf687218c
6 changed files with 288 additions and 45 deletions
|
@ -30,6 +30,23 @@ tracing:
|
||||||
By default, the OpenTelemetry trace exporter will sample 100% of traces.
|
By default, the OpenTelemetry trace exporter will sample 100% of traces.
|
||||||
See [OpenTelemetry's SDK configuration](https://opentelemetry.io/docs/reference/specification/sdk-environment-variables/#general-sdk-configuration) to customize the sampling strategy.
|
See [OpenTelemetry's SDK configuration](https://opentelemetry.io/docs/reference/specification/sdk-environment-variables/#general-sdk-configuration) to customize the sampling strategy.
|
||||||
|
|
||||||
|
!!! info "Propagation"
|
||||||
|
|
||||||
|
Traefik supports the `OTEL_PROPAGATORS` env variable to set up the propragators. The supported propagators are:
|
||||||
|
|
||||||
|
- tracecontext (default)
|
||||||
|
- baggage (default)
|
||||||
|
- b3
|
||||||
|
- b3multi
|
||||||
|
- jaeger
|
||||||
|
- xray
|
||||||
|
- ottrace
|
||||||
|
|
||||||
|
Example of configuration:
|
||||||
|
|
||||||
|
OTEL_PROPAGATORS=b3,jaeger
|
||||||
|
|
||||||
|
|
||||||
### HTTP configuration
|
### HTTP configuration
|
||||||
|
|
||||||
_Optional_
|
_Optional_
|
||||||
|
|
15
go.mod
15
go.mod
|
@ -67,16 +67,17 @@ require (
|
||||||
github.com/vulcand/oxy/v2 v2.0.0-20230427132221-be5cf38f3c1c
|
github.com/vulcand/oxy/v2 v2.0.0-20230427132221-be5cf38f3c1c
|
||||||
github.com/vulcand/predicate v1.2.0
|
github.com/vulcand/predicate v1.2.0
|
||||||
go.opentelemetry.io/collector/pdata v0.66.0
|
go.opentelemetry.io/collector/pdata v0.66.0
|
||||||
go.opentelemetry.io/otel v1.21.0
|
go.opentelemetry.io/contrib/propagators/autoprop v0.48.0
|
||||||
|
go.opentelemetry.io/otel v1.23.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
|
||||||
go.opentelemetry.io/otel/metric v1.21.0
|
go.opentelemetry.io/otel/metric v1.23.0
|
||||||
go.opentelemetry.io/otel/sdk v1.21.0
|
go.opentelemetry.io/otel/sdk v1.23.0
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.21.0
|
go.opentelemetry.io/otel/sdk/metric v1.21.0
|
||||||
go.opentelemetry.io/otel/trace v1.21.0
|
go.opentelemetry.io/otel/trace v1.23.0
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
|
||||||
golang.org/x/mod v0.14.0
|
golang.org/x/mod v0.14.0
|
||||||
golang.org/x/net v0.20.0
|
golang.org/x/net v0.20.0
|
||||||
|
@ -173,7 +174,7 @@ require (
|
||||||
github.com/go-errors/errors v1.0.1 // indirect
|
github.com/go-errors/errors v1.0.1 // indirect
|
||||||
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
|
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||||
github.com/go-logr/logr v1.3.0 // indirect
|
github.com/go-logr/logr v1.4.1 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||||
|
@ -308,6 +309,10 @@ require (
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
|
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
|
||||||
go.etcd.io/etcd/client/v3 v3.5.9 // indirect
|
go.etcd.io/etcd/client/v3 v3.5.9 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/propagators/aws v1.23.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/propagators/b3 v1.23.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/propagators/jaeger v1.23.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/propagators/ot v1.23.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.uber.org/mock v0.3.0 // indirect
|
go.uber.org/mock v0.3.0 // indirect
|
||||||
|
|
30
go.sum
30
go.sum
|
@ -355,8 +355,8 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV
|
||||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||||
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.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.1/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-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||||
|
@ -1178,8 +1178,18 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
go.opentelemetry.io/collector/pdata v0.66.0 h1:UdE5U6MsDNzuiWaXdjGx2lC3ElVqWmN/hiUE8vyvSuM=
|
go.opentelemetry.io/collector/pdata v0.66.0 h1:UdE5U6MsDNzuiWaXdjGx2lC3ElVqWmN/hiUE8vyvSuM=
|
||||||
go.opentelemetry.io/collector/pdata v0.66.0/go.mod h1:pqyaznLzk21m+1KL6fwOsRryRELL+zNM0qiVSn0MbVc=
|
go.opentelemetry.io/collector/pdata v0.66.0/go.mod h1:pqyaznLzk21m+1KL6fwOsRryRELL+zNM0qiVSn0MbVc=
|
||||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
go.opentelemetry.io/contrib/propagators/autoprop v0.48.0 h1:sBPzh/5mNVo4yknFgh0iTezFeljhV8FO9mcj79LsdOg=
|
||||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
go.opentelemetry.io/contrib/propagators/autoprop v0.48.0/go.mod h1:Ij+STHaLubeiNHJVgYaRU8XPI1Y7DmlMq0HwJboIc1k=
|
||||||
|
go.opentelemetry.io/contrib/propagators/aws v1.23.0 h1:pY2NxI5WwbvuUXSnqahpjqdZrA1JI/elKCGwElimPWA=
|
||||||
|
go.opentelemetry.io/contrib/propagators/aws v1.23.0/go.mod h1:4sNW/xRJ8qpkj7AnStkrjJu0lBQjgiuW4rpEpRfY+dw=
|
||||||
|
go.opentelemetry.io/contrib/propagators/b3 v1.23.0 h1:aaIGWc5JdfRGpCafLRxMJbD65MfTa206AwSKkvGS0Hg=
|
||||||
|
go.opentelemetry.io/contrib/propagators/b3 v1.23.0/go.mod h1:Gyz7V7XghvwTq+mIhLFlTgcc03UDroOg8vezs4NLhwU=
|
||||||
|
go.opentelemetry.io/contrib/propagators/jaeger v1.23.0 h1:KFxfTCTkH1usVFzDaWzbmNdFX7ybUTCtkLsUTww0nG4=
|
||||||
|
go.opentelemetry.io/contrib/propagators/jaeger v1.23.0/go.mod h1:xU+81opGquQICJGzwscLXAQLnIPWI+q7Zu4AQSrgXf8=
|
||||||
|
go.opentelemetry.io/contrib/propagators/ot v1.23.0 h1:JCvB5Mg4bPR57nuKbENxzCsUAlTwVggCsLdew3mqyoU=
|
||||||
|
go.opentelemetry.io/contrib/propagators/ot v1.23.0/go.mod h1:cO0XToAIUsLnIJrrN0jVFH4fJvZPlHvZfsPrcfPwQdg=
|
||||||
|
go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E=
|
||||||
|
go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 h1:bflGWrfYyuulcdxf14V6n9+CoQcu5SAAdHmDPAJnlps=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 h1:bflGWrfYyuulcdxf14V6n9+CoQcu5SAAdHmDPAJnlps=
|
||||||
|
@ -1190,14 +1200,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqhe
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
|
||||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo=
|
||||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo=
|
||||||
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
|
go.opentelemetry.io/otel/sdk v1.23.0 h1:0KM9Zl2esnl+WSukEmlaAEjVY5HDZANOHferLq36BPc=
|
||||||
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
|
go.opentelemetry.io/otel/sdk v1.23.0/go.mod h1:wUscup7byToqyKJSilEtMf34FgdCAsFpFOjXnAwFfO0=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0=
|
go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q=
|
go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q=
|
||||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI=
|
||||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"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/propagation"
|
|
||||||
"go.opentelemetry.io/otel/sdk/resource"
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||||
|
@ -82,7 +81,6 @@ func (c *Config) Setup(serviceName string, sampleRate float64, globalAttributes
|
||||||
)
|
)
|
||||||
|
|
||||||
otel.SetTracerProvider(tracerProvider)
|
otel.SetTracerProvider(tracerProvider)
|
||||||
otel.SetTextMapPropagator(propagation.TraceContext{})
|
|
||||||
|
|
||||||
log.Debug().Msg("OpenTelemetry tracer configured")
|
log.Debug().Msg("OpenTelemetry tracer configured")
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,9 @@ import (
|
||||||
func TestTracing(t *testing.T) {
|
func TestTracing(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
propagators string
|
||||||
headers map[string]string
|
headers map[string]string
|
||||||
|
wantServiceHeadersFn func(t *testing.T, headers http.Header)
|
||||||
assertFn func(*testing.T, string)
|
assertFn func(*testing.T, string)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -37,11 +39,18 @@ func TestTracing(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "context propagation",
|
desc: "TraceContext propagation",
|
||||||
|
propagators: "tracecontext",
|
||||||
headers: map[string]string{
|
headers: map[string]string{
|
||||||
"traceparent": "00-00000000000000000000000000000001-0000000000000001-01",
|
"traceparent": "00-00000000000000000000000000000001-0000000000000001-01",
|
||||||
"tracestate": "foo=bar",
|
"tracestate": "foo=bar",
|
||||||
},
|
},
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(00-00000000000000000000000000000001-\w{16}-01)`, headers["Traceparent"][0])
|
||||||
|
assert.Equal(t, []string{"foo=bar"}, headers["Tracestate"])
|
||||||
|
},
|
||||||
assertFn: func(t *testing.T, trace string) {
|
assertFn: func(t *testing.T, trace string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
@ -50,6 +59,188 @@ func TestTracing(t *testing.T) {
|
||||||
assert.Regexp(t, `("traceState":"foo=bar")`, trace)
|
assert.Regexp(t, `("traceState":"foo=bar")`, trace)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "root span TraceContext propagation",
|
||||||
|
propagators: "tracecontext",
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(00-\w{32}-\w{16}-01)`, headers["Traceparent"][0])
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "B3 propagation",
|
||||||
|
propagators: "b3",
|
||||||
|
headers: map[string]string{
|
||||||
|
"b3": "00000000000000000000000000000001-0000000000000002-1-0000000000000001",
|
||||||
|
},
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(00000000000000000000000000000001-\w{16}-1)`, headers["B3"][0])
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"0000000000000002")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "root span B3 propagation",
|
||||||
|
propagators: "b3",
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(\w{32}-\w{16}-1)`, headers["B3"][0])
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "B3 propagation Multiple Headers",
|
||||||
|
propagators: "b3multi",
|
||||||
|
headers: map[string]string{
|
||||||
|
"x-b3-traceid": "00000000000000000000000000000001",
|
||||||
|
"x-b3-parentspanid": "0000000000000001",
|
||||||
|
"x-b3-spanid": "0000000000000002",
|
||||||
|
"x-b3-sampled": "1",
|
||||||
|
},
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, "00000000000000000000000000000001", headers["X-B3-Traceid"][0])
|
||||||
|
assert.Equal(t, "0000000000000001", headers["X-B3-Parentspanid"][0])
|
||||||
|
assert.Equal(t, "1", headers["X-B3-Sampled"][0])
|
||||||
|
assert.Len(t, headers["X-B3-Spanid"][0], 16)
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"0000000000000002")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "root span B3 propagation Multiple Headers",
|
||||||
|
propagators: "b3multi",
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(\w{32})`, headers["X-B3-Traceid"][0])
|
||||||
|
assert.Equal(t, "1", headers["X-B3-Sampled"][0])
|
||||||
|
assert.Regexp(t, `(\w{16})`, headers["X-B3-Spanid"][0])
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Baggage propagation",
|
||||||
|
propagators: "baggage",
|
||||||
|
headers: map[string]string{
|
||||||
|
"baggage": "userId=id",
|
||||||
|
},
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, []string{"userId=id"}, headers["Baggage"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Jaeger propagation",
|
||||||
|
propagators: "jaeger",
|
||||||
|
headers: map[string]string{
|
||||||
|
"uber-trace-id": "00000000000000000000000000000001:0000000000000002:0000000000000001:1",
|
||||||
|
},
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(00000000000000000000000000000001:\w{16}:0:1)`, headers["Uber-Trace-Id"][0])
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "root span Jaeger propagation",
|
||||||
|
propagators: "jaeger",
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(\w{32}:\w{16}:0:1)`, headers["Uber-Trace-Id"][0])
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "XRay propagation",
|
||||||
|
propagators: "xray",
|
||||||
|
headers: map[string]string{
|
||||||
|
"X-Amzn-Trace-Id": "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1",
|
||||||
|
},
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(Root=1-5759e988-bd862e3fe1be46a994272793;Parent=\w{16};Sampled=1)`, headers["X-Amzn-Trace-Id"][0])
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"5759e988bd862e3fe1be46a994272793")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "root span XRay propagation",
|
||||||
|
propagators: "xray",
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `(Root=1-\w{8}-\w{24};Parent=\w{16};Sampled=1)`, headers["X-Amzn-Trace-Id"][0])
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "no propagation",
|
||||||
|
propagators: "none",
|
||||||
|
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Empty(t, headers)
|
||||||
|
},
|
||||||
|
assertFn: func(t *testing.T, trace string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||||
|
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
traceCh := make(chan string)
|
traceCh := make(chan string)
|
||||||
|
@ -71,6 +262,24 @@ func TestTracing(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
t.Cleanup(collector.Close)
|
t.Cleanup(collector.Close)
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Setenv("OTEL_PROPAGATORS", test.propagators)
|
||||||
|
|
||||||
|
service := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tracer := tracing.TracerFromContext(r.Context())
|
||||||
|
ctx, span := tracer.Start(r.Context(), "service")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
|
tracing.InjectContextIntoCarrier(r)
|
||||||
|
|
||||||
|
if test.wantServiceHeadersFn != nil {
|
||||||
|
test.wantServiceHeadersFn(t, r.Header)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
tracingConfig := &static.Tracing{
|
tracingConfig := &static.Tracing{
|
||||||
ServiceName: "traefik",
|
ServiceName: "traefik",
|
||||||
SampleRate: 1.0,
|
SampleRate: 1.0,
|
||||||
|
@ -88,11 +297,9 @@ func TestTracing(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
chain := alice.New(tracingMiddle.WrapEntryPointHandler(context.Background(), newTracing, "test"))
|
chain := alice.New(tracingMiddle.WrapEntryPointHandler(context.Background(), newTracing, "test"))
|
||||||
epHandler, err := chain.Then(http.NotFoundHandler())
|
epHandler, err := chain.Then(service)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "http://www.test.com", nil)
|
req := httptest.NewRequest(http.MethodGet, "http://www.test.com", nil)
|
||||||
for k, v := range test.headers {
|
for k, v := range test.headers {
|
||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
|
@ -107,9 +314,11 @@ func TestTracing(t *testing.T) {
|
||||||
t.Error("Trace not exported")
|
t.Error("Trace not exported")
|
||||||
|
|
||||||
case trace := <-traceCh:
|
case trace := <-traceCh:
|
||||||
assert.Equal(t, http.StatusNotFound, rw.Code)
|
assert.Equal(t, http.StatusOK, rw.Code)
|
||||||
|
if test.assertFn != nil {
|
||||||
test.assertFn(t, trace)
|
test.assertFn(t, trace)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||||
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
|
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
|
||||||
|
"go.opentelemetry.io/contrib/propagators/autoprop"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"go.opentelemetry.io/otel/codes"
|
"go.opentelemetry.io/otel/codes"
|
||||||
"go.opentelemetry.io/otel/propagation"
|
"go.opentelemetry.io/otel/propagation"
|
||||||
|
@ -37,6 +39,8 @@ func NewTracing(conf *static.Tracing) (trace.Tracer, io.Closer, error) {
|
||||||
backend = defaultBackend
|
backend = defaultBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
otel.SetTextMapPropagator(autoprop.NewTextMapPropagator())
|
||||||
|
|
||||||
return backend.Setup(conf.ServiceName, conf.SampleRate, conf.GlobalAttributes)
|
return backend.Setup(conf.ServiceName, conf.SampleRate, conf.GlobalAttributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,13 +61,13 @@ func TracerFromContext(ctx context.Context) trace.Tracer {
|
||||||
|
|
||||||
// ExtractCarrierIntoContext reads cross-cutting concerns from the carrier into a Context.
|
// ExtractCarrierIntoContext reads cross-cutting concerns from the carrier into a Context.
|
||||||
func ExtractCarrierIntoContext(ctx context.Context, headers http.Header) context.Context {
|
func ExtractCarrierIntoContext(ctx context.Context, headers http.Header) context.Context {
|
||||||
propagator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
|
propagator := otel.GetTextMapPropagator()
|
||||||
return propagator.Extract(ctx, propagation.HeaderCarrier(headers))
|
return propagator.Extract(ctx, propagation.HeaderCarrier(headers))
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectContextIntoCarrier sets cross-cutting concerns from the request context into the request headers.
|
// InjectContextIntoCarrier sets cross-cutting concerns from the request context into the request headers.
|
||||||
func InjectContextIntoCarrier(req *http.Request) {
|
func InjectContextIntoCarrier(req *http.Request) {
|
||||||
propagator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
|
propagator := otel.GetTextMapPropagator()
|
||||||
propagator.Inject(req.Context(), propagation.HeaderCarrier(req.Header))
|
propagator.Inject(req.Context(), propagation.HeaderCarrier(req.Header))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue